Merge pull request #1238 from umbraco/feature/document-collection-ui
Document Collection UI (part 2)
This commit is contained in:
@@ -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<UmbRoute> = [];
|
||||
|
||||
if (views) {
|
||||
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;
|
||||
|
||||
@@ -31,6 +31,9 @@ export class UmbDefaultCollectionContext<
|
||||
#filter = new UmbObjectState<FilterModelType | object>({});
|
||||
public readonly filter = this.#filter.asObservable();
|
||||
|
||||
#userDefinedProperties = new UmbArrayState<any>([], (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) => {
|
||||
|
||||
@@ -11,12 +11,14 @@ export interface UmbCollectionBulkActionPermissions {
|
||||
}
|
||||
|
||||
export interface UmbCollectionConfiguration {
|
||||
unique?: string;
|
||||
dataTypeId?: string;
|
||||
allowedEntityBulkActions?: UmbCollectionBulkActionPermissions;
|
||||
includeProperties?: Array<any>;
|
||||
orderBy?: string;
|
||||
orderDirection?: string;
|
||||
pageSize?: number;
|
||||
useInfiniteEditor?: boolean;
|
||||
userDefinedProperties?: Array<any>;
|
||||
}
|
||||
|
||||
export interface UmbCollectionContext {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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`<uui-table-row>
|
||||
<uui-table-cell><uui-icon name="icon-navigation"></uui-icon></uui-table-cell>
|
||||
${configuration.isSystem
|
||||
${configuration.isSystem === 1
|
||||
? this.#renderSystemFieldRow(configuration)
|
||||
: this.#renderCustomFieldRow(configuration)}
|
||||
<uui-table-cell>
|
||||
|
||||
@@ -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`<uui-loader></uui-loader>`;
|
||||
return html`<umb-collection alias="Umb.Collection.Document" .config=${this._config}></umb-collection>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,14 +28,8 @@ export class UmbDocumentCollectionToolbarElement extends UmbLitElement {
|
||||
render() {
|
||||
return html`
|
||||
<umb-collection-action-bundle></umb-collection-action-bundle>
|
||||
${this.#renderSearch()}
|
||||
<umb-collection-view-bundle></umb-collection-view-bundle>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderSearch() {
|
||||
return html`
|
||||
<uui-input @input=${this.#updateSearch} label="Search" placeholder="Search..." id="input-search"></uui-input>
|
||||
<umb-collection-view-bundle></umb-collection-view-bundle>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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<UmbDocumentTreeItemModel> {
|
||||
export class UmbDocumentCollectionServerDataSource implements UmbCollectionDataSource<UmbDocumentCollectionItemModel> {
|
||||
#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,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 }>;
|
||||
}
|
||||
|
||||
@@ -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<UmbDocumentTreeItemModel> = [];
|
||||
private _items: Array<UmbDocumentCollectionItemModel> = [];
|
||||
|
||||
@state()
|
||||
private _selection: Array<string | null> = [];
|
||||
@@ -17,7 +16,7 @@ export class UmbDocumentGridCollectionViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _loading = false;
|
||||
|
||||
#collectionContext?: UmbDefaultCollectionContext<UmbDocumentTreeItemModel, UmbDocumentCollectionFilterModel>;
|
||||
#collectionContext?: UmbDefaultCollectionContext<UmbDocumentCollectionItemModel, UmbDocumentCollectionFilterModel>;
|
||||
|
||||
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`
|
||||
<uui-card-content-node
|
||||
.name=${item.name ?? 'Unnamed Document'}
|
||||
@@ -70,7 +69,7 @@ export class UmbDocumentGridCollectionViewElement extends UmbLitElement {
|
||||
@open=${() => this._handleOpenCard(item.unique ?? '')}
|
||||
@selected=${() => this.#onSelect(item)}
|
||||
@deselected=${() => this.#onDeselect(item)}>
|
||||
<uui-icon slot="icon" name=${item.documentType.icon}></uui-icon>
|
||||
<uui-icon slot="icon" name=${item.icon}></uui-icon>
|
||||
</uui-card-content-node>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
@@ -18,7 +17,13 @@ import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collec
|
||||
@customElement('umb-document-table-collection-view')
|
||||
export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _items?: Array<UmbDocumentTreeItemModel>;
|
||||
private _busy = false;
|
||||
|
||||
@state()
|
||||
private _userDefinedProperties?: Array<any>;
|
||||
|
||||
@state()
|
||||
private _items?: Array<UmbDocumentCollectionItemModel>;
|
||||
|
||||
@state()
|
||||
private _tableConfig: UmbTableConfig = {
|
||||
@@ -26,7 +31,9 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
|
||||
};
|
||||
|
||||
@state()
|
||||
private _tableColumns: Array<UmbTableColumn> = [
|
||||
private _tableColumns: Array<UmbTableColumn> = [];
|
||||
|
||||
#systemColumns: Array<UmbTableColumn> = [
|
||||
{
|
||||
name: 'Name',
|
||||
alias: 'entityName',
|
||||
@@ -40,7 +47,10 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _selection: Array<string> = [];
|
||||
|
||||
private _collectionContext?: UmbDefaultCollectionContext<UmbDocumentTreeItemModel, UmbDocumentCollectionFilterModel>;
|
||||
private _collectionContext?: UmbDefaultCollectionContext<
|
||||
UmbDocumentCollectionItemModel,
|
||||
UmbDocumentCollectionFilterModel
|
||||
>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -53,9 +63,14 @@ 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);
|
||||
this.#createTableItems(this._items);
|
||||
});
|
||||
|
||||
this.observe(this._collectionContext.selection.selection, (selection) => {
|
||||
@@ -63,24 +78,55 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _createTableItems(items: Array<UmbDocumentTreeItemModel>) {
|
||||
#createTableHeadings() {
|
||||
if (this._userDefinedProperties && this._userDefinedProperties.length > 0) {
|
||||
const userColumns: Array<UmbTableColumn> = this._userDefinedProperties.map((item) => {
|
||||
return {
|
||||
name: item.header,
|
||||
alias: item.alias,
|
||||
elementName: item.elementName,
|
||||
allowSorting: true,
|
||||
};
|
||||
});
|
||||
|
||||
this._tableColumns = [...this.#systemColumns, ...userColumns];
|
||||
}
|
||||
}
|
||||
|
||||
#createTableItems(items: Array<UmbDocumentCollectionItemModel>) {
|
||||
// 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,
|
||||
icon: item.documentType.icon,
|
||||
data: [
|
||||
{
|
||||
columnAlias: 'entityName',
|
||||
value: item.name || 'Unnamed Document',
|
||||
},
|
||||
// {
|
||||
// columnAlias: 'entityActions',
|
||||
// value: {
|
||||
// entityType: item.entityType,
|
||||
// },
|
||||
// },
|
||||
],
|
||||
icon: item.icon,
|
||||
data: data,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -103,10 +149,18 @@ 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() {
|
||||
if (this._busy) return html`<div class="container"><uui-loader></uui-loader></div>`;
|
||||
|
||||
if (this._tableItems.length === 0)
|
||||
return html`<div class="container"><p>${this.localize.term('content_listViewNoItems')}</p></div>`;
|
||||
|
||||
return html`
|
||||
<umb-table
|
||||
.config=${this._tableConfig}
|
||||
@@ -134,6 +188,12 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
|
||||
umb-table {
|
||||
padding: 0; /* To fix the embedded padding in the table component. */
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface UmbDocumentItemModel {
|
||||
documentType: {
|
||||
unique: string;
|
||||
icon: string;
|
||||
hasListView: boolean;
|
||||
hasCollection: boolean;
|
||||
};
|
||||
variants: Array<UmbDocumentItemVariantModel>;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,32 +44,33 @@ 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',
|
||||
'_observeConfigDataType',
|
||||
);
|
||||
}
|
||||
},
|
||||
'#observeConfig.documentType',
|
||||
'_observeConfigDocumentType',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#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<UmbCollectionBulkActionPermissions>('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`<uui-loader></uui-loader>`;
|
||||
return html`<umb-collection alias="Umb.Collection.Document" .config=${this._config}></umb-collection>`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user