Merge pull request #335 from umbraco/feature/tree-store-from-manifest

This commit is contained in:
Niels Lyngsø
2022-12-20 15:40:21 +01:00
committed by GitHub
25 changed files with 307 additions and 444 deletions

View File

@@ -12,7 +12,6 @@ import './components/extension-slot/extension-slot.element';
import './sections/shared/section-main/section-main.element';
import './sections/shared/section-sidebar/section-sidebar.element';
import './sections/shared/section.element';
import './trees/shared/tree-base.element';
import './trees/shared/tree.element';
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';

View File

@@ -0,0 +1,45 @@
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.DataTypes';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Data Types Tree',
weight: 100,
meta: {
label: 'Data Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
storeContextAlias: 'umbDataTypeStore',
},
};
const treeItemActions: Array<ManifestTreeItemAction> = [
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.DataType.Create',
name: 'Tree Item Action Create',
loader: () => import('./actions/create/action-data-type-create.element'),
weight: 200,
meta: {
trees: [treeAlias],
label: 'Create',
icon: 'umb:add',
},
},
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.DataType.Delete',
name: 'Tree Item Action Delete',
loader: () => import('./actions/delete/action-data-type-delete.element'),
weight: 100,
meta: {
trees: [treeAlias],
label: 'Delete',
icon: 'umb:delete',
},
},
];
export const manifests = [tree, ...treeItemActions];

View File

@@ -1,69 +0,0 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
import type { ManifestTreeItemAction } from '@umbraco-cms/models';
import '../shared/tree-navigator.element';
import { UmbDataTypesStore } from 'src/core/stores/data-types/data-types.store';
@customElement('umb-tree-data-types')
export class UmbTreeDataTypesElement extends UmbContextProviderMixin(UmbContextConsumerMixin(UmbTreeBase)) {
constructor() {
super();
this._registerTreeItemActions();
// TODO: how do we best expose the tree api to the tree navigator element?
this.consumeContext('umbDataTypeStore', (dataTypeStore: UmbDataTypesStore) => {
this.provideContext('umbTreeStore', dataTypeStore);
});
}
private _registerTreeItemActions() {
const dashboards: Array<ManifestTreeItemAction> = [
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.DataType.Create',
name: 'Tree Item Action Create',
loader: () => import('./actions/create/action-data-type-create.element'),
weight: 200,
meta: {
trees: ['Umb.Tree.DataTypes'],
label: 'Create',
icon: 'umb:add',
},
},
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.DataType.Delete',
name: 'Tree Item Action Delete',
loader: () => import('./actions/delete/action-data-type-delete.element'),
weight: 100,
meta: {
trees: ['Umb.Tree.DataTypes'],
label: 'Delete',
icon: 'umb:delete',
},
},
];
dashboards.forEach((dashboard) => {
if (umbExtensionsRegistry.isRegistered(dashboard.alias)) return;
umbExtensionsRegistry.register(dashboard);
});
}
render() {
return html`<umb-tree-navigator></umb-tree-navigator>`;
}
}
export default UmbTreeDataTypesElement;
declare global {
interface HTMLElementTagNameMap {
'umb-tree-data-types': UmbTreeDataTypesElement;
}
}

View File

@@ -0,0 +1,18 @@
import type { ManifestTree } from '@umbraco-cms/extensions-registry';
const treeAlias = 'Umb.Tree.DocumentTypes';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Document Types Tree',
weight: 400,
meta: {
label: 'Document Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
storeContextAlias: 'umbDocumentTypeStore',
},
};
export const manifests = [tree];

View File

@@ -1,31 +0,0 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import '../shared/tree-navigator.element';
import { UmbDocumentTypeStore } from 'src/core/stores/document-type/document-type.store';
@customElement('umb-tree-document-types')
export class UmbTreeDocumentTypes extends UmbContextConsumerMixin(UmbContextProviderMixin(UmbTreeBase)) {
constructor() {
super();
// TODO: how do we best expose the tree api to the tree navigator element?
this.consumeContext('umbDocumentTypeStore', (store: UmbDocumentTypeStore) => {
this.provideContext('umbTreeStore', store);
});
}
render() {
return html`<umb-tree-navigator></umb-tree-navigator>`;
}
}
export default UmbTreeDocumentTypes;
declare global {
interface HTMLElementTagNameMap {
'umb-tree-document-types': UmbTreeDocumentTypes;
}
}

