From f7b3ef0c46e03734e8917679ddc3cfc1d9cc6803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Mach?= <92859870+JMach1@users.noreply.github.com> Date: Mon, 22 Aug 2022 20:19:50 +0200 Subject: [PATCH] custom widgets df testing fixes (#1917) * displayName required * overrides handling - no longer valid override cleanup * customWidgetList refresh configs in constructor * listenForSecretsRequests managementApiUrl + ensureUrlArmified --- .../custom-widget-list/createWidget.html | 2 +- .../custom-widget-list/createWidget.ts | 2 + .../custom-widget-list/customWidgetList.ts | 13 +++-- .../loadCustomWidgetConfigs.ts | 50 +++++++++++-------- .../customWidget.design.module.ts | 2 +- .../customWidget.runtime.module.ts | 2 +- ...equests.ts => listenForSecretsRequests.ts} | 8 ++- 7 files changed, 51 insertions(+), 28 deletions(-) rename src/components/custom-widget/{ListenForSecretsRequests.ts => listenForSecretsRequests.ts} (86%) diff --git a/src/components/custom-widget-list/createWidget.html b/src/components/custom-widget-list/createWidget.html index a585c0375..dfb274a62 100644 --- a/src/components/custom-widget-list/createWidget.html +++ b/src/components/custom-widget-list/createWidget.html @@ -9,7 +9,7 @@ data-bind="textInput: displayName, validationElement: displayName, attr: {disabled: !!$component.config}" maxlength="2000" spellcheck="false" aria-required="true" /> - + diff --git a/src/components/custom-widget-list/createWidget.ts b/src/components/custom-widget-list/createWidget.ts index 030828e1e..240df24ca 100644 --- a/src/components/custom-widget-list/createWidget.ts +++ b/src/components/custom-widget-list/createWidget.ts @@ -52,6 +52,8 @@ export class CreateWidget { errorElementClass: "is-invalid", decorateInputElement: true }); + + this.displayName.extend({ required: { message: `Name is required.` } }); } @Param() diff --git a/src/components/custom-widget-list/customWidgetList.ts b/src/components/custom-widget-list/customWidgetList.ts index 523f9d589..a6fad9673 100644 --- a/src/components/custom-widget-list/customWidgetList.ts +++ b/src/components/custom-widget-list/customWidgetList.ts @@ -5,6 +5,7 @@ import { Component } from "@paperbits/common/ko/decorators"; import { MapiBlobStorage } from "../../persistence"; import { TCustomWidgetConfig } from "../custom-widget"; import template from "./customWidgetList.html"; +import { listConfigBlobs } from "./loadCustomWidgetConfigs"; @Component({ @@ -21,9 +22,15 @@ export class ContentWorkshop { customWidgetConfigsPromise: Promise, ) { this.customWidgetConfigs = ko.observable(); - customWidgetConfigsPromise.then(configs => - this.customWidgetConfigs(configs.sort(ContentWorkshop.sortByName)) - ); + const refreshConfigs = listConfigBlobs(blobStorage); // in case some configs on the blob storage got deleted/updated/added + Promise.all([refreshConfigs, customWidgetConfigsPromise]).then(([configBlobs, configsAll]) => { + const configs: Record = {}; + configBlobs.forEach(config => configs[config.name] = config); + configsAll.forEach(config => { + if (config.override) configs[config.name] = config + }); + this.customWidgetConfigs(Object.values(configs).sort(ContentWorkshop.sortByName)) + }); } private static sortByName(a: TCustomWidgetConfig, b: TCustomWidgetConfig): number { diff --git a/src/components/custom-widget-list/loadCustomWidgetConfigs.ts b/src/components/custom-widget-list/loadCustomWidgetConfigs.ts index 67c0e5418..88a0412da 100644 --- a/src/components/custom-widget-list/loadCustomWidgetConfigs.ts +++ b/src/components/custom-widget-list/loadCustomWidgetConfigs.ts @@ -5,13 +5,34 @@ import * as Constants from "../../constants"; import { MapiBlobStorage } from "../../persistence"; import { TCustomWidgetConfig } from "../custom-widget"; +export async function listConfigBlobs(blobStorage: MapiBlobStorage): Promise { + const configsNames = await blobStorage.listBlobs(`${BLOB_ROOT}/${BLOB_CONFIGS_FOLDER}/`); + const configsUint8s = await Promise.all(configsNames.map(blobName => blobStorage.downloadBlob(blobName))); + return configsUint8s.map(uint8 => JSON.parse(new TextDecoder().decode(uint8))); +} + +function showToast(viewManager: ViewManager, widgetSource: TCustomWidgetConfig): void { + const sessionStorageKey = Constants.overrideToastSessionKeyPrefix + widgetSource.name + if (window.sessionStorage.getItem(sessionStorageKey)) return + + let message = `Custom widget "${widgetSource.displayName}" URL is overridden`; + if (typeof widgetSource.override === "string") message += ` with ${widgetSource.override}`; + const toast = viewManager.addToast(widgetSource.displayName, message, [{ + title: "Got it", + action: async () => { + window.sessionStorage.setItem(sessionStorageKey, "true"); + viewManager.removeToast(toast); + } + }]); +} + export async function loadCustomWidgetConfigs( blobStorage: MapiBlobStorage, viewManager: ViewManager, ): Promise { - const sourcesSession = Object.keys(window.sessionStorage) + const sourcesSessionKeys = Object.keys(window.sessionStorage) .filter((key: string) => key.startsWith(Constants.overrideConfigSessionKeyPrefix)) - .map(key => window.sessionStorage.getItem(key)); + const sourcesSession = sourcesSessionKeys.map(key => window.sessionStorage.getItem(key)); const sourcesSearchParams = new URLSearchParams(window.location.search) .getAll(OVERRIDE_PORT_KEY) .map(port => new URL("http://localhost:" + (isNaN(parseInt(port)) ? OVERRIDE_DEFAULT_PORT : port)).href); @@ -28,33 +49,22 @@ export async function loadCustomWidgetConfigs( } }); - const configsNames = await blobStorage.listBlobs(`${BLOB_ROOT}/${BLOB_CONFIGS_FOLDER}/`); - const configsUint8s = await Promise.all(configsNames.map(blobName => blobStorage.downloadBlob(blobName))); - const configs: TCustomWidgetConfig[] = configsUint8s.map(uint8 => JSON.parse(new TextDecoder().decode(uint8))); - const configurations: Record = {}; + (await listConfigBlobs(blobStorage)).forEach(config => configurations[config.name] = config); - configs.forEach(config => configurations[config.name] = config); (await Promise.all(overridesPromises)).forEach(({override, source}) => { - if (!override) return; + if (!override) { + const key = sourcesSessionKeys.find(key => window.sessionStorage.getItem(key) === source); + if (key) sessionStorage.removeItem(key); + return; + } const href = new URL(source).href; window.sessionStorage.setItem(Constants.overrideConfigSessionKeyPrefix + override.name, href); const widgetSource = {...override, override: href ?? true}; configurations[override.name] = widgetSource - const sessionStorageKey = Constants.overrideToastSessionKeyPrefix + override.name - if (window.sessionStorage.getItem(sessionStorageKey)) return - - let message = `Custom widget "${override.displayName}" URL is overridden`; - if (typeof widgetSource.override === "string") message += ` with ${widgetSource.override}`; - const toast = viewManager.addToast(override.displayName, message, [{ - title: "Got it", - action: async () => { - window.sessionStorage.setItem(sessionStorageKey, "true"); - viewManager.removeToast(toast); - } - }]); + showToast(viewManager, widgetSource); }); return Object.values(configurations); diff --git a/src/components/custom-widget/customWidget.design.module.ts b/src/components/custom-widget/customWidget.design.module.ts index bffb4d18e..457f7f418 100644 --- a/src/components/custom-widget/customWidget.design.module.ts +++ b/src/components/custom-widget/customWidget.design.module.ts @@ -1,7 +1,7 @@ import { IInjectorModule, IInjector } from "@paperbits/common/injection"; import { CustomWidgetEditorViewModel, CustomWidgetViewModel, CustomWidgetViewModelBinder } from "./ko"; import { CustomWidgetModelBinder } from "."; -import { ListenForSecretsRequests } from "./ListenForSecretsRequests"; +import { ListenForSecretsRequests } from "./listenForSecretsRequests"; export class CustomWidgetDesignModule implements IInjectorModule { public register(injector: IInjector): void { diff --git a/src/components/custom-widget/customWidget.runtime.module.ts b/src/components/custom-widget/customWidget.runtime.module.ts index 2e5ca51d4..a8d30cc56 100644 --- a/src/components/custom-widget/customWidget.runtime.module.ts +++ b/src/components/custom-widget/customWidget.runtime.module.ts @@ -1,5 +1,5 @@ import { IInjectorModule, IInjector } from "@paperbits/common/injection"; -import { ListenForSecretsRequests } from "./ListenForSecretsRequests"; +import { ListenForSecretsRequests } from "./listenForSecretsRequests"; export class CustomWidgetRuntimeModule implements IInjectorModule { public register(injector: IInjector): void { diff --git a/src/components/custom-widget/ListenForSecretsRequests.ts b/src/components/custom-widget/listenForSecretsRequests.ts similarity index 86% rename from src/components/custom-widget/ListenForSecretsRequests.ts rename to src/components/custom-widget/listenForSecretsRequests.ts index 7733a3f7b..1da8becf0 100644 --- a/src/components/custom-widget/ListenForSecretsRequests.ts +++ b/src/components/custom-widget/listenForSecretsRequests.ts @@ -2,6 +2,7 @@ import { APIM_ASK_FOR_SECRETS_MESSAGE_KEY, Secrets } from "@azure/api-management import { ISettingsProvider } from "@paperbits/common/configuration"; import { AccessToken, IAuthenticator } from "../../authentication"; import { managementApiVersion, SettingNames } from "../../constants"; +import { Utils } from "../../utils"; export class ListenForSecretsRequests { constructor( @@ -20,8 +21,11 @@ export class ListenForSecretsRequests { : window.document.getElementById(instanceId) ) as HTMLIFrameElement; - const managementApiUrl = await settingsProvider.getSetting(SettingNames.managementApiUrl) - const secrets: Secrets = { managementApiUrl, apiVersion: managementApiVersion }; + const managementApiUrl = await settingsProvider.getSetting(SettingNames.managementApiUrl); + const secrets: Secrets = { + managementApiUrl: Utils.ensureUrlArmified(managementApiUrl), + apiVersion: managementApiVersion + }; const token = await authenticator.getAccessTokenAsString(); if (token) {