From 3aaecaab1fd501d45619246d3e3015b36d2c78ca Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 1 Feb 2024 20:42:50 +0100 Subject: [PATCH] extension workspace as collection --- .../registry/extension.registry.ts | 4 + .../collection/manifests.ts | 18 +++ .../extension-collection.repository.ts | 21 ++++ .../collection/repository/index.ts | 2 + .../collection/repository/manifests.ts | 13 ++ ...sion-table-action-column-layout.element.ts | 50 ++++++++ .../collection/views/manifests.ts | 24 ++++ ...extension-table-collection-view.element.ts | 115 ++++++++++++++++++ .../core/extension-registry/manifests.ts | 3 +- .../extension-root-workspace.element.ts | 100 +-------------- .../extension-registry/workspace/manifests.ts | 2 + 11 files changed, 256 insertions(+), 96 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/extension-collection.repository.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/extension-table-action-column-layout.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/table/extension-table-collection-view.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts index 4729708047..621b237ba8 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/registry/extension.registry.ts @@ -114,6 +114,10 @@ export class UmbExtensionRegistry< this._extensions.setValue([...this._extensions.getValue(), manifest as ManifestTypes]); } + getExtensions(): Array { + return this._extensions.getValue(); + } + registerMany(manifests: Array>): void { // we have to register extensions individually, so we ensure a manifest is valid before continuing to the next one manifests.forEach((manifest) => this.register(manifest)); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/manifests.ts new file mode 100644 index 0000000000..a6e46985ca --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/manifests.ts @@ -0,0 +1,18 @@ +import { UMB_EXTENSION_COLLECTION_REPOSITORY_ALIAS } from './repository/index.js'; +import { manifests as collectionRepositoryManifests } from './repository/manifests.js'; +import { manifests as collectionViewManifests } from './views/manifests.js'; +import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_EXTENSION_COLLECTION_ALIAS = 'Umb.Collection.Extension'; + +const collectionManifest: ManifestTypes = { + type: 'collection', + kind: 'default', + alias: UMB_EXTENSION_COLLECTION_ALIAS, + name: 'Extension Collection', + meta: { + repositoryAlias: UMB_EXTENSION_COLLECTION_REPOSITORY_ALIAS, + }, +}; + +export const manifests = [collectionManifest, ...collectionRepositoryManifests, ...collectionViewManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/extension-collection.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/extension-collection.repository.ts new file mode 100644 index 0000000000..fe51c7ca13 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/extension-collection.repository.ts @@ -0,0 +1,21 @@ +import { umbExtensionsRegistry } from '../../registry.js'; +import { UmbRepositoryBase, type UmbCollectionRepository } from '@umbraco-cms/backoffice/repository'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; + +export class UmbExtensionCollectionRepository extends UmbRepositoryBase implements UmbCollectionRepository { + constructor(host: UmbControllerHost) { + super(host); + } + + async requestCollection(filter: any) { + const extensions = umbExtensionsRegistry.getExtensions(); + const total = extensions.length; + const items = extensions.slice(filter.skip, filter.skip + filter.take); + const data = { items, total }; + return { data }; + } + + destroy(): void {} +} + +export default UmbExtensionCollectionRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/index.ts new file mode 100644 index 0000000000..c724b817ee --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/index.ts @@ -0,0 +1,2 @@ +export { UMB_EXTENSION_COLLECTION_REPOSITORY_ALIAS } from './manifests.js'; +export { UmbExtensionCollectionRepository } from './extension-collection.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/manifests.ts new file mode 100644 index 0000000000..15cf8232e5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/repository/manifests.ts @@ -0,0 +1,13 @@ +import { UmbExtensionCollectionRepository } from './extension-collection.repository.js'; +import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_EXTENSION_COLLECTION_REPOSITORY_ALIAS = 'Umb.Repository.ExtensionCollection'; + +const repository: ManifestRepository = { + type: 'repository', + alias: UMB_EXTENSION_COLLECTION_REPOSITORY_ALIAS, + name: 'Extension Collection Repository', + api: UmbExtensionCollectionRepository, +}; + +export const manifests = [repository]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/extension-table-action-column-layout.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/extension-table-action-column-layout.element.ts new file mode 100644 index 0000000000..bb3990305e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/extension-table-action-column-layout.element.ts @@ -0,0 +1,50 @@ +import { umbExtensionsRegistry, type ManifestTypes } from '../../index.js'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { UMB_CONFIRM_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; + +@customElement('umb-extension-table-action-column-layout') +export class UmbExtensionTableActionColumnLayoutElement extends UmbLitElement { + @property({ attribute: false }) + value!: ManifestTypes; + + #modalContext?: UmbModalManagerContext; + + constructor() { + super(); + this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => { + this.#modalContext = instance; + }); + } + + async #removeExtension() { + const modalContext = this.#modalContext?.open(UMB_CONFIRM_MODAL, { + data: { + headline: 'Unload extension', + confirmLabel: 'Unload', + content: html`

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

`, + color: 'danger', + }, + }); + + await modalContext?.onSubmit(); + umbExtensionsRegistry.unregister(this.value.alias); + } + + render() { + return html` + + + + `; + } + + static styles = [UmbTextStyles]; +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-extension-table-action-column-layout': UmbExtensionTableActionColumnLayoutElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/manifests.ts new file mode 100644 index 0000000000..b577757db8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/manifests.ts @@ -0,0 +1,24 @@ +import { UMB_COLLECTION_ALIAS_CONDITION } from '@umbraco-cms/backoffice/collection'; +import type { ManifestCollectionView } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_EXTENSION_TABLE_COLLECTION_VIEW_ALIAS = 'Umb.CollectionView.Extension.Table'; + +const tableCollectionView: ManifestCollectionView = { + type: 'collectionView', + alias: UMB_EXTENSION_TABLE_COLLECTION_VIEW_ALIAS, + name: 'Extension Table Collection View', + js: () => import('./table/extension-table-collection-view.element.js'), + meta: { + label: 'Table', + icon: 'icon-list', + pathName: 'table', + }, + conditions: [ + { + alias: UMB_COLLECTION_ALIAS_CONDITION, + match: 'Umb.Collection.Extension', + }, + ], +}; + +export const manifests = [tableCollectionView]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/table/extension-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/table/extension-table-collection-view.element.ts new file mode 100644 index 0000000000..3156c3c6ef --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/collection/views/table/extension-table-collection-view.element.ts @@ -0,0 +1,115 @@ +import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection'; +import { UMB_DEFAULT_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection'; +import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/backoffice/components'; +import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import type { ManifestBase } from '@umbraco-cms/backoffice/extension-api'; + +import '../extension-table-action-column-layout.element.js'; + +@customElement('umb-extension-table-collection-view') +export class UmbExtensionTableCollectionViewElement extends UmbLitElement { + @state() + private _tableConfig: UmbTableConfig = { + allowSelection: false, + }; + + @state() + private _tableColumns: Array = [ + { + name: 'Type', + alias: 'extensionType', + }, + { + name: 'Name', + alias: 'extensionName', + }, + { + name: 'Alias', + alias: 'extensionAlias', + }, + { + name: 'Weight', + alias: 'extensionWeight', + }, + { + name: '', + alias: 'extensionAction', + elementName: 'umb-extension-table-action-column-layout', + }, + ]; + + @state() + private _tableItems: Array = []; + + #collectionContext?: UmbDefaultCollectionContext; + + constructor() { + super(); + + this.consumeContext(UMB_DEFAULT_COLLECTION_CONTEXT, (instance) => { + this.#collectionContext = instance; + this.#observeCollectionItems(); + }); + } + + #observeCollectionItems() { + if (!this.#collectionContext) return; + this.observe(this.#collectionContext.items, (items) => this.#createTableItems(items), 'umbCollectionItemsObserver'); + } + + #createTableItems(extensions: Array) { + this._tableItems = extensions.map((extension) => { + return { + id: extension.alias, + data: [ + { + columnAlias: 'extensionType', + value: extension.type, + }, + { + columnAlias: 'extensionName', + value: extension.name, + }, + { + columnAlias: 'extensionAlias', + value: extension.alias, + }, + { + columnAlias: 'extensionWeight', + value: extension.weight, + }, + { + columnAlias: 'extensionAction', + value: extension, + }, + ], + }; + }); + } + + render() { + return html` + + `; + } + + static styles = [ + UmbTextStyles, + css` + :host { + display: flex; + flex-direction: column; + } + `, + ]; +} + +export default UmbExtensionTableCollectionViewElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-extension-table-collection-view': UmbExtensionTableCollectionViewElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/manifests.ts index c3622896ba..c1d204e6ba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/manifests.ts @@ -1,5 +1,6 @@ import { manifests as conditionManifests } from './conditions/manifests.js'; import { manifests as menuItemManifests } from './menu-item/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; +import { manifests as collectionManifests } from './collection/manifests.js'; -export const manifests = [...conditionManifests, ...menuItemManifests, ...workspaceManifests]; +export const manifests = [...conditionManifests, ...menuItemManifests, ...workspaceManifests, ...collectionManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/extension-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/extension-root-workspace.element.ts index c053f8596a..67321c8c21 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/extension-root-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/extension-root-workspace.element.ts @@ -1,107 +1,17 @@ -import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import { map } from '@umbraco-cms/backoffice/external/rxjs'; -import type { ManifestTypes} from '@umbraco-cms/backoffice/extension-registry'; -import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { UMB_EXTENSION_COLLECTION_ALIAS } from '../collection/manifests.js'; +import { UMB_EXTENSION_ROOT_WORKSPACE_ALIAS } from './manifests.js'; +import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import type { UmbModalManagerContext} from '@umbraco-cms/backoffice/modal'; -import { UMB_MODAL_MANAGER_CONTEXT, UMB_CONFIRM_MODAL } from '@umbraco-cms/backoffice/modal'; @customElement('umb-extension-root-workspace') export class UmbExtensionRootWorkspaceElement extends UmbLitElement { - @state() - private _extensions?: Array = undefined; - - private _modalContext?: UmbModalManagerContext; - - connectedCallback(): void { - super.connectedCallback(); - this._observeExtensions(); - - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => { - this._modalContext = instance; - }); - } - - private _observeExtensions() { - this.observe( - umbExtensionsRegistry.extensions.pipe( - map((exts) => - exts.sort((a, b) => { - // If type is the same, sort by weight - if (a.type === b.type) { - return (b.weight || 0) - (a.weight || 0); - } - // Otherwise sort by type - return a.type.localeCompare(b.type); - }), - ), - ), - (extensions) => { - this._extensions = extensions || undefined; - }, - '_observeExtensionRegistry', - ); - } - - async #removeExtension(extension: ManifestTypes) { - const modalContext = this._modalContext?.open(UMB_CONFIRM_MODAL, { - data: { - headline: 'Unload extension', - confirmLabel: 'Unload', - content: html`

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

`, - color: 'danger', - }, - }); - - await modalContext?.onSubmit(); - umbExtensionsRegistry.unregister(extension.alias); - } - render() { return html` - - - - - Type - Name - Alias - Weight - Actions - - - ${this._extensions?.map( - (extension) => html` - - ${extension.type} - ${extension.name} - ${extension.alias} - ${extension.weight ? extension.weight : ''} - - this.#removeExtension(extension)}> - - - - - `, - )} - - + + `; } - - static styles = [ - css` - uui-box { - margin: var(--uui-size-layout-1); - } - `, - ]; } export default UmbExtensionRootWorkspaceElement; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/manifests.ts index 37939145b4..5ac83bbc20 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/workspace/manifests.ts @@ -4,6 +4,8 @@ import type { ManifestWorkspaceView, } from '@umbraco-cms/backoffice/extension-registry'; +export const UMB_EXTENSION_ROOT_WORKSPACE_ALIAS = 'Umb.Workspace.ExtensionRoot'; + const workspace: ManifestWorkspace = { type: 'workspace', alias: 'Umb.Workspace.ExtensionRoot',