View File

@@ -0,0 +1,57 @@
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.Documents';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Documents Tree',
weight: 100,
meta: {
label: 'Documents',
icon: 'umb:folder',
sections: ['Umb.Section.Content'],
storeContextAlias: 'umbDocumentStore',
},
};
const treeItemActions: Array<ManifestTreeItemAction> = [
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.Document.Create',
name: 'Document Tree Item Action Create',
loader: () => import('./actions/action-document-create.element'),
weight: 100,
meta: {
trees: [treeAlias],
label: 'Create',
icon: 'add',
},
},
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.Document.Delete',
name: 'Document Tree Item Action Delete',
loader: () => import('./actions/action-document-delete.element'),
weight: 100,
meta: {
trees: [treeAlias],
label: 'Delete',
icon: 'delete',
},
},
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.Document.Paged',
name: 'Document Tree Item Action Paged',
loader: () => import('./actions/action-document-paged.element'),
weight: 100,
meta: {
trees: [treeAlias],
label: 'Paged',
icon: 'favorite',
},
},
];
export const manifests = [tree, ...treeItemActions];

View File

@@ -1,80 +0,0 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import type { ManifestTreeItemAction } from '@umbraco-cms/models';
import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
import { UmbDocumentStore } from 'src/core/stores/document/document.store';
import '../shared/tree-navigator.element';
@customElement('umb-tree-documents')
export class UmbTreeDocumentsElement extends UmbContextProviderMixin(UmbContextConsumerMixin(UmbTreeBase)) {
constructor() {
super();
this._registerTreeItemActions();
// TODO: how do we best expose the tree api to the tree navigator element?
this.consumeContext('umbDocumentStore', (store: UmbDocumentStore) => {
this.provideContext('umbTreeStore', store);
});
}
private _registerTreeItemActions() {
const dashboards: Array<ManifestTreeItemAction> = [
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.Document.Create',
name: 'Document Tree Item Action Create',
loader: () => import('./actions/action-document-create.element'),
weight: 100,
meta: {
trees: ['Umb.Tree.Documents'],
label: 'Create',
icon: 'add',
},
},
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.Document.Delete',
name: 'Document Tree Item Action Delete',
loader: () => import('./actions/action-document-delete.element'),
weight: 100,
meta: {
trees: ['Umb.Tree.Documents'],
label: 'Delete',
icon: 'delete',
},
},
{
type: 'treeItemAction',
alias: 'Umb.TreeItemAction.Document.Paged',
name: 'Document Tree Item Action Paged',
loader: () => import('./actions/action-document-paged.element'),
weight: 100,
meta: {
trees: ['Umb.Tree.Documents'],
label: 'Paged',
icon: 'favorite',
},
},
];
dashboards.forEach((dashboard) => {
if (umbExtensionsRegistry.isRegistered(dashboard.alias)) return;
umbExtensionsRegistry.register(dashboard);
});
}
render() {
return html`<umb-tree-navigator></umb-tree-navigator>`;
}
}
export default UmbTreeDocumentsElement;
declare global {
interface HTMLElementTagNameMap {
'umb-tree-documents': UmbTreeDocumentsElement;
}
}

View File

@@ -0,0 +1,18 @@
import { ManifestTree } from '@umbraco-cms/extensions-registry';
const treeAlias = 'Umb.Tree.Extensions';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Extensions Tree',
weight: 500,
meta: {
label: 'Extensions',
icon: 'umb:favorite',
sections: ['Umb.Section.Settings'],
rootNodeEntityType: 'extension-root', // TODO: how do we want to handle 'single node trees'. Trees without any children but still needs to open an workspace? Currently an workspace is chosen based on the entity type. The tree root node doesn't have one, so we need to tell which workspace to use.
},
};
export const manifests = [tree];

View File

