diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts index 84ffec33a5..96c68fe39e 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts @@ -1278,6 +1278,11 @@ export default { defineRootNode: 'Pick root node', defineXPathOrigin: 'Specify via XPath', defineDynamicRoot: 'Specify a Dynamic Root', + unsupportedHeadline: (type?: string) => + `Unsupported ${type ?? 'content'} items
The following content is no longer supported in this Editor.`, + unsupportedMessage: + 'If you still require this content, please contact your administrator. Otherwise you can remove it.', + unsupportedRemove: 'Remove unsupported items?', }, dynamicRoot: { configurationTitle: 'Dynamic Root Query', diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index 057ba23d72..b773d48ddd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -115,7 +115,7 @@ export class UmbPickerInputContext< color: 'danger', headline: `Remove ${item.name}?`, content: 'Are you sure you want to remove this item', - confirmLabel: 'Remove', + confirmLabel: '#actions_remove', }); this.#removeItem(unique); diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 3d1485052e..f31164aaa2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -1,14 +1,13 @@ import type { UmbContentPickerSource } from '../../types.js'; import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; -import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; -const elementName = 'umb-input-content'; -@customElement(elementName) +@customElement('umb-input-content') export class UmbInputContentElement extends UmbFormControlMixin( UmbLitElement, ) { @@ -174,6 +173,6 @@ export { UmbInputContentElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbInputContentElement; + 'umb-input-content': UmbInputContentElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index d763d63531..8dd3fe7000 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -1,7 +1,9 @@ import { UmbContentPickerDynamicRootRepository } from './dynamic-root/repository/index.js'; import type { UmbInputContentElement } from './components/input-content/index.js'; import type { UmbContentPickerSource, UmbContentPickerSourceType } from './types.js'; -import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { css, customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UMB_DOCUMENT_ENTITY_TYPE } from '@umbraco-cms/backoffice/document'; @@ -15,16 +17,13 @@ import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; // import of local component import './components/input-content/index.js'; -import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; type UmbContentPickerValueType = UmbInputContentElement['selection']; -const elementName = 'umb-property-editor-ui-content-picker'; - /** * @element umb-property-editor-ui-content-picker */ -@customElement(elementName) +@customElement('umb-property-editor-ui-content-picker') export class UmbPropertyEditorUIContentPickerElement extends UmbFormControlMixin(UmbLitElement, undefined) implements UmbPropertyEditorUiElement @@ -48,31 +47,34 @@ export class UmbPropertyEditorUIContentPickerElement readonly = false; @state() - _type: UmbContentPickerSource['type'] = 'content'; + private _type: UmbContentPickerSource['type'] = 'content'; @state() - _min = 0; + private _min = 0; @state() - _minMessage = ''; + private _minMessage = ''; @state() - _max = Infinity; + private _max = Infinity; @state() - _maxMessage = ''; + private _maxMessage = ''; @state() - _allowedContentTypeUniques?: string | null; + private _allowedContentTypeUniques?: string | null; @state() - _showOpenButton?: boolean; + private _showOpenButton?: boolean; @state() - _rootUnique?: string | null; + private _rootUnique?: string | null; @state() - _rootEntityType?: string; + private _rootEntityType?: string; + + @state() + private _invalidData?: UmbContentPickerValueType; #dynamicRoot?: UmbContentPickerSource['dynamicRoot']; #dynamicRootRepository = new UmbContentPickerDynamicRootRepository(this); @@ -92,6 +94,12 @@ export class UmbPropertyEditorUIContentPickerElement this._rootUnique = startNode.id; this._rootEntityType = this.#entityTypeDictionary[startNode.type]; this.#dynamicRoot = startNode.dynamicRoot; + + // NOTE: Filter out any items that do not match the entity type. [LK] + this._invalidData = this.#value?.filter((x) => x.type !== this._rootEntityType); + if (this._invalidData?.length) { + this.readonly = true; + } } this._min = this.#parseInt(config.getValueByAlias('minNumber'), 0); @@ -152,6 +160,19 @@ export class UmbPropertyEditorUIContentPickerElement this.dispatchEvent(new UmbChangeEvent()); } + async #onRemoveInvalidData() { + await umbConfirmModal(this, { + color: 'danger', + headline: '#contentPicker_unsupportedRemove', + content: '#defaultdialogs_confirmSure', + confirmLabel: '#actions_remove', + }); + + this.value = this.value?.filter((x) => x.type === this._rootEntityType); + this._invalidData = undefined; + this.readonly = false; + } + override render() { const startNode: UmbTreeStartNode | undefined = this._rootUnique && this._rootEntityType @@ -170,15 +191,68 @@ export class UmbPropertyEditorUIContentPickerElement .allowedContentTypeIds=${this._allowedContentTypeUniques ?? ''} ?showOpenButton=${this._showOpenButton} ?readonly=${this.readonly} - @change=${this.#onChange}> + @change=${this.#onChange}> + + ${this.#renderInvalidData()} `; } + + #renderInvalidData() { + if (!this._invalidData?.length) return nothing; + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + const groupby = Object.groupBy(this._invalidData, (x) => x.type); + const grouped = Object.keys(groupby) + .sort((a, b) => a.localeCompare(b)) + .map((key) => ({ key, items: groupby[key] })); + + const toPickerType = (type: string): UmbContentPickerSourceType => { + return type === UMB_DOCUMENT_ENTITY_TYPE ? 'content' : (type as UmbContentPickerSourceType); + }; + + return html` +
+ ${repeat( + grouped, + (group) => group.key, + (group) => html` +

+ + Unsupported ${group.key} items
+ The following content is no longer supported in this Editor. +
+

+ +

+ + If you still require this content, please contact your administrator. Otherwise you can remove it. + +

+ + `, + )} +
+ `; + } + + static override readonly styles = [ + css` + #messages { + color: var(--uui-color-danger-standalone); + } + `, + ]; } export { UmbPropertyEditorUIContentPickerElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbPropertyEditorUIContentPickerElement; + 'umb-property-editor-ui-content-picker': UmbPropertyEditorUIContentPickerElement; } }