diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/views/edit/workspace-view-data-type-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/views/edit/workspace-view-data-type-edit.element.ts index f6023e45ba..c87be82b69 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/views/edit/workspace-view-data-type-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/views/edit/workspace-view-data-type-edit.element.ts @@ -4,7 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; import { UmbModalService } from '../../../../../../core/modal'; import { UmbWorkspaceDataTypeContext } from '../../workspace-data-type.context'; -import type { DataTypeDetails, ManifestPropertyEditorUI } from '@umbraco-cms/models'; +import type { DataTypeDetails } from '@umbraco-cms/models'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import '../../../../../shared/property-editors/shared/property-editor-config/property-editor-config.element'; @@ -78,15 +78,15 @@ export class UmbWorkspaceViewDataTypeEditElement extends UmbLitElement { if (!propertyEditorUIAlias) return; this.observe( - umbExtensionsRegistry.getByAlias(propertyEditorUIAlias), + umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', propertyEditorUIAlias), (propertyEditorUI) => { // TODO: show error. We have stored a PropertyEditorUIAlias and can't find the PropertyEditorUI in the registry. if (!propertyEditorUI) return; this._propertyEditorUIName = propertyEditorUI?.meta.label ?? propertyEditorUI?.name ?? ''; this._propertyEditorUIAlias = propertyEditorUI?.alias ?? ''; - this._propertyEditorUIIcon = propertyEditorUI?.meta?.icon ?? ''; - this._propertyEditorModelAlias = propertyEditorUI?.meta?.propertyEditorModel ?? ''; + this._propertyEditorUIIcon = propertyEditorUI?.meta.icon ?? ''; + this._propertyEditorModelAlias = propertyEditorUI?.meta.propertyEditorModel ?? ''; this._workspaceContext?.update({ propertyEditorModelAlias: this._propertyEditorModelAlias }); } 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 f0f0eb1a86..557c5f01e3 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 @@ -2,13 +2,13 @@ import { html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { isManifestElementNameType } from '@umbraco-cms/extensions-api'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; -import type { ManifestTypes } from '@umbraco-cms/models'; +import type { ManifestBase } from '@umbraco-cms/models'; import { UmbLitElement } from '@umbraco-cms/element'; @customElement('umb-extension-root-workspace') export class UmbExtensionRootWorkspaceElement extends UmbLitElement { @state() - private _extensions?: Array = undefined; + private _extensions?: Array = undefined; connectedCallback(): void { super.connectedCallback(); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-property/entity-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-property/entity-property.element.ts index 2b582722ec..5817a831d4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-property/entity-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-property/entity-property.element.ts @@ -135,14 +135,12 @@ export class UmbEntityPropertyElement extends UmbLitElement { private _observePropertyEditorUI() { this.propertyEditorUIObserver?.destroy(); - this.propertyEditorUIObserver = new UmbObserverController(this, umbExtensionsRegistry.getByAlias(this.propertyEditorUIAlias), (manifest) => { - if (manifest?.type === 'propertyEditorUI') { - this._gotData(manifest); - } + this.propertyEditorUIObserver = this.observe(umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', this.propertyEditorUIAlias), (manifest) => { + this._gotEditor(manifest); }); } - private _gotData(propertyEditorUIManifest?: ManifestPropertyEditorUI) { + private _gotEditor(propertyEditorUIManifest?: ManifestPropertyEditorUI | null) { if (!propertyEditorUIManifest) { // TODO: if dataTypeKey didn't exist in store, we should do some nice UI. return; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.element.ts index 7b1e9dc401..c17dc74ded 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/extension-slot/extension-slot.element.ts @@ -2,7 +2,7 @@ import { nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { map } from 'rxjs'; import { repeat } from 'lit/directives/repeat.js'; -import { ManifestBase, ManifestTypes, umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; +import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import { createExtensionElement } from '@umbraco-cms/extensions-api'; import { isManifestElementableType } from 'src/core/extensions-api/is-manifest-elementable-type.function'; import { UmbLitElement } from '@umbraco-cms/element'; @@ -40,7 +40,7 @@ export class UmbExtensionSlotElement extends UmbLitElement { umbExtensionsRegistry ?.extensionsOfType(this.type) .pipe(map((extensions) => extensions.filter(this.filter))), - async (extensions: ManifestTypes[]) => { + async (extensions) => { const oldLength = this._extensions.length; this._extensions = this._extensions.filter(current => extensions.find(incoming => incoming.alias === current.alias)); @@ -48,7 +48,7 @@ export class UmbExtensionSlotElement extends UmbLitElement { this.requestUpdate('_extensions'); } - extensions.forEach(async (extension: ManifestTypes) => { + extensions.forEach(async (extension) => { const hasExt = this._extensions.find(x => x.alias === extension.alias); if(!hasExt) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/shared/property-editor-config/property-editor-config.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/shared/property-editor-config/property-editor-config.element.ts index 4e3f96478a..f6dc453062 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/shared/property-editor-config/property-editor-config.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/property-editors/shared/property-editor-config/property-editor-config.element.ts @@ -58,27 +58,23 @@ export class UmbPropertyEditorConfigElement extends UmbLitElement { private _observePropertyEditorUIConfig() { if (!this._propertyEditorUIAlias) return; - this.observe(umbExtensionsRegistry.getByAlias(this.propertyEditorUIAlias), (manifest) => { - if (manifest?.type === 'propertyEditorUI') { - this._observePropertyEditorModelConfig(manifest.meta.propertyEditorModel); - this._propertyEditorUIConfigProperties = manifest?.meta.config?.properties || []; - this._propertyEditorUIConfigDefaultData = manifest?.meta.config?.defaultData || []; - this._mergeConfigProperties(); - this._mergeConfigDefaultData(); - } + this.observe(umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', this.propertyEditorUIAlias), (manifest) => { + this._observePropertyEditorModelConfig(manifest?.meta.propertyEditorModel); + this._propertyEditorUIConfigProperties = manifest?.meta.config?.properties || []; + this._propertyEditorUIConfigDefaultData = manifest?.meta.config?.defaultData || []; + this._mergeConfigProperties(); + this._mergeConfigDefaultData(); }); } private _observePropertyEditorModelConfig(propertyEditorModelAlias?: string) { if (!propertyEditorModelAlias) return; - this.observe(umbExtensionsRegistry.getByAlias(propertyEditorModelAlias), (manifest) => { - if (manifest?.type === 'propertyEditorModel') { - this._propertyEditorModelConfigProperties = manifest?.meta.config?.properties || []; - this._propertyEditorModelConfigDefaultData = manifest?.meta.config?.defaultData || []; - this._mergeConfigProperties(); - this._mergeConfigDefaultData(); - } + this.observe(umbExtensionsRegistry.getByTypeAndAlias('propertyEditorModel', propertyEditorModelAlias), (manifest) => { + this._propertyEditorModelConfigProperties = manifest?.meta.config?.properties || []; + this._propertyEditorModelConfigDefaultData = manifest?.meta.config?.defaultData || []; + this._mergeConfigProperties(); + this._mergeConfigDefaultData(); }); } diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-api/create-extension-element.function.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-api/create-extension-element.function.ts index ba7d6c4c49..9bdf96dc5c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-api/create-extension-element.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-api/create-extension-element.function.ts @@ -1,9 +1,9 @@ -import type { ManifestElementType } from '../models'; +import type { ManifestElement } from '../models'; import { hasDefaultExport } from './has-default-export.function'; import { isManifestElementNameType } from './is-manifest-element-name-type.function'; import { loadExtension } from './load-extension.function'; -export async function createExtensionElement(manifest: ManifestElementType): Promise { +export async function createExtensionElement(manifest: ManifestElement): Promise { //TODO: Write tests for these extension options: const js = await loadExtension(manifest); diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-element-name-type.function.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-element-name-type.function.ts index ccc3ae245c..a5176b90c8 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-element-name-type.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-element-name-type.function.ts @@ -1,7 +1,7 @@ -import type { ManifestElementType, ManifestElementWithElementName } from '../models'; +import type { ManifestElement, ManifestElementWithElementName } from '../models'; export function isManifestElementNameType(manifest: unknown): manifest is ManifestElementWithElementName { return ( - typeof manifest === 'object' && manifest !== null && (manifest as ManifestElementType).elementName !== undefined + typeof manifest === 'object' && manifest !== null && (manifest as ManifestElement).elementName !== undefined ); } diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-elementable-type.function.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-elementable-type.function.ts index ada5464619..84454a5e57 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-elementable-type.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-elementable-type.function.ts @@ -1,8 +1,8 @@ -import type { ManifestElementType, ManifestTypes } from "../extensions-registry/models"; +import type { ManifestElement, ManifestBase } from "../extensions-registry/models"; import { isManifestElementNameType } from "./is-manifest-element-name-type.function"; import { isManifestJSType } from "./is-manifest-js-type.function"; import { isManifestLoaderType } from "./is-manifest-loader-type.function"; -export function isManifestElementableType(manifest: ManifestTypes): manifest is ManifestElementType { +export function isManifestElementableType(manifest: ManifestBase): manifest is ManifestElement { return isManifestElementNameType(manifest) || isManifestLoaderType(manifest) || isManifestJSType(manifest); } diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-js-type.function.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-js-type.function.ts index ee56fff0b8..f49e604547 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-js-type.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-js-type.function.ts @@ -1,6 +1,6 @@ -import type { ManifestTypes } from "../extensions-registry/models"; +import type { ManifestBase } from "../extensions-registry/models"; import { ManifestJSType } from "./load-extension.function"; -export function isManifestJSType(manifest: ManifestTypes): manifest is ManifestJSType { +export function isManifestJSType(manifest: ManifestBase): manifest is ManifestJSType { return (manifest as ManifestJSType).js !== undefined; } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-loader-type.function.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-loader-type.function.ts index 27ad690c4d..8303cb7e55 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-loader-type.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-loader-type.function.ts @@ -1,6 +1,6 @@ -import type { ManifestTypes } from "../extensions-registry/models"; +import type { ManifestBase } from "../extensions-registry/models"; import { ManifestLoaderType } from "./load-extension.function"; -export function isManifestLoaderType(manifest: ManifestTypes): manifest is ManifestLoaderType { +export function isManifestLoaderType(manifest: ManifestBase): manifest is ManifestLoaderType { return typeof (manifest as ManifestLoaderType).loader === 'function'; } diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-api/load-extension.function.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-api/load-extension.function.ts index c26d441c12..f1ebdbbe88 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-api/load-extension.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-api/load-extension.function.ts @@ -1,11 +1,11 @@ -import type { ManifestTypes } from '../models'; +import type { ManifestElement } from '../models'; import { isManifestJSType } from './is-manifest-js-type.function'; import { isManifestLoaderType } from './is-manifest-loader-type.function'; -export type ManifestLoaderType = ManifestTypes & { loader: () => Promise }; -export type ManifestJSType = ManifestTypes & { js: string }; +export type ManifestLoaderType = ManifestElement & { loader: () => Promise }; +export type ManifestJSType = ManifestElement & { js: string }; -export async function loadExtension(manifest: ManifestTypes): Promise { +export async function loadExtension(manifest: ManifestElement): Promise { try { if (isManifestLoaderType(manifest)) { return manifest.loader(); diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-api/registry/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-api/registry/extension.registry.ts index a7fa6e245a..2120de9e15 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-api/registry/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-api/registry/extension.registry.ts @@ -1,30 +1,16 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; import type { ManifestTypes, - ManifestDashboard, - ManifestWorkspaceView, - ManifestEntrypoint, - ManifestPropertyAction, - ManifestPropertyEditorUI, - ManifestPropertyEditorModel, - ManifestSection, - ManifestSectionView, - ManifestTree, - ManifestTreeItemAction, - ManifestWorkspace, - ManifestWorkspaceAction, - ManifestCustom, - ManifestPackageView, - ManifestExternalLoginProvider, - ManifestHeaderApp, - ManifestCollectionView, - ManifestCollectionBulkAction, + ManifestTypeMap, + ManifestBase } from '../../models'; import { hasDefaultExport } from '../has-default-export.function'; import { loadExtension } from '../load-extension.function'; +type SpecificManifestTypeOrManifestBase = T extends keyof ManifestTypeMap ? ManifestTypeMap[T] : ManifestBase; + export class UmbExtensionRegistry { - private _extensions = new BehaviorSubject>([]); + private _extensions = new BehaviorSubject>([]); public readonly extensions = this._extensions.asObservable(); register(manifest: ManifestTypes & { loader?: () => Promise }): void { @@ -70,43 +56,27 @@ export class UmbExtensionRegistry { } - getByAlias(alias: string): Observable { + getByAlias(alias: string) { // TODO: make pipes prettier/simpler/reuseable - return this.extensions.pipe(map((dataTypes) => dataTypes.find((extension) => extension.alias === alias) || null)) as Observable; + return this.extensions.pipe(map((dataTypes) => dataTypes.find((extension) => extension.alias === alias) || null)); + } + + getByTypeAndAlias(type: Key, alias: string) { + return this.extensionsOfType(type).pipe(map((extensions) => extensions.find((extension) => extension.alias === alias) || null)); } // TODO: implement unregister of extension - // Typings concept, need to put all core types to get a good array return type for the provided type... - extensionsOfType(type: 'headerApp'): Observable>; - extensionsOfType(type: 'section'): Observable>; - extensionsOfType(type: 'sectionView'): Observable>; - extensionsOfType(type: 'tree'): Observable>; - extensionsOfType(type: 'workspace'): Observable>; - extensionsOfType(type: 'treeItemAction'): Observable>; - extensionsOfType(type: 'dashboard'): Observable>; - extensionsOfType(type: 'dashboardCollection'): Observable>; - extensionsOfType(type: 'workspaceView'): Observable>; - extensionsOfType(type: 'workspaceAction'): Observable>; - extensionsOfType(type: 'propertyEditorUI'): Observable>; - extensionsOfType(type: 'propertyEditorModel'): Observable>; - extensionsOfType(type: 'propertyAction'): Observable>; - extensionsOfType(type: 'packageView'): Observable>; - extensionsOfType(type: 'entrypoint'): Observable>; - extensionsOfType(type: 'custom'): Observable>; - extensionsOfType(type: 'externalLoginProvider'): Observable>; - extensionsOfType(type: 'collectionView'): Observable>; - extensionsOfType(type: 'collectionBulkAction'): Observable>; - extensionsOfType(type: string): Observable>; - extensionsOfType(type: string): Observable> { + + extensionsOfType>(type: Key) { return this.extensions.pipe( map((exts) => exts.filter((ext) => ext.type === type).sort((a, b) => (b.weight || 0) - (a.weight || 0))) - ); + ) as Observable>; } - extensionsOfTypes(types: string[]): Observable> { + extensionsOfTypes(types: string[]): Observable> { return this.extensions.pipe( map((exts) => exts.filter((ext) => (types.indexOf(ext.type) !== -1)).sort((a, b) => (b.weight || 0) - (a.weight || 0))) ) as Observable>; } -} +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-registry/models.ts index 66614007be..7be0281f1a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-registry/models.ts @@ -37,6 +37,7 @@ export * from './collection-bulk-action.models'; export * from './collection-view.models'; export type ManifestTypes = + | ManifestCustom | ManifestHeaderApp | ManifestSection | ManifestSectionView @@ -55,48 +56,16 @@ export type ManifestTypes = | ManifestPackageView | ManifestExternalLoginProvider | ManifestEntrypoint - | ManifestCustom | ManifestCollectionBulkAction | ManifestCollectionView; -export type ManifestStandardTypes = - | 'headerApp' - | 'section' - | 'sectionView' - | 'tree' - | 'workspace' - | 'workspaceAction' - | 'workspaceView' - | 'workspaceViewCollection' - | 'treeItemAction' - | 'propertyEditorUI' - | 'propertyEditorModel' - | 'dashboard' - | 'dashboardCollection' - | 'userDashboard' - | 'propertyAction' - | 'packageView' - | 'entrypoint' - | 'externalLoginProvider' - | 'collectionBulkAction' - | 'collectionView'; +export type ManifestStandardTypes = ManifestTypes['type']; + +export type ManifestTypeMap = { + [Manifest in ManifestTypes as Manifest['type']]: Manifest; +}; + -export type ManifestElementType = - | ManifestSection - | ManifestSectionView - | ManifestTree - | ManifestTreeItemAction - | ManifestWorkspace - | ManifestWorkspaceView - | ManifestPropertyAction - | ManifestPropertyEditorUI - | ManifestDashboard - | ManifestUserDashboard - | ManifestWorkspaceAction - | ManifestPackageView - | ManifestExternalLoginProvider - | ManifestCollectionBulkAction - | ManifestCollectionView; export interface ManifestBase { type: string;