From 0006a9bd87090632a78d3afce4100256f11f1c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 29 Jan 2025 22:59:40 +0100 Subject: [PATCH 01/11] peek error notification element + controller/method --- .../src/packages/core/manifests.ts | 2 + .../controllers/peek-error/index.ts | 1 + .../peek-error-notification.element.ts | 38 ++++++++++++ .../peek-error/peek-error.controller.ts | 33 +++++++++++ .../extractUmbNotificationColor.function.ts | 2 +- .../src/packages/core/notification/index.ts | 12 ++-- .../packages/core/notification/manifests.ts | 3 + .../error-viewer-modal.element.ts | 56 ++++++++++++++++++ .../error-viewer/error-viewer-modal.token.ts | 17 ++++++ .../notification/modals/error-viewer/index.ts | 2 + .../modals/error-viewer/manifest.ts | 8 +++ .../notification/notification-handler.test.ts | 2 +- .../core/notification/notification-handler.ts | 23 ++------ .../core/notification/notification.context.ts | 42 +++++--------- .../src/packages/core/notification/types.ts | 29 ++++++++++ .../core/resources/resource.controller.ts | 58 ++++++++----------- .../entity-detail-workspace-base.ts | 2 +- 17 files changed, 241 insertions(+), 89 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/manifest.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/notification/types.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts index 25e388e063..e904142eac 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/manifests.ts @@ -11,6 +11,7 @@ import { manifests as iconRegistryManifests } from './icon-registry/manifests.js import { manifests as localizationManifests } from './localization/manifests.js'; import { manifests as menuManifests } from './menu/manifests.js'; import { manifests as modalManifests } from './modal/manifests.js'; +import { manifests as notificationManifests } from './notification/manifests.js'; import { manifests as pickerManifests } from './picker/manifests.js'; import { manifests as propertyActionManifests } from './property-action/manifests.js'; import { manifests as propertyEditorManifests } from './property-editor/manifests.js'; @@ -39,6 +40,7 @@ export const manifests: Array = ...localizationManifests, ...menuManifests, ...modalManifests, + ...notificationManifests, ...pickerManifests, ...propertyActionManifests, ...propertyEditorManifests, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/index.ts new file mode 100644 index 0000000000..c6d8745627 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/index.ts @@ -0,0 +1 @@ +export * from './peek-error.controller.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts new file mode 100644 index 0000000000..73a2d064d0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts @@ -0,0 +1,38 @@ +import { customElement, html, ifDefined, nothing, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { UmbNotificationHandler } from '../../notification-handler'; +import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import type { UmbPeekErrorArgs } from '../../types.js'; +import { UMB_ERROR_VIEWER_MODAL } from '../../index.js'; + +@customElement('umb-peek-error-notification') +export class UmbPeekErrorNotificationElement extends UmbLitElement { + @property({ attribute: false }) + public data?: UmbPeekErrorArgs; + + public notificationHandler!: UmbNotificationHandler; + + async #onClick() { + const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + + modalManager.open(this, UMB_ERROR_VIEWER_MODAL, { data: this.data }); + + this.notificationHandler.close(); + } + + protected override render() { + return this.data + ? html`${this.data.message}${this.data.details + ? html`` + : nothing}` + : nothing; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-peek-error-notification': UmbPeekErrorNotificationElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts new file mode 100644 index 0000000000..6993a710ca --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts @@ -0,0 +1,33 @@ +import { UMB_NOTIFICATION_CONTEXT } from '../../notification.context.js'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbPeekErrorArgs } from '../../types.js'; + +import './peek-error-notification.element.js'; + +export class UmbPeekErrorController extends UmbControllerBase { + async open(args: UmbPeekErrorArgs): Promise { + const context = await this.getContext(UMB_NOTIFICATION_CONTEXT); + + context.peek('danger', { + elementName: 'umb-peek-error-notification', + data: args, + }); + + // This is a one time off, so we can destroy our selfs. + this.destroy(); + + return; + } +} + +/** + * + * @param host {UmbControllerHost} - The host controller + * @param args {UmbPeekErrorArgs} - The data to pass to the notification + * @returns {UmbPeekErrorController} The notification peek controller instance + */ +export function umbPeekError(host: UmbControllerHost, args: UmbPeekErrorArgs) { + console.log(host); + return new UmbPeekErrorController(host).open(args); +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts index 6ad0399501..d15b9cbcee 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts @@ -1,5 +1,5 @@ -import type { UmbNotificationColor } from './notification.context.js'; import { EventMessageTypeModel } from '@umbraco-cms/backoffice/external/backend-api'; +import type { UmbNotificationColor } from './types'; /** * diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/index.ts index ed8dcb76fc..8c3df6fa4c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/index.ts @@ -1,7 +1,9 @@ import './layouts/default/index.js'; - -export * from './notification.context.js'; -export * from './notification-handler.js'; - -export * from './isUmbNotifications.function.js'; +export * from './controllers/peek-error/index.js'; export * from './extractUmbNotificationColor.function.js'; +export * from './isUmbNotifications.function.js'; +export * from './modals/error-viewer/index.js'; +export * from './notification-handler.js'; +export * from './notification.context.js'; + +export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/manifests.ts new file mode 100644 index 0000000000..a00e363447 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/manifests.ts @@ -0,0 +1,3 @@ +import { manifest } from './modals/error-viewer/manifest.js'; + +export const manifests = [manifest]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts new file mode 100644 index 0000000000..e33597d604 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts @@ -0,0 +1,56 @@ +import type { UmbErrorViewerModalData, UmbErrorViewerModalValue } from './error-viewer-modal.token.js'; +import { css, customElement, html, nothing } from '@umbraco-cms/backoffice/external/lit'; +import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; + +@customElement('umb-error-viewer-modal') +export class UmbErrorViewerModalElement extends UmbModalBaseElement { + // Code adapted from https://stackoverflow.com/a/57668208/12787 + // Licensed under the permissions of the CC BY-SA 4.0 DEED + #stringify(obj: any): string { + let output = '{'; + for (const key in obj) { + let value = obj[key]; + if (typeof value === 'function') { + value = value.toString(); + } else if (value instanceof Array) { + value = JSON.stringify(value); + } else if (typeof value === 'object') { + value = this.#stringify(value); + } else { + value = `"${value}"`; + } + output += `\n ${key}: ${value},`; + } + return output + '\n}'; + } + + override render() { + return html` + + ${this.data + ? html`${this.#stringify(this.data)}` + : nothing} +
+ +
+
+ `; + } + + static override styles = [ + css` + umb-code-block { + border: none; + height: 100%; + } + `, + ]; +} + +export default UmbErrorViewerModalElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-error-viewer-modal': UmbErrorViewerModalElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts new file mode 100644 index 0000000000..7cf1b87c03 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts @@ -0,0 +1,17 @@ +import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; +import type { UmbPeekErrorArgs } from '../../types'; + +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface UmbErrorViewerModalData extends UmbPeekErrorArgs {} + +export type UmbErrorViewerModalValue = undefined; + +export const UMB_ERROR_VIEWER_MODAL = new UmbModalToken( + 'Umb.Modal.ErrorViewer', + { + modal: { + type: 'sidebar', + size: 'medium', + }, + }, +); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/index.ts new file mode 100644 index 0000000000..585082c38e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/index.ts @@ -0,0 +1,2 @@ +export * from './error-viewer-modal.token.js'; +export * from './manifest.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/manifest.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/manifest.ts new file mode 100644 index 0000000000..7aae9d47bf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/manifest.ts @@ -0,0 +1,8 @@ +import type { ManifestModal } from '@umbraco-cms/backoffice/modal'; + +export const manifest: ManifestModal = { + type: 'modal', + alias: 'Umb.Modal.ErrorViewer', + name: 'Error Viewer Modal', + element: () => import('./error-viewer-modal.element.js'), +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.test.ts index 79a22c4cbf..155180f7e5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.test.ts @@ -1,5 +1,5 @@ import { UmbNotificationHandler } from './notification-handler.js'; -import type { UmbNotificationOptions } from './notification.context.js'; +import type { UmbNotificationOptions } from './types.js'; import { assert, expect } from '@open-wc/testing'; import { UmbId } from '@umbraco-cms/backoffice/id'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.ts index 09ff5d168d..ebbf9992e2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification-handler.ts @@ -1,11 +1,9 @@ -import type { - UmbNotificationOptions, - UmbNotificationColor, - UmbNotificationDefaultData, -} from './notification.context.js'; +import type { UmbNotificationOptions, UmbNotificationColor, UmbNotificationDefaultData } from './types.js'; import type { UUIToastNotificationElement } from '@umbraco-cms/backoffice/external/uui'; import { UmbId } from '@umbraco-cms/backoffice/id'; +const DEFAULT_LAYOUT = 'umb-notification-layout-default'; + /** * @class UmbNotificationHandler */ @@ -17,10 +15,9 @@ export class UmbNotificationHandler { private _defaultColor: UmbNotificationColor = 'default'; private _defaultDuration = 6000; - private _defaultLayout = 'umb-notification-layout-default'; public key: string; - public element: any; + public element!: UUIToastNotificationElement; public color: UmbNotificationColor; public duration: number | null; @@ -34,23 +31,13 @@ export class UmbNotificationHandler { this.color = options.color || this._defaultColor; this.duration = options.duration !== undefined ? options.duration : this._defaultDuration; - this._elementName = options.elementName || this._defaultLayout; + this._elementName = options.elementName || DEFAULT_LAYOUT; this._data = options.data; this._closePromise = new Promise((res) => { this._closeResolver = res; }); - this._createElement(); - } - - /** - * @private - * @memberof UmbNotificationHandler - */ - private _createElement() { - if (!this._elementName) return; - const notification: UUIToastNotificationElement = document.createElement('uui-toast-notification'); notification.color = this.color; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification.context.ts index 5bdbf98670..73f26422a2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/notification.context.ts @@ -3,29 +3,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api'; - -/** - * The default data of notifications - * @interface UmbNotificationDefaultData - */ -export interface UmbNotificationDefaultData { - message: string; - headline?: string; - structuredList?: Record>; -} - -/** - * @interface UmbNotificationOptions - * @template UmbNotificationData - */ -export interface UmbNotificationOptions { - color?: UmbNotificationColor; - duration?: number | null; - elementName?: string; - data?: UmbNotificationData; -} - -export type UmbNotificationColor = '' | 'default' | 'positive' | 'warning' | 'danger'; +import type { UmbNotificationColor, UmbNotificationOptions } from './types.js'; export class UmbNotificationContext extends UmbContextBase { // Notice this cannot use UniqueBehaviorSubject as it holds a HTML Element. which cannot be Serialized to JSON (it has some circular references) @@ -42,9 +20,9 @@ export class UmbNotificationContext extends UmbContextBase(options: T): UmbNotificationHandler { const notificationHandler = new UmbNotificationHandler(options); - notificationHandler.element.addEventListener('closed', () => this._handleClosed(notificationHandler)); + notificationHandler.element?.addEventListener('closed', () => this._handleClosed(notificationHandler)); this._notifications.setValue([...this._notifications.getValue(), notificationHandler]); @@ -78,8 +56,11 @@ export class UmbNotificationContext extends UmbContextBase( + color: UmbNotificationColor, + options: T, + ): UmbNotificationHandler { + return this.#open({ color, ...options }); } /** @@ -89,8 +70,11 @@ export class UmbNotificationContext extends UmbContextBase( + color: UmbNotificationColor, + options: T, + ): UmbNotificationHandler { + return this.#open({ ...options, color, duration: null }); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/types.ts new file mode 100644 index 0000000000..a843dc7ac6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/types.ts @@ -0,0 +1,29 @@ +/** + * The default data of notifications + * @interface UmbNotificationDefaultData + */ +export interface UmbNotificationDefaultData { + message: string; + headline?: string; + /** + * @deprecated, do not use this. It will be removed in v.16 — Use UmbPeekError instead + */ + structuredList?: Record>; +} + +/** + * @interface UmbNotificationOptions + * @template UmbNotificationData + */ +export interface UmbNotificationOptions { + color?: UmbNotificationColor; + duration?: number | null; + elementName?: string; + data?: UmbNotificationData; +} + +export type UmbNotificationColor = '' | 'default' | 'positive' | 'warning' | 'danger'; + +export interface UmbPeekErrorArgs extends UmbNotificationDefaultData { + details?: any; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts index d92a68a38c..2f3b53b3c8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts @@ -5,7 +5,11 @@ import type { XhrRequestOptions } from './types.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; -import { UMB_NOTIFICATION_CONTEXT, type UmbNotificationOptions } from '@umbraco-cms/backoffice/notification'; +import { + UMB_NOTIFICATION_CONTEXT, + umbPeekError, + type UmbNotificationOptions, +} from '@umbraco-cms/backoffice/notification'; import type { UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository'; import { ApiError, @@ -17,29 +21,14 @@ import { export class UmbResourceController extends UmbControllerBase { #promise: Promise; - #notificationContext?: typeof UMB_NOTIFICATION_CONTEXT.TYPE; - - #authContext?: typeof UMB_AUTH_CONTEXT.TYPE; - constructor(host: UmbControllerHost, promise: Promise, alias?: string) { super(host, alias); this.#promise = promise; - - new UmbContextConsumerController(host, UMB_NOTIFICATION_CONTEXT, (_instance) => { - this.#notificationContext = _instance; - }); - - new UmbContextConsumerController(host, UMB_AUTH_CONTEXT, (_instance) => { - this.#authContext = _instance; - }); - } - - override hostConnected(): void { - // Do nothing } override hostDisconnected(): void { + super.hostDisconnected(); this.cancel(); } @@ -82,6 +71,7 @@ export class UmbResourceController extends UmbControllerBase { console.error('Request failed', error.request); console.error('Request body', error.body); console.error('Error', error); + console.groupEnd(); let problemDetails: ProblemDetails | null = null; @@ -111,23 +101,14 @@ export class UmbResourceController extends UmbControllerBase { switch (error.status ?? 0) { case 401: { // See if we can get the UmbAuthContext and let it know the user is timed out - if (this.#authContext) { - this.#authContext.timeOut(); - } else { - // If we can't get the auth context, show a notification - this.#notificationContext?.peek('warning', { - data: { - headline: 'Session Expired', - message: 'Your session has expired. Please refresh the page.', - }, - }); - } + const authContext = await this.getContext(UMB_AUTH_CONTEXT); + authContext.timeOut(); break; } case 500: // Server Error - if (!isCancelledByNotification && this.#notificationContext) { + if (!isCancelledByNotification) { let headline = problemDetails?.title ?? error.name ?? 'Server Error'; let message = 'A fatal server error occurred. If this continues, please reach out to your administrator.'; @@ -141,7 +122,8 @@ export class UmbResourceController extends UmbControllerBase { 'The Umbraco object cache is corrupt, but your action may still have been executed. Please restart the server to reset the cache. This is a work in progress.'; } - this.#notificationContext.peek('danger', { + const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + notificationContext.peek('danger', { data: { headline, message, @@ -152,8 +134,11 @@ export class UmbResourceController extends UmbControllerBase { break; default: // Other errors - if (!isCancelledByNotification && this.#notificationContext) { - this.#notificationContext.peek('danger', { + if (!isCancelledByNotification) { + /* + + const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); + notificationContext.peek('danger', { data: { headline: problemDetails?.title ?? error.name ?? 'Server Error', message: problemDetails?.detail ?? error.message ?? 'Something went wrong', @@ -163,10 +148,15 @@ export class UmbResourceController extends UmbControllerBase { }, ...options, }); + */ + const headline = problemDetails?.title ?? error.name ?? 'Server Error'; + umbPeekError(this, { + headline: problemDetails?.detail ? headline : undefined, + message: problemDetails?.detail ?? headline, + details: problemDetails?.errors, + }); } } - - console.groupEnd(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts index 574f0e6faf..0c9cff4af9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts @@ -382,7 +382,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase< this, umbExtensionsRegistry, repositoryAlias, - [this._host], + [], (permitted, ctrl) => { this._detailRepository = permitted ? ctrl.api : undefined; this.#checkIfInitialized(); From 6f9e66de8aa09e54642ac2ec821e51487baf56ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 30 Jan 2025 14:00:27 +0100 Subject: [PATCH 02/11] localizations --- src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts | 2 ++ src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts | 2 ++ src/Umbraco.Web.UI.Client/src/assets/lang/en.ts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts index c6d6f63dbd..4769c1949d 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts @@ -583,6 +583,8 @@ export default { deleteLayout: 'You are deleting the layout', deletingALayout: 'Modifying layout will result in loss of data for any existing content that is based on this configuration.', + seeErrorAction: 'Se fejlen', + seeErrorDialogHeadline: 'Fejl detaljer', }, dictionary: { noItems: 'Der er ingen ordbogselementer.', diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts index 995beb00d3..91897bc62b 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts @@ -614,6 +614,8 @@ export default { deleteLayout: 'You are deleting the layout', deletingALayout: 'Modifying layout will result in loss of data for any existing content that is based on this configuration.', + seeErrorAction: 'See error', + seeErrorDialogHeadline: 'Error details', }, dictionary: { importDictionaryItemHelp: diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts index dae39aa00f..1fc60ad171 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts @@ -606,6 +606,8 @@ export default { deletingALayout: 'Modifying layout will result in loss of data for any existing content that is based on this configuration.', selectEditorConfiguration: 'Select configuration', + seeErrorAction: 'See error', + seeErrorDialogHeadline: 'Error details', }, dictionary: { importDictionaryItemHelp: From 7d703cc9bd2cac270d82160ec0851c89fb1f13a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 30 Jan 2025 14:01:31 +0100 Subject: [PATCH 03/11] peek error modal --- .../peek-error-notification.element.ts | 9 ++++-- .../error-viewer-modal.element.ts | 30 +++++++++++++++---- .../core/resources/resource.controller.ts | 24 +++++---------- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts index 73a2d064d0..d9907b66cc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts @@ -15,7 +15,7 @@ export class UmbPeekErrorNotificationElement extends UmbLitElement { async #onClick() { const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - modalManager.open(this, UMB_ERROR_VIEWER_MODAL, { data: this.data }); + modalManager.open(this, UMB_ERROR_VIEWER_MODAL, { data: this.data?.details }); this.notificationHandler.close(); } @@ -24,7 +24,12 @@ export class UmbPeekErrorNotificationElement extends UmbLitElement { return this.data ? html`${this.data.message}${this.data.details - ? html`` + ? html`` : nothing}` : nothing; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts index e33597d604..51a377cced 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts @@ -1,9 +1,15 @@ import type { UmbErrorViewerModalData, UmbErrorViewerModalValue } from './error-viewer-modal.token.js'; -import { css, customElement, html, nothing } from '@umbraco-cms/backoffice/external/lit'; +import { css, customElement, html, nothing, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; @customElement('umb-error-viewer-modal') export class UmbErrorViewerModalElement extends UmbModalBaseElement { + @state() + _displayError?: string; + + @state() + _displayLang?: string; + // Code adapted from https://stackoverflow.com/a/57668208/12787 // Licensed under the permissions of the CC BY-SA 4.0 DEED #stringify(obj: any): string { @@ -24,12 +30,26 @@ export class UmbErrorViewerModalElement extends UmbModalBaseElement - ${this.data - ? html`${this.#stringify(this.data)}` - : nothing} + + ${this.data ? html`${this.data}` : nothing}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts index 2f3b53b3c8..e1b0521c78 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts @@ -4,12 +4,7 @@ import { isApiError, isCancelError, isCancelablePromise } from './apiTypeValidat import type { XhrRequestOptions } from './types.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; -import { - UMB_NOTIFICATION_CONTEXT, - umbPeekError, - type UmbNotificationOptions, -} from '@umbraco-cms/backoffice/notification'; +import { umbPeekError, type UmbNotificationOptions } from '@umbraco-cms/backoffice/notification'; import type { UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository'; import { ApiError, @@ -122,13 +117,10 @@ export class UmbResourceController extends UmbControllerBase { 'The Umbraco object cache is corrupt, but your action may still have been executed. Please restart the server to reset the cache. This is a work in progress.'; } - const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); - notificationContext.peek('danger', { - data: { - headline, - message, - }, - ...options, + umbPeekError(this, { + headline: headline, + message: message, + details: problemDetails?.errors ?? problemDetails?.detail, }); } break; @@ -136,7 +128,6 @@ export class UmbResourceController extends UmbControllerBase { // Other errors if (!isCancelledByNotification) { /* - const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT); notificationContext.peek('danger', { data: { @@ -151,9 +142,8 @@ export class UmbResourceController extends UmbControllerBase { */ const headline = problemDetails?.title ?? error.name ?? 'Server Error'; umbPeekError(this, { - headline: problemDetails?.detail ? headline : undefined, - message: problemDetails?.detail ?? headline, - details: problemDetails?.errors, + message: headline, + details: problemDetails?.errors ?? problemDetails?.detail, }); } } From 2ca4e0e1bd9c5bd7533053b625f15613c558a463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 30 Jan 2025 14:01:51 +0100 Subject: [PATCH 04/11] remove max-height setting from code-block --- .../packages/core/components/code-block/code-block.element.ts | 1 - .../models-builder/models-builder-dashboard.element.ts | 2 +- .../templating-page-field-builder-modal.element.ts | 2 +- .../modals/query-builder/query-builder-modal.element.ts | 4 +++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/code-block/code-block.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/code-block/code-block.element.ts index ddcead0191..94551f5185 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/code-block/code-block.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/code-block/code-block.element.ts @@ -68,7 +68,6 @@ export class UmbCodeBlockElement extends LitElement { } uui-scroll-container { - max-height: 500px; overflow-y: auto; overflow-wrap: anywhere; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/models-builder/models-builder-dashboard.element.ts b/src/Umbraco.Web.UI.Client/src/packages/models-builder/models-builder-dashboard.element.ts index 358d7ce045..de399a97e1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/models-builder/models-builder-dashboard.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/models-builder/models-builder-dashboard.element.ts @@ -95,7 +95,7 @@ export class UmbModelsBuilderDashboardElement extends UmbLitElement {

${this._modelsBuilder?.lastError ? html`

Last generation failed with the following error:

- ${this._modelsBuilder.lastError}` + ${this._modelsBuilder.lastError}` : nothing} `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.element.ts index 9d1eec32e3..f6092ec62d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/templating-page-field-builder/templating-page-field-builder-modal.element.ts @@ -94,7 +94,7 @@ export class UmbTemplatingPageFieldBuilderModalElement extends UmbModalBaseEleme ?disabled=${this._field ? false : true}> Output sample - ${this._field ? getUmbracoFieldSnippet(this._field, this._default, this._recursive) : ''} diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts index 9edc5850e5..a3e2863471 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts @@ -254,7 +254,9 @@ export default class UmbTemplateQueryBuilderModalElement extends UmbModalBaseEle (sample) => html`${sample.name}`, ) ?? ''} - ${this._templateQuery?.queryExpression ?? ''} + ${this._templateQuery?.queryExpression ?? ''} From 32a2bab4f0dc5d57889971f2c139112e00df2974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 30 Jan 2025 14:15:32 +0100 Subject: [PATCH 05/11] todo --- .../src/packages/core/resources/resource.controller.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts index e1b0521c78..44ae915af3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts @@ -32,6 +32,7 @@ export class UmbResourceController extends UmbControllerBase { * @param promise */ static async tryExecute(promise: Promise): Promise> { + // TODO: tryExecute should not take a promise as argument, but should utilize the class property `#promise` instead. (In this way the promise can be cancelled when disconnected) try { return { data: await promise }; } catch (error) { From 69e36a3b9444fb18d79b6bb3d15a389e94e513b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 30 Jan 2025 14:15:44 +0100 Subject: [PATCH 06/11] fix json display --- .../modals/error-viewer/error-viewer-modal.element.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts index 51a377cced..40b6924fea 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.element.ts @@ -32,7 +32,6 @@ export class UmbErrorViewerModalElement extends UmbModalBaseElement - ${this.data ? html`${this.data}` : nothing} + ${this.data + ? html`${this._displayError}` + : nothing}
From e034a647233f9fa76cc8a3bd72f30b8385c62f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 4 Feb 2025 13:44:18 +0100 Subject: [PATCH 07/11] Update src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> --- .../core/notification/extractUmbNotificationColor.function.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts index d15b9cbcee..cf9b9e89d8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/extractUmbNotificationColor.function.ts @@ -1,5 +1,5 @@ import { EventMessageTypeModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbNotificationColor } from './types'; +import type { UmbNotificationColor } from './types.js'; /** * From cab07ba6f6e5d5e608941de7321f714e55b32df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 4 Feb 2025 13:44:25 +0100 Subject: [PATCH 08/11] Update src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> --- .../modals/error-viewer/error-viewer-modal.token.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts index 7cf1b87c03..1c09ed590c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/modals/error-viewer/error-viewer-modal.token.ts @@ -1,5 +1,5 @@ import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; -import type { UmbPeekErrorArgs } from '../../types'; +import type { UmbPeekErrorArgs } from '../../types.js'; // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface UmbErrorViewerModalData extends UmbPeekErrorArgs {} From 97046b954696232751420e8bc4d04191d8a1d655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 4 Feb 2025 13:44:33 +0100 Subject: [PATCH 09/11] Update src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> --- .../controllers/peek-error/peek-error-notification.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts index d9907b66cc..a8b070cdbf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts @@ -1,6 +1,6 @@ import { customElement, html, ifDefined, nothing, property } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import type { UmbNotificationHandler } from '../../notification-handler'; +import type { UmbNotificationHandler } from '../../notification-handler.js'; import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import type { UmbPeekErrorArgs } from '../../types.js'; import { UMB_ERROR_VIEWER_MODAL } from '../../index.js'; From e2fd2afabd23d2ae87e8b62cdbcb84b36a5ea275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 5 Feb 2025 15:49:47 +0100 Subject: [PATCH 10/11] mark options as deprecated and avoid lint issue on the argument not used --- .../packages/core/resources/resource.controller.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts index 44ae915af3..24e142c6f1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts @@ -12,6 +12,7 @@ import { CancelError, type ProblemDetails, } from '@umbraco-cms/backoffice/external/backend-api'; +import { UmbDeprecation } from '../utils/deprecation/deprecation.js'; export class UmbResourceController extends UmbControllerBase { #promise: Promise; @@ -48,11 +49,20 @@ export class UmbResourceController extends UmbControllerBase { /** * Wrap the {tryExecute} function in a try/catch block and return the result. * If the executor function throws an error, then show the details in a notification. - * @param options + * @param _options */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars async tryExecuteAndNotify(options?: UmbNotificationOptions): Promise> { const { data, error } = await UmbResourceController.tryExecute(this.#promise); + if (options) { + new UmbDeprecation({ + deprecated: 'tryExecuteAndNotify `options` argument is deprecated.', + removeInVersion: '17.0.0', + solution: 'Use the method without arguments.', + }).warn(); + } + if (error) { /** * Determine if we want to show a notification or just log the error to the console. From 64efd73dd8853d06f3b9428e3987fd751fc40389 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 12 Feb 2025 11:02:37 +0100 Subject: [PATCH 11/11] Update peek-error.controller.ts remove console log --- .../notification/controllers/peek-error/peek-error.controller.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts index 6993a710ca..80dc9638a1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error.controller.ts @@ -28,6 +28,5 @@ export class UmbPeekErrorController extends UmbControllerBase { * @returns {UmbPeekErrorController} The notification peek controller instance */ export function umbPeekError(host: UmbControllerHost, args: UmbPeekErrorArgs) { - console.log(host); return new UmbPeekErrorController(host).open(args); }