diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/libs/extensions-api/registry/extension.registry.ts index 7e562cb17b..df0e30cca2 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-api/registry/extension.registry.ts @@ -80,4 +80,19 @@ export class UmbExtensionRegistry { ) ) as Observable>; } + + extensionsSortedByTypeAndWeight(): Observable> { + return this.extensions.pipe( + map((exts) => exts + .sort((a, b) => { + // If type is the same, sort by weight + if (a.type === b.type) { + return (a.weight || 0) - (b.weight || 0); + } + + // Otherwise sort by type + return a.type.localeCompare(b.type); + })) + ) as Observable>; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/workspace/extension-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/workspace/extension-root-workspace.element.ts index 26bcf43f2a..563af4962a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/workspace/extension-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/workspace/extension-root-workspace.element.ts @@ -1,33 +1,55 @@ import { html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; -import { isManifestElementNameType , umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; +import { isManifestElementNameType, umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import type { ManifestBase } from '@umbraco-cms/models'; import { UmbLitElement } from '@umbraco-cms/element'; +import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; @customElement('umb-extension-root-workspace') export class UmbExtensionRootWorkspaceElement extends UmbLitElement { @state() private _extensions?: Array = undefined; + private _modalService?: UmbModalService; + connectedCallback(): void { super.connectedCallback(); this._observeExtensions(); + + this.consumeContext(UMB_MODAL_SERVICE_CONTEXT_TOKEN, (modalService) => { + this._modalService = modalService; + }); } private _observeExtensions() { - this.observe(umbExtensionsRegistry.extensions, (extensions) => { + this.observe(umbExtensionsRegistry.extensionsSortedByTypeAndWeight(), (extensions) => { this._extensions = extensions || undefined; }); } + #removeExtension(extension: ManifestBase) { + const modalHandler = this._modalService?.confirm({ + headline: 'Unload extension', + confirmLabel: 'Unload', + content: html`

Are you sure you want to unload the extension ${extension.alias}?

`, + color: 'danger', + }); + + modalHandler?.onClose().then(({ confirmed }: any) => { + if (confirmed) { + umbExtensionsRegistry.unregister(extension.alias); + } + }); + } + render() { return html` -

List of currently loaded extensions

Type + Weight Name Alias Actions @@ -37,14 +59,19 @@ export class UmbExtensionRootWorkspaceElement extends UmbLitElement { (extension) => html` ${extension.type} + ${extension.weight ? extension.weight : 'Not Set'} - ${isManifestElementNameType(extension) ? extension.name : 'Custom extension'} + ${isManifestElementNameType(extension) ? extension.name : `[Custom extension] ${extension.name}`} ${extension.alias} umbExtensionsRegistry.unregister(extension.alias)}> + label="Unload" + color="danger" + look="primary" + @click=${() => this.#removeExtension(extension)}> + + `