Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4001fd8
Add editorAlias to values available in collection view.
AndyButland Nov 5, 2025
e8c2b44
Add property value presentation for collection views of color, date o…
AndyButland Nov 5, 2025
e76564b
Apply to card view.
AndyButland Nov 6, 2025
7f742fc
Renamed enum to match expected convention.
AndyButland Nov 6, 2025
afaef0a
Further linting.
AndyButland Nov 6, 2025
dcef7d4
Apply for other date pickers, amend sizing of color swatch.
AndyButland Nov 6, 2025
efa3c22
Code re-use.
AndyButland Nov 7, 2025
0774248
Merge branch 'main' into v17/feature/collection-view-property-display
AndyButland Nov 7, 2025
05e4ac9
Attempt to improve performance by getting all extension of types once…
AndyButland Nov 7, 2025
3f9ff17
Linting.
AndyButland Nov 7, 2025
89b37f6
Linting.
AndyButland Nov 7, 2025
9d03e33
Linting + adjustments
leekelleher Nov 10, 2025
f2e2c44
Linting + refinements
leekelleher Nov 10, 2025
55a807d
Added importmap for "@umbraco-cms/backoffice/property-value-presentat…
leekelleher Nov 11, 2025
6653c3c
Removed "alias" and "display" from `UmbPropertyValuePresentationBaseE…
leekelleher Nov 11, 2025
808dcaf
Refactored `propertyValuePresentation` extension elements
leekelleher Nov 11, 2025
d9208fd
Renamed `propertyEditorAlias` to `forPropertyEditorSchemaAlias`
leekelleher Nov 11, 2025
4f347a4
Extracted out the system values to "umb-document-table-column-system-…
leekelleher Nov 11, 2025
3b3d3cb
Refactored "umb-document-table-column-property-value" to focus on use…
leekelleher Nov 11, 2025
3eb3670
Refactored "umb-document-grid-collection-card" to remove markup from …
leekelleher Nov 11, 2025
2da794b
Removed `getPropertyValueByAlias` from `UmbDocumentCollectionContext`
leekelleher Nov 11, 2025
0e6691b
Aligned media collection code
leekelleher Nov 11, 2025
05b0d71
Removed unused imports
leekelleher Nov 11, 2025
fd2abf7
Corrected class name (bad code copy)
leekelleher Nov 11, 2025
6f44a72
Merge branch 'main' into v17/feature/collection-view-property-display
AndyButland Nov 12, 2025
ab92e2c
Introduced `UmbDocumentCollectionItemDataResolver` to de-duplicate th…
leekelleher Nov 12, 2025
73c540c
Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/col…
leekelleher Nov 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Umbraco.Web.UI.Client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"./property-action": "./dist-cms/packages/core/property-action/index.js",
"./property-editor-data-source": "./dist-cms/packages/core/property-editor-data-source/index.js",
"./property-editor": "./dist-cms/packages/core/property-editor/index.js",
"./property-value-presentation": "./dist-cms/packages/core/property-value-presentation/index.js",
"./property-type": "./dist-cms/packages/content/property-type/index.js",
"./property": "./dist-cms/packages/core/property/index.js",
"./recycle-bin": "./dist-cms/packages/core/recycle-bin/index.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { UmbPropertyValuePresentationBaseElement } from './property-value-presentation-base.element.js';
export type * from './types.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';

export abstract class UmbPropertyValuePresentationBaseElement<TValue = string> extends UmbLitElement {
@property({ type: Object })
value?: TValue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { ManifestElement } from '@umbraco-cms/backoffice/extension-api';

export interface ManifestPropertyValuePresentation extends ManifestElement {
type: 'propertyValuePresentation';
forPropertyEditorSchemaAlias: string | Array<string>;
}

declare global {
interface UmbExtensionManifestMap {
umbPropertyValuePresentation: ManifestPropertyValuePresentation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { ManifestPropertyValuePresentation } from './property-value-presentation.extension.js';
1 change: 1 addition & 0 deletions src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default defineConfig({
'property-action/index': './property-action/index.ts',
'property-editor-data-source/index': './property-editor-data-source/index.ts',
'property-editor/index': './property-editor/index.ts',
'property-value-presentation/index': './property-value-presentation/index.ts',
'property/index': './property/index.ts',
'recycle-bin/index': './recycle-bin/index.ts',
'repository/index': './repository/index.ts',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { UmbDocumentItemDataResolver } from '../item/document-item-data-resolver.js';
import type { UmbDocumentCollectionItemModel, UmbDocumentCollectionItemPropertyValueModel } from './types.js';
import { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbItemDataResolver } from '@umbraco-cms/backoffice/entity-item';

export class UmbDocumentCollectionItemDataResolver
extends UmbDocumentItemDataResolver<UmbDocumentCollectionItemModel>
implements UmbItemDataResolver
{
getPropertyByAlias(alias: string): UmbDocumentCollectionItemPropertyValueModel | undefined {
const item = this.getData();
const culture = this.getCulture();
const prop = item?.values.find((x) => x.alias === alias && (!x.culture || x.culture === culture));
return prop;
}

getSystemValue(alias: string): string | number | null | undefined {
const item = this.getData();
switch (alias) {
case 'contentTypeAlias':
return item?.documentType.alias;

case 'createDate': {
const variant = this._getCurrentVariant();
return variant?.createDate?.toLocaleString();
}

case 'creator':
case 'owner':
return item?.creator;

case 'published': {
const variant = this._getCurrentVariant();
return variant?.state !== DocumentVariantStateModel.DRAFT ? 'True' : 'False';
}

case 'sortOrder':
return item?.sortOrder;

case 'updateDate': {
const variant = this._getCurrentVariant();
return variant?.updateDate?.toLocaleString();
}
case 'updater':
return item?.updater;

default:
return null;
}
}

Check warning on line 50 in src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/document-collection-item-data-resolver.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ New issue: Complex Method

UmbDocumentCollectionItemDataResolver.getSystemValue has a cyclomatic complexity of 19, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from './types.js';
import { UMB_DOCUMENT_TABLE_COLLECTION_VIEW_ALIAS } from './constants.js';
import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from './types.js';
import { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UMB_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/variant';
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';
import { UmbDeprecation } from '@umbraco-cms/backoffice/utils';
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';
import { UMB_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/variant';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

export class UmbDocumentCollectionContext extends UmbDefaultCollectionContext<
UmbDocumentCollectionItemModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class UmbDocumentCollectionServerDataSource implements UmbCollectionDataS
flags: item.flags,
values: item.values.map((item) => {
return {
editorAlias: item.editorAlias,
alias: item.alias,
culture: item.culture ?? undefined,
segment: item.segment ?? undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,18 @@ export interface UmbDocumentCollectionItemModel extends UmbEntityWithFlags {
sortOrder: number;
unique: string;
updater?: string | null;
values: Array<{ alias: string; culture?: string; segment?: string; value: string }>;
values: Array<UmbDocumentCollectionItemPropertyValueModel>;
variants: Array<UmbDocumentItemVariantModel>;
}

export interface UmbDocumentCollectionItemPropertyValueModel {
alias: string;
editorAlias: string;
culture?: string;
segment?: string;
value: string;
}

export interface UmbEditableDocumentCollectionItemModel {
item: UmbDocumentCollectionItemModel;
editPath: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import { UmbDocumentItemDataResolver } from '../../../item/document-item-data-resolver.js';
import { UmbDocumentCollectionItemDataResolver } from '../../document-collection-item-data-resolver.js';
import type { UmbDocumentCollectionItemModel } from '../../types.js';
import { css, customElement, html, property, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
import { fromCamelCase } from '@umbraco-cms/backoffice/utils';
import { css, customElement, html, nothing, property, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
import { fromCamelCase, stringOrStringArrayContains } from '@umbraco-cms/backoffice/utils';
import { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
import { UUICardContentNodeElement } from '@umbraco-cms/backoffice/external/uui';
import type { ManifestPropertyValuePresentation } from '@umbraco-cms/backoffice/property-value-presentation';
import type { UmbCollectionColumnConfiguration } from '@umbraco-cms/backoffice/collection';
import type { UUIInterfaceColor } from '@umbraco-cms/backoffice/external/uui';

@customElement('umb-document-grid-collection-card')
export class UmbDocumentGridCollectionCardElement extends UmbElementMixin(UUICardContentNodeElement) {
#resolver = new UmbDocumentItemDataResolver(this);

@state()
private _createDate?: Date;
#resolver = new UmbDocumentCollectionItemDataResolver(this);

@state()
private _state?: string;

@state()
private _updateDate?: Date;

@property({ attribute: false })
columns?: Array<UmbCollectionColumnConfiguration>;

Expand All @@ -40,38 +35,7 @@
super();

this.#resolver.observe(this.#resolver.name, (name) => (this.name = name || ''));
this.#resolver.observe(this.#resolver.state, (state) => (this._state = state || ''));

Check notice on line 38 in src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-card.element.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ No longer an issue: Complex Method

UmbDocumentGridCollectionCardElement.getPropertyValueByAlias is no longer above the threshold for cyclomatic complexity
this.#resolver.observe(this.#resolver.createDate, (createDate) => (this._createDate = createDate));
this.#resolver.observe(this.#resolver.updateDate, (updateDate) => (this._updateDate = updateDate));
}

#getPropertyValueByAlias(alias: string) {
switch (alias) {
case 'contentTypeAlias':
return this.item.documentType.alias;
case 'createDate':
return this._createDate?.toLocaleString();
case 'creator':
case 'owner':
return this.item.creator;
case 'name':
return this.name;
case 'state':
return this._state ? fromCamelCase(this._state) : '';
case 'published':
return this._state !== DocumentVariantStateModel.DRAFT ? 'True' : 'False';
case 'sortOrder':
return this.item.sortOrder;
case 'updateDate':
return this._updateDate?.toLocaleString();
case 'updater':
return this.item.updater;
default: {
const culture = this.#resolver.getCulture();
const prop = this.item.values.find((x) => x.alias === alias && (!x.culture || x.culture === culture));
return prop?.value ?? '';
}
}
}

#getStateTagConfig(): { color: UUIInterfaceColor; label: string } | undefined {
Expand Down Expand Up @@ -121,14 +85,37 @@
}

#renderProperty(column: UmbCollectionColumnConfiguration) {
const value = this.#getPropertyValueByAlias(column.alias);
let value: string | number | null | undefined;
let editorAlias: string | null | undefined;

if (column.isSystem) {
value = this.#resolver.getSystemValue(column.alias);
} else {
const prop = this.#resolver.getPropertyByAlias(column.alias);
editorAlias = prop?.editorAlias;
value = prop?.value;
}

return html`
<li>
<span>${this.localize.string(column.header)}:</span>
${when(
column.nameTemplate,
() => html`<umb-ufm-render inline .markdown=${column.nameTemplate} .value=${{ value }}></umb-ufm-render>`,
() => html`${value}`,
() =>
when(
editorAlias,
(schemaAlias) => html`
<umb-extension-slot
type="propertyValuePresentation"
.filter=${(m: ManifestPropertyValuePresentation) =>
stringOrStringArrayContains(m.forPropertyEditorSchemaAlias, schemaAlias)}
.props=${{ value }}>
${value ?? nothing}
</umb-extension-slot>
`,
() => (value ? html`${value}` : nothing),
),
)}
</li>
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { UMB_EDIT_DOCUMENT_WORKSPACE_PATH_PATTERN } from '../../../paths.js';
import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from '../../types.js';
import { css, customElement, html, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbDefaultCollectionContext, UmbCollectionColumnConfiguration } from '@umbraco-cms/backoffice/collection';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbDefaultCollectionContext, UmbCollectionColumnConfiguration } from '@umbraco-cms/backoffice/collection';

import '@umbraco-cms/backoffice/ufm';
import './document-grid-collection-card.element.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import { UmbDocumentCollectionItemDataResolver } from '../../../document-collection-item-data-resolver.js';
import type { UmbEditableDocumentCollectionItemModel } from '../../../types.js';
import { UmbDocumentItemDataResolver } from '../../../../item/index.js';
import { customElement, html, nothing, property, state, when } from '@umbraco-cms/backoffice/external/lit';
import { customElement, html, nothing, property, when } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbTableColumn, UmbTableColumnLayoutElement, UmbTableItem } from '@umbraco-cms/backoffice/components';
import { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { ManifestPropertyValuePresentation } from '@umbraco-cms/backoffice/property-value-presentation';
import { stringOrStringArrayContains } from '@umbraco-cms/backoffice/utils';

@customElement('umb-document-table-column-property-value')
export class UmbDocumentTableColumnPropertyValueElement extends UmbLitElement implements UmbTableColumnLayoutElement {
#resolver = new UmbDocumentItemDataResolver(this);

@state()
private _createDate?: Date;

@state()
private _state?: string;

@state()
private _updateDate?: Date;
#resolver = new UmbDocumentCollectionItemDataResolver(this);

column!: UmbTableColumn;
item!: UmbTableItem;
Expand All @@ -34,48 +26,27 @@
}
#value!: UmbEditableDocumentCollectionItemModel;

constructor() {
super();

this.#resolver.observe(this.#resolver.state, (state) => (this._state = state || ''));
this.#resolver.observe(this.#resolver.createDate, (createDate) => (this._createDate = createDate));
this.#resolver.observe(this.#resolver.updateDate, (updateDate) => (this._updateDate = updateDate));
}
override render() {
if (!this.value?.item) return nothing;
const prop = this.#resolver.getPropertyByAlias(this.column.alias);
const props = { value: prop?.value ?? '' };

#getPropertyValueByAlias() {
const alias = this.column.alias;
const item = this.value.item;
switch (alias) {
case 'contentTypeAlias':
return item.documentType.alias;
case 'createDate':
return this._createDate?.toLocaleString();
case 'creator':
case 'owner':
return item.creator;
case 'published':
return this._state !== DocumentVariantStateModel.DRAFT ? 'True' : 'False';
case 'sortOrder':
return item.sortOrder;
case 'updateDate':
return this._updateDate?.toLocaleString();
case 'updater':
return item.updater;
default: {
const culture = this.#resolver.getCulture();
const prop = item.values.find((x) => x.alias === alias && (!x.culture || x.culture === culture));
return prop?.value ?? '';
}
if (this.column.labelTemplate) {
return html`<umb-ufm-render inline .markdown=${this.column.labelTemplate} .value=${props}></umb-ufm-render>`;
}

Check notice on line 36 in src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/column-layouts/document-table-column-property-value.element.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ No longer an issue: Complex Method

UmbDocumentTableColumnPropertyValueElement.getPropertyValueByAlias is no longer above the threshold for cyclomatic complexity
}

override render() {
if (!this.value) return nothing;
const value = this.#getPropertyValueByAlias();
return when(
this.column.labelTemplate,
() => html`<umb-ufm-render inline .markdown=${this.column.labelTemplate} .value=${{ value }}></umb-ufm-render>`,
() => html`${value}`,
prop?.editorAlias,
(schemaAlias) => html`
<umb-extension-slot
type="propertyValuePresentation"
.filter=${(m: ManifestPropertyValuePresentation) =>
stringOrStringArrayContains(m.forPropertyEditorSchemaAlias, schemaAlias)}
.props=${props}>
${prop?.value ?? nothing}
</umb-extension-slot>
`,
() => (prop?.value ? html`${prop.value}` : nothing),
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { UmbDocumentCollectionItemDataResolver } from '../../../document-collection-item-data-resolver.js';
import type { UmbEditableDocumentCollectionItemModel } from '../../../types.js';
import { customElement, html, nothing, property, when } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbTableColumn, UmbTableColumnLayoutElement, UmbTableItem } from '@umbraco-cms/backoffice/components';

@customElement('umb-document-table-column-system-value')
export class UmbDocumentTableColumnSystemValueElement extends UmbLitElement implements UmbTableColumnLayoutElement {
#resolver = new UmbDocumentCollectionItemDataResolver(this);

column!: UmbTableColumn;
item!: UmbTableItem;

@property({ attribute: false })
public set value(value: UmbEditableDocumentCollectionItemModel) {
this.#value = value;
if (value.item) {
this.#resolver.setData(value.item);
}
}
public get value(): UmbEditableDocumentCollectionItemModel {
return this.#value;
}
#value!: UmbEditableDocumentCollectionItemModel;

override render() {
if (!this.value) return nothing;
const value = this.#resolver.getSystemValue(this.column.alias);
return when(
this.column.labelTemplate,
() => html`<umb-ufm-render inline .markdown=${this.column.labelTemplate} .value=${{ value }}></umb-ufm-render>`,
() => html`${value}`,
);
}
}

export default UmbDocumentTableColumnSystemValueElement;

declare global {
interface HTMLElementTagNameMap {
'umb-document-table-column-system-value': UmbDocumentTableColumnSystemValueElement;
}
}
Loading
Loading