Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content Picker: Filter out invalid entity types #18660

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/Umbraco.Web.UI.Client/src/assets/lang/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,11 @@ export default {
defineRootNode: 'Pick root node',
defineXPathOrigin: 'Specify via XPath',
defineDynamicRoot: 'Specify a Dynamic Root',
unsupportedHeadline: (type?: string) =>
`<strong>Unsupported ${type ?? 'content'} items</strong><br>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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<string | undefined, typeof UmbLitElement>(
UmbLitElement,
) {
Expand Down Expand Up @@ -174,6 +173,6 @@ export { UmbInputContentElement as element };

declare global {
interface HTMLElementTagNameMap {
[elementName]: UmbInputContentElement;
'umb-input-content': UmbInputContentElement;
}
}
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<UmbContentPickerValueType | undefined, typeof UmbLitElement>(UmbLitElement, undefined)
implements UmbPropertyEditorUiElement
Expand All @@ -48,31 +47,34 @@ export class UmbPropertyEditorUIContentPickerElement
readonly = false;

@state()
_type: UmbContentPickerSource['type'] = 'content';
private _type: UmbContentPickerSource['type'] = 'content';

@state()
private _min = 0;

@state()
_min = 0;
private _minMessage = '';

@state()
_minMessage = '';
private _max = Infinity;

@state()
_max = Infinity;
private _maxMessage = '';

@state()
_maxMessage = '';
private _allowedContentTypeUniques?: string | null;

@state()
_allowedContentTypeUniques?: string | null;
private _showOpenButton?: boolean;

@state()
_showOpenButton?: boolean;
private _rootUnique?: string | null;

@state()
_rootUnique?: string | null;
private _rootEntityType?: string;

@state()
_rootEntityType?: string;
private _invalidData?: UmbContentPickerValueType;

#dynamicRoot?: UmbContentPickerSource['dynamicRoot'];
#dynamicRootRepository = new UmbContentPickerDynamicRootRepository(this);
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -170,15 +191,68 @@ export class UmbPropertyEditorUIContentPickerElement
.allowedContentTypeIds=${this._allowedContentTypeUniques ?? ''}
?showOpenButton=${this._showOpenButton}
?readonly=${this.readonly}
@change=${this.#onChange}></umb-input-content>
@change=${this.#onChange}>
</umb-input-content>
${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`
<div id="messages">
${repeat(
grouped,
(group) => group.key,
(group) => html`
<p>
<umb-localize key="contentPicker_unsupportedHeadline" .args=${[group.key]}>
<strong>Unsupported ${group.key} items</strong><br />
The following content is no longer supported in this Editor.
</umb-localize>
</p>
<umb-input-content readonly .selection=${group.items} .type=${toPickerType(group.key)}></umb-input-content>
<p>
<umb-localize key="contentPicker_unsupportedMessage">
If you still require this content, please contact your administrator. Otherwise you can remove it.
</umb-localize>
</p>
<uui-button
color="danger"
look="outline"
label=${this.localize.term('contentPicker_unsupportedRemove')}
@click=${this.#onRemoveInvalidData}></uui-button>
`,
)}
</div>
`;
}

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;
}
}
Loading