Feature: Data Type Folder workspace (#17996)

* implement folder workspace view for data types

* Update index.ts

* export consts
This commit is contained in:
Mads Rasmussen
2025-01-16 12:52:52 +01:00
committed by GitHub
parent 37343b24bb
commit 434bac788f
28 changed files with 301 additions and 21 deletions

View File

@@ -1 +1,2 @@
export { UmbDataTypeCollectionRepository } from './repository/index.js';
export { UMB_DATA_TYPE_COLLECTION_ALIAS } from './constants.js';

View File

@@ -1,4 +1,5 @@
import { UMB_DATA_TYPE_COLLECTION_ALIAS, UMB_DATA_TYPE_COLLECTION_REPOSITORY_ALIAS } from './constants.js';
import { UMB_DATA_TYPE_COLLECTION_REPOSITORY_ALIAS } from './repository/constants.js';
import { UMB_DATA_TYPE_COLLECTION_ALIAS } from './constants.js';
import { manifests as collectionRepositoryManifests } from './repository/manifests.js';
export const manifests: Array<UmbExtensionManifest> = [

View File

@@ -1 +1,2 @@
export { UMB_DATA_TYPE_COLLECTION_REPOSITORY_ALIAS } from './constants.js';
export { UmbDataTypeCollectionRepository } from './data-type-collection.repository.js';

View File

@@ -1,11 +1,12 @@
export * from './collection/constants.js';
export * from './modals/constants.js';
export * from './data-type-root/constants.js';
export * from './entity-actions/constants.js';
export * from './modals/constants.js';
export * from './paths.js';
export * from './reference/constants.js';
export * from './repository/constants.js';
export * from './tree/constants.js';
export * from './workspace/constants.js';
export * from './paths.js';
export {
UMB_DATA_TYPE_ENTITY_TYPE,
UMB_DATA_TYPE_ROOT_ENTITY_TYPE,

View File

@@ -0,0 +1 @@
export const UMB_DATA_TYPE_ROOT_WORKSPACE_ALIAS = 'Umb.Workspace.DataType.Root';

View File

@@ -0,0 +1 @@
export * from './constants.js';

View File

@@ -0,0 +1,14 @@
import { UMB_DATA_TYPE_ROOT_ENTITY_TYPE } from '../entity.js';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'workspace',
kind: 'default',
alias: 'Umb.Workspace.DataType.Root',
name: 'Data Type Root Workspace',
meta: {
entityType: UMB_DATA_TYPE_ROOT_ENTITY_TYPE,
headline: '#treeHeaders_dataTypes',
},
},
];

View File

@@ -1,4 +1,5 @@
import { manifests as collectionManifests } from './collection/manifests.js';
import { manifests as dataTypeRootManifest } from './data-type-root/manifests.js';
import { manifests as entityActions } from './entity-actions/manifests.js';
import { manifests as menuManifests } from './menu/manifests.js';
import { manifests as modalManifests } from './modals/manifests.js';
@@ -9,6 +10,7 @@ import { manifests as workspaceManifests } from './workspace/manifests.js';
export const manifests: Array<UmbExtensionManifest> = [
...collectionManifests,
...dataTypeRootManifest,
...entityActions,
...menuManifests,
...modalManifests,

View File

@@ -18,3 +18,8 @@ export const UMB_CREATE_DATA_TYPE_WORKSPACE_PATH_PATTERN = new UmbPathPattern<{
parentEntityType: UmbEntityModel['entityType'];
parentUnique: UmbEntityModel['unique'];
}>('create/parent/:parentEntityType/:parentUnique', UMB_DATA_TYPE_WORKSPACE_PATH);
export const UMB_EDIT_DATA_TYPE_WORKSPACE_PATH_PATTERN = new UmbPathPattern<{ unique: string }>(
'edit/:unique',
UMB_DATA_TYPE_WORKSPACE_PATH,
);

View File

@@ -1,6 +1,7 @@
export { UMB_DATA_TYPE_TREE_STORE_CONTEXT } from './data-type-tree.store.context-token.js';
export * from './folder/constants.js';
export * from './tree-item-children/constants.js';
export const UMB_DATA_TYPE_TREE_REPOSITORY_ALIAS = 'Umb.Repository.DataType.Tree';
export const UMB_DATA_TYPE_TREE_STORE_ALIAS = 'Umb.Store.DataType.Tree';
export const UMB_DATA_TYPE_TREE_ALIAS = 'Umb.Tree.DataType';
export { UMB_DATA_TYPE_TREE_STORE_CONTEXT } from './data-type-tree.store.context-token.js';
export * from './folder/constants.js';

View File

@@ -1,7 +1,9 @@
import { UMB_DATA_TYPE_FOLDER_ENTITY_TYPE } from '../../entity.js';
import { UMB_DATA_TYPE_ROOT_WORKSPACE_ALIAS } from '../../data-type-root/index.js';
import { UMB_DATA_TYPE_FOLDER_REPOSITORY_ALIAS } from './repository/index.js';
import { manifests as workspaceManifests } from './workspace/manifests.js';
import { manifests as repositoryManifests } from './repository/manifests.js';
import { UMB_DATA_TYPE_FOLDER_WORKSPACE_ALIAS } from './workspace/index.js';
export const manifests: Array<UmbExtensionManifest> = [
{
@@ -24,6 +26,24 @@ export const manifests: Array<UmbExtensionManifest> = [
folderRepositoryAlias: UMB_DATA_TYPE_FOLDER_REPOSITORY_ALIAS,
},
},
{
type: 'workspaceView',
kind: 'collection',
alias: 'Umb.WorkspaceView.DataType.TreeItemChildrenCollection',
name: 'Data Type Tree Item Children Collection Workspace View',
meta: {
label: 'Folder',
pathname: 'folder',
icon: 'icon-folder',
collectionAlias: 'Umb.Collection.DataType.TreeItemChildren',
},
conditions: [
{
alias: 'Umb.Condition.WorkspaceAlias',
oneOf: [UMB_DATA_TYPE_ROOT_WORKSPACE_ALIAS, UMB_DATA_TYPE_FOLDER_WORKSPACE_ALIAS],
},
],
},
...repositoryManifests,
...workspaceManifests,
];

View File

@@ -1,2 +1,4 @@
export const UMB_DATA_TYPE_FOLDER_WORKSPACE_ALIAS = 'Umb.Workspace.DataType.Folder';
export { UMB_DATA_TYPE_FOLDER_WORKSPACE_CONTEXT } from './data-type-folder.workspace.context-token.js';
export * from './paths.js';
export const UMB_DATA_TYPE_FOLDER_WORKSPACE_ALIAS = 'Umb.Workspace.DataType.Folder';

View File

@@ -1,2 +1,3 @@
export * from './constants.js';
export * from './data-type-folder.workspace.context-token.js';
export * from './paths.js';

View File

@@ -0,0 +1,14 @@
import { UMB_DATA_TYPE_FOLDER_ENTITY_TYPE } from '../../../entity.js';
import { UmbPathPattern } from '@umbraco-cms/backoffice/router';
import { UMB_SETTINGS_SECTION_PATHNAME } from '@umbraco-cms/backoffice/settings';
import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace';
export const UMB_DATA_TYPE_FOLDER_WORKSPACE_PATH = UMB_WORKSPACE_PATH_PATTERN.generateAbsolute({
sectionName: UMB_SETTINGS_SECTION_PATHNAME,
entityType: UMB_DATA_TYPE_FOLDER_ENTITY_TYPE,
});
export const UMB_EDIT_DATA_TYPE_FOLDER_WORKSPACE_PATH_PATTERN = new UmbPathPattern<{ unique: string }>(
'edit/:unique',
UMB_DATA_TYPE_FOLDER_WORKSPACE_PATH,
);

View File

@@ -1,6 +1,5 @@
import { UMB_DATA_TYPE_ROOT_ENTITY_TYPE } from '../entity.js';
import { manifests as folderManifests } from './folder/manifests.js';
import { manifests as reloadManifests } from './reload-tree-item-children/manifests.js';
import { manifests as treeItemChildren } from './tree-item-children/manifests.js';
import {
UMB_DATA_TYPE_TREE_ALIAS,
UMB_DATA_TYPE_TREE_REPOSITORY_ALIAS,
@@ -36,16 +35,6 @@ export const manifests: Array<UmbExtensionManifest> = [
name: 'Data Type Tree Item',
forEntityTypes: ['data-type-root', 'data-type', 'data-type-folder'],
},
{
type: 'workspace',
kind: 'default',
alias: 'Umb.Workspace.DataType.Root',
name: 'Data Type Root Workspace',
meta: {
entityType: UMB_DATA_TYPE_ROOT_ENTITY_TYPE,
headline: '#treeHeaders_dataTypes',
},
},
...folderManifests,
...reloadManifests,
...treeItemChildren,
];

View File

@@ -0,0 +1,2 @@
export * from './repository/constants.js';
export const UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_ALIAS = 'Umb.Collection.DataType.TreeItemChildren';

View File

@@ -0,0 +1,2 @@
export * from './constants.js';
export * from './repository/index.js';

View File

@@ -0,0 +1,18 @@
import { manifests as viewManifests } from './views/manifests.js';
import { manifests as repositoryManifests } from './repository/manifests.js';
import { UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_ALIAS } from './constants.js';
import { UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_REPOSITORY_ALIAS } from './repository/index.js';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'collection',
kind: 'default',
alias: UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_ALIAS,
name: 'Data Type Tree Item Children Collection',
meta: {
repositoryAlias: UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_REPOSITORY_ALIAS,
},
},
...viewManifests,
...repositoryManifests,
];