@@ -0,0 +1,18 @@
import type { ManifestTree } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.Languages';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Languages Tree',
weight: 100,
meta: {
label: 'Languages',
icon: 'umb:globe',
sections: ['Umb.Section.Settings'],
rootNodeEntityType: 'language-root', // TODO: how do we want to handle 'single node trees'. Trees without any children but still needs to open an workspace? Currently an workspace is chosen based on the entity type. The tree root node doesn't have one, so we need to tell which workspace to use.
},
};
export const manifests = [tree];

View File

@@ -1,112 +1,23 @@
import type { ManifestTree } from '@umbraco-cms/models';
import { manifests as dataTypeTreeManifests } from './data-types/manifests';
import { manifests as documentTypeTreeManifests } from './document-types/manifests';
import { manifests as documentTreeManifests } from './documents/manifests';
import { manifests as extensionTreeManifests } from './extensions/manifests';
import { manifests as languageTreeManifests } from './languages/manifests';
import { manifests as mediaTreeManifests } from './media/manifests';
import { manifests as mediaTypeTreeManifests } from './media-types/manifests';
import { manifests as memberGroupTreeManifests } from './member-groups/manifests';
import { manifests as memberTypesTreeManifests } from './member-types/manifests';
export const manifests: Array<ManifestTree> = [
{
type: 'tree',
alias: 'Umb.Tree.Extensions',
name: 'Extensions Tree',
weight: 500,
meta: {
label: 'Extensions',
icon: 'umb:favorite',
sections: ['Umb.Section.Settings'],
rootNodeEntityType: 'extension-root', // TODO: how do we want to handle 'single node trees'. Trees without any children but still needs to open an workspace? Currently an workspace is chosen based on the entity type. The tree root node doesn't have one, so we need to tell which workspace to use.
},
},
{
type: 'tree',
alias: 'Umb.Tree.DocumentTypes',
name: 'Document Types Tree',
loader: () => import('./document-types/tree-document-types.element'),
weight: 400,
meta: {
label: 'Document Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
},
},
{
type: 'tree',
alias: 'Umb.Tree.MediaTypes',
name: 'Media Types Tree',
loader: () => import('./media-types/tree-media-types.element'),
weight: 300,
meta: {
label: 'Media Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
},
},
{
type: 'tree',
alias: 'Umb.Tree.MemberTypes',
name: 'Member Types Tree',
loader: () => import('./member-types/tree-member-types.element'),
weight: 200,
meta: {
label: 'Member Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
},
},
{
type: 'tree',
alias: 'Umb.Tree.DataTypes',
name: 'Data Types Tree',
loader: () => import('./data-types/tree-data-types.element'),
weight: 100,
meta: {
label: 'Data Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
},
},
{
type: 'tree',
alias: 'Umb.Tree.MemberGroups',
name: 'Member Groups Tree',
loader: () => import('./member-groups/tree-member-groups.element'),
weight: 1,
meta: {
label: 'Member Groups',
icon: 'umb:folder',
sections: ['Umb.Section.Members'],
},
},
{
type: 'tree',
alias: 'Umb.Tree.Media',
name: 'Media Tree',
loader: () => import('./media/tree-media.element'),
weight: 100,
meta: {
label: 'Media',
icon: 'umb:folder',
sections: ['Umb.Section.Media'],
},
},
{
type: 'tree',
alias: 'Umb.Tree.Documents',
name: 'Documents Tree',
loader: () => import('./documents/tree-documents.element'),
weight: 100,
meta: {
label: 'Documents',
icon: 'umb:folder',
sections: ['Umb.Section.Content'],
},
},
{
type: 'tree',
alias: 'Umb.Tree.Languages',
name: 'Languages Tree',
weight: 100,
meta: {
label: 'Languages',
icon: 'umb:globe',
sections: ['Umb.Section.Settings'],
rootNodeEntityType: 'language-root', // TODO: how do we want to handle 'single node trees'. Trees without any children but still needs to open an workspace? Currently an workspace is chosen based on the entity type. The tree root node doesn't have one, so we need to tell which workspace to use.
},
},
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
export const manifests: Array<ManifestTree | ManifestTreeItemAction> = [
...dataTypeTreeManifests,
...documentTypeTreeManifests,
...documentTreeManifests,
...extensionTreeManifests,
...languageTreeManifests,
...mediaTreeManifests,
...mediaTypeTreeManifests,
...memberGroupTreeManifests,
...memberTypesTreeManifests,
];

View File

@@ -0,0 +1,20 @@
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.MemberTypes';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Member Types Tree',
weight: 200,
meta: {
label: 'Member Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
storeContextAlias: 'umbMemberTypeStore',
},
};
const treeItemActions: Array<ManifestTreeItemAction> = [];
export const manifests = [tree, ...treeItemActions];

