common workspace-view-collection
This commit is contained in:
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ManifestSection | ManifestDashboard | ManifestSectionView> = [
|
||||
export const manifests: Array<ManifestSection | ManifestDashboardCollection | ManifestDashboard | ManifestSectionView> = [
|
||||
...contentSectionManifests,
|
||||
...mediaSectionManifests,
|
||||
...memberSectionManifests,
|
||||
|
||||
@@ -17,7 +17,7 @@ const DefaultDataTypeData = ({
|
||||
export class UmbWorkspaceDataTypeContext extends UmbWorkspaceNodeContext<UmbDataTypeStoreItemType, UmbDataTypeStore> {
|
||||
|
||||
constructor(target:HTMLElement, entityKey: string) {
|
||||
super(target, DefaultDataTypeData, 'umbDataTypeStore', entityKey);
|
||||
super(target, DefaultDataTypeData, 'umbDataTypeStore', entityKey, 'dataType');
|
||||
}
|
||||
|
||||
public setPropertyValue(propertyAlias: string, value: any) {
|
||||
|
||||
@@ -20,7 +20,7 @@ export class UmbWorkspaceDictionaryElement extends LitElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-workspace-entity-layout alias="Umb.Workspace.Dictionary">Dictionary Workspace</umb-workspace-entity-layout>
|
||||
<umb-workspace-entity alias="Umb.Workspace.Dictionary">Dictionary Workspace</umb-workspace-entity>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const DefaultDocumentTypeData = ({
|
||||
export class UmbWorkspaceDocumentTypeContext extends UmbWorkspaceNodeContext<UmbDocumentTypeStoreItemType, UmbDocumentTypeStore> {
|
||||
|
||||
constructor(target:HTMLElement, entityKey: string) {
|
||||
super(target, DefaultDocumentTypeData, 'umbDocumentTypeStore', entityKey);
|
||||
super(target, DefaultDocumentTypeData, 'umbDocumentTypeStore', entityKey, 'documentType');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ const DefaultDocumentData = ({
|
||||
export class UmbWorkspaceDocumentContext extends UmbWorkspaceNodeContext<UmbDocumentStoreItemType, UmbDocumentStore> {
|
||||
|
||||
constructor(target:HTMLElement, entityKey: string) {
|
||||
super(target, DefaultDocumentData, 'umbDocumentStore', entityKey);
|
||||
super(target, DefaultDocumentData, 'umbDocumentStore', entityKey, 'document');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
<uui-table-row>
|
||||
<uui-table-cell>${extension.type}</uui-table-cell>
|
||||
<uui-table-cell>
|
||||
${isManifestElementType(extension) ? extension.name : 'Custom extension'}
|
||||
${isManifestElementNameType(extension) ? extension.name : 'Custom extension'}
|
||||
</uui-table-cell>
|
||||
<uui-table-cell>${extension.alias}</uui-table-cell>
|
||||
<uui-table-cell>
|
||||
|
||||
@@ -34,7 +34,7 @@ const DefaultMediaData = ({
|
||||
export class UmbWorkspaceMediaContext extends UmbWorkspaceNodeContext<UmbMediaStoreItemType, UmbMediaStore> {
|
||||
|
||||
constructor(target:HTMLElement, entityKey: string) {
|
||||
super(target, DefaultMediaData, 'umbMediaStore', entityKey);
|
||||
super(target, DefaultMediaData, 'umbMediaStore', entityKey, 'media');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<ManifestWorkspaceView> = [
|
||||
const dashboards: Array<ManifestWorkspaceView | ManifestWorkspaceViewCollection> = [
|
||||
{
|
||||
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'
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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<UmbMediaStoreItemType, UmbMediaStore>;
|
||||
|
||||
|
||||
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`<umb-collection entityType="media"></umb-collection>`;
|
||||
return html`<umb-collection entityType=${ifDefined(this._workspaceContext?.entityType)}></umb-collection>`;
|
||||
}
|
||||
}
|
||||
|
||||
export default UmbWorkspaceViewCollectionMediaElement;
|
||||
export default UmbWorkspaceViewCollectionElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-workspace-view-collection-media': UmbWorkspaceViewCollectionMediaElement;
|
||||
'umb-workspace-view-collection': UmbWorkspaceViewCollectionElement;
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,9 @@ export class UmbWorkspaceNodeContext<ContentTypeType extends ContentTreeItem = C
|
||||
protected _notificationConsumer!:UmbContextConsumer;
|
||||
|
||||
public entityKey:string;
|
||||
public entityType:string;
|
||||
|
||||
constructor(target:HTMLElement, defaultData:ContentTypeType, storeAlias:string, entityKey: string) {
|
||||
constructor(target:HTMLElement, defaultData:ContentTypeType, storeAlias:string, entityKey: string, entityType: string) {
|
||||
super(target, defaultData, storeAlias);
|
||||
|
||||
this._notificationConsumer = new UmbContextConsumer(this._target, 'umbNotificationService', (_instance: UmbNotificationService) => {
|
||||
@@ -21,6 +22,7 @@ export class UmbWorkspaceNodeContext<ContentTypeType extends ContentTreeItem = C
|
||||
});
|
||||
|
||||
this.entityKey = entityKey;
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
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 { 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 '../../../components/body-layout/body-layout.element';
|
||||
import '../workspace-action-extension/workspace-action-extension.element';
|
||||
|
||||
/**
|
||||
* @element umb-workspace-entity-layout
|
||||
* @description
|
||||
* @slot icon - Slot for rendering the entity icon
|
||||
* @slot name - Slot for rendering the entity name
|
||||
* @slot footer - Slot for rendering the entity footer
|
||||
* @slot actions - Slot for rendering the entity actions
|
||||
* @slot default - slot for main content
|
||||
* @export
|
||||
* @class UmbWorkspaceEntityLayout
|
||||
* @extends {UmbContextConsumerMixin(LitElement)}
|
||||
*/
|
||||
@customElement('umb-workspace-entity-layout')
|
||||
export class UmbWorkspaceEntityLayout extends UmbContextConsumerMixin(UmbObserverMixin(LitElement)) {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
uui-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
uui-tab-group {
|
||||
--uui-tab-divider: var(--uui-color-border);
|
||||
border-left: 1px solid var(--uui-color-border);
|
||||
border-right: 1px solid var(--uui-color-border);
|
||||
}
|
||||
|
||||
router-slot {
|
||||
height: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
/**
|
||||
* Alias of the workspace. The Layout will render the workspace views that are registered for this workspace alias.
|
||||
* @public
|
||||
* @type {string}
|
||||
* @attr
|
||||
* @default ''
|
||||
*/
|
||||
@property()
|
||||
public headline = '';
|
||||
|
||||
@property()
|
||||
public alias = '';
|
||||
|
||||
@state()
|
||||
private _workspaceViews: Array<ManifestWorkspaceView> = [];
|
||||
|
||||
@state()
|
||||
private _currentView = '';
|
||||
|
||||
@state()
|
||||
private _routes: Array<IRoute> = [];
|
||||
|
||||
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<ManifestWorkspaceView[]>(
|
||||
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`
|
||||
<uui-tab-group slot="tabs">
|
||||
${this._workspaceViews.map(
|
||||
(view: ManifestWorkspaceView) => html`
|
||||
<uui-tab
|
||||
.label="${view.meta.label || view.name}"
|
||||
href="${this._routerFolder}/view/${view.meta.pathname}"
|
||||
?active="${this._currentView.includes(view.meta.pathname)}">
|
||||
<uui-icon slot="icon" name="${view.meta.icon}"></uui-icon>
|
||||
${view.meta.label || view.name}
|
||||
</uui-tab>
|
||||
`
|
||||
)}
|
||||
</uui-tab-group>
|
||||
`
|
||||
: nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-body-layout .headline=${this.headline}>
|
||||
<slot name="header" slot="header"></slot>
|
||||
${this._renderTabs()}
|
||||
|
||||
<router-slot .routes="${this._routes}"></router-slot>
|
||||
<slot></slot>
|
||||
|
||||
<slot name="footer" slot="footer"></slot>
|
||||
<umb-extension-slot
|
||||
slot="actions"
|
||||
type="workspaceAction"
|
||||
.filter=${(extension: any) => extension.meta.workspaces.includes(this.alias)}></umb-extension-slot>
|
||||
<slot name="actions" slot="actions"></slot>
|
||||
</umb-body-layout>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-workspace-entity-layout': UmbWorkspaceEntityLayout;
|
||||
}
|
||||
}
|
||||
@@ -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<ManifestWorkspaceView> = [];
|
||||
private _workspaceViews: Array<ManifestWorkspaceView | ManifestWorkspaceViewCollection> = [];
|
||||
|
||||
@state()
|
||||
private _currentView = '';
|
||||
|
||||
@state()
|
||||
private _routes: Array<IRoute> = [];
|
||||
private _routes: Array<any> = [];
|
||||
|
||||
private _routerFolder = '';
|
||||
|
||||
@@ -87,8 +87,8 @@ export class UmbWorkspaceEntity extends UmbContextConsumerMixin(UmbObserverMixin
|
||||
private _observeWorkspaceViews() {
|
||||
this.observe<ManifestWorkspaceView[]>(
|
||||
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> | 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`
|
||||
<uui-tab-group slot="tabs">
|
||||
${this._workspaceViews.map(
|
||||
(view: ManifestWorkspaceView) => html`
|
||||
(view: ManifestWorkspaceView | ManifestWorkspaceViewCollection) => html`
|
||||
<uui-tab
|
||||
.label="${view.meta.label || view.name}"
|
||||
href="${this._routerFolder}/view/${view.meta.pathname}"
|
||||
|
||||
@@ -16,7 +16,7 @@ const DefaultDataTypeData = ({
|
||||
export class UmbWorkspaceUserGroupContext extends UmbWorkspaceNodeContext<UmbUserGroupStoreItemType, UmbUserGroupStore> {
|
||||
|
||||
constructor(target:HTMLElement, entityKey: string) {
|
||||
super(target, DefaultDataTypeData, 'umbUserStore', entityKey);
|
||||
super(target, DefaultDataTypeData, 'umbUserStore', entityKey, 'userGroup');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ const DefaultDataTypeData = ({
|
||||
export class UmbWorkspaceUserContext extends UmbWorkspaceNodeContext<UmbUserStoreItemType, UmbUserStore> {
|
||||
|
||||
constructor(target:HTMLElement, entityKey: string) {
|
||||
super(target, DefaultDataTypeData, 'umbUserStore', entityKey);
|
||||
super(target, DefaultDataTypeData, 'umbUserStore', entityKey, 'user');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<HTMLElement | undefined> {
|
||||
export async function createExtensionElement(manifest: ManifestElementType): Promise<HTMLElement | undefined> {
|
||||
|
||||
//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<H
|
||||
return new js.default();
|
||||
}
|
||||
|
||||
if(!Object.getOwnPropertyDescriptor(manifest, 'element')) {
|
||||
console.error('-- Extension did not succeed creating an element, missing the manifest `element` or default export', manifest);
|
||||
}
|
||||
console.error('-- Extension did not succeed creating an element, missing a default export of the served JavaScript file', manifest);
|
||||
|
||||
// If some JS was loaded and it did not at least contain a default export, then we are safe to assume that it executed as a module and does not need to be returned
|
||||
return undefined;
|
||||
}
|
||||
|
||||
console.error('-- Extension did not succeed creating an element', manifest);
|
||||
console.error('-- Extension did not succeed creating an element, missing a default export or `elementName` in the manifest.', manifest);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export * from './registry/extension.registry';
|
||||
export * from './create-extension-element.function';
|
||||
export * from './has-default-export.function';
|
||||
export * from './is-extension.function';
|
||||
export * from './is-manifest-element-name-type.function';
|
||||
export * from './load-extension.function';
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { ManifestElementType } from '../models';
|
||||
|
||||
export function isManifestElementType(manifest: unknown): manifest is ManifestElementType {
|
||||
return (
|
||||
typeof manifest === 'object' && manifest !== null && (manifest as ManifestElementType).elementName !== undefined
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { ManifestElementType, ManifestElementWithElementName } from '../models';
|
||||
|
||||
export function isManifestElementNameType(manifest: unknown): manifest is ManifestElementWithElementName {
|
||||
return (
|
||||
typeof manifest === 'object' && manifest !== null && (manifest as ManifestElementType).elementName !== undefined
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { ManifestElementType, ManifestTypes } 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 {
|
||||
return isManifestElementNameType(manifest) || isManifestLoaderType(manifest) || isManifestJSType(manifest);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { ManifestTypes } from "../extensions-registry/models";
|
||||
import { ManifestJSType } from "./load-extension.function";
|
||||
|
||||
export function isManifestJSType(manifest: ManifestTypes): manifest is ManifestJSType {
|
||||
return (manifest as ManifestJSType).js !== undefined;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { ManifestTypes } from "../extensions-registry/models";
|
||||
import { ManifestLoaderType } from "./load-extension.function";
|
||||
|
||||
export function isManifestLoaderType(manifest: ManifestTypes): manifest is ManifestLoaderType {
|
||||
return typeof (manifest as ManifestLoaderType).loader === 'function';
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import type { ManifestTypes } from '../models';
|
||||
import { isManifestJSType } from './is-manifest-js-type.function';
|
||||
import { isManifestLoaderType } from './is-manifest-loader-type.function';
|
||||
|
||||
export type ManifestLoaderType = ManifestTypes & { loader: () => Promise<object | HTMLElement> };
|
||||
export type ManifestJSType = ManifestTypes & { js: string };
|
||||
@@ -18,12 +20,4 @@ export async function loadExtension(manifest: ManifestTypes): Promise<object | H
|
||||
}
|
||||
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
export function isManifestLoaderType(manifest: ManifestTypes): manifest is ManifestLoaderType {
|
||||
return typeof (manifest as ManifestLoaderType).loader === 'function';
|
||||
}
|
||||
|
||||
export function isManifestJSType(manifest: ManifestTypes): manifest is ManifestJSType {
|
||||
return (manifest as ManifestJSType).js !== undefined;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,8 @@ import type {
|
||||
ManifestCollectionView,
|
||||
ManifestCollectionBulkAction,
|
||||
} from '../../models';
|
||||
import { createExtensionElement } from '../create-extension-element.function';
|
||||
import { hasDefaultExport } from '../has-default-export.function';
|
||||
import { loadExtension } from '../load-extension.function';
|
||||
|
||||
export class UmbExtensionRegistry {
|
||||
private _extensions = new BehaviorSubject<Array<ManifestTypes>>([]);
|
||||
@@ -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.`)
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@ export interface MetaDashboardCollection {
|
||||
sections: string[];
|
||||
pathname: string;
|
||||
label?: string;
|
||||
entityType: string,
|
||||
storeAlias: string
|
||||
entityType: string;
|
||||
storeAlias: string;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -17,6 +17,9 @@ export type UmbDataTypeStoreItemType = DataTypeDetails | FolderTreeItem;
|
||||
* @description - Data Store for Data Types
|
||||
*/
|
||||
export class UmbDataTypeStore extends UmbDataStoreBase<UmbDataTypeStoreItemType> {
|
||||
|
||||
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
|
||||
|
||||
@@ -9,6 +9,9 @@ import { ApiError, DictionaryResource, EntityTreeItem, ProblemDetails } from '@u
|
||||
* @description - Data Store for Dictionary Items.
|
||||
*/
|
||||
export class UmbDictionaryStore extends UmbDataStoreBase<EntityTreeItem> {
|
||||
|
||||
public readonly storeAlias = 'umbDictionaryStore';
|
||||
|
||||
/**
|
||||
* @description - Get the root of the tree.
|
||||
* @return {*} {Observable<Array<PagedEntityTreeItem>>}
|
||||
|
||||
@@ -16,6 +16,9 @@ export type UmbDocumentTypeStoreItemType = DocumentTypeDetails | DocumentTypeTre
|
||||
* @description - Data Store for Document Types
|
||||
*/
|
||||
export class UmbDocumentTypeStore extends UmbDataStoreBase<UmbDocumentTypeStoreItemType> {
|
||||
|
||||
public readonly storeAlias = 'umbDocumentTypeStore';
|
||||
|
||||
getByKey(key: string): Observable<DocumentTypeDetails | null> {
|
||||
// TODO: use Fetcher API.
|
||||
// TODO: only fetch if the data type is not in the store?
|
||||
|
||||
@@ -16,6 +16,9 @@ export type UmbDocumentStoreItemType = DocumentDetails | DocumentTreeItem
|
||||
* @description - Data Store for Documents
|
||||
*/
|
||||
export class UmbDocumentStore extends UmbNodeStoreBase<UmbDocumentStoreItemType> {
|
||||
|
||||
public readonly storeAlias = 'umbDocumentStore';
|
||||
|
||||
getByKey(key: string): Observable<DocumentDetails | null> {
|
||||
// TODO: use backend cli when available.
|
||||
fetch(`/umbraco/management/api/v1/document/details/${key}`)
|
||||
|
||||
@@ -13,6 +13,8 @@ export type UmbMediaTypeStoreItemType = MediaTypeDetails | FolderTreeItem;
|
||||
*/
|
||||
export class UmbMediaTypeStore extends UmbNodeStoreBase<UmbMediaTypeStoreItemType> {
|
||||
|
||||
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
|
||||
|
||||
@@ -17,6 +17,9 @@ export type UmbMediaStoreItemType = MediaDetails | ContentTreeItem;
|
||||
* @description - Data Store for Media
|
||||
*/
|
||||
export class UmbMediaStore extends UmbDataStoreBase<UmbMediaStoreItemType> {
|
||||
|
||||
public readonly storeAlias = 'umbMediaStore';
|
||||
|
||||
getByKey(key: string): Observable<MediaDetails | null> {
|
||||
// fetch from server and update store
|
||||
fetch(`/umbraco/management/api/v1/media/details/${key}`)
|
||||
|
||||
@@ -13,6 +13,8 @@ export type UmbMemberGroupStoreItemType = MemberGroupDetails | EntityTreeItem;
|
||||
*/
|
||||
export class UmbMemberGroupStore extends UmbNodeStoreBase<UmbMemberGroupStoreItemType> {
|
||||
|
||||
public readonly storeAlias = 'umbMemberGroupStore';
|
||||
|
||||
getByKey(key: string): Observable<UmbMemberGroupStoreItemType | null> {
|
||||
return null as any;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export type UmbMemberTypeStoreItemType = MemberTypeDetails | EntityTreeItem
|
||||
*/
|
||||
export class UmbMemberTypeStore extends UmbDataStoreBase<UmbMemberTypeStoreItemType> {
|
||||
|
||||
public readonly storeAlias = 'umbMemberTypeStore';
|
||||
|
||||
getByKey(key: string): Observable<UmbMemberTypeStoreItemType | null> {
|
||||
return null as any;
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface UmbDataStoreIdentifiers {
|
||||
}
|
||||
|
||||
export interface UmbDataStore<T> {
|
||||
readonly storeAlias: string;
|
||||
readonly items: Observable<Array<T>>;
|
||||
updateItems(items: Array<T>): void;
|
||||
}
|
||||
@@ -23,6 +24,9 @@ export interface UmbTreeDataStore<T> extends UmbDataStore<T> {
|
||||
* @description - Base class for Data Stores
|
||||
*/
|
||||
export abstract class UmbDataStoreBase<T extends UmbDataStoreIdentifiers> implements UmbDataStore<T> {
|
||||
|
||||
public abstract readonly storeAlias:string;
|
||||
|
||||
protected _items: BehaviorSubject<Array<T>> = new BehaviorSubject(<Array<T>>[]);
|
||||
public readonly items: Observable<Array<T>> = this._items.asObservable();
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ export type UmbUserGroupStoreItemType = UserGroupDetails & { users?: Array<strin
|
||||
* @description - Data Store for Users
|
||||
*/
|
||||
export class UmbUserGroupStore extends UmbDataStoreBase<UmbUserGroupStoreItemType> {
|
||||
|
||||
|
||||
public readonly storeAlias = 'umbUserGroupStore';
|
||||
|
||||
getAll(): Observable<Array<UmbUserGroupStoreItemType>> {
|
||||
// TODO: use Fetcher API.
|
||||
// TODO: only fetch if the data type is not in the store?
|
||||
|
||||
@@ -11,6 +11,11 @@ export type UmbUserStoreItemType = UserDetails;
|
||||
* @description - Data Store for Users
|
||||
*/
|
||||
export class UmbUserStore extends UmbDataStoreBase<UmbUserStoreItemType> {
|
||||
|
||||
|
||||
public readonly storeAlias = 'umbUserStore';
|
||||
|
||||
|
||||
private _totalUsers: BehaviorSubject<number> = new BehaviorSubject(0);
|
||||
public readonly totalUsers: Observable<number> = this._totalUsers.asObservable();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user