Content/Document Picker: make not existing items appear as not found items (#20198)
make not existing items appear as not found items
This commit is contained in:
@@ -120,6 +120,12 @@ export class UmbEntityItemRefElement extends UmbLitElement {
|
||||
}
|
||||
}
|
||||
|
||||
@property({ type: Boolean })
|
||||
error?: boolean;
|
||||
|
||||
@property({ type: String, attribute: 'error-message', reflect: false })
|
||||
errorMessage?: string;
|
||||
|
||||
#pathAddendum = new UmbRoutePathAddendumContext(this);
|
||||
|
||||
#onSelected(event: UmbSelectedEvent) {
|
||||
@@ -155,6 +161,7 @@ export class UmbEntityItemRefElement extends UmbLitElement {
|
||||
this._component?.remove();
|
||||
const component = extensionControllers[0]?.component || document.createElement('umb-default-item-ref');
|
||||
|
||||
// TODO: I would say this code can use feature of the UmbExtensionsElementInitializer, to set properties and get a fallback element. [NL]
|
||||
// assign the properties to the component
|
||||
component.item = this.#item;
|
||||
component.readonly = this.readonly;
|
||||
@@ -182,7 +189,25 @@ export class UmbEntityItemRefElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`${this._component}`;
|
||||
if (this._component) {
|
||||
return html`${this._component}`;
|
||||
}
|
||||
// Error:
|
||||
if (this.error) {
|
||||
return html`<uui-ref-node
|
||||
style="color: var(--uui-color-danger);"
|
||||
.name=${this.localize.string(this.errorMessage ?? '#general_notFound')}
|
||||
.readonly=${this.readonly}
|
||||
.standalone=${this.standalone}
|
||||
.selectOnly=${this.selectOnly}
|
||||
.selected=${this.selected}
|
||||
.disabled=${this.disabled}>
|
||||
<uui-icon slot="icon" name="icon-alert" style="color: var(--uui-color-danger);"></uui-icon>
|
||||
<slot name="actions"></slot>
|
||||
</uui-ref-node>`;
|
||||
}
|
||||
// Loading:
|
||||
return html`<uui-loader-bar style="margin-top:10px;"></uui-loader-bar>`;
|
||||
}
|
||||
|
||||
override destroy(): void {
|
||||
|
||||
@@ -29,6 +29,7 @@ export class UmbPickerInputContext<
|
||||
|
||||
public readonly selection;
|
||||
public readonly selectedItems;
|
||||
public readonly statuses;
|
||||
public readonly interactionMemory = new UmbInteractionMemoryManager(this);
|
||||
|
||||
/**
|
||||
@@ -84,6 +85,7 @@ export class UmbPickerInputContext<
|
||||
this.#itemManager = new UmbRepositoryItemsManager<PickedItemType>(this, repositoryAlias, getUniqueMethod);
|
||||
|
||||
this.selection = this.#itemManager.uniques;
|
||||
this.statuses = this.#itemManager.statuses;
|
||||
this.selectedItems = this.#itemManager.items;
|
||||
}
|
||||
|
||||
@@ -116,12 +118,12 @@ export class UmbPickerInputContext<
|
||||
|
||||
async requestRemoveItem(unique: string) {
|
||||
const item = this.#itemManager.getItems().find((item) => this.#getUnique(item) === unique);
|
||||
if (!item) throw new Error('Could not find item with unique: ' + unique);
|
||||
|
||||
const name = item?.name ?? '#general_notFound';
|
||||
await umbConfirmModal(this, {
|
||||
color: 'danger',
|
||||
headline: `#actions_remove ${item.name}?`,
|
||||
content: `#defaultdialogs_confirmremove ${item.name}?`,
|
||||
headline: `#actions_remove ${name}?`,
|
||||
content: `#defaultdialogs_confirmremove ${name}?`,
|
||||
confirmLabel: '#actions_remove',
|
||||
});
|
||||
|
||||
|
||||
@@ -7,17 +7,10 @@ import { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-ap
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
|
||||
import { UmbEntityUpdatedEvent } from '@umbraco-cms/backoffice/entity-action';
|
||||
import type { UmbRepositoryItemsStatus } from './types.js';
|
||||
|
||||
const ObserveRepositoryAlias = Symbol();
|
||||
|
||||
interface UmbRepositoryItemsStatus {
|
||||
state: {
|
||||
type: 'success' | 'error' | 'loading';
|
||||
error?: string;
|
||||
};
|
||||
unique: string;
|
||||
}
|
||||
|
||||
export class UmbRepositoryItemsManager<ItemType extends { unique: string }> extends UmbControllerBase {
|
||||
//
|
||||
repository?: UmbItemRepository<ItemType>;
|
||||
|
||||
@@ -11,6 +11,14 @@ export interface UmbRepositoryResponse<T> extends UmbDataSourceResponse<T> {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface UmbRepositoryErrorResponse extends UmbDataSourceErrorResponse {}
|
||||
|
||||
export interface UmbRepositoryItemsStatus {
|
||||
state: {
|
||||
type: 'success' | 'error' | 'loading';
|
||||
error?: string;
|
||||
};
|
||||
unique: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for a repository that can return a paged model.
|
||||
* @template T - The type of items in the paged model.
|
||||
|
||||
@@ -11,6 +11,7 @@ import { UmbSorterController } from '@umbraco-cms/backoffice/sorter';
|
||||
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type';
|
||||
import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree';
|
||||
import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory';
|
||||
import type { UmbRepositoryItemsStatus } from '@umbraco-cms/backoffice/repository';
|
||||
|
||||
@customElement('umb-input-document')
|
||||
export class UmbInputDocumentElement extends UmbFormControlMixin<string | undefined, typeof UmbLitElement>(
|
||||
@@ -139,6 +140,9 @@ export class UmbInputDocumentElement extends UmbFormControlMixin<string | undefi
|
||||
@state()
|
||||
private _items?: Array<UmbDocumentItemModel>;
|
||||
|
||||
@state()
|
||||
private _statuses?: Array<UmbRepositoryItemsStatus>;
|
||||
|
||||
#pickerInputContext = new UmbDocumentPickerInputContext(this);
|
||||
|
||||
constructor() {
|
||||
@@ -168,6 +172,8 @@ export class UmbInputDocumentElement extends UmbFormControlMixin<string | undefi
|
||||
'_observerItems',
|
||||
);
|
||||
|
||||
this.observe(this.#pickerInputContext.statuses, (statuses) => (this._statuses = statuses), '_observerStatuses');
|
||||
|
||||
this.observe(
|
||||
this.#pickerInputContext.interactionMemory.memories,
|
||||
(memories) => {
|
||||
@@ -199,8 +205,8 @@ export class UmbInputDocumentElement extends UmbFormControlMixin<string | undefi
|
||||
);
|
||||
}
|
||||
|
||||
#onRemove(item: UmbDocumentItemModel) {
|
||||
this.#pickerInputContext.requestRemoveItem(item.unique);
|
||||
#onRemove(unique: string) {
|
||||
this.#pickerInputContext.requestRemoveItem(unique);
|
||||
}
|
||||
|
||||
override render() {
|
||||
@@ -224,16 +230,20 @@ export class UmbInputDocumentElement extends UmbFormControlMixin<string | undefi
|
||||
}
|
||||
|
||||
#renderItems() {
|
||||
if (!this._items) return;
|
||||
if (!this._statuses) return;
|
||||
return html`
|
||||
<uui-ref-list>
|
||||
${repeat(
|
||||
this._items,
|
||||
(item) => item.unique,
|
||||
(item) =>
|
||||
html`<umb-entity-item-ref
|
||||
id=${item.unique}
|
||||
this._statuses,
|
||||
(status) => status.unique,
|
||||
(status) => {
|
||||
const unique = status.unique;
|
||||
const item = this._items?.find((x) => x.unique === unique);
|
||||
return html`<umb-entity-item-ref
|
||||
id=${unique}
|
||||
.item=${item}
|
||||
?error=${status.state.type === 'error'}
|
||||
.errorMessage=${status.state.error}
|
||||
?readonly=${this.readonly}
|
||||
?standalone=${this.max === 1}>
|
||||
${when(
|
||||
@@ -242,11 +252,12 @@ export class UmbInputDocumentElement extends UmbFormControlMixin<string | undefi
|
||||
<uui-action-bar slot="actions">
|
||||
<uui-button
|
||||
label=${this.localize.term('general_remove')}
|
||||
@click=${() => this.#onRemove(item)}></uui-button>
|
||||
@click=${() => this.#onRemove(unique)}></uui-button>
|
||||
</uui-action-bar>
|
||||
`,
|
||||
)}
|
||||
</umb-entity-item-ref>`,
|
||||
</umb-entity-item-ref>`;
|
||||
},
|
||||
)}
|
||||
</uui-ref-list>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user