View File

@@ -1,31 +0,0 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import { UmbMediaTypeStore } from 'src/core/stores/media-type/media-type.store';
import '../shared/tree-navigator.element';
@customElement('umb-tree-media-types')
export class UmbTreeMediaTypes extends UmbContextConsumerMixin(UmbContextProviderMixin(UmbTreeBase)) {
constructor() {
super();
// TODO: how do we best expose the tree api to the tree navigator element?
this.consumeContext('umbMediaTypeStore', (store: UmbMediaTypeStore) => {
this.provideContext('umbTreeStore', store);
});
}
render() {
return html`<umb-tree-navigator></umb-tree-navigator>`;
}
}
export default UmbTreeMediaTypes;
declare global {
interface HTMLElementTagNameMap {
'umb-tree-media-types': UmbTreeMediaTypes;
}
}

View File

@@ -0,0 +1,20 @@
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.Media';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Media Tree',
weight: 100,
meta: {
label: 'Media',
icon: 'umb:folder',
sections: ['Umb.Section.Media'],
storeContextAlias: 'umbMediaStore',
},
};
const treeItemActions: Array<ManifestTreeItemAction> = [];
export const manifests = [tree, ...treeItemActions];

View File

@@ -1,31 +0,0 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import { UmbMediaStore } from 'src/core/stores/media/media.store';
import '../shared/tree-navigator.element';
@customElement('umb-tree-media')
export class UmbTreeMediaElement extends UmbContextProviderMixin(UmbContextConsumerMixin(UmbTreeBase)) {
constructor() {
super();
// TODO: how do we best expose the tree api to the tree navigator element?
this.consumeContext('umbMediaStore', (store: UmbMediaStore) => {
this.provideContext('umbTreeStore', store);
});
}
render() {
return html`<umb-tree-navigator></umb-tree-navigator>`;
}
}
export default UmbTreeMediaElement;
declare global {
interface HTMLElementTagNameMap {
'umb-tree-media': UmbTreeMediaElement;
}
}

View File

@@ -0,0 +1,20 @@
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.MemberGroups';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Member Groups Tree',
weight: 1,
meta: {
label: 'Member Groups',
icon: 'umb:folder',
sections: ['Umb.Section.Members'],
storeContextAlias: 'umbMemberGroupStore',
},
};
const treeItemActions: Array<ManifestTreeItemAction> = [];
export const manifests = [tree, ...treeItemActions];

View File

@@ -1,30 +0,0 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import { UmbMemberGroupStore } from 'src/core/stores/member-group/member-group.store';
import '../shared/tree-navigator.element';
@customElement('umb-tree-member-groups')
export class UmbTreeMemberGroups extends UmbContextProviderMixin(UmbContextConsumerMixin(UmbTreeBase)) {
constructor() {
super();
// TODO: how do we best expose the tree api to the tree navigator element?
this.consumeContext('umbMemberGroupStore', (store: UmbMemberGroupStore) => {
this.provideContext('umbTreeStore', store);
});
}
render() {
return html`<umb-tree-navigator></umb-tree-navigator>`;
}
}
export default UmbTreeMemberGroups;
declare global {
interface HTMLElementTagNameMap {
'umb-tree-member-groups': UmbTreeMemberGroups;
}
}

View File

