From cbc4f412e64c44965f8f5f03aaa46347573ead4b Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 19 Feb 2024 12:41:18 +0000 Subject: [PATCH 1/7] Refactored the repository, introduced `UmbDocumentCollectionItemModel` --- .../collection/document-collection.context.ts | 5 +- .../document-collection.repository.ts | 4 +- .../document-collection.server.data-source.ts | 81 ++++++++++--------- .../documents/documents/collection/types.ts | 25 +++++- .../document-grid-collection-view.element.ts | 15 ++-- .../document-table-collection-view.element.ts | 30 +++++-- 6 files changed, 96 insertions(+), 64 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection.context.ts index f0ae2555d7..139d393fd6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection.context.ts @@ -1,11 +1,10 @@ -import type { UmbDocumentDetailModel } from '../types.js'; -import type { UmbDocumentCollectionFilterModel } from './types.js'; +import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from './types.js'; import { UMB_DOCUMENT_TABLE_COLLECTION_VIEW_ALIAS } from './views/index.js'; import { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; export class UmbDocumentCollectionContext extends UmbDefaultCollectionContext< - UmbDocumentDetailModel, + UmbDocumentCollectionItemModel, UmbDocumentCollectionFilterModel > { constructor(host: UmbControllerHost) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.repository.ts index e55d9882b5..ebd5b771b2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.repository.ts @@ -10,8 +10,8 @@ export class UmbDocumentCollectionRepository implements UmbCollectionRepository this.#collectionSource = new UmbDocumentCollectionServerDataSource(host); } - async requestCollection(filter: UmbDocumentCollectionFilterModel) { - return this.#collectionSource.getCollection(filter); + async requestCollection(query: UmbDocumentCollectionFilterModel) { + return this.#collectionSource.getCollection(query); } destroy(): void {} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.server.data-source.ts index 68e5150b99..febaef4250 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/repository/document-collection.server.data-source.ts @@ -1,61 +1,62 @@ -import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js'; -import type { UmbDocumentCollectionFilterModel } from '../types.js'; -import type { UmbDocumentTreeItemModel } from '../../tree/types.js'; -import { DocumentResource } from '@umbraco-cms/backoffice/external/backend-api'; +import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from '../types.js'; +import { DirectionModel, DocumentResource } from '@umbraco-cms/backoffice/external/backend-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; -import type { DocumentTreeItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; +import type { DocumentCollectionResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/repository'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -export class UmbDocumentCollectionServerDataSource implements UmbCollectionDataSource { +export class UmbDocumentCollectionServerDataSource implements UmbCollectionDataSource { #host: UmbControllerHost; constructor(host: UmbControllerHost) { this.#host = host; } - async getCollection(filter: UmbDocumentCollectionFilterModel) { - // TODO: [LK] Replace the Management API call with the correct endpoint once it is available. - const { data, error } = await tryExecuteAndNotify(this.#host, DocumentResource.getTreeDocumentRoot(filter)); + async getCollection(query: UmbDocumentCollectionFilterModel) { + if (!query.unique) { + throw new Error('Unique ID is required to fetch a collection.'); + } + + if (!query.dataTypeId) { + throw new Error('Data type ID is required to fetch a collection.'); + } + + const params = { + id: query.unique, + dataTypeId: query.dataTypeId, + orderBy: query.orderBy ?? 'updateDate', + orderCulture: query.orderCulture ?? 'en-US', + orderDirection: query.orderDirection === 'asc' ? DirectionModel.ASCENDING : DirectionModel.DESCENDING, + filter: query.filter, + skip: query.skip ?? 0, + take: query.take ?? 100, + }; + + const { data, error } = await tryExecuteAndNotify(this.#host, DocumentResource.getCollectionDocumentById(params)); if (data) { - const skip = Number(filter.skip) ?? 0; - const take = Number(filter.take) ?? 100; + const items = data.items.map((item: DocumentCollectionResponseModel) => { - const items = data.items.slice(skip, skip + take).map((item) => this.#mapper(item)); + // TODO: [LK] Temp solution, review how to get the name from the corresponding variant. + const variant = item.variants[0]; - //console.log('UmbDocumentCollectionServerDataSource.getCollection', [data, items]); + const model: UmbDocumentCollectionItemModel = { + unique: item.id, + createDate: new Date(variant.createDate), + creator: item.creator, + icon: item.documentType.icon, + name: variant.name, + state: variant.state, + updateDate: new Date(variant.updateDate), + updater: item.updater, + values: item.values.map((item) => { return { alias: item.alias, value: item.value }; }), + }; + return model; + }); return { data: { items, total: data.total } }; } return { error }; } - - // TODO: [LK] Temp solution. Copied from "src\packages\documents\documents\tree\document-tree.server.data-source.ts" - #mapper = (item: DocumentTreeItemResponseModel): UmbDocumentTreeItemModel => { - return { - unique: item.id, - parentUnique: item.parent ? item.parent.id : null, - entityType: UMB_DOCUMENT_ENTITY_TYPE, - noAccess: item.noAccess, - isTrashed: item.isTrashed, - hasChildren: item.hasChildren, - isProtected: item.isProtected, - documentType: { - unique: item.documentType.id, - icon: item.documentType.icon, - hasCollection: item.documentType.hasListView, - }, - variants: item.variants.map((variant) => { - return { - name: variant.name, - culture: variant.culture || null, - state: variant.state, - }; - }), - name: item.variants[0]?.name, // TODO: this is not correct. We need to get it from the variants. This is a temp solution. - isFolder: false, - }; - }; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/types.ts index fa6136bb06..dc13ccc403 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/types.ts @@ -1,5 +1,22 @@ -export interface UmbDocumentCollectionFilterModel { - skip?: number; - take?: number; - filter?: string; +import type { UmbCollectionFilterModel } from '@umbraco-cms/backoffice/collection'; + +export interface UmbDocumentCollectionFilterModel extends UmbCollectionFilterModel { + unique: string; + dataTypeId?: string; + orderBy?: string; + orderCulture?: string; + orderDirection?: 'asc' | 'desc'; + userDefinedProperties: Array<{alias: string, header: string, isSystem: boolean}>; +} + +export interface UmbDocumentCollectionItemModel { + unique: string; + createDate: Date; + creator?: string | null; + icon: string; + name: string; + state: string; + updateDate: Date; + updater?: string | null; + values: Array<{ alias: string; value: string }>; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts index d4579cd483..849d61d38b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts @@ -1,5 +1,4 @@ -import type { UmbDocumentCollectionFilterModel } from '../../types.js'; -import type { UmbDocumentTreeItemModel } from '../../../tree/types.js'; +import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from '../../types.js'; import { css, html, nothing, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @@ -9,7 +8,7 @@ import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collec @customElement('umb-document-grid-collection-view') export class UmbDocumentGridCollectionViewElement extends UmbLitElement { @state() - private _items: Array = []; + private _items: Array = []; @state() private _selection: Array = []; @@ -17,7 +16,7 @@ export class UmbDocumentGridCollectionViewElement extends UmbLitElement { @state() private _loading = false; - #collectionContext?: UmbDefaultCollectionContext; + #collectionContext?: UmbDefaultCollectionContext; constructor() { super(); @@ -39,11 +38,11 @@ export class UmbDocumentGridCollectionViewElement extends UmbLitElement { history.pushState(null, '', 'section/content/workspace/document/edit/' + id); } - #onSelect(item: UmbDocumentTreeItemModel) { + #onSelect(item: UmbDocumentCollectionItemModel) { this.#collectionContext?.selection.select(item.unique ?? ''); } - #onDeselect(item: UmbDocumentTreeItemModel) { + #onDeselect(item: UmbDocumentCollectionItemModel) { this.#collectionContext?.selection.deselect(item.unique ?? ''); } @@ -60,7 +59,7 @@ export class UmbDocumentGridCollectionViewElement extends UmbLitElement { `; } - #renderCard(item: UmbDocumentTreeItemModel) { + #renderCard(item: UmbDocumentCollectionItemModel) { return html` this._handleOpenCard(item.unique ?? '')} @selected=${() => this.#onSelect(item)} @deselected=${() => this.#onDeselect(item)}> - + `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts index 99aeff126e..8824d99342 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts @@ -1,5 +1,4 @@ -import type { UmbDocumentCollectionFilterModel } from '../../types.js'; -import type { UmbDocumentTreeItemModel } from '../../../tree/types.js'; +import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from '../../types.js'; import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @@ -20,7 +19,10 @@ import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collec @customElement('umb-document-table-collection-view') export class UmbDocumentTableCollectionViewElement extends UmbLitElement { @state() - private _items?: Array; + private _busy = false; + + @state() + private _items?: Array; @state() private _tableConfig: UmbTableConfig = { @@ -49,7 +51,10 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { @state() private _selection: Array = []; - private _collectionContext?: UmbDefaultCollectionContext; + private _collectionContext?: UmbDefaultCollectionContext< + UmbDocumentCollectionItemModel, + UmbDocumentCollectionFilterModel + >; constructor() { super(); @@ -64,7 +69,7 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { this.observe(this._collectionContext.items, (items) => { this._items = items; - this._createTableItems(this._items); + this.#createTableItems(this._items); }); this.observe(this._collectionContext.selection.selection, (selection) => { @@ -72,12 +77,11 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { }); } - private _createTableItems(items: Array) { + #createTableItems(items: Array) { this._tableItems = items.map((item) => { if (!item.unique) throw new Error('Item id is missing.'); return { id: item.unique, - icon: item.documentType.icon, data: [ { columnAlias: 'entityName', @@ -90,6 +94,7 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { // }, // }, ], + icon: item.icon, }; }); } @@ -116,6 +121,11 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { } render() { + if (this._busy) return html`
`; + + if (this._tableItems.length === 0) + return html`

${this.localize.term('content_listViewNoItems')}

`; + return html` Date: Mon, 19 Feb 2024 12:49:54 +0000 Subject: [PATCH 2/7] Wired up the Collection data-type configuration Note, `dataTypeUnique` is still hardcoded, until https://github.com/umbraco/Umbraco-CMS/pull/15687 has been merged in. --- .../default/collection-default.context.ts | 11 ++- .../src/packages/core/collection/types.ts | 4 +- ...perty-editor-ui-collection-view.element.ts | 33 ++++++++- .../document-table-collection-view.element.ts | 68 +++++++++++++++---- ...ument-workspace-view-collection.element.ts | 22 ++++-- 5 files changed, 115 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts index dcf199554d..96c9375d6b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts @@ -31,6 +31,9 @@ export class UmbDefaultCollectionContext< #filter = new UmbObjectState({}); public readonly filter = this.#filter.asObservable(); + #userDefinedProperties = new UmbArrayState([], (x) => x); + public readonly userDefinedProperties = this.#userDefinedProperties.asObservable(); + repository?: UmbCollectionRepository; #initResolver?: () => void; @@ -131,7 +134,13 @@ export class UmbDefaultCollectionContext< #configure() { this.selection.setMultiple(true); this.pagination.setPageSize(this.#config.pageSize!); - this.#filter.setValue({ ...this.#filter.getValue(), skip: 0, take: this.#config.pageSize }); + this.#filter.setValue({ + ...this.#config, + ...this.#filter.getValue(), + skip: 0, + take: this.#config.pageSize, + }); + this.#userDefinedProperties.setValue(this.#config.userDefinedProperties ?? []); } #onPageChange = (event: UmbChangeEvent) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts index 1a39fdb5a9..6304e5fbf5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts @@ -11,12 +11,14 @@ export interface UmbCollectionBulkActionPermissions { } export interface UmbCollectionConfiguration { + unique?: string; + dataTypeId?: string; allowedEntityBulkActions?: UmbCollectionBulkActionPermissions; - includeProperties?: Array; orderBy?: string; orderDirection?: string; pageSize?: number; useInfiniteEditor?: boolean; + userDefinedProperties?: Array; } export interface UmbCollectionContext { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/property-editor-ui-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/property-editor-ui-collection-view.element.ts index aae8535519..ec7f581a90 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/property-editor-ui-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/property-editor-ui-collection-view.element.ts @@ -3,9 +3,12 @@ import type { UmbCollectionConfiguration, } from '../../../../core/collection/types.js'; import type { UmbPropertyEditorConfigCollection } from '../../config/index.js'; -import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; +import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; +import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property'; +import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/document'; /** * @element umb-property-editor-ui-collection-view @@ -23,6 +26,32 @@ export class UmbPropertyEditorUICollectionViewElement extends UmbLitElement impl this._config = this.#mapDataTypeConfigToCollectionConfig(config); } + constructor() { + super(); + + // Gets the Data Type ID for the current property. + this.consumeContext(UMB_PROPERTY_CONTEXT, (propertyContext) => { + // TODO: [LK:2024-02-01] Replace `UMB_DOCUMENT_WORKSPACE_CONTEXT` + // with an abstracted context that supports both document and media workspaces. + this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (workspaceContext) => { + this.observe(workspaceContext.unique, (unique) => { + if (this._config) { + this._config.unique = unique; + } + }); + this.observe(propertyContext.alias, async (propertyAlias) => { + if (propertyAlias) { + const property = await workspaceContext.structure.getPropertyStructureByAlias(propertyAlias); + if (property && this._config) { + this._config.dataTypeId = property.dataType.unique; + this.requestUpdate('_config'); + } + } + }); + }); + }); + } + #mapDataTypeConfigToCollectionConfig( config: UmbPropertyEditorConfigCollection | undefined, ): UmbCollectionConfiguration { @@ -32,10 +61,12 @@ export class UmbPropertyEditorUICollectionViewElement extends UmbLitElement impl orderDirection: config?.getValueByAlias('orderDirection') ?? 'asc', pageSize: Number(config?.getValueByAlias('pageSize')) ?? 50, useInfiniteEditor: config?.getValueByAlias('useInfiniteEditor') ?? false, + userDefinedProperties: config?.getValueByAlias('includeProperties'), }; } render() { + if (!this._config?.unique || !this._config?.dataTypeId) return html``; return html``; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts index 8824d99342..8be688f611 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts @@ -21,6 +21,9 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { @state() private _busy = false; + @state() + private _userDefinedProperties?: Array; + @state() private _items?: Array; @@ -67,6 +70,11 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { private _observeCollectionContext() { if (!this._collectionContext) return; + this.observe(this._collectionContext.userDefinedProperties, (userDefinedProperties) => { + this._userDefinedProperties = userDefinedProperties; + this.#createTableHeadings(); + }); + this.observe(this._collectionContext.items, (items) => { this._items = items; this.#createTableItems(this._items); @@ -77,24 +85,55 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { }); } + #createTableHeadings() { + if (this._userDefinedProperties && this._userDefinedProperties.length > 0) { + const userColumns: Array = this._userDefinedProperties.map((item) => { + return { + name: item.header, + alias: item.alias, + elementName: item.elementName, + allowSorting: true, + }; + }); + + this._tableColumns = [...this.#systemColumns, ...userColumns]; + } + } + #createTableItems(items: Array) { + // TODO: [LK] This is a temporary solution. Let's explore a nicer way to display the values. + const getValue = (item: UmbDocumentCollectionItemModel, alias: string) => { + switch (alias) { + case 'createDate': + return item.createDate.toLocaleString(); + case 'owner': + return item.creator; + case 'published': + return item.state !== 'Draft' ? 'True' : 'False'; + case 'updateDate': + return item.updateDate.toLocaleString(); + case 'updater': + return item.updater; + default: + return item.values.find((value) => value.alias === alias)?.value ?? ''; + } + }; + this._tableItems = items.map((item) => { if (!item.unique) throw new Error('Item id is missing.'); + + const data = + this._tableColumns?.map((column) => { + return { + columnAlias: column.alias, + value: column.elementName ? item : getValue(item, column.alias), + }; + }) ?? []; + return { id: item.unique, - data: [ - { - columnAlias: 'entityName', - value: item.name || 'Unnamed Document', - }, - // { - // columnAlias: 'entityActions', - // value: { - // entityType: item.entityType, - // }, - // }, - ], icon: item.icon, + data: data, }; }); } @@ -117,7 +156,10 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { const table = event.target as UmbTableElement; const orderingColumn = table.orderingColumn; const orderingDesc = table.orderingDesc; - console.log(`fetch media items, order column: ${orderingColumn}, desc: ${orderingDesc}`); + this._collectionContext?.setFilter({ + orderBy: orderingColumn, + orderDirection: orderingDesc ? 'desc' : 'asc', + }); } render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts index 6d34977565..ec9573543a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts @@ -7,6 +7,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbDataTypeDetailRepository } from '@umbraco-cms/backoffice/data-type'; import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor'; import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/document'; +import type { UmbDataTypeDetailModel } from '@umbraco-cms/backoffice/data-type'; import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry'; @customElement('umb-document-workspace-view-collection') @@ -14,6 +15,9 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp @state() private _config?: UmbCollectionConfiguration; + @state() + private _documentUnique?: string; + #dataTypeDetailRepository = new UmbDataTypeDetailRepository(this); constructor() { @@ -23,13 +27,16 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp async #observeConfig() { this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (workspaceContext) => { + this.observe(workspaceContext.unique, (unique) => { + this._documentUnique = unique; + }); this.observe( workspaceContext.structure.ownerContentType(), async (documentType) => { if (!documentType) return; // TODO: [LK] Temp hard-coded. Once the API is ready, wire up the data-type ID from the content-type. - const dataTypeUnique = 'dt-collectionView'; + const dataTypeUnique = 'c0808dd3-8133-4e4b-8ce8-e2bea84a96a4'; // documentType.collection.dataTypeId; if (dataTypeUnique) { await this.#dataTypeDetailRepository.requestByUnique(dataTypeUnique); @@ -37,9 +44,7 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp await this.#dataTypeDetailRepository.byUnique(dataTypeUnique), (dataType) => { if (!dataType) return; - this._config = this.#mapDataTypeConfigToCollectionConfig( - new UmbPropertyEditorConfigCollection(dataType.values), - ); + this._config = this.#mapDataTypeConfigToCollectionConfig(dataType); }, '#observeConfig.dataType', ); @@ -50,19 +55,22 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp }); } - #mapDataTypeConfigToCollectionConfig( - config: UmbPropertyEditorConfigCollection | undefined, - ): UmbCollectionConfiguration { + #mapDataTypeConfigToCollectionConfig(dataType: UmbDataTypeDetailModel): UmbCollectionConfiguration { + const config = new UmbPropertyEditorConfigCollection(dataType.values); return { + unique: this._documentUnique, + dataTypeId: dataType.unique, allowedEntityBulkActions: config?.getValueByAlias('bulkActionPermissions'), orderBy: config?.getValueByAlias('orderBy') ?? 'updateDate', orderDirection: config?.getValueByAlias('orderDirection') ?? 'asc', pageSize: Number(config?.getValueByAlias('pageSize')) ?? 50, useInfiniteEditor: config?.getValueByAlias('useInfiniteEditor') ?? false, + userDefinedProperties: config?.getValueByAlias('includeProperties'), }; } render() { + if (!this._config?.unique || !this._config?.dataTypeId) return html``; return html``; } } From a04ade67c9f42d38b05d0ba02c93a440c445ed23 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 19 Feb 2024 12:51:10 +0000 Subject: [PATCH 3/7] Temp fix for `isSystem` flag As the server API is currently expecting a `1` or `0` value, not a boolean type. --- ...ditor-ui-collection-view-column-configuration.element.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/column-configuration/property-editor-ui-collection-view-column-configuration.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/column-configuration/property-editor-ui-collection-view-column-configuration.element.ts index 4625960edb..1b8baa7f5c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/column-configuration/property-editor-ui-collection-view-column-configuration.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/column-configuration/property-editor-ui-collection-view-column-configuration.element.ts @@ -9,7 +9,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; interface ColumnConfig { alias: string; header: string; - isSystem: boolean; + isSystem: 1 | 0; nameTemplate?: string; } @@ -77,7 +77,7 @@ export class UmbPropertyEditorUICollectionViewColumnConfigurationElement const config: ColumnConfig = { alias: selected.value, header: selected.name, - isSystem: selected?.group === 'System Fields', + isSystem: selected?.group === 'System Fields' ? 1 : 0, }; this.value = [...this.value, config]; @@ -133,7 +133,7 @@ export class UmbPropertyEditorUICollectionViewColumnConfigurationElement (configuration) => html` - ${configuration.isSystem + ${configuration.isSystem === 1 ? this.#renderSystemFieldRow(configuration) : this.#renderCustomFieldRow(configuration)} From e11cefad097e3d65d23cb2a8fbb53257e160ee08 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 19 Feb 2024 12:52:20 +0000 Subject: [PATCH 4/7] Toolbar markup tidy-up --- .../collection/document-collection-toolbar.element.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection-toolbar.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection-toolbar.element.ts index def5e1065d..b34019e6aa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection-toolbar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection-toolbar.element.ts @@ -28,14 +28,8 @@ export class UmbDocumentCollectionToolbarElement extends UmbLitElement { render() { return html` - ${this.#renderSearch()} - - `; - } - - #renderSearch() { - return html` + `; } From 84dfa9e53f0f1e3cba391620d2f217de9aacac0e Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 19 Feb 2024 12:55:52 +0000 Subject: [PATCH 5/7] Swapped missed `hasListView` to `hasCollection` --- .../repository/item/document-item.server.data-source.ts | 2 +- .../src/packages/documents/documents/repository/item/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/document-item.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/document-item.server.data-source.ts index 293ab5935d..989fb63a77 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/document-item.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/document-item.server.data-source.ts @@ -38,7 +38,7 @@ const mapper = (item: DocumentItemResponseModel): UmbDocumentItemModel => { documentType: { unique: item.documentType.id, icon: item.documentType.icon, - hasListView: item.documentType.hasListView, + hasCollection: item.documentType.hasListView, }, variants: item.variants.map((variant) => { return { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/types.ts index 9da5379a3c..7de3100c2a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/item/types.ts @@ -8,7 +8,7 @@ export interface UmbDocumentItemModel { documentType: { unique: string; icon: string; - hasListView: boolean; + hasCollection: boolean; }; variants: Array; } From 2e185dd1c69eceb74e77f404b9a44ac1a49ebb46 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 19 Feb 2024 13:10:24 +0000 Subject: [PATCH 6/7] Applied fixes from @nielslyngsoe's investigation PR #1225 --- .../core/collection/collection-view.manager.ts | 6 +++--- .../packages/core/components/table/table.element.ts | 2 +- .../table/document-table-collection-view.element.ts | 4 +++- .../document-workspace-has-collection.condition.ts | 12 ++++++++---- .../workspace/document-workspace-editor.element.ts | 9 +++++---- .../workspace/document-workspace.element.ts | 13 ++++++------- .../document-workspace-view-collection.element.ts | 4 ++-- 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts index 67ff3afc51..ae656dabc5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts @@ -1,9 +1,9 @@ import { UmbBaseController } from '@umbraco-cms/backoffice/class-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbExtensionsManifestInitializer, createExtensionElement } from '@umbraco-cms/backoffice/extension-api'; -import type { ManifestCollectionView} from '@umbraco-cms/backoffice/extension-registry'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbArrayState, UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; +import type { ManifestCollectionView } from '@umbraco-cms/backoffice/extension-registry'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbRoute } from '@umbraco-cms/backoffice/router'; export interface UmbCollectionViewManagerConfig { @@ -68,7 +68,7 @@ export class UmbCollectionViewManager extends UmbBaseController { #createRoutes(views: ManifestCollectionView[] | null) { let routes: Array = []; - if (views) { + if (views && views.length > 0) { // find the default view from the config. If it doesn't exist, use the first view const defaultView = views.find((view) => view.alias === this.#defaultViewAlias); const fallbackView = defaultView?.meta.pathName || views[0].meta.pathName; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts index 2fe80b1517..a10cd863ba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts @@ -103,7 +103,7 @@ export class UmbTableElement extends LitElement { @property({ type: String, attribute: false }) public orderingColumn = ''; - @property({ type: String, attribute: false }) + @property({ type: Boolean, attribute: false }) public orderingDesc = false; @state() diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts index 8be688f611..581876563a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts @@ -33,7 +33,9 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement { }; @state() - private _tableColumns: Array = [ + private _tableColumns: Array = []; + + #systemColumns: Array = [ { name: 'Name', alias: 'entityName', diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/conditions/document-workspace-has-collection.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/conditions/document-workspace-has-collection.condition.ts index 2adc8e7d1b..b1327b24cd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/conditions/document-workspace-has-collection.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/conditions/document-workspace-has-collection.condition.ts @@ -18,10 +18,14 @@ export class UmbDocumentWorkspaceHasCollectionCondition extends UmbBaseControlle this.#onChange = args.onChange; this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => { - this.observe(context.contentTypeHasCollection, (hasCollection) => { - this.permitted = hasCollection === true; - this.#onChange(); - }); + this.observe( + context.contentTypeHasCollection, + (hasCollection) => { + this.permitted = hasCollection ?? false; + this.#onChange(); + }, + 'observeCollection', + ); }); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts index 924a06d0e0..49a5d76926 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts @@ -1,12 +1,13 @@ -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbDocumentWorkspaceSplitViewElement } from './document-workspace-split-view.element.js'; import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from './document-workspace.context-token.js'; -import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { customElement, state, css, html } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbVariantModel } from '@umbraco-cms/backoffice/variant'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; -import type { UmbRoute, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router'; import type { ActiveVariant } from '@umbraco-cms/backoffice/workspace'; +import type { UmbRoute, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router'; +import type { UmbVariantModel } from '@umbraco-cms/backoffice/variant'; + @customElement('umb-document-workspace-editor') export class UmbDocumentWorkspaceEditorElement extends UmbLitElement { //private _defaultVariant?: VariantViewModelBaseModel; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts index a5c0f89026..133c6eaeee 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts @@ -1,15 +1,14 @@ -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbDocumentWorkspaceContext } from './document-workspace.context.js'; import { UmbDocumentWorkspaceEditorElement } from './document-workspace-editor.element.js'; -import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbRoute } from '@umbraco-cms/backoffice/router'; - -import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/workspace'; -import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbExtensionsApiInitializer, createExtensionApi } from '@umbraco-cms/backoffice/extension-api'; -import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/workspace'; +import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; +import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; +import type { UmbRoute } from '@umbraco-cms/backoffice/router'; @customElement('umb-document-workspace') export class UmbDocumentWorkspaceElement extends UmbLitElement { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts index ec9573543a..f9103b6219 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts @@ -46,11 +46,11 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp if (!dataType) return; this._config = this.#mapDataTypeConfigToCollectionConfig(dataType); }, - '#observeConfig.dataType', + '_observeConfigDataType', ); } }, - '#observeConfig.documentType', + '_observeConfigDocumentType', ); }); } From 8bf8e7301ad4c0b38aa02db31e097251a210ac73 Mon Sep 17 00:00:00 2001 From: Lee Kelleher Date: Mon, 19 Feb 2024 13:42:04 +0000 Subject: [PATCH 7/7] Update src/packages/core/collection/collection-view.manager.ts Simplifying the check. Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> --- .../src/packages/core/collection/collection-view.manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts index ae656dabc5..e8fdc32f3e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts @@ -68,7 +68,7 @@ export class UmbCollectionViewManager extends UmbBaseController { #createRoutes(views: ManifestCollectionView[] | null) { let routes: Array = []; - if (views && views.length > 0) { + if (views?.length) { // find the default view from the config. If it doesn't exist, use the first view const defaultView = views.find((view) => view.alias === this.#defaultViewAlias); const fallbackView = defaultView?.meta.pathName || views[0].meta.pathName;