From bb231261318931154a7609971fd0761b10cc8da2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 12 Sep 2023 16:17:06 +0200 Subject: [PATCH] add document recycle bin --- .../src/packages/documents/documents/index.ts | 1 + .../packages/documents/documents/manifests.ts | 2 + .../documents/menu-item/manifests.ts | 2 +- .../documents/documents/recycle-bin/index.ts | 1 + .../documents/recycle-bin/manifests.ts | 5 ++ .../document-recycle-bin-menu-item.element.ts | 17 ++++ .../recycle-bin/menu-item/manifests.ts | 16 ++++ .../document-recycle-bin.repository.ts | 77 +++++++++++++++++++ .../documents/recycle-bin/repository/index.ts | 1 + .../recycle-bin/repository/manifests.ts | 13 ++++ .../document-recycle-bin.tree.server.data.ts | 53 +++++++++++++ .../documents/recycle-bin/tree/manifests.ts | 23 ++++++ 12 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/document-recycle-bin-menu-item.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/document-recycle-bin.repository.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/sources/document-recycle-bin.tree.server.data.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/tree/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts index 79edea5a02..661e019300 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts @@ -1,5 +1,6 @@ export * from './repository/index.js'; export * from './workspace/index.js'; +export * from './recycle-bin/index.js'; import './components/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts index ea4d0dc985..c9fd54a5da 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts @@ -6,6 +6,7 @@ import { manifests as workspaceManifests } from './workspace/manifests.js'; import { manifests as entityActionManifests } from './entity-actions/manifests.js'; import { manifests as entityBulkActionManifests } from './entity-bulk-actions/manifests.js'; import { manifests as propertyEditorManifests } from './property-editors/manifests.js'; +import { manifests as recycleBinManifests } from './recycle-bin/manifests.js'; export const manifests = [ ...collectionManifests, @@ -16,4 +17,5 @@ export const manifests = [ ...entityActionManifests, ...entityBulkActionManifests, ...propertyEditorManifests, + ...recycleBinManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/menu-item/manifests.ts index fb1b999d66..9494e04164 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/menu-item/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/menu-item/manifests.ts @@ -4,7 +4,7 @@ const menuItem: ManifestMenuItem = { type: 'menuItem', alias: 'Umb.MenuItem.Documents', name: 'Documents Menu Item', - weight: 100, + weight: 200, loader: () => import('./document-menu-item.element.js'), meta: { label: 'Documents', diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/index.ts new file mode 100644 index 0000000000..3d76f338dd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/index.ts @@ -0,0 +1 @@ +export * from './repository/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/manifests.ts new file mode 100644 index 0000000000..2e00f85703 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/manifests.ts @@ -0,0 +1,5 @@ +import { manifests as repositoryManifests } from './repository/manifests.js'; +import { manifests as treeManifests } from './tree/manifests.js'; +import { manifests as menuItemManifests } from './menu-item/manifests.js'; + +export const manifests = [...repositoryManifests, ...treeManifests, ...menuItemManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/document-recycle-bin-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/document-recycle-bin-menu-item.element.ts new file mode 100644 index 0000000000..c0d1131aec --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/document-recycle-bin-menu-item.element.ts @@ -0,0 +1,17 @@ +import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; + +@customElement('umb-document-recycle-bin-menu-item') +export class UmbDocumentRecycleMenuItemElement extends UmbLitElement { + render() { + return html``; + } +} + +export default UmbDocumentRecycleMenuItemElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-document-recycle-bin-menu-item': UmbDocumentRecycleMenuItemElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/manifests.ts new file mode 100644 index 0000000000..d3fc174eb8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/backoffice/extension-registry'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.DocumentRecycleBin', + name: 'Document Recycle Bin Menu Item', + weight: 100, + loader: () => import('./document-recycle-bin-menu-item.element.js'), + meta: { + label: 'Recycle Bin', + icon: 'umb:trash', + menus: ['Umb.Menu.Content'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/document-recycle-bin.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/document-recycle-bin.repository.ts new file mode 100644 index 0000000000..0f18b3614c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/document-recycle-bin.repository.ts @@ -0,0 +1,77 @@ +import { UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN, UmbDocumentTreeStore } from '../../repository/document.tree.store.js'; +import { UmbDocumentRecycleBinTreeServerDataSource } from './sources/document-recycle-bin.tree.server.data.js'; +import type { UmbTreeDataSource, UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; +import { DocumentTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; + +export class UmbDocumentRecycleBinRepository implements UmbTreeRepository { + #init!: Promise; + + #host: UmbControllerHostElement; + + #treeSource: UmbTreeDataSource; + #treeStore?: UmbDocumentTreeStore; + + constructor(host: UmbControllerHostElement) { + this.#host = host; + + // TODO: figure out how spin up get the correct data source + this.#treeSource = new UmbDocumentRecycleBinTreeServerDataSource(this.#host); + + this.#init = Promise.all([ + new UmbContextConsumerController(this.#host, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN, (instance) => { + this.#treeStore = instance; + }), + ]); + } + + async requestTreeRoot() { + await this.#init; + + const data = { + id: null, + type: 'document-recycle-bin-root', + name: 'Recycle Bin', + icon: 'umb:trash', + hasChildren: true, + }; + + return { data }; + } + + async requestRootTreeItems() { + await this.#init; + + const { data, error } = await this.#treeSource.getRootItems(); + + if (data) { + this.#treeStore?.appendItems(data.items); + } + + return { data, error, asObservable: () => this.#treeStore!.rootItems }; + } + + async requestTreeItemsOf(parentId: string | null) { + await this.#init; + if (parentId === undefined) throw new Error('Parent id is missing'); + + const { data, error } = await this.#treeSource.getChildrenOf(parentId); + + if (data) { + this.#treeStore?.appendItems(data.items); + } + + return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentId) }; + } + + async rootTreeItems() { + await this.#init; + return this.#treeStore!.rootItems; + } + + async treeItemsOf(parentId: string | null) { + await this.#init; + return this.#treeStore!.childrenOf(parentId); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/index.ts new file mode 100644 index 0000000000..619562bea1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/index.ts @@ -0,0 +1 @@ +export { UmbDocumentRecycleBinRepository } from './document-recycle-bin.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/manifests.ts new file mode 100644 index 0000000000..2304c822bf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/manifests.ts @@ -0,0 +1,13 @@ +import { UmbDocumentRecycleBinRepository } from './document-recycle-bin.repository.js'; +import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; + +export const DOCUMENT_RECYCLE_BIN_REPOSITORY_ALIAS = 'Umb.Repository.DocumentRecycleBin'; + +const repository: ManifestRepository = { + type: 'repository', + alias: DOCUMENT_RECYCLE_BIN_REPOSITORY_ALIAS, + name: 'Document Recycle Bin Repository', + class: UmbDocumentRecycleBinRepository, +}; + +export const manifests = [repository]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/sources/document-recycle-bin.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/sources/document-recycle-bin.tree.server.data.ts new file mode 100644 index 0000000000..9c6090bac5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/repository/sources/document-recycle-bin.tree.server.data.ts @@ -0,0 +1,53 @@ +import type { UmbTreeDataSource } from '@umbraco-cms/backoffice/repository'; +import { DocumentResource } from '@umbraco-cms/backoffice/backend-api'; +import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source for the Document Recycle Bin tree that fetches data from the server + * @export + * @class UmbDocumentRecycleBinTreeServerDataSource + * @implements {UmbTreeDataSource} + */ +export class UmbDocumentRecycleBinTreeServerDataSource implements UmbTreeDataSource { + #host: UmbControllerHostElement; + + /** + * Creates an instance of UmbDocumentRecycleBinTreeServerDataSource. + * @param {UmbControllerHostElement} host + * @memberof UmbDocumentTreeServerDataSource + */ + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Fetches the root items for the tree from the server + * @memberof UmbDocumentRecycleBinTreeServerDataSource + */ + async getRootItems() { + return tryExecuteAndNotify(this.#host, DocumentResource.getRecycleBinDocumentRoot({})); + } + + /** + * Fetches the children of a given parent id from the server + * @param {(string | null)} parentId + * @memberof UmbDocumentTreeServerDataSource + */ + async getChildrenOf(parentId: string | null) { + if (parentId === undefined) throw new Error('Parent id is missing'); + + /* TODO: should we make getRootItems() internal + so it only is a server concern that there are two endpoints? */ + if (parentId === null) { + return this.getRootItems(); + } else { + return tryExecuteAndNotify( + this.#host, + DocumentResource.getRecycleBinDocumentChildren({ + parentId, + }), + ); + } + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/tree/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/tree/manifests.ts new file mode 100644 index 0000000000..e5f06df0aa --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/recycle-bin/tree/manifests.ts @@ -0,0 +1,23 @@ +import { DOCUMENT_RECYCLE_BIN_REPOSITORY_ALIAS } from '../repository/manifests.js'; +import type { ManifestTree, ManifestTreeItem } from '@umbraco-cms/backoffice/extension-registry'; + +const tree: ManifestTree = { + type: 'tree', + alias: 'Umb.Tree.DocumentRecycleBin', + name: 'Document Recycle Bin Tree', + meta: { + repositoryAlias: DOCUMENT_RECYCLE_BIN_REPOSITORY_ALIAS, + }, +}; + +const treeItem: ManifestTreeItem = { + type: 'treeItem', + kind: 'entity', + alias: 'Umb.TreeItem.DocumentRecycleBin', + name: 'Document Recycle Bin Tree Item', + meta: { + entityTypes: ['document-recycle-bin-root'], + }, +}; + +export const manifests = [tree, treeItem];