@@ -0,0 +1,20 @@
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.MemberTypes';
const tree: ManifestTree = {
type: 'tree',
alias: treeAlias,
name: 'Member Types Tree',
weight: 200,
meta: {
label: 'Member Types',
icon: 'umb:folder',
sections: ['Umb.Section.Settings'],
storeContextAlias: 'umbMemberTypeStore',
},
};
const treeItemActions: Array<ManifestTreeItemAction> = [];
export const manifests = [tree, ...treeItemActions];

View File

@@ -1,31 +0,0 @@
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import { UmbMemberTypeStore } from 'src/core/stores/member-type/member-type.store';
import '../shared/tree-navigator.element';
@customElement('umb-tree-member-types')
export class UmbTreeMemberTypes extends UmbContextConsumerMixin(UmbContextProviderMixin(UmbTreeBase)) {
constructor() {
super();
// TODO: how do we best expose the tree api to the tree navigator element?
this.consumeContext('umbMemberTypeStore', (store: UmbMemberTypeStore) => {
this.provideContext('umbTreeStore', store);
});
}
render() {
return html`<umb-tree-navigator></umb-tree-navigator>`;
}
}
export default UmbTreeMemberTypes;
declare global {
interface HTMLElementTagNameMap {
'umb-tree-member-types': UmbTreeMemberTypes;
}
}

View File

@@ -1,15 +0,0 @@
import { LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import type { ManifestTree } from '@umbraco-cms/models';
@customElement('umb-tree-base')
export class UmbTreeBase extends LitElement {
@property({ type: Object, attribute: false })
tree?: ManifestTree;
}
declare global {
interface HTMLElementTagNameMap {
'umb-tree-base': UmbTreeBase;
}
}

View File

@@ -4,6 +4,7 @@ import { customElement, property, state } from 'lit/decorators.js';
import { createExtensionElement } from '@umbraco-cms/extensions-api';
import type { ManifestTree } from '@umbraco-cms/models';
import './tree-navigator.element';
import './context-menu/tree-context-menu-page-action-list.element';
import './context-menu/tree-context-menu-page.service';
import './context-menu/tree-context-menu.service';

View File

@@ -39,7 +39,7 @@ export class UmbTreeItem extends UmbContextConsumerMixin(UmbObserverMixin(LitEle
private _isActive = false;
private _treeContext?: UmbTreeContextBase;
private _treeStore?: UmbDataStore<unknown>;
private _store?: UmbDataStore<unknown>;
private _sectionContext?: UmbSectionContext;
private _treeContextMenuService?: UmbTreeContextMenuService;
@@ -52,8 +52,8 @@ export class UmbTreeItem extends UmbContextConsumerMixin(UmbObserverMixin(LitEle
this._observeIsSelected();
});
this.consumeContext('umbTreeStore', (store: UmbDataStore<unknown>) => {
this._treeStore = store;
this.consumeContext('umbStore', (store: UmbDataStore<unknown>) => {
this._store = store;
});
this.consumeContext('umbSectionContext', (sectionContext: UmbSectionContext) => {
@@ -131,11 +131,11 @@ export class UmbTreeItem extends UmbContextConsumerMixin(UmbObserverMixin(LitEle
}
private _observeChildren() {
if (!this._treeStore?.getTreeItemChildren) return;
if (!this._store?.getTreeItemChildren) return;
this._loading = true;
this.observe<Entity[]>(this._treeStore.getTreeItemChildren(this.treeItem.key), (childItems) => {
this.observe<Entity[]>(this._store.getTreeItemChildren(this.treeItem.key), (childItems) => {
if (childItems?.length === 0) return;
this._childItems = childItems;
this._loading = false;

View File

@@ -1,22 +1,32 @@
import { css, html, LitElement } from 'lit';
import { repeat } from 'lit/directives/repeat.js';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, state } from 'lit/decorators.js';
import { customElement, property, state } from 'lit/decorators.js';
import { ifDefined } from 'lit-html/directives/if-defined.js';
import { UmbSectionContext } from '../../sections/section.context';
import { UmbTreeContext } from '../tree.context';
import { UmbObserverMixin } from '@umbraco-cms/observable-api';
import { UmbContextConsumerMixin } from '@umbraco-cms/context-api';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import type { Entity, ManifestSection, ManifestTree } from '@umbraco-cms/models';
import { UmbDataStore } from 'src/core/stores/store';
import './tree-item.element';
import { UmbDocumentTypeStore } from '@umbraco-cms/stores/document-type/document-type.store';
@customElement('umb-tree-navigator')
export class UmbTreeNavigator extends UmbContextConsumerMixin(UmbObserverMixin(LitElement)) {
export class UmbTreeNavigator extends UmbContextConsumerMixin(UmbContextProviderMixin(UmbObserverMixin(LitElement))) {
static styles = [UUITextStyles, css``];
private _storeContextAlias = '';
@property({ attribute: 'store-context-alias' })
public get storeContextAlias() {
return this._storeContextAlias;
}
public set storeContextAlias(value) {
this._storeContextAlias = value;
this._provideStoreContext();
}
@state()
private _loading = true;
@@ -29,14 +39,14 @@ export class UmbTreeNavigator extends UmbContextConsumerMixin(UmbObserverMixin(L
@state()
private _href?: string;
private _treeStore?: UmbDataStore<unknown>;
private _store?: UmbDataStore<unknown>;
private _sectionContext?: UmbSectionContext;
constructor() {
super();
this.consumeContext('umbTreeStore', (treeStore) => {
this._treeStore = treeStore;
this.consumeContext('umbStore', (store) => {
this._store = store;
});
this.consumeContext('umbTreeContext', (treeContext: UmbTreeContext) => {
@@ -49,16 +59,25 @@ export class UmbTreeNavigator extends UmbContextConsumerMixin(UmbObserverMixin(L
});
}
private _provideStoreContext() {
if (!this._storeContextAlias) return;
this.consumeContext(this._storeContextAlias, (store) => {
this._store = store;
this.provideContext('umbStore', store);
});
}
private _onShowRoot() {
this._observeTreeRoot();
}
private _observeTreeRoot() {
if (!this._treeStore?.getTreeRoot) return;
if (!this._store?.getTreeRoot) return;
this._loading = true;
this.observe<Entity[]>(this._treeStore.getTreeRoot(), (rootItems) => {
this.observe<Entity[]>(this._store.getTreeRoot(), (rootItems) => {
if (rootItems?.length === 0) return;
this._items = rootItems;
this._loading = false;

View File

@@ -7,6 +7,7 @@ import { UmbObserverMixin } from '@umbraco-cms/observable-api';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import type { ManifestTree } from '@umbraco-cms/models';
import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
import { UmbDataStore } from '@umbraco-cms/stores/store';
@customElement('umb-tree')
export class UmbTreeElement extends UmbContextProviderMixin(UmbContextConsumerMixin(UmbObserverMixin(LitElement))) {
@@ -68,8 +69,14 @@ export class UmbTreeElement extends UmbContextProviderMixin(UmbContextConsumerMi
.extensionsOfType('tree')
.pipe(map((trees) => trees.find((tree) => tree.alias === this.alias))),
(tree) => {
if (this._tree?.alias === tree.alias) return;
this._tree = tree;
this._provideTreeContext();
if (this._tree.meta.storeContextAlias) {
this._provideStore();
}
}
);
}
@@ -84,6 +91,14 @@ export class UmbTreeElement extends UmbContextProviderMixin(UmbContextConsumerMi
this.provideContext('umbTreeContext', this._treeContext);
}
private _provideStore() {
if (!this._tree?.meta.storeContextAlias) return;
this.consumeContext(this._tree.meta.storeContextAlias, (store: UmbDataStore<unknown>) =>
this.provideContext('umbStore', store)
);
}
private _observeSelection() {
if (!this._treeContext) return;

View File

@@ -10,4 +10,5 @@ export interface MetaTree {
icon: string;
sections: Array<string>;
rootNodeEntityType?: string;
storeContextAlias?: string;
}

View File

@@ -8,7 +8,6 @@ export interface UmbModalContentPickerData {
selection: Array<string>;
}
import '../../../../../backoffice/trees/documents/tree-documents.element';
import { UmbTreeElement } from '../../../../../backoffice/trees/shared/tree.element';
// TODO: make use of UmbPickerLayoutBase