From b2366fcc38af79a38d0b82d4b037240d841dca50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 22 Dec 2022 15:17:48 +0100 Subject: [PATCH] common workspace-view-collection --- .../collection-view-media-grid.element.ts | 1 + .../extension-slot/extension-slot.element.ts | 10 +- .../src/backoffice/sections/manifests.ts | 4 +- .../data-type/workspace-data-type.context.ts | 2 +- .../workspace-dictionary.element.ts | 2 +- .../workspace-document-type.context.ts | 2 +- .../document/workspace-document.context.ts | 2 +- .../workspace-extension-root.element.ts | 4 +- .../media/workspace-media.context.ts | 2 +- .../media/workspace-media.element.ts | 9 +- ...s => workspace-view-collection.element.ts} | 15 +- .../workspace-node.context.ts | 4 +- .../workspace-entity-layout.element.ts | 180 ------------------ .../workspace-entity.element.ts | 31 ++- .../workspace-user-group.context.ts | 2 +- .../workspaces/user/workspace-user.context.ts | 2 +- .../create-extension-element.function.ts | 15 +- .../src/core/extensions-api/index.ts | 2 +- .../extensions-api/is-extension.function.ts | 7 - .../is-manifest-element-name-type.function.ts | 7 + .../is-manifest-elementable-type.function.ts | 8 + .../is-manifest-js-type.function.ts | 6 + .../is-manifest-loader-type.function.ts | 6 + .../extensions-api/load-extension.function.ts | 12 +- .../registry/extension.registry.ts | 14 +- .../dashboard-collection.models.ts | 4 +- .../src/core/extensions-registry/models.ts | 13 +- .../workspace-view-collection.models.ts | 15 ++ .../core/stores/data-type/data-type.store.ts | 3 + .../stores/dictionary/dictionary.store.ts | 3 + .../document-type/document-type.store.ts | 3 + .../core/stores/document/document.store.ts | 3 + .../stores/media-type/media-type.store.ts | 2 + .../src/core/stores/media/media.store.ts | 3 + .../stores/member-group/member-group.store.ts | 2 + .../stores/member-type/member-type.store.ts | 1 + .../src/core/stores/store.ts | 4 + .../src/core/stores/user/user-group.store.ts | 4 + .../src/core/stores/user/user.store.ts | 5 + 39 files changed, 167 insertions(+), 247 deletions(-) rename src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-content/views/collection/{workspace-view-media-collection.element.ts => workspace-view-collection.element.ts} (73%) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-entity-layout/workspace-entity-layout.element.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/core/extensions-api/is-extension.function.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-element-name-type.function.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-elementable-type.function.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-js-type.function.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/extensions-api/is-manifest-loader-type.function.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/extensions-registry/workspace-view-collection.models.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts index 29bf8daba8..5c3f00d591 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/collection/views/collection-view-media-grid.element.ts @@ -86,6 +86,7 @@ export class UmbCollectionViewsMediaGridElement extends UmbContextConsumerMixin( this.toggleAttribute('dragging', false); }); this.consumeContext('umbCollectionContext', (instance) => { + console.log("umbCollectionContext", instance) this._collectionContext = instance; this._observeCollectionContext(); }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/extension-slot/extension-slot.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/extension-slot/extension-slot.element.ts index 62281f5d25..dfe8bca542 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/extension-slot/extension-slot.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/extension-slot/extension-slot.element.ts @@ -4,7 +4,8 @@ import { map } from 'rxjs'; import { repeat } from 'lit/directives/repeat.js'; import { ManifestTypes, umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; -import { createExtensionElement } from '@umbraco-cms/extensions-api'; +import { createExtensionElement, isManifestElementNameType } from '@umbraco-cms/extensions-api'; +import { isManifestElementableType } from 'src/core/extensions-api/is-manifest-elementable-type.function'; type InitializedExtensionItem = {alias: string, weight: number, component: HTMLElement|null} @@ -62,7 +63,12 @@ export class UmbExtensionSlotElement extends UmbObserverMixin(LitElement) { if(!hasExt) { const extensionObject:InitializedExtensionItem = {alias: extension.alias, weight: (extension as any).weight || 0, component: null}; this._extensions.push(extensionObject); - const component = await createExtensionElement(extension); + let component; + if(isManifestElementableType(extension)) { + component = await createExtensionElement(extension); + } else { + // TODO: ability to use a default element. or fail at creating this type. + } if(component) { (component as any).manifest = extension; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/manifests.ts index 85bfea2c8e..86a79ae3cc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/manifests.ts @@ -6,9 +6,9 @@ import { manifests as settingsSectionManifests } from './settings/manifests'; import { manifests as translationSectionManifests } from './translation/manifests'; import { manifests as userSectionManifests } from './users/manifests'; -import type { ManifestDashboard, ManifestSection, ManifestSectionView } from '@umbraco-cms/models'; +import type { ManifestDashboard, ManifestDashboardCollection, ManifestSection, ManifestSectionView } from '@umbraco-cms/models'; -export const manifests: Array = [ +export const manifests: Array = [ ...contentSectionManifests, ...mediaSectionManifests, ...memberSectionManifests, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/data-type/workspace-data-type.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/data-type/workspace-data-type.context.ts index ce33a1fb3c..8c33787976 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/data-type/workspace-data-type.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/data-type/workspace-data-type.context.ts @@ -17,7 +17,7 @@ const DefaultDataTypeData = ({ export class UmbWorkspaceDataTypeContext extends UmbWorkspaceNodeContext { constructor(target:HTMLElement, entityKey: string) { - super(target, DefaultDataTypeData, 'umbDataTypeStore', entityKey); + super(target, DefaultDataTypeData, 'umbDataTypeStore', entityKey, 'dataType'); } public setPropertyValue(propertyAlias: string, value: any) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/dictionary/workspace-dictionary.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/dictionary/workspace-dictionary.element.ts index 0a8a4cb2e4..2c7a82067e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/dictionary/workspace-dictionary.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/dictionary/workspace-dictionary.element.ts @@ -20,7 +20,7 @@ export class UmbWorkspaceDictionaryElement extends LitElement { render() { return html` - Dictionary Workspace + Dictionary Workspace `; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document-type/workspace-document-type.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document-type/workspace-document-type.context.ts index a6928e0afe..24eba4577f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document-type/workspace-document-type.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document-type/workspace-document-type.context.ts @@ -15,7 +15,7 @@ const DefaultDocumentTypeData = ({ export class UmbWorkspaceDocumentTypeContext extends UmbWorkspaceNodeContext { constructor(target:HTMLElement, entityKey: string) { - super(target, DefaultDocumentTypeData, 'umbDocumentTypeStore', entityKey); + super(target, DefaultDocumentTypeData, 'umbDocumentTypeStore', entityKey, 'documentType'); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document/workspace-document.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document/workspace-document.context.ts index 5683cef050..f7b200fa2d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document/workspace-document.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/document/workspace-document.context.ts @@ -34,7 +34,7 @@ const DefaultDocumentData = ({ export class UmbWorkspaceDocumentContext extends UmbWorkspaceNodeContext { constructor(target:HTMLElement, entityKey: string) { - super(target, DefaultDocumentData, 'umbDocumentStore', entityKey); + super(target, DefaultDocumentData, 'umbDocumentStore', entityKey, 'document'); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/extension-root/workspace-extension-root.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/extension-root/workspace-extension-root.element.ts index c1edfdb76b..f857292dc9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/extension-root/workspace-extension-root.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/extension-root/workspace-extension-root.element.ts @@ -1,7 +1,7 @@ import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; -import { isManifestElementType } from '@umbraco-cms/extensions-api'; +import { isManifestElementNameType } from '@umbraco-cms/extensions-api'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import { UmbContextConsumerMixin } from '@umbraco-cms/context-api'; import type { ManifestTypes } from '@umbraco-cms/models'; @@ -40,7 +40,7 @@ export class UmbWorkspaceExtensionRootElement extends UmbContextConsumerMixin(Um ${extension.type} - ${isManifestElementType(extension) ? extension.name : 'Custom extension'} + ${isManifestElementNameType(extension) ? extension.name : 'Custom extension'} ${extension.alias} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.context.ts index e630f02c5f..7ba440b539 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.context.ts @@ -34,7 +34,7 @@ const DefaultMediaData = ({ export class UmbWorkspaceMediaContext extends UmbWorkspaceNodeContext { constructor(target:HTMLElement, entityKey: string) { - super(target, DefaultMediaData, 'umbMediaStore', entityKey); + super(target, DefaultMediaData, 'umbMediaStore', entityKey, 'media'); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.element.ts index 80d1da0d55..045f37f9b9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/media/workspace-media.element.ts @@ -2,7 +2,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { UmbWorkspaceMediaContext } from './workspace-media.context'; -import type { ManifestWorkspaceView } from '@umbraco-cms/models'; +import type { ManifestWorkspaceView, ManifestWorkspaceViewCollection } from '@umbraco-cms/models'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api'; @@ -60,18 +60,19 @@ export class UmbWorkspaceMediaElement extends UmbContextConsumerMixin(UmbContext } private _registerWorkspaceViews() { - const dashboards: Array = [ + const dashboards: Array = [ { - type: 'workspaceView', + type: 'workspaceViewCollection', alias: 'Umb.WorkspaceView.Media.Collection', name: 'Media Workspace Collection View', - loader: () => import('../shared/workspace-content/views/collection/workspace-view-media-collection.element'), weight: 300, meta: { workspaces: ['Umb.Workspace.Media'], label: 'Media', pathname: 'collection', icon: 'umb:grid', + entityType: 'media', + storeAlias: 'umbMediaStore' }, }, { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-content/views/collection/workspace-view-media-collection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-content/views/collection/workspace-view-collection.element.ts similarity index 73% rename from src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-content/views/collection/workspace-view-media-collection.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-content/views/collection/workspace-view-collection.element.ts index 41d1010143..5e8b48e1b5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-content/views/collection/workspace-view-media-collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-content/views/collection/workspace-view-collection.element.ts @@ -1,6 +1,7 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement } from 'lit/decorators.js'; +import { ifDefined } from 'lit-html/directives/if-defined.js'; import type { UmbWorkspaceNodeContext } from '../../../workspace-context/workspace-node.context'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; @@ -10,8 +11,8 @@ import 'src/backoffice/dashboards/collection/dashboard-collection.element'; import { UmbCollectionContext } from '@umbraco-cms/components/collection/collection.context'; import { UmbMediaStore, UmbMediaStoreItemType } from '@umbraco-cms/stores/media/media.store'; -@customElement('umb-workspace-view-collection-media') -export class UmbWorkspaceViewCollectionMediaElement extends UmbContextProviderMixin(UmbContextConsumerMixin(UmbObserverMixin(LitElement))) { +@customElement('umb-workspace-view-collection') +export class UmbWorkspaceViewCollectionElement extends UmbContextProviderMixin(UmbContextConsumerMixin(UmbObserverMixin(LitElement))) { static styles = [ UUITextStyles, css` @@ -25,6 +26,7 @@ export class UmbWorkspaceViewCollectionMediaElement extends UmbContextProviderMi private _workspaceContext?: UmbWorkspaceNodeContext; private _collectionContext?:UmbCollectionContext; + constructor() { super(); @@ -48,7 +50,8 @@ export class UmbWorkspaceViewCollectionMediaElement extends UmbContextProviderMi protected _provideWorkspace() { if(this._workspaceContext?.entityKey != null) { - this._collectionContext = new UmbCollectionContext(this, this._workspaceContext.entityKey, 'umbMediaStore'); + console.log("collection:", this._workspaceContext.entityType, this._workspaceContext.entityKey, this._workspaceContext.getStore().storeAlias) + this._collectionContext = new UmbCollectionContext(this, this._workspaceContext.entityKey, this._workspaceContext.getStore().storeAlias); this._collectionContext.connectedCallback(); this.provideContext('umbCollectionContext', this._collectionContext); } @@ -57,14 +60,14 @@ export class UmbWorkspaceViewCollectionMediaElement extends UmbContextProviderMi render() { - return html``; + return html``; } } -export default UmbWorkspaceViewCollectionMediaElement; +export default UmbWorkspaceViewCollectionElement; declare global { interface HTMLElementTagNameMap { - 'umb-workspace-view-collection-media': UmbWorkspaceViewCollectionMediaElement; + 'umb-workspace-view-collection': UmbWorkspaceViewCollectionElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-context/workspace-node.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-context/workspace-node.context.ts index bfa2cef3a8..c491de9bb2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-context/workspace-node.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-context/workspace-node.context.ts @@ -12,8 +12,9 @@ export class UmbWorkspaceNodeContext { @@ -21,6 +22,7 @@ export class UmbWorkspaceNodeContext = []; - - @state() - private _currentView = ''; - - @state() - private _routes: Array = []; - - private _routerFolder = ''; - - connectedCallback(): void { - super.connectedCallback(); - - this._observeWorkspaceViews(); - - /* TODO: find a way to construct absolute urls */ - this._routerFolder = window.location.pathname.split('/view')[0]; - } - - private _observeWorkspaceViews() { - this.observe( - umbExtensionsRegistry - .extensionsOfType('workspaceView') - .pipe(map((extensions) => extensions.filter((extension) => extension.meta.workspaces.includes(this.alias)))), - (workspaceViews) => { - this._workspaceViews = workspaceViews; - this._createRoutes(); - } - ); - } - - private async _createRoutes() { - if (this._workspaceViews.length > 0) { - this._routes = []; - - this._routes = this._workspaceViews.map((view) => { - return { - path: `view/${view.meta.pathname}`, - component: () => createExtensionElement(view) as unknown as PageComponent, - setup: (_element: HTMLElement, info: IRoutingInfo) => { - this._currentView = info.match.route.path; - }, - }; - }); - - this._routes.push({ - path: '**', - redirectTo: `view/${this._workspaceViews?.[0].meta.pathname}`, - }); - - this.requestUpdate(); - await this.updateComplete; - - this._forceRouteRender(); - } - } - - // TODO: Figure out why this has been necessary for this case. Come up with another case - private _forceRouteRender() { - const routerSlotEl = this.shadowRoot?.querySelector('router-slot') as RouterSlot; - if (routerSlotEl) { - routerSlotEl.render(); - } - } - - private _renderTabs() { - return html` - ${this._workspaceViews?.length > 0 - ? html` - - ${this._workspaceViews.map( - (view: ManifestWorkspaceView) => html` - - - ${view.meta.label || view.name} - - ` - )} - - ` - : nothing} - `; - } - - render() { - return html` - - - ${this._renderTabs()} - - - - - - extension.meta.workspaces.includes(this.alias)}> - - - `; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'umb-workspace-entity-layout': UmbWorkspaceEntityLayout; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-entity/workspace-entity.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-entity/workspace-entity.element.ts index 10074a3cc0..1511f2f33d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-entity/workspace-entity.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/shared/workspace-entity/workspace-entity.element.ts @@ -1,14 +1,14 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement, nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { IRoute, IRoutingInfo, PageComponent, RouterSlot } from 'router-slot'; +import { IRoutingInfo, RouterSlot } from 'router-slot'; import { map } from 'rxjs'; import { UmbObserverMixin } from '@umbraco-cms/observable-api'; import { createExtensionElement } from '@umbraco-cms/extensions-api'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; import { UmbContextConsumerMixin } from '@umbraco-cms/context-api'; -import type { ManifestWorkspaceView } from '@umbraco-cms/models'; +import type { ManifestWithMeta, ManifestWorkspaceView, ManifestWorkspaceViewCollection } from '@umbraco-cms/models'; import '../../../components/body-layout/body-layout.element'; import '../../../components/extension-slot/extension-slot.element'; @@ -65,13 +65,13 @@ export class UmbWorkspaceEntity extends UmbContextConsumerMixin(UmbObserverMixin public alias = ''; @state() - private _workspaceViews: Array = []; + private _workspaceViews: Array = []; @state() private _currentView = ''; @state() - private _routes: Array = []; + private _routes: Array = []; private _routerFolder = ''; @@ -87,8 +87,8 @@ export class UmbWorkspaceEntity extends UmbContextConsumerMixin(UmbObserverMixin private _observeWorkspaceViews() { this.observe( umbExtensionsRegistry - .extensionsOfType('workspaceView') - .pipe(map((extensions) => extensions.filter((extension) => extension.meta.workspaces.includes(this.alias)))), + .extensionsOfTypes(['workspaceView', 'workspaceViewCollection']) + .pipe(map((extensions) => extensions.filter((extension) => (extension as ManifestWithMeta).meta.workspaces.includes(this.alias)))), (workspaceViews) => { this._workspaceViews = workspaceViews; this._createRoutes(); @@ -103,10 +103,21 @@ export class UmbWorkspaceEntity extends UmbContextConsumerMixin(UmbObserverMixin this._routes = this._workspaceViews.map((view) => { return { path: `view/${view.meta.pathname}`, - component: () => createExtensionElement(view) as unknown as PageComponent, - setup: (_element: HTMLElement, info: IRoutingInfo) => { - this._currentView = info.match.route.path; + component: () => { + if (view.type === 'workspaceViewCollection') { + console.log("!!!!!workspaceViewCollection") + return import('src/backoffice/workspaces/shared/workspace-content/views/collection/workspace-view-collection.element'); + } + return createExtensionElement(view) }, + setup: (component: Promise | HTMLElement, info: IRoutingInfo) => { + this._currentView = info.match.route.path; + // When its using import, we get an element, when using createExtensionElement we get a Promise. + (component as any).manifest = view; + if((component as any).then) { + (component as any).then((el: any) => el.manifest = view); + } + } }; }); @@ -136,7 +147,7 @@ export class UmbWorkspaceEntity extends UmbContextConsumerMixin(UmbObserverMixin ? html` ${this._workspaceViews.map( - (view: ManifestWorkspaceView) => html` + (view: ManifestWorkspaceView | ManifestWorkspaceViewCollection) => html` { constructor(target:HTMLElement, entityKey: string) { - super(target, DefaultDataTypeData, 'umbUserStore', entityKey); + super(target, DefaultDataTypeData, 'umbUserStore', entityKey, 'userGroup'); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/user/workspace-user.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/user/workspace-user.context.ts index 6839f9810e..c998dbbd41 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/user/workspace-user.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/workspaces/user/workspace-user.context.ts @@ -23,7 +23,7 @@ const DefaultDataTypeData = ({ export class UmbWorkspaceUserContext extends UmbWorkspaceNodeContext { constructor(target:HTMLElement, entityKey: string) { - super(target, DefaultDataTypeData, 'umbUserStore', entityKey); + super(target, DefaultDataTypeData, 'umbUserStore', entityKey, 'user'); } } 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 e731e60142..ba7d6c4c49 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,13 +1,14 @@ -import type { ManifestTypes } from '../models'; +import type { ManifestElementType } from '../models'; import { hasDefaultExport } from './has-default-export.function'; -import { isManifestElementType } from './is-extension.function'; +import { isManifestElementNameType } from './is-manifest-element-name-type.function'; import { loadExtension } from './load-extension.function'; -export async function createExtensionElement(manifest: ManifestTypes): Promise { +export async function createExtensionElement(manifest: ManifestElementType): Promise { + //TODO: Write tests for these extension options: const js = await loadExtension(manifest); - if (isManifestElementType(manifest) && manifest.elementName) { + if (isManifestElementNameType(manifest)) { // created by manifest method providing HTMLElement return document.createElement(manifest.elementName); } @@ -19,14 +20,12 @@ export async function createExtensionElement(manifest: ManifestTypes): Promise Promise }; export type ManifestJSType = ManifestTypes & { js: string }; @@ -18,12 +20,4 @@ export async function loadExtension(manifest: ManifestTypes): Promise>([]); @@ -37,9 +38,16 @@ export class UmbExtensionRegistry { this._extensions.next([...extensionsValues, manifest]); - // If entrypoint extension, we should load it immediately + // If entrypoint extension, we should load and run it immediately if (manifest.type === 'entrypoint') { - createExtensionElement(manifest); + loadExtension(manifest).then((js) => { + if (hasDefaultExport(js)) { + new js.default(); + } else { + console.error(`Extension with alias '${manifest.alias}' of type 'entrypoint' must have a default export of its JavaScript module.`) + } + }); + } } diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-registry/dashboard-collection.models.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-registry/dashboard-collection.models.ts index de6d57e247..bb10c6d4f8 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extensions-registry/dashboard-collection.models.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-registry/dashboard-collection.models.ts @@ -9,6 +9,6 @@ export interface MetaDashboardCollection { sections: string[]; pathname: string; label?: string; - entityType: string, - storeAlias: string + entityType: string; + storeAlias: string; } 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 4f11a004a2..3fba383b32 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 @@ -6,6 +6,7 @@ import type { ManifestTreeItemAction } from './tree-item-action.models'; import type { ManifestWorkspace } from './workspace.models'; import type { ManifestWorkspaceAction } from './workspace-action.models'; import type { ManifestWorkspaceView } from './workspace-view.models'; +import type { ManifestWorkspaceViewCollection } from './workspace-view-collection.models'; import type { ManifestPropertyEditorUI, ManifestPropertyEditorModel } from './property-editor.models'; import type { ManifestDashboard } from './dashboard.models'; import type { ManifestDashboardCollection } from './dashboard-collection.models'; @@ -24,6 +25,7 @@ export * from './tree-item-action.models'; export * from './workspace.models'; export * from './workspace-action.models'; export * from './workspace-view.models'; +export * from './workspace-view-collection.models'; export * from './property-editor.models'; export * from './dashboard.models'; export * from './dashboard-collection.models'; @@ -42,6 +44,7 @@ export type ManifestTypes = | ManifestWorkspace | ManifestWorkspaceAction | ManifestWorkspaceView + | ManifestWorkspaceViewCollection | ManifestTreeItemAction | ManifestPropertyEditorUI | ManifestPropertyEditorModel @@ -62,8 +65,9 @@ export type ManifestStandardTypes = | 'sectionView' | 'tree' | 'workspace' - | 'workspaceView' | 'workspaceAction' + | 'workspaceView' + | 'workspaceViewCollection' | 'treeItemAction' | 'propertyEditorUI' | 'propertyEditorModel' @@ -83,12 +87,11 @@ export type ManifestElementType = | ManifestTree | ManifestTreeItemAction | ManifestWorkspace + | ManifestWorkspaceView | ManifestPropertyAction | ManifestPropertyEditorUI | ManifestDashboard - | ManifestDashboardCollection | ManifestUserDashboard - | ManifestWorkspaceView | ManifestWorkspaceAction | ManifestPackageView | ManifestExternalLoginProvider @@ -110,6 +113,10 @@ export interface ManifestElement extends ManifestBase { meta?: any; } +export interface ManifestElementWithElementName extends ManifestElement { + elementName: string; +} + export interface ManifestCustom extends ManifestBase { type: 'custom'; meta?: any; diff --git a/src/Umbraco.Web.UI.Client/src/core/extensions-registry/workspace-view-collection.models.ts b/src/Umbraco.Web.UI.Client/src/core/extensions-registry/workspace-view-collection.models.ts new file mode 100644 index 0000000000..b14f232a5c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/extensions-registry/workspace-view-collection.models.ts @@ -0,0 +1,15 @@ +import type { ManifestBase } from './models'; + +export interface ManifestWorkspaceViewCollection extends ManifestBase { + type: 'workspaceViewCollection'; + meta: MetaEditorViewCollection; +} + +export interface MetaEditorViewCollection { + workspaces: string[]; + pathname: string; + label: string; + icon: string; + entityType: string; + storeAlias: string; +} diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/data-type/data-type.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/data-type/data-type.store.ts index d67ebafb68..a156d75b9a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/data-type/data-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/data-type/data-type.store.ts @@ -17,6 +17,9 @@ export type UmbDataTypeStoreItemType = DataTypeDetails | FolderTreeItem; * @description - Data Store for Data Types */ export class UmbDataTypeStore extends UmbDataStoreBase { + + public readonly storeAlias = 'umbDataTypeStore'; + /** * @description - Request a Data Type by key. The Data Type is added to the store and is returned as an Observable. * @param {string} key diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/dictionary/dictionary.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/dictionary/dictionary.store.ts index 0f60028410..9be3ad0f32 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/dictionary/dictionary.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/dictionary/dictionary.store.ts @@ -9,6 +9,9 @@ import { ApiError, DictionaryResource, EntityTreeItem, ProblemDetails } from '@u * @description - Data Store for Dictionary Items. */ export class UmbDictionaryStore extends UmbDataStoreBase { + + public readonly storeAlias = 'umbDictionaryStore'; + /** * @description - Get the root of the tree. * @return {*} {Observable>} diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/document-type/document-type.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/document-type/document-type.store.ts index 20b1c63cc8..f011e1cbad 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/document-type/document-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/document-type/document-type.store.ts @@ -16,6 +16,9 @@ export type UmbDocumentTypeStoreItemType = DocumentTypeDetails | DocumentTypeTre * @description - Data Store for Document Types */ export class UmbDocumentTypeStore extends UmbDataStoreBase { + + public readonly storeAlias = 'umbDocumentTypeStore'; + getByKey(key: string): Observable { // TODO: use Fetcher API. // TODO: only fetch if the data type is not in the store? diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/document/document.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/document/document.store.ts index 5d0379ab2b..4476f9080c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/document/document.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/document/document.store.ts @@ -16,6 +16,9 @@ export type UmbDocumentStoreItemType = DocumentDetails | DocumentTreeItem * @description - Data Store for Documents */ export class UmbDocumentStore extends UmbNodeStoreBase { + + public readonly storeAlias = 'umbDocumentStore'; + getByKey(key: string): Observable { // TODO: use backend cli when available. fetch(`/umbraco/management/api/v1/document/details/${key}`) diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/media-type/media-type.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/media-type/media-type.store.ts index e82080f343..2bc7898b2a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/media-type/media-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/media-type/media-type.store.ts @@ -13,6 +13,8 @@ export type UmbMediaTypeStoreItemType = MediaTypeDetails | FolderTreeItem; */ export class UmbMediaTypeStore extends UmbNodeStoreBase { + public readonly storeAlias = 'umbMediaTypeStore'; + /** * @description - Request a Data Type by key. The Data Type is added to the store and is returned as an Observable. * @param {string} key diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/media/media.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/media/media.store.ts index 460a59c792..170e3364b5 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/media/media.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/media/media.store.ts @@ -17,6 +17,9 @@ export type UmbMediaStoreItemType = MediaDetails | ContentTreeItem; * @description - Data Store for Media */ export class UmbMediaStore extends UmbDataStoreBase { + + public readonly storeAlias = 'umbMediaStore'; + getByKey(key: string): Observable { // fetch from server and update store fetch(`/umbraco/management/api/v1/media/details/${key}`) diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/member-group/member-group.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/member-group/member-group.store.ts index fe4a22212d..dcce68e6ff 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/member-group/member-group.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/member-group/member-group.store.ts @@ -13,6 +13,8 @@ export type UmbMemberGroupStoreItemType = MemberGroupDetails | EntityTreeItem; */ export class UmbMemberGroupStore extends UmbNodeStoreBase { + public readonly storeAlias = 'umbMemberGroupStore'; + getByKey(key: string): Observable { return null as any; } diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/member-type/member-type.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/member-type/member-type.store.ts index 540c4ff1f3..19f743eabc 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/member-type/member-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/member-type/member-type.store.ts @@ -13,6 +13,7 @@ export type UmbMemberTypeStoreItemType = MemberTypeDetails | EntityTreeItem */ export class UmbMemberTypeStore extends UmbDataStoreBase { + public readonly storeAlias = 'umbMemberTypeStore'; getByKey(key: string): Observable { return null as any; diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts index cfe8b81100..d961e1c61c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts @@ -6,6 +6,7 @@ export interface UmbDataStoreIdentifiers { } export interface UmbDataStore { + readonly storeAlias: string; readonly items: Observable>; updateItems(items: Array): void; } @@ -23,6 +24,9 @@ export interface UmbTreeDataStore extends UmbDataStore { * @description - Base class for Data Stores */ export abstract class UmbDataStoreBase implements UmbDataStore { + + public abstract readonly storeAlias:string; + protected _items: BehaviorSubject> = new BehaviorSubject(>[]); public readonly items: Observable> = this._items.asObservable(); diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts index a22b286778..e85ff7dab9 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts @@ -12,6 +12,10 @@ export type UmbUserGroupStoreItemType = UserGroupDetails & { users?: Array { + + + public readonly storeAlias = 'umbUserGroupStore'; + getAll(): Observable> { // TODO: use Fetcher API. // TODO: only fetch if the data type is not in the store? diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts index 154b740d33..d2fcfff9c1 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts @@ -11,6 +11,11 @@ export type UmbUserStoreItemType = UserDetails; * @description - Data Store for Users */ export class UmbUserStore extends UmbDataStoreBase { + + + public readonly storeAlias = 'umbUserStore'; + + private _totalUsers: BehaviorSubject = new BehaviorSubject(0); public readonly totalUsers: Observable = this._totalUsers.asObservable();