From 54f01a88ad044f1a3d03a5913831fda5aa059659 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 23 Jan 2024 10:52:51 +0100 Subject: [PATCH] implement document type folders --- .../folder/data-type-folder.repository.ts | 6 +- .../entity-actions/create/create.action.ts | 2 +- ...ument-type-create-options-modal.element.ts | 65 ++++----- .../entity-actions/create/modal/index.ts | 2 +- .../folder/document-type-folder.repository.ts | 30 +++++ ...document-type-folder.server.data-source.ts | 123 ++++++++++++++++++ .../document-types/tree/folder/index.ts | 2 + .../document-types/tree/folder/manifests.ts | 44 +++++++ .../document-types/tree/folder/types.ts | 6 + .../documents/document-types/tree/index.ts | 2 + .../document-types/tree/manifests.ts | 15 ++- 11 files changed, 251 insertions(+), 46 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.repository.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.server.data-source.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/types.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/index.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/data-type/tree/folder/data-type-folder.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/core/data-type/tree/folder/data-type-folder.repository.ts index 5bbc1b5ba6..fe78102a76 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/data-type/tree/folder/data-type-folder.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/data-type/tree/folder/data-type-folder.repository.ts @@ -11,8 +11,8 @@ export class UmbDataTypeFolderRepository extends UmbFolderRepositoryBase { - const folderTreeItem: UmbDataTypeFolderTreeItemModel = { +const folderToDataTypeTreeItemMapper = (folder: UmbFolderModel): UmbDataTypeFolderTreeItemModel => { + return { unique: folder.unique, parentUnique: folder.parentUnique, name: folder.name, @@ -21,6 +21,4 @@ const folderToDataTypeTreeItemMapper = (folder: UmbFolderModel) => { hasChildren: false, isFolder: true, }; - - return folderTreeItem; }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts index dbb08b58a6..5c3cc0ad17 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/create.action.ts @@ -21,7 +21,7 @@ export class UmbCreateDataTypeEntityAction extends UmbEntityActionBase; +export class UmbDataTypeCreateOptionsModalElement extends UmbModalBaseElement { + #createFolderAction?: UmbCreateFolderEntityAction; - @property({ type: Object }) - data?: UmbDocumentTypeCreateOptionsModalData; + connectedCallback(): void { + super.connectedCallback(); - #modalContext?: UmbModalManagerContext; + if (this.data?.parentUnique === undefined) throw new Error('A parent unique is required to create a folder'); - constructor() { - super(); - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { - this.#modalContext = instance; - }); + this.#createFolderAction = new UmbCreateFolderEntityAction( + this, + UMB_DOCUMENT_TYPE_FOLDER_REPOSITORY_ALIAS, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // TODO: allow null for entity actions. Some actions can be executed on the root item + this.data.parentUnique, + ); } - #onClick(event: PointerEvent) { + async #onCreateFolderClick(event: PointerEvent) { event.stopPropagation(); - if (this.data?.parentKey === undefined) throw new Error('A parent unique is required to create a folder'); - const folderModalHandler = this.#modalContext?.open(UMB_FOLDER_CREATE_MODAL, { - data: { - folderRepositoryAlias: DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS, - parentUnique: this.data?.parentKey, - }, - }); - folderModalHandler?.onSubmit().then(() => this.modalContext?.submit()); + try { + await this.#createFolderAction?.execute(); + this._submitModal(); + } catch (error) { + console.error(error); + } } // close the modal when navigating to data type #onNavigate() { - this.modalContext?.submit(); - } - - #onCancel() { - this.modalContext?.reject(); + this._rejectModal(); } render() { @@ -55,16 +46,16 @@ export class UmbDataTypeCreateOptionsModalElement extends UmbLitElement { } - + } - Cancel + Cancel `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/modal/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/modal/index.ts index 2ad6689d9c..7ad338cdf7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/modal/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/create/modal/index.ts @@ -1,7 +1,7 @@ import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; export interface UmbDocumentTypeCreateOptionsModalData { - parentKey: string | null; + parentUnique: string | null; } export const UMB_DOCUMENT_TYPE_CREATE_OPTIONS_MODAL = new UmbModalToken( diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.repository.ts new file mode 100644 index 0000000000..6a56a658be --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.repository.ts @@ -0,0 +1,30 @@ +import { UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE } from '../../entity.js'; +import { UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT } from '../../tree/index.js'; +import { UmbDocumentTypeFolderServerDataSource } from './document-type-folder.server.data-source.js'; +import { UmbDocumentTypeFolderTreeItemModel } from './types.js'; +import { type UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbFolderModel, UmbFolderRepositoryBase } from '@umbraco-cms/backoffice/tree'; + +export class UmbDocumentTypeFolderRepository extends UmbFolderRepositoryBase { + constructor(host: UmbControllerHost) { + super( + host, + UmbDocumentTypeFolderServerDataSource, + UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT, + folderToDocumentTypeTreeItemMapper, + ); + } +} + +const folderToDocumentTypeTreeItemMapper = (folder: UmbFolderModel): UmbDocumentTypeFolderTreeItemModel => { + return { + unique: folder.unique, + parentUnique: folder.parentUnique, + name: folder.name, + entityType: UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE, + isContainer: false, + hasChildren: false, + isFolder: true, + isElement: false, + }; +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.server.data-source.ts new file mode 100644 index 0000000000..42b3d91614 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/document-type-folder.server.data-source.ts @@ -0,0 +1,123 @@ +import { UmbCreateFolderModel, UmbFolderDataSource, UmbUpdateFolderModel } from '@umbraco-cms/backoffice/tree'; +import { DocumentTypeResource } from '@umbraco-cms/backoffice/backend-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source for a Document Type folder that fetches data from the server + * @export + * @class UmbDocumentTypeFolderServerDataSource + * @implements {RepositoryDetailDataSource} + */ +export class UmbDocumentTypeFolderServerDataSource implements UmbFolderDataSource { + #host: UmbControllerHost; + + /** + * Creates an instance of UmbDocumentTypeFolderServerDataSource. + * @param {UmbControllerHost} host + * @memberof UmbDocumentTypeFolderServerDataSource + */ + constructor(host: UmbControllerHost) { + this.#host = host; + } + + /** + * Fetches a Document Type folder from the server + * @param {string} unique + * @return {*} + * @memberof UmbDocumentTypeFolderServerDataSource + */ + async read(unique: string) { + if (!unique) throw new Error('Unique is missing'); + + const { data, error } = await tryExecuteAndNotify( + this.#host, + DocumentTypeResource.getDocumentTypeFolderById({ + id: unique, + }), + ); + + if (data) { + const mappedData = { + unique: data.id, + name: data.name, + parentUnique: data.parentId || null, + }; + + return { data: mappedData }; + } + + return { error }; + } + + /** + * Creates a Document Type folder on the server + * @param {UmbCreateFolderModel} args + * @return {*} + * @memberof UmbDocumentTypeFolderServerDataSource + */ + async create(args: UmbCreateFolderModel) { + if (args.parentUnique === undefined) throw new Error('Parent unique is missing'); + if (!args.name) throw new Error('Name is missing'); + + const requestBody = { + id: args.unique, + parentId: args.parentUnique, + name: args.name, + }; + + const { error } = await tryExecuteAndNotify( + this.#host, + DocumentTypeResource.postDocumentTypeFolder({ + requestBody, + }), + ); + + if (!error) { + return this.read(args.unique); + } + + return { error }; + } + + /** + * Updates a Document Type folder on the server + * @param {UmbUpdateFolderModel} args + * @return {*} + * @memberof UmbDocumentTypeFolderServerDataSource + */ + async update(args: UmbUpdateFolderModel) { + if (!args.unique) throw new Error('Unique is missing'); + if (!args.name) throw new Error('Folder name is missing'); + + const { error } = await tryExecuteAndNotify( + this.#host, + DocumentTypeResource.putDocumentTypeFolderById({ + id: args.unique, + requestBody: { name: args.name }, + }), + ); + + if (!error) { + return this.read(args.unique); + } + + return { error }; + } + + /** + * Deletes a Document Type folder on the server + * @param {string} unique + * @return {*} + * @memberof UmbDocumentTypeServerDataSource + */ + async delete(unique: string) { + if (!unique) throw new Error('Unique is missing'); + return tryExecuteAndNotify( + this.#host, + DocumentTypeResource.deleteDocumentTypeFolderById({ + id: unique, + }), + ); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/index.ts new file mode 100644 index 0000000000..863773e971 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/index.ts @@ -0,0 +1,2 @@ +export { UmbDocumentTypeFolderRepository } from './document-type-folder.repository.js'; +export { UMB_DOCUMENT_TYPE_FOLDER_REPOSITORY_ALIAS } from './manifests.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/manifests.ts new file mode 100644 index 0000000000..a7ced4e26a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/manifests.ts @@ -0,0 +1,44 @@ +import { UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE } from '../../entity.js'; +import { UmbDocumentTypeFolderRepository } from './document-type-folder.repository.js'; +import { UmbDeleteFolderEntityAction, UmbFolderUpdateEntityAction } from '@umbraco-cms/backoffice/tree'; +import type { ManifestEntityAction, ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_DOCUMENT_TYPE_FOLDER_REPOSITORY_ALIAS = 'Umb.Repository.DocumentType.Folder'; + +const folderRepository: ManifestRepository = { + type: 'repository', + alias: UMB_DOCUMENT_TYPE_FOLDER_REPOSITORY_ALIAS, + name: 'Document Type Folder Repository', + api: UmbDocumentTypeFolderRepository, +}; + +const entityActions: Array = [ + { + type: 'entityAction', + alias: 'Umb.EntityAction.DocumentType.DeleteFolder', + name: 'Delete Document Type Folder Entity Action', + weight: 800, + api: UmbDeleteFolderEntityAction, + meta: { + icon: 'icon-trash', + label: 'Delete Folder...', + repositoryAlias: UMB_DOCUMENT_TYPE_FOLDER_REPOSITORY_ALIAS, + entityTypes: [UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE], + }, + }, + { + type: 'entityAction', + alias: 'Umb.EntityAction.DocumentType.RenameFolder', + name: 'Rename Document Type Folder Entity Action', + weight: 700, + api: UmbFolderUpdateEntityAction, + meta: { + icon: 'icon-edit', + label: 'Rename Folder...', + repositoryAlias: UMB_DOCUMENT_TYPE_FOLDER_REPOSITORY_ALIAS, + entityTypes: [UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE], + }, + }, +]; + +export const manifests = [folderRepository, ...entityActions]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/types.ts new file mode 100644 index 0000000000..be478b7c16 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/folder/types.ts @@ -0,0 +1,6 @@ +import { UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE } from '../../entity.js'; +import { UmbDocumentTypeTreeItemModel } from '../types.js'; + +export interface UmbDocumentTypeFolderTreeItemModel extends UmbDocumentTypeTreeItemModel { + entityType: typeof UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/index.ts new file mode 100644 index 0000000000..3c8096f8a5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/index.ts @@ -0,0 +1,2 @@ +export { UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT } from './document-type.tree.store.js'; +export * from './folder/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/manifests.ts index 2f0762f7c0..a4992d329c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/tree/manifests.ts @@ -1,6 +1,11 @@ -import { UMB_DOCUMENT_TYPE_ENTITY_TYPE, UMB_DOCUMENT_TYPE_ROOT_ENTITY_TYPE } from '../entity.js'; +import { + UMB_DOCUMENT_TYPE_ENTITY_TYPE, + UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE, + UMB_DOCUMENT_TYPE_ROOT_ENTITY_TYPE, +} from '../entity.js'; import { UmbDocumentTypeTreeRepository } from './document-type-tree.repository.js'; import { UmbDocumentTypeTreeStore } from './document-type.tree.store.js'; +import { manifests as folderManifests } from './folder/manifests.js'; import type { ManifestRepository, ManifestTree, @@ -41,8 +46,12 @@ const treeItem: ManifestTreeItem = { alias: 'Umb.TreeItem.DocumentType', name: 'Document Type Tree Item', meta: { - entityTypes: [UMB_DOCUMENT_TYPE_ROOT_ENTITY_TYPE, UMB_DOCUMENT_TYPE_ENTITY_TYPE], + entityTypes: [ + UMB_DOCUMENT_TYPE_ROOT_ENTITY_TYPE, + UMB_DOCUMENT_TYPE_ENTITY_TYPE, + UMB_DOCUMENT_TYPE_FOLDER_ENTITY_TYPE, + ], }, }; -export const manifests = [treeRepository, treeStore, tree, treeItem]; +export const manifests = [treeRepository, treeStore, tree, treeItem, ...folderManifests];