View File

@@ -0,0 +1,2 @@
export const UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_REPOSITORY_ALIAS =
'Umb.Repository.DataType.TreeItemChildrenCollection';

View File

@@ -0,0 +1,33 @@
import { UmbDataTypeTreeRepository } from '../../../data-type-tree.repository.js';
import type { UmbCollectionFilterModel, UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
import { UMB_ENTITY_CONTEXT, type UmbEntityModel } from '@umbraco-cms/backoffice/entity';
export class UmbDataTypeTreeItemChildrenCollectionRepository
extends UmbRepositoryBase
implements UmbCollectionRepository
{
#treeRepository = new UmbDataTypeTreeRepository(this);
async requestCollection(filter: UmbCollectionFilterModel) {
// TODO: get parent from args
const entityContext = await this.getContext(UMB_ENTITY_CONTEXT);
if (!entityContext) throw new Error('Entity context not found');
const entityType = entityContext.getEntityType();
const unique = entityContext.getUnique();
if (!entityType) throw new Error('Entity type not found');
if (unique === undefined) throw new Error('Unique not found');
const parent: UmbEntityModel = { entityType, unique };
if (parent.unique === null) {
return this.#treeRepository.requestTreeRootItems({ skip: filter.skip, take: filter.take });
} else {
return this.#treeRepository.requestTreeItemsOf({ parent, skip: filter.skip, take: filter.take });
}
}
}
export { UmbDataTypeTreeItemChildrenCollectionRepository as api };

View File

@@ -0,0 +1 @@
export * from './constants.js';

View File

@@ -0,0 +1,10 @@
import { UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_REPOSITORY_ALIAS } from './constants.js';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'repository',
alias: UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_REPOSITORY_ALIAS,
name: 'Data Type Tree Item Children Collection Repository',
api: () => import('./data-type-tree-item-children-collection.repository.js'),
},
];

View File

@@ -0,0 +1,6 @@
import type { UmbCollectionFilterModel } from '@umbraco-cms/backoffice/collection';
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
export interface UmbDataTypeTreeItemChildrenCollectionFilterModel extends UmbCollectionFilterModel {
parent: UmbEntityModel;
}

View File

@@ -0,0 +1,126 @@
import type { UmbDataTypeTreeItemModel } from '../../../types.js';
import { UMB_EDIT_DATA_TYPE_WORKSPACE_PATH_PATTERN } from '../../../../paths.js';
import { UMB_EDIT_DATA_TYPE_FOLDER_WORKSPACE_PATH_PATTERN } from '../../../folder/index.js';
import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
import { UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/backoffice/components';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbModalRouteRegistrationController, type UmbModalRouteBuilder } from '@umbraco-cms/backoffice/router';
import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace';
@customElement('umb-data-type-tree-item-table-collection-view')
export class UmbDataTypeTreeItemTableCollectionViewElement extends UmbLitElement {
@state()
private _tableConfig: UmbTableConfig = {
allowSelection: false,
};
@state()
private _tableColumns: Array<UmbTableColumn> = [
{
name: 'Name',
alias: 'name',
},
{
name: '',
alias: 'entityActions',
},
];
@state()
private _tableItems: Array<UmbTableItem> = [];
#collectionContext?: UmbDefaultCollectionContext<any>;
#routeBuilder?: UmbModalRouteBuilder;
constructor() {
super();
this.consumeContext(UMB_COLLECTION_CONTEXT, (instance) => {
this.#collectionContext = instance;
});
this.#registerModalRoute();
}
#registerModalRoute() {
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath(':entityType')
.onSetup((params) => {
return { data: { entityType: params.entityType, preset: {} } };
})
.observeRouteBuilder((routeBuilder) => {
this.#routeBuilder = routeBuilder;
// NOTE: Configuring the observations AFTER the route builder is ready,
// otherwise there is a race condition and `#collectionContext.items` tends to win. [LK]
this.#observeCollectionItems();
});
}
#observeCollectionItems() {
if (!this.#collectionContext) return;
this.observe(this.#collectionContext.items, (items) => this.#createTableItems(items), 'umbCollectionItemsObserver');
}
#createTableItems(items: Array<UmbDataTypeTreeItemModel>) {
const routeBuilder = this.#routeBuilder;
if (!routeBuilder) throw new Error('Route builder not ready');
this._tableItems = items.map((item) => {
const modalEditPath =
routeBuilder({ entityType: item.entityType }) +
UMB_EDIT_DATA_TYPE_WORKSPACE_PATH_PATTERN.generateLocal({ unique: item.unique });
const inlineEditPath = UMB_EDIT_DATA_TYPE_FOLDER_WORKSPACE_PATH_PATTERN.generateAbsolute({
unique: item.unique,
});
return {
id: item.unique,
icon: item.isFolder && !item.icon ? 'icon-folder' : item.icon,
data: [
{
columnAlias: 'name',
value: html`<uui-button
href=${item.isFolder ? inlineEditPath : modalEditPath}
label=${item.name}></uui-button>`,
},
{
columnAlias: 'entityActions',
value: html`<umb-entity-actions-table-column-view
.value=${{
entityType: item.entityType,
unique: item.unique,
}}></umb-entity-actions-table-column-view>`,
},
],
};
});
}
override render() {
return html`
<umb-table .config=${this._tableConfig} .columns=${this._tableColumns} .items=${this._tableItems}></umb-table>
`;
}
static override styles = [
UmbTextStyles,
css`
:host {
display: flex;
flex-direction: column;
}
`,
];
}
export { UmbDataTypeTreeItemTableCollectionViewElement as element };
declare global {
interface HTMLElementTagNameMap {
['umb-data-type-tree-item-table-collection-view']: UmbDataTypeTreeItemTableCollectionViewElement;
}
}

View File

@@ -0,0 +1,23 @@
import { UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_ALIAS } from '../constants.js';
import { UMB_COLLECTION_ALIAS_CONDITION } from '@umbraco-cms/backoffice/collection';
export const manifests: Array<UmbExtensionManifest> = [
{
type: 'collectionView',
alias: 'Umb.CollectionView.DataType.TreeItem.Table',
name: 'Data Type Tree Item Table Collection View',
element: () => import('./data-type-tree-item-table-collection-view.element.js'),
weight: 300,
meta: {
label: 'Table',
icon: 'icon-list',
pathName: 'table',
},
conditions: [
{
alias: UMB_COLLECTION_ALIAS_CONDITION,
match: UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_ALIAS,
},
],
},
];

View File

@@ -0,0 +1 @@
export * from './collection/constants.js';

View File

@@ -1,6 +1,8 @@
import { UMB_DATA_TYPE_FOLDER_ENTITY_TYPE, UMB_DATA_TYPE_ROOT_ENTITY_TYPE } from '../../entity.js';
import { manifests as collectionManifests } from './collection/manifests.js';
export const manifests: Array<UmbExtensionManifest> = [
...collectionManifests,
{
type: 'entityAction',
kind: 'reloadTreeItemChildren',

View File

@@ -116,7 +116,7 @@ export const foundConsts = [{
},
{
path: '@umbraco-cms/backoffice/data-type',
consts: ["UMB_DATA_TYPE_COLLECTION_ALIAS","UMB_DATA_TYPE_COLLECTION_REPOSITORY_ALIAS","UMB_DATA_TYPE_CREATE_OPTIONS_MODAL","UMB_DUPLICATE_DATA_TYPE_REPOSITORY_ALIAS","UMB_MOVE_DATA_TYPE_REPOSITORY_ALIAS","UMB_DATA_TYPE_ENTITY_TYPE","UMB_DATA_TYPE_ROOT_ENTITY_TYPE","UMB_DATA_TYPE_FOLDER_ENTITY_TYPE","UMB_DATA_TYPE_PICKER_FLOW_DATA_TYPE_PICKER_MODAL","UMB_DATA_TYPE_PICKER_FLOW_MODAL","UMB_DATA_TYPE_PICKER_MODAL","UMB_DATA_TYPE_WORKSPACE_PATH","UMB_DATA_TYPE_ROOT_WORKSPACE_PATH","UMB_CREATE_DATA_TYPE_WORKSPACE_PATH_PATTERN","UMB_DATA_TYPE_REFERENCE_REPOSITORY_ALIAS","UMB_DATA_TYPE_DETAIL_REPOSITORY_ALIAS","UMB_DATA_TYPE_DETAIL_STORE_ALIAS","UMB_DATA_TYPE_DETAIL_STORE_CONTEXT","UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS","UMB_DATA_TYPE_STORE_ALIAS","UMB_DATA_TYPE_ITEM_STORE_CONTEXT","UMB_DATA_TYPE_TREE_REPOSITORY_ALIAS","UMB_DATA_TYPE_TREE_STORE_ALIAS","UMB_DATA_TYPE_TREE_ALIAS","UMB_DATA_TYPE_TREE_STORE_CONTEXT","UMB_DATA_TYPE_FOLDER_REPOSITORY_ALIAS","UMB_DATA_TYPE_FOLDER_STORE_ALIAS","UMB_DATA_TYPE_FOLDER_STORE_CONTEXT","UMB_DATA_TYPE_FOLDER_WORKSPACE_ALIAS","UMB_DATA_TYPE_FOLDER_WORKSPACE_CONTEXT","UMB_DATA_TYPE_WORKSPACE_ALIAS","UMB_DATA_TYPE_WORKSPACE_CONTEXT","UMB_DATATYPE_WORKSPACE_MODAL"]
consts: ["UMB_DATA_TYPE_COLLECTION_ALIAS","UMB_DATA_TYPE_COLLECTION_REPOSITORY_ALIAS","UMB_DATA_TYPE_ROOT_WORKSPACE_ALIAS","UMB_DATA_TYPE_CREATE_OPTIONS_MODAL","UMB_DUPLICATE_DATA_TYPE_REPOSITORY_ALIAS","UMB_MOVE_DATA_TYPE_REPOSITORY_ALIAS","UMB_DATA_TYPE_ENTITY_TYPE","UMB_DATA_TYPE_ROOT_ENTITY_TYPE","UMB_DATA_TYPE_FOLDER_ENTITY_TYPE","UMB_DATA_TYPE_PICKER_FLOW_DATA_TYPE_PICKER_MODAL","UMB_DATA_TYPE_PICKER_FLOW_MODAL","UMB_DATA_TYPE_PICKER_MODAL","UMB_DATA_TYPE_WORKSPACE_PATH","UMB_DATA_TYPE_ROOT_WORKSPACE_PATH","UMB_CREATE_DATA_TYPE_WORKSPACE_PATH_PATTERN","UMB_EDIT_DATA_TYPE_WORKSPACE_PATH_PATTERN","UMB_DATA_TYPE_REFERENCE_REPOSITORY_ALIAS","UMB_DATA_TYPE_DETAIL_REPOSITORY_ALIAS","UMB_DATA_TYPE_DETAIL_STORE_ALIAS","UMB_DATA_TYPE_DETAIL_STORE_CONTEXT","UMB_DATA_TYPE_ITEM_REPOSITORY_ALIAS","UMB_DATA_TYPE_STORE_ALIAS","UMB_DATA_TYPE_ITEM_STORE_CONTEXT","UMB_DATA_TYPE_TREE_REPOSITORY_ALIAS","UMB_DATA_TYPE_TREE_STORE_ALIAS","UMB_DATA_TYPE_TREE_ALIAS","UMB_DATA_TYPE_TREE_STORE_CONTEXT","UMB_DATA_TYPE_FOLDER_REPOSITORY_ALIAS","UMB_DATA_TYPE_FOLDER_STORE_ALIAS","UMB_DATA_TYPE_FOLDER_STORE_CONTEXT","UMB_DATA_TYPE_FOLDER_WORKSPACE_ALIAS","UMB_DATA_TYPE_FOLDER_WORKSPACE_CONTEXT","UMB_DATA_TYPE_FOLDER_WORKSPACE_PATH","UMB_EDIT_DATA_TYPE_FOLDER_WORKSPACE_PATH_PATTERN","UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_ALIAS","UMB_DATA_TYPE_TREE_ITEM_CHILDREN_COLLECTION_REPOSITORY_ALIAS","UMB_DATA_TYPE_WORKSPACE_ALIAS","UMB_DATA_TYPE_WORKSPACE_CONTEXT","UMB_DATATYPE_WORKSPACE_MODAL"]
},
{
path: '@umbraco-cms/backoffice/debug',