Merge remote-tracking branch 'origin/main' into bugfix/collection-context-loading
This commit is contained in:
@@ -8,6 +8,7 @@ import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registr
|
||||
import type { ManifestSection } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbExtensionManifestInitializer } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
export class UmbBackofficeContext extends UmbContextBase<UmbBackofficeContext> {
|
||||
#activeSectionAlias = new UmbStringState(undefined);
|
||||
@@ -26,7 +27,13 @@ export class UmbBackofficeContext extends UmbContextBase<UmbBackofficeContext> {
|
||||
this.#allowedSections.setValue([...sections]);
|
||||
});
|
||||
|
||||
this.#getVersion();
|
||||
// TODO: We need to ensure this request is called every time the user logs in, but this should be done somewhere across the app and not here [JOV]
|
||||
this.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
|
||||
this.observe(authContext.isAuthorized, (isAuthorized) => {
|
||||
if (!isAuthorized) return;
|
||||
this.#getVersion();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async #getVersion() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbServerExtensionRegistrator } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
import './components/index.js';
|
||||
|
||||
@@ -58,7 +59,15 @@ export class UmbBackofficeElement extends UmbLitElement {
|
||||
umbExtensionsRegistry.registerMany(packageModule.extensions);
|
||||
});
|
||||
|
||||
new UmbServerExtensionRegistrator(this, umbExtensionsRegistry).registerPrivateExtensions();
|
||||
const serverExtensions = new UmbServerExtensionRegistrator(this, umbExtensionsRegistry);
|
||||
|
||||
// TODO: We need to ensure this request is called every time the user logs in, but this should be done somewhere across the app and not here [JOV]
|
||||
this.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
|
||||
this.observe(authContext.isAuthorized, (isAuthorized) => {
|
||||
if (!isAuthorized) return;
|
||||
serverExtensions.registerPrivateExtensions();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -988,7 +988,7 @@ export const data: Array<UmbMockDataTypeModel> = [
|
||||
id: 'dt-integer',
|
||||
parent: null,
|
||||
editorAlias: 'Umbraco.Integer',
|
||||
editorUiAlias: 'Umb.PropertyEditorUi.Integer',
|
||||
editorUiAlias: 'Umb.PropertyEditorUi.Number',
|
||||
hasChildren: false,
|
||||
isFolder: false,
|
||||
isDeletable: true,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { UUIColorSwatchesEvent, UUIIconElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
import { css, html, customElement, state, repeat, query, nothing } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
@@ -64,12 +64,9 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
|
||||
}
|
||||
}
|
||||
|
||||
#changeIcon(e: InputEvent | KeyboardEvent) {
|
||||
#changeIcon(e: InputEvent | KeyboardEvent, iconName: string) {
|
||||
if (e.type == 'click' || (e.type == 'keyup' && (e as KeyboardEvent).key == 'Enter')) {
|
||||
const iconName = (e.target as UUIIconElement).name;
|
||||
if (iconName) {
|
||||
this.modalContext?.updateValue({ icon: iconName });
|
||||
}
|
||||
this.modalContext?.updateValue({ icon: iconName });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,8 +139,8 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
|
||||
label="${icon.name}"
|
||||
title="${icon.name}"
|
||||
class="${icon.name === this._currentIcon ? 'selected' : ''}"
|
||||
@click="${this.#changeIcon}"
|
||||
@keyup="${this.#changeIcon}">
|
||||
@click=${(e: InputEvent) => this.#changeIcon(e, icon.name)}
|
||||
@keyup=${(e: KeyboardEvent) => this.#changeIcon(e, icon.name)}>
|
||||
<uui-icon
|
||||
style="--uui-icon-color: var(${extractUmbColorVariable(this._currentColor)})"
|
||||
name="${icon.name}">
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
// TODO: Make a store for the App Languages.
|
||||
// TODO: Implement default language end-point, in progress at backend team, so we can avoid getting all languages.
|
||||
@@ -28,7 +29,14 @@ export class UmbAppLanguageContext extends UmbContextBase<UmbAppLanguageContext>
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host, UMB_APP_LANGUAGE_CONTEXT);
|
||||
this.#languageCollectionRepository = new UmbLanguageCollectionRepository(this);
|
||||
this.#observeLanguages();
|
||||
|
||||
// TODO: We need to ensure this request is called every time the user logs in, but this should be done somewhere across the app and not here [JOV]
|
||||
this.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
|
||||
this.observe(authContext.isAuthorized, (isAuthorized) => {
|
||||
if (!isAuthorized) return;
|
||||
this.#observeLanguages();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setLanguage(unique: string) {
|
||||
|
||||
@@ -32,12 +32,15 @@ export class UmbMediaCollectionServerDataSource implements UmbCollectionDataSour
|
||||
|
||||
const model: UmbMediaCollectionItemModel = {
|
||||
unique: item.id,
|
||||
entityType: 'media',
|
||||
contentTypeAlias: item.mediaType.alias,
|
||||
createDate: new Date(variant.createDate),
|
||||
creator: item.creator,
|
||||
icon: item.mediaType.icon,
|
||||
name: variant.name,
|
||||
sortOrder: item.sortOrder,
|
||||
updateDate: new Date(variant.updateDate),
|
||||
updater: item.creator, // TODO: Check if the `updater` is available for media items. [LK]
|
||||
values: item.values.map((item) => {
|
||||
return { alias: item.alias, value: item.value as string };
|
||||
}),
|
||||
|
||||
@@ -10,11 +10,20 @@ export interface UmbMediaCollectionFilterModel extends UmbCollectionFilterModel
|
||||
|
||||
export interface UmbMediaCollectionItemModel {
|
||||
unique: string;
|
||||
entityType: string;
|
||||
contentTypeAlias: string;
|
||||
createDate: Date;
|
||||
creator?: string | null;
|
||||
icon: string;
|
||||
name: string;
|
||||
sortOrder: number;
|
||||
updateDate: Date;
|
||||
updater?: string | null;
|
||||
values: Array<{ alias: string; value: string }>;
|
||||
}
|
||||
|
||||
export interface UmbEditableMediaCollectionItemModel {
|
||||
item: UmbMediaCollectionItemModel;
|
||||
editPath: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import type { UmbMediaCollectionFilterModel, UmbMediaCollectionItemModel } from '../../types.js';
|
||||
import { css, html, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UMB_EDIT_MEDIA_WORKSPACE_PATH_PATTERN } from '../../../paths.js';
|
||||
import type { UmbMediaCollectionItemModel } from '../../types.js';
|
||||
import type { UmbMediaCollectionContext } from '../../media-collection.context.js';
|
||||
import { css, customElement, html, nothing, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
|
||||
import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
|
||||
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
@customElement('umb-media-grid-collection-view')
|
||||
export class UmbMediaGridCollectionViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _editMediaPath = '';
|
||||
|
||||
@state()
|
||||
private _items: Array<UmbMediaCollectionItemModel> = [];
|
||||
|
||||
@@ -16,7 +21,7 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _selection: Array<string | null> = [];
|
||||
|
||||
#collectionContext?: UmbDefaultCollectionContext<UmbMediaCollectionItemModel, UmbMediaCollectionFilterModel>;
|
||||
#collectionContext?: UmbMediaCollectionContext;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -24,23 +29,43 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
|
||||
this.#collectionContext = collectionContext;
|
||||
this.#observeCollectionContext();
|
||||
});
|
||||
|
||||
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
|
||||
.addAdditionalPath('media')
|
||||
.onSetup(() => {
|
||||
return { data: { entityType: 'media', preset: {} } };
|
||||
})
|
||||
.onReject(() => {
|
||||
this.#collectionContext?.requestCollection();
|
||||
})
|
||||
.onSubmit(() => {
|
||||
this.#collectionContext?.requestCollection();
|
||||
})
|
||||
.observeRouteBuilder((routeBuilder) => {
|
||||
this._editMediaPath = routeBuilder({});
|
||||
});
|
||||
}
|
||||
|
||||
#observeCollectionContext() {
|
||||
if (!this.#collectionContext) return;
|
||||
|
||||
this.observe(this.#collectionContext.items, (items) => (this._items = items), 'umbCollectionItemsObserver');
|
||||
this.observe(this.#collectionContext.loading, (loading) => (this._loading = loading), '_observeLoading');
|
||||
|
||||
this.observe(this.#collectionContext.items, (items) => (this._items = items), '_observeItems');
|
||||
|
||||
this.observe(
|
||||
this.#collectionContext.selection.selection,
|
||||
(selection) => (this._selection = selection),
|
||||
'umbCollectionSelectionObserver',
|
||||
'_observeSelection',
|
||||
);
|
||||
}
|
||||
|
||||
#onOpen(item: UmbMediaCollectionItemModel) {
|
||||
//TODO: Fix when we have dynamic routing
|
||||
history.pushState(null, '', 'section/media/workspace/media/edit/' + item.unique);
|
||||
#onOpen(event: Event, unique: string) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const url = this._editMediaPath + UMB_EDIT_MEDIA_WORKSPACE_PATH_PATTERN.generateLocal({ unique });
|
||||
window.history.pushState(null, '', url);
|
||||
}
|
||||
|
||||
#onSelect(item: UmbMediaCollectionItemModel) {
|
||||
@@ -60,26 +85,37 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this._loading) {
|
||||
return html`<div class="container"><uui-loader></uui-loader></div>`;
|
||||
}
|
||||
|
||||
if (this._items.length === 0) {
|
||||
return html`<div class="container"><p>${this.localize.term('content_listViewNoItems')}</p></div>`;
|
||||
}
|
||||
return this._items.length === 0 ? this.#renderEmpty() : this.#renderItems();
|
||||
}
|
||||
|
||||
#renderEmpty() {
|
||||
if (this._items.length > 0) return nothing;
|
||||
return html`
|
||||
<div id="media-grid">
|
||||
${repeat(
|
||||
this._items,
|
||||
(item) => item.unique,
|
||||
(item) => this.#renderCard(item),
|
||||
<div class="container">
|
||||
${when(
|
||||
this._loading,
|
||||
() => html`<uui-loader></uui-loader>`,
|
||||
() => html`<p>${this.localize.term('content_listViewNoItems')}</p>`,
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderCard(item: UmbMediaCollectionItemModel) {
|
||||
#renderItems() {
|
||||
if (this._items.length === 0) return nothing;
|
||||
return html`
|
||||
<div id="media-grid">
|
||||
${repeat(
|
||||
this._items,
|
||||
(item) => item.unique,
|
||||
(item) => this.#renderItem(item),
|
||||
)}
|
||||
</div>
|
||||
${when(this._loading, () => html`<uui-loader-bar></uui-loader-bar>`)}
|
||||
`;
|
||||
}
|
||||
|
||||
#renderItem(item: UmbMediaCollectionItemModel) {
|
||||
// TODO: Fix the file extension when media items have a file extension. [?]
|
||||
return html`
|
||||
<uui-card-media
|
||||
@@ -87,7 +123,7 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
|
||||
selectable
|
||||
?select-only=${this._selection && this._selection.length > 0}
|
||||
?selected=${this.#isSelected(item)}
|
||||
@open=${() => this.#onOpen(item)}
|
||||
@open=${(event: Event) => this.#onOpen(event, item.unique)}
|
||||
@selected=${() => this.#onSelect(item)}
|
||||
@deselected=${() => this.#onDeselect(item)}
|
||||
class="media-item"
|
||||
|
||||
@@ -1,50 +1,32 @@
|
||||
import type { UmbMediaCollectionItemModel } from '../../../types.js';
|
||||
import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbEditableMediaCollectionItemModel } from '../../../types.js';
|
||||
import { css, customElement, html, nothing, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||
import type { UmbTableColumn, UmbTableColumnLayoutElement, UmbTableItem } from '@umbraco-cms/backoffice/components';
|
||||
import type { UUIButtonElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
@customElement('umb-media-table-column-name')
|
||||
export class UmbMediaTableColumnNameElement extends UmbLitElement implements UmbTableColumnLayoutElement {
|
||||
@state()
|
||||
private _editMediaPath = '';
|
||||
|
||||
@property({ type: Object, attribute: false })
|
||||
column!: UmbTableColumn;
|
||||
|
||||
@property({ type: Object, attribute: false })
|
||||
item!: UmbTableItem;
|
||||
|
||||
@property({ attribute: false })
|
||||
value!: UmbMediaCollectionItemModel;
|
||||
value!: UmbEditableMediaCollectionItemModel;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
|
||||
.addAdditionalPath('media')
|
||||
.onSetup(() => {
|
||||
return { data: { entityType: 'media', preset: {} } };
|
||||
})
|
||||
.observeRouteBuilder((routeBuilder) => {
|
||||
this._editMediaPath = routeBuilder({});
|
||||
});
|
||||
}
|
||||
|
||||
#onClick(event: Event) {
|
||||
// TODO: [LK] Review the `stopPropagation` usage, as it causes a page reload.
|
||||
// But we still need a say to prevent the `umb-table` from triggering a selection event.
|
||||
#onClick(event: Event & { target: UUIButtonElement }) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
window.history.pushState(null, '', event.target.href);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<uui-button
|
||||
look="default"
|
||||
color="default"
|
||||
compact
|
||||
href="${this._editMediaPath}edit/${this.value.unique}"
|
||||
label="${this.value.name}"
|
||||
@click=${this.#onClick}></uui-button>`;
|
||||
if (!this.value) return nothing;
|
||||
return html`
|
||||
<uui-button
|
||||
compact
|
||||
href=${this.value.editPath}
|
||||
label=${this.value.item.name}
|
||||
@click=${this.#onClick}></uui-button>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { UMB_EDIT_MEDIA_WORKSPACE_PATH_PATTERN } from '../../../paths.js';
|
||||
import type { UmbCollectionColumnConfiguration } from '../../../../../core/collection/types.js';
|
||||
import type { UmbMediaCollectionFilterModel, UmbMediaCollectionItemModel } from '../../types.js';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, customElement, html, nothing, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
|
||||
@@ -14,6 +15,8 @@ import type {
|
||||
UmbTableOrderedEvent,
|
||||
UmbTableSelectedEvent,
|
||||
} from '@umbraco-cms/backoffice/components';
|
||||
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
|
||||
import type { UmbModalRouteBuilder } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
import './column-layouts/media-table-column-name.element.js';
|
||||
|
||||
@@ -51,29 +54,52 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
@state()
|
||||
private _selection: Array<string> = [];
|
||||
|
||||
@state()
|
||||
private _skip: number = 0;
|
||||
|
||||
#collectionContext?: UmbDefaultCollectionContext<UmbMediaCollectionItemModel, UmbMediaCollectionFilterModel>;
|
||||
|
||||
#routeBuilder?: UmbModalRouteBuilder;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_COLLECTION_CONTEXT, (collectionContext) => {
|
||||
this.#collectionContext = collectionContext;
|
||||
this.#observeCollectionContext();
|
||||
});
|
||||
|
||||
this.#registerModalRoute();
|
||||
}
|
||||
|
||||
#registerModalRoute() {
|
||||
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
|
||||
.addAdditionalPath(':entityType')
|
||||
.onSetup((params) => {
|
||||
return { data: { entityType: params.entityType, preset: {} } };
|
||||
})
|
||||
.onReject(() => {
|
||||
this.#collectionContext?.requestCollection();
|
||||
})
|
||||
.onSubmit(() => {
|
||||
this.#collectionContext?.requestCollection();
|
||||
})
|
||||
.observeRouteBuilder((routeBuilder) => {
|
||||
this.#routeBuilder = routeBuilder;
|
||||
|
||||
// NOTE: Configuring the observations AFTER the route builder is ready,
|
||||
// otherwise there is a race condition and `#collectionContext.items` tends to win. [LK]
|
||||
this.#observeCollectionContext();
|
||||
});
|
||||
}
|
||||
|
||||
#observeCollectionContext() {
|
||||
if (!this.#collectionContext) return;
|
||||
|
||||
this.observe(this.#collectionContext.loading, (loading) => (this._loading = loading), '_observeLoading');
|
||||
|
||||
this.observe(
|
||||
this.#collectionContext.userDefinedProperties,
|
||||
(userDefinedProperties) => {
|
||||
this._userDefinedProperties = userDefinedProperties;
|
||||
this.#createTableHeadings();
|
||||
},
|
||||
'umbCollectionUserDefinedPropertiesObserver',
|
||||
'_observeUserDefinedProperties',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
@@ -82,7 +108,7 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
this._items = items;
|
||||
this.#createTableItems(this._items);
|
||||
},
|
||||
'umbCollectionItemsObserver',
|
||||
'_observeItems',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
@@ -90,15 +116,7 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
(selection) => {
|
||||
this._selection = selection as string[];
|
||||
},
|
||||
'umbCollectionSelectionObserver',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
this.#collectionContext.pagination.skip,
|
||||
(skip) => {
|
||||
this._skip = skip;
|
||||
},
|
||||
'umbCollectionSkipObserver',
|
||||
'_observeSelection',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -129,15 +147,21 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
|
||||
const data =
|
||||
this._tableColumns?.map((column) => {
|
||||
const editPath = this.#routeBuilder
|
||||
? this.#routeBuilder({ entityType: item.entityType }) +
|
||||
UMB_EDIT_MEDIA_WORKSPACE_PATH_PATTERN.generateLocal({ unique: item.unique })
|
||||
: '';
|
||||
|
||||
return {
|
||||
columnAlias: column.alias,
|
||||
value: column.elementName ? item : this.#getPropertyValueByAlias(item, column.alias),
|
||||
value: column.elementName ? { item, editPath } : this.#getPropertyValueByAlias(item, column.alias),
|
||||
};
|
||||
}) ?? [];
|
||||
|
||||
return {
|
||||
id: item.unique,
|
||||
icon: item.icon,
|
||||
entityType: 'media',
|
||||
data: data,
|
||||
};
|
||||
});
|
||||
@@ -145,6 +169,8 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
|
||||
#getPropertyValueByAlias(item: UmbMediaCollectionItemModel, alias: string) {
|
||||
switch (alias) {
|
||||
case 'contentTypeAlias':
|
||||
return item.contentTypeAlias;
|
||||
case 'createDate':
|
||||
return item.createDate.toLocaleString();
|
||||
case 'name':
|
||||
@@ -156,6 +182,8 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
return item.sortOrder;
|
||||
case 'updateDate':
|
||||
return item.updateDate.toLocaleString();
|
||||
case 'updater':
|
||||
return item.updater;
|
||||
default:
|
||||
return item.values.find((value) => value.alias === alias)?.value ?? '';
|
||||
}
|
||||
@@ -186,23 +214,34 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this._loading) {
|
||||
return html`<div class="container"><uui-loader></uui-loader></div>`;
|
||||
}
|
||||
return this._tableItems.length === 0 ? this.#renderEmpty() : this.#renderItems();
|
||||
}
|
||||
|
||||
if (this._tableItems.length === 0) {
|
||||
return html`<div class="container"><p>${this.localize.term('content_listViewNoItems')}</p></div>`;
|
||||
}
|
||||
#renderEmpty() {
|
||||
if (this._tableItems.length > 0) return nothing;
|
||||
return html`
|
||||
<div class="container">
|
||||
${when(
|
||||
this._loading,
|
||||
() => html`<uui-loader></uui-loader>`,
|
||||
() => html`<p>${this.localize.term('content_listViewNoItems')}</p>`,
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderItems() {
|
||||
if (this._tableItems.length === 0) return nothing;
|
||||
return html`
|
||||
<umb-table
|
||||
.config=${this._tableConfig}
|
||||
.columns=${this._tableColumns}
|
||||
.items=${this._tableItems}
|
||||
.selection=${this._selection}
|
||||
@selected="${this.#handleSelect}"
|
||||
@deselected="${this.#handleDeselect}"
|
||||
@ordered="${this.#handleOrdering}"></umb-table>
|
||||
@selected=${this.#handleSelect}
|
||||
@deselected=${this.#handleDeselect}
|
||||
@ordered=${this.#handleOrdering}></umb-table>
|
||||
${when(this._loading, () => html`<uui-loader-bar></uui-loader-bar>`)}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ export * from './workspace/index.js';
|
||||
export * from './reference/index.js';
|
||||
export * from './components/index.js';
|
||||
export * from './entity.js';
|
||||
export * from './paths.js';
|
||||
export * from './utils/index.js';
|
||||
|
||||
export { UMB_MEDIA_TREE_ALIAS, UMB_MEDIA_TREE_PICKER_MODAL } from './tree/index.js';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { UmbPathPattern } from '@umbraco-cms/backoffice/router';
|
||||
|
||||
export const UMB_EDIT_MEDIA_WORKSPACE_PATH_PATTERN = new UmbPathPattern<{ unique: string }>('edit/:unique');
|
||||
@@ -1,34 +1,44 @@
|
||||
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
|
||||
import type { UmbCollectionColumnConfiguration } from '../../../../core/collection/types.js';
|
||||
import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
/**
|
||||
* @element umb-property-editor-ui-collection-order-by
|
||||
*/
|
||||
@customElement('umb-property-editor-ui-collection-order-by')
|
||||
export class UmbPropertyEditorUICollectionOrderByElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||
private _value = '';
|
||||
@property()
|
||||
public set value(v: string) {
|
||||
this._value = v;
|
||||
this._options = this._options.map((option) => (option.value === v ? { ...option, selected: true } : option));
|
||||
}
|
||||
public get value() {
|
||||
return this._value;
|
||||
}
|
||||
public value: string = '';
|
||||
|
||||
public config?: UmbPropertyEditorConfigCollection;
|
||||
|
||||
@state()
|
||||
_options: Array<Option> = [
|
||||
{ value: 'name', name: 'Name' },
|
||||
{ value: 'updateDate', name: 'Last edited' },
|
||||
{ value: 'owner', name: 'Created by' },
|
||||
];
|
||||
private _options: Array<Option> = [];
|
||||
|
||||
@property({ type: Object, attribute: false })
|
||||
public config?: UmbPropertyEditorConfigCollection;
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (instance) => {
|
||||
const workspace = instance;
|
||||
this.observe(
|
||||
await workspace.propertyValueByAlias<Array<UmbCollectionColumnConfiguration>>('includeProperties'),
|
||||
(includeProperties) => {
|
||||
if (!includeProperties) return;
|
||||
this._options = includeProperties.map((property) => ({
|
||||
name: property.header,
|
||||
value: property.alias,
|
||||
selected: property.alias === this.value,
|
||||
}));
|
||||
},
|
||||
'_observeIncludeProperties',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#onChange(e: UUISelectEvent) {
|
||||
this.value = e.target.value as string;
|
||||
@@ -36,6 +46,7 @@ export class UmbPropertyEditorUICollectionOrderByElement extends UmbLitElement i
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this._options.length) return html`<p><em>Add a column (above) to order by.</em></p>`;
|
||||
return html`<uui-select label="select" .options=${this._options} @change=${this.#onChange}></uui-select>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,6 @@ const propertyEditorUiManifest: ManifestPropertyEditorUi = {
|
||||
description: 'The properties that will be displayed for each column.',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Collection.LayoutConfiguration',
|
||||
},
|
||||
{
|
||||
alias: 'pageSize',
|
||||
label: 'Page Size',
|
||||
description: 'Number of items per page.',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Number',
|
||||
config: [{ alias: 'min', value: 0 }],
|
||||
},
|
||||
{
|
||||
alias: 'orderBy',
|
||||
label: 'Order By',
|
||||
@@ -41,6 +34,13 @@ const propertyEditorUiManifest: ManifestPropertyEditorUi = {
|
||||
label: 'Order Direction',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.OrderDirection',
|
||||
},
|
||||
{
|
||||
alias: 'pageSize',
|
||||
label: 'Page Size',
|
||||
description: 'Number of items per page.',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Number',
|
||||
config: [{ alias: 'min', value: 0 }],
|
||||
},
|
||||
{
|
||||
alias: 'bulkActionPermissions',
|
||||
label: 'Bulk Action Permissions',
|
||||
|
||||
@@ -6,7 +6,7 @@ export const manifests: Array<ManifestTypes> = [
|
||||
name: 'Integer',
|
||||
alias: 'Umbraco.Integer',
|
||||
meta: {
|
||||
defaultPropertyEditorUiAlias: 'Umb.PropertyEditorUi.Integer',
|
||||
defaultPropertyEditorUiAlias: 'Umb.PropertyEditorUi.Number',
|
||||
settings: {
|
||||
properties: [
|
||||
{
|
||||
|
||||
@@ -2,35 +2,7 @@ import { manifests as decimalSchemaManifests } from './Umbraco.Decimal.js';
|
||||
import { manifests as integerSchemaManifests } from './Umbraco.Integer.js';
|
||||
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
// TODO: we don't really want this config value to be changed from the UI. We need a way to handle hidden config properties.
|
||||
const allowDecimalsConfig = {
|
||||
alias: 'allowDecimals',
|
||||
label: 'Allow decimals',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Toggle',
|
||||
};
|
||||
|
||||
export const manifests: Array<ManifestTypes> = [
|
||||
{
|
||||
type: 'propertyEditorUi',
|
||||
alias: 'Umb.PropertyEditorUi.Integer',
|
||||
name: 'Integer Property Editor UI',
|
||||
element: () => import('./property-editor-ui-number.element.js'),
|
||||
meta: {
|
||||
label: 'Integer',
|
||||
propertyEditorSchemaAlias: 'Umbraco.Integer',
|
||||
icon: 'icon-autofill',
|
||||
group: 'common',
|
||||
settings: {
|
||||
properties: [allowDecimalsConfig],
|
||||
defaultData: [
|
||||
{
|
||||
alias: 'allowDecimals',
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'propertyEditorUi',
|
||||
alias: 'Umb.PropertyEditorUi.Decimal',
|
||||
@@ -42,12 +14,8 @@ export const manifests: Array<ManifestTypes> = [
|
||||
icon: 'icon-autofill',
|
||||
group: 'common',
|
||||
settings: {
|
||||
properties: [allowDecimalsConfig],
|
||||
properties: [],
|
||||
defaultData: [
|
||||
{
|
||||
alias: 'allowDecimals',
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
alias: 'step',
|
||||
value: '0.01',
|
||||
|
||||
Reference in New Issue
Block a user