add entity tree item kind

This commit is contained in:
Mads Rasmussen
2023-03-23 13:00:06 +01:00
parent 89f5832d2c
commit c63eabb03e
7 changed files with 95 additions and 26 deletions

View File

@@ -14,9 +14,9 @@ const tree: ManifestTree = {
const treeItem: ManifestTreeItem = {
type: 'treeItem',
kind: 'entity',
alias: 'Umb.TreeItem.Document',
name: 'Document Tree Item',
loader: () => import('./tree-item/document-tree-item.element'),
conditions: {
entityType: 'document',
},

View File

@@ -1,5 +1,5 @@
import { UmbMediaRepository } from '../repository/media.repository';
import type { ManifestTree } from '@umbraco-cms/backoffice/extensions-registry';
import type { ManifestTree, ManifestTreeItem } from '@umbraco-cms/backoffice/extensions-registry';
const treeAlias = 'Umb.Tree.Media';
@@ -12,4 +12,14 @@ const tree: ManifestTree = {
},
};
export const manifests = [tree];
const treeItem: ManifestTreeItem = {
type: 'treeItem',
kind: 'entity',
alias: 'Umb.TreeItem.Media',
name: 'Media Tree Item',
conditions: {
entityType: 'media',
},
};
export const manifests = [tree, treeItem];

View File

@@ -34,6 +34,7 @@ import './section/section-sidebar/section-sidebar.element';
import './section/section.element';
import './table/table.element';
import './tree/tree.element';
import './tree/entity-tree-item/entity-tree-item.element';
import './tree/tree-menu-item/tree-menu-item.element';
import './variantable-property/variantable-property.element';
import './workspace/workspace-action-menu/workspace-action-menu.element';

View File

@@ -0,0 +1,10 @@
import { UmbTreeItemContextBase } from '../tree-item-base/tree-item-base.context';
import { UmbControllerHostInterface } from '@umbraco-cms/backoffice/controller';
import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
// TODO get unique method from an entity repository static method
export class UmbEntityTreeItemContext extends UmbTreeItemContextBase<EntityTreeItemResponseModel> {
constructor(host: UmbControllerHostInterface, treeItem: EntityTreeItemResponseModel) {
super(host, treeItem, (x: EntityTreeItemResponseModel) => x.key);
}
}

View File

@@ -0,0 +1,41 @@
import { css, html, nothing } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, property } from 'lit/decorators.js';
import { UmbEntityTreeItemContext } from './entity-tree-item.context';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
import { ManifestKind } from '@umbraco-cms/backoffice/extensions-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
// TODO: Move to separate file:
const manifest: ManifestKind = {
type: 'kind',
alias: 'Umb.Kind.EntityTreeItem',
matchKind: 'entity',
matchType: 'treeItem',
manifest: {
type: 'treeItem',
elementName: 'umb-entity-tree-item',
},
};
umbExtensionsRegistry.register(manifest);
@customElement('umb-entity-tree-item')
export class UmbEntityTreeItemElement extends UmbLitElement {
static styles = [UUITextStyles, css``];
@property({ type: Object, attribute: false })
item?: EntityTreeItemResponseModel;
render() {
if (!this.item) return nothing;
new UmbEntityTreeItemContext(this, this.item);
return html`<umb-tree-item-base .item=${this.item}></umb-tree-item-base>`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-entity-tree-item': UmbEntityTreeItemElement;
}
}

View File

@@ -15,12 +15,18 @@ import {
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api';
import type { TreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api';
// add type for unique function
export type UmbTreeItemUniqueFunction<T extends TreeItemPresentationModel> = (x: T) => string | null | undefined;
export class UmbTreeItemContextBase<T extends TreeItemPresentationModel = TreeItemPresentationModel> {
public host: UmbControllerHostInterface;
public treeItem: T;
public unique: string;
public type: string;
#hasChildren = new BooleanState(false);
hasChildren = this.#hasChildren.asObservable();
#isLoading = new BooleanState(false);
isLoading = this.#isLoading.asObservable();
@@ -43,36 +49,22 @@ export class UmbTreeItemContextBase<T extends TreeItemPresentationModel = TreeIt
#sectionContext?: UmbSectionContext;
#sectionSidebarContext?: UmbSectionSidebarContext;
constructor(host: UmbControllerHostInterface, treeItem: T, getUnique: (x: T) => string | null | undefined) {
constructor(host: UmbControllerHostInterface, treeItem: T, getUniqueFunction: UmbTreeItemUniqueFunction<T>) {
this.host = host;
this.treeItem = treeItem;
const unique = getUnique(this.treeItem);
const unique = getUniqueFunction(this.treeItem);
if (!unique) throw new Error('Could not create tree item context, unique key is missing');
this.unique = unique;
if (!this.treeItem.type) throw new Error('Could not create tree item context, tree item type is missing');
this.type = this.treeItem.type;
new UmbContextConsumerController(host, UMB_SECTION_CONTEXT_TOKEN, (instance) => {
this.#sectionContext = instance;
this.#observeSectionPath();
});
new UmbContextConsumerController(host, UMB_SECTION_SIDEBAR_CONTEXT_TOKEN, (instance) => {
this.#sectionSidebarContext = instance;
});
new UmbContextConsumerController(host, 'umbTreeContext', (treeContext: UmbTreeContextBase) => {
this.treeContext = treeContext;
this.#observeIsSelectable();
this.#observeIsSelected();
});
new UmbContextProviderController(host, UMB_TREE_ITEM_CONTEXT_TOKEN, this);
this.#observeTreeItemActions();
this.#hasChildren.next(this.treeItem.hasChildren || false);
this.#consumeContexts();
new UmbContextProviderController(host, UMB_TREE_ITEM_CONTEXT_TOKEN, this);
}
public async requestChildren() {
@@ -95,6 +87,23 @@ export class UmbTreeItemContextBase<T extends TreeItemPresentationModel = TreeIt
this.treeContext?.deselect(this.unique);
}
#consumeContexts() {
new UmbContextConsumerController(this.host, UMB_SECTION_CONTEXT_TOKEN, (instance) => {
this.#sectionContext = instance;
this.#observeSectionPath();
});
new UmbContextConsumerController(this.host, UMB_SECTION_SIDEBAR_CONTEXT_TOKEN, (instance) => {
this.#sectionSidebarContext = instance;
});
new UmbContextConsumerController(this.host, 'umbTreeContext', (treeContext: UmbTreeContextBase) => {
this.treeContext = treeContext;
this.#observeIsSelectable();
this.#observeIsSelected();
});
}
#observeIsSelectable() {
if (!this.treeContext) return;
new UmbObserverController(this.host, this.treeContext.selectable, (value) => this.#isSelectable.next(value));

View File

@@ -22,9 +22,6 @@ export class UmbTreeItemBaseElement extends UmbLitElement {
this.requestUpdate('item', oldVal);
}
@property({ type: Boolean, attribute: 'has-children' })
hasChildren = false;
@state()
private _childItems?: EntityTreeItemResponseModel[];
@@ -52,6 +49,7 @@ export class UmbTreeItemBaseElement extends UmbLitElement {
this.#treeItemContext = instance;
if (!this.#treeItemContext) return;
// TODO: investigate if we can make an observe decorator
this.observe(this.#treeItemContext.hasChildren, (value) => (this.hasChildren = value));
this.observe(this.#treeItemContext.isLoading, (value) => (this._isLoading = value));
this.observe(this.#treeItemContext.isSelectable, (value) => (this._isSelectable = value));
this.observe(this.#treeItemContext.isSelected, (value) => (this._isSelected = value));