From 410794d00fe873f44b0783585b2072f3d454ccdd Mon Sep 17 00:00:00 2001 From: leekelleher Date: Wed, 29 Jan 2025 17:25:55 +0000 Subject: [PATCH 1/7] Reverted `elementName` constant --- .../ufm/components/content-name/content-name.element.ts | 7 +++---- .../ufm/components/label-value/label-value.element.ts | 7 +++---- .../src/packages/ufm/components/link/link.element.ts | 7 +++---- .../packages/ufm/components/localize/localize.element.ts | 7 +++---- .../ufm/components/ufm-render/ufm-render.element.ts | 9 ++++----- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts index b9875ce9f958..88c5d05ad9d1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts @@ -6,9 +6,8 @@ import { UmbId } from '@umbraco-cms/backoffice/id'; import { UmbMediaItemRepository, UMB_MEDIA_ENTITY_TYPE } from '@umbraco-cms/backoffice/media'; import { UmbMemberItemRepository, UMB_MEMBER_ENTITY_TYPE } from '@umbraco-cms/backoffice/member'; -const elementName = 'ufm-content-name'; - -@customElement(elementName) +// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name +@customElement('ufm-content-name') export class UmbUfmContentNameElement extends UmbUfmElementBase { @property() alias?: string; @@ -95,6 +94,6 @@ export { UmbUfmContentNameElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbUfmContentNameElement; + 'ufm-content-name': UmbUfmContentNameElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts index f2ab78c8ac4b..5d828a4cfb4a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts @@ -2,9 +2,8 @@ import { UMB_UFM_RENDER_CONTEXT } from '../ufm-render/ufm-render.context.js'; import { UmbUfmElementBase } from '../ufm-element-base.js'; import { customElement, property } from '@umbraco-cms/backoffice/external/lit'; -const elementName = 'ufm-label-value'; - -@customElement(elementName) +// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name +@customElement('ufm-label-value') export class UmbUfmLabelValueElement extends UmbUfmElementBase { @property() alias?: string; @@ -32,6 +31,6 @@ export { UmbUfmLabelValueElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbUfmLabelValueElement; + 'ufm-label-value': UmbUfmLabelValueElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts index 268cd9c82fdd..b882beadeb5d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts @@ -5,9 +5,8 @@ import { UmbDocumentItemRepository, UMB_DOCUMENT_ENTITY_TYPE } from '@umbraco-cm import { UmbMediaItemRepository, UMB_MEDIA_ENTITY_TYPE } from '@umbraco-cms/backoffice/media'; import type { UmbLinkPickerLink } from '@umbraco-cms/backoffice/multi-url-picker'; -const elementName = 'ufm-link'; - -@customElement(elementName) +// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name +@customElement('ufm-link') export class UmbUfmLinkElement extends UmbUfmElementBase { @property() alias?: string; @@ -79,6 +78,6 @@ export { UmbUfmLinkElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbUfmLinkElement; + 'ufm-link': UmbUfmLinkElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts index 9f440de11a30..bd044dcb3cba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts @@ -1,9 +1,8 @@ import { UmbUfmElementBase } from '../ufm-element-base.js'; import { customElement, property } from '@umbraco-cms/backoffice/external/lit'; -const elementName = 'ufm-localize'; - -@customElement(elementName) +// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name +@customElement('ufm-localize') export class UmbUfmLocalizeElement extends UmbUfmElementBase { @property() public set alias(value: string | undefined) { @@ -21,6 +20,6 @@ export { UmbUfmLocalizeElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbUfmLocalizeElement; + 'ufm-localize': UmbUfmLocalizeElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts index a589c32d3478..2a9f2250ebd6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts @@ -4,9 +4,7 @@ import { css, customElement, nothing, property, unsafeHTML, until } from '@umbra import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -const elementName = 'umb-ufm-render'; - -@customElement(elementName) +@customElement('umb-ufm-render') export class UmbUfmRenderElement extends UmbLitElement { #context = new UmbUfmRenderContext(this); @@ -16,7 +14,8 @@ export class UmbUfmRenderElement extends UmbLitElement { @property() markdown?: string; - // No reactive property declaration cause its causing a re-render that is not needed. This just works as a shortcut to set the values on the context. [NL] + // No reactive property declaration cause its causing a re-render that is not needed. + // This just works as a shortcut to set the values on the context. [NL] public set value(value: string | unknown | undefined) { this.#context.setValue(value); } @@ -75,6 +74,6 @@ export { UmbUfmRenderElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbUfmRenderElement; + 'umb-ufm-render': UmbUfmRenderElement; } } From 5005317995fef099dbdcc8e00c2d08450f714012 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 7 Jul 2025 15:14:12 +0100 Subject: [PATCH 2/7] UFM base element: simplify context check --- .../src/packages/ufm/components/ufm-element-base.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts index 14e9d85201ff..9e108cc10c4d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts @@ -1,10 +1,12 @@ import { UMB_UFM_CONTEXT } from '../contexts/ufm.context.js'; -import { nothing, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; export abstract class UmbUfmElementBase extends UmbLitElement { #filterFuncArgs?: Array<{ alias: string; args: Array }>; + #ufmContext?: typeof UMB_UFM_CONTEXT.TYPE; + @property() public set filters(value: string | undefined) { this.#filters = value; @@ -25,8 +27,6 @@ export abstract class UmbUfmElementBase extends UmbLitElement { @state() value?: unknown; - #ufmContext?: typeof UMB_UFM_CONTEXT.TYPE; - constructor() { super(); @@ -36,12 +36,11 @@ export abstract class UmbUfmElementBase extends UmbLitElement { } override render() { - if (!this.#ufmContext) return nothing; - let values = Array.isArray(this.value) ? this.value : [this.value]; + if (this.#filterFuncArgs) { for (const item of this.#filterFuncArgs) { - const filter = this.#ufmContext.getFilterByAlias(item.alias); + const filter = this.#ufmContext?.getFilterByAlias(item.alias); if (filter) { values = values.map((value) => filter(value, ...item.args)); } From 21ef3bf1fee3fd39f74cd033fba2dd552f62a425 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 7 Jul 2025 15:19:37 +0100 Subject: [PATCH 3/7] Adds console warning if UFM filter does not exist --- .../src/packages/ufm/components/ufm-element-base.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts index 9e108cc10c4d..5892a3910134 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts @@ -43,6 +43,8 @@ export abstract class UmbUfmElementBase extends UmbLitElement { const filter = this.#ufmContext?.getFilterByAlias(item.alias); if (filter) { values = values.map((value) => filter(value, ...item.args)); + } else { + console.warn(`UFM filter with alias "${item.alias}" was not found.`); } } } From 013fd534ec125a79d3b8ad83bac0f7c105523bdf Mon Sep 17 00:00:00 2001 From: leekelleher Date: Mon, 7 Jul 2025 16:51:11 +0100 Subject: [PATCH 4/7] Removed unnecessary casting/typing --- .../src/packages/ufm/contexts/ufm.context.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/contexts/ufm.context.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/contexts/ufm.context.ts index 743a17c5d41d..bf8681a46ed4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/contexts/ufm.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/contexts/ufm.context.ts @@ -34,9 +34,7 @@ export const UmbMarked = new Marked({ gfm: true, breaks: true, hooks: { - postprocess: (markup) => { - return UmbDomPurify.sanitize(markup, UmbDomPurifyConfig) as string; - }, + postprocess: (markup) => UmbDomPurify.sanitize(markup, UmbDomPurifyConfig), }, }); From 884d441f179f80ab25bfd5675da82ef94036bcc1 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Tue, 8 Jul 2025 10:14:49 +0200 Subject: [PATCH 5/7] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../packages/ufm/components/ufm-render/ufm-render.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts index 2a9f2250ebd6..54f7d0c8c023 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-render/ufm-render.element.ts @@ -14,7 +14,7 @@ export class UmbUfmRenderElement extends UmbLitElement { @property() markdown?: string; - // No reactive property declaration cause its causing a re-render that is not needed. + // No reactive property declaration because it's causing a re-render that is not needed. // This just works as a shortcut to set the values on the context. [NL] public set value(value: string | unknown | undefined) { this.#context.setValue(value); From afd863420a00e09ea8a85f6d9a80e4f234e3bf9b Mon Sep 17 00:00:00 2001 From: leekelleher Date: Tue, 8 Jul 2025 12:43:59 +0100 Subject: [PATCH 6/7] Moved console warnings outside of loop --- .../src/packages/ufm/components/ufm-element-base.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts index 5892a3910134..7e16889dbe62 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/ufm-element-base.ts @@ -39,14 +39,20 @@ export abstract class UmbUfmElementBase extends UmbLitElement { let values = Array.isArray(this.value) ? this.value : [this.value]; if (this.#filterFuncArgs) { + const missing = new Set(); + for (const item of this.#filterFuncArgs) { const filter = this.#ufmContext?.getFilterByAlias(item.alias); if (filter) { values = values.map((value) => filter(value, ...item.args)); } else { - console.warn(`UFM filter with alias "${item.alias}" was not found.`); + missing.add(item.alias); } } + + if (missing.size > 0) { + console.warn(`UFM filters with aliases "${Array.from(missing).join('", "')}" were not found.`); + } } return values.join(', '); From 068d0531d6527bb34bc2b60b2f4b919f9ceb6b0b Mon Sep 17 00:00:00 2001 From: leekelleher Date: Tue, 8 Jul 2025 12:53:50 +0100 Subject: [PATCH 7/7] Added "ufm-" prefix to eslint local rules --- .../eslint/rules/enforce-umb-prefix-on-element-name.cjs | 7 ++++--- .../examples/ufm-custom-component/custom-ufm-component.ts | 1 - .../ufm/components/content-name/content-name.element.ts | 1 - .../ufm/components/label-value/label-value.element.ts | 1 - .../src/packages/ufm/components/link/link.element.ts | 1 - .../packages/ufm/components/localize/localize.element.ts | 1 - 6 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/devops/eslint/rules/enforce-umb-prefix-on-element-name.cjs b/src/Umbraco.Web.UI.Client/devops/eslint/rules/enforce-umb-prefix-on-element-name.cjs index 5db023e93234..2fc62a385af3 100644 --- a/src/Umbraco.Web.UI.Client/devops/eslint/rules/enforce-umb-prefix-on-element-name.cjs +++ b/src/Umbraco.Web.UI.Client/devops/eslint/rules/enforce-umb-prefix-on-element-name.cjs @@ -23,13 +23,14 @@ module.exports = { if (isCustomElementDecorator) { const elementName = node.arguments[0].value; - // check if the element name starts with 'umb-', or 'test-', to be allow tests to have custom elements: - const isElementNameValid = elementName.startsWith('umb-') ? true : elementName.startsWith('test-'); + // check if the element name starts with 'umb-', 'ufm-', or 'test-', to be allow tests to have custom elements: + const prefixes = ['umb-', 'ufm-', 'test-']; + const isElementNameValid = prefixes.some((prefix) => elementName.startsWith(prefix)); if (!isElementNameValid) { context.report({ node, - message: 'Custom Element name should start with "umb-".', + message: 'Custom Element name should start with "umb-" or "ufm-".', // There is no fixer on purpose because it's not safe to automatically rename the element name. // Renaming should be done manually with consideration of potential impacts. }); diff --git a/src/Umbraco.Web.UI.Client/examples/ufm-custom-component/custom-ufm-component.ts b/src/Umbraco.Web.UI.Client/examples/ufm-custom-component/custom-ufm-component.ts index 9f4486eb7a2d..8df2bc229a52 100644 --- a/src/Umbraco.Web.UI.Client/examples/ufm-custom-component/custom-ufm-component.ts +++ b/src/Umbraco.Web.UI.Client/examples/ufm-custom-component/custom-ufm-component.ts @@ -11,7 +11,6 @@ export class UmbCustomUfmComponent extends UmbUfmComponentBase { } } -// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name @customElement('ufm-custom-component') export class UmbCustomUfmComponentElement extends UmbLitElement { @property() diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts index 88c5d05ad9d1..176e58c3b68a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/content-name/content-name.element.ts @@ -6,7 +6,6 @@ import { UmbId } from '@umbraco-cms/backoffice/id'; import { UmbMediaItemRepository, UMB_MEDIA_ENTITY_TYPE } from '@umbraco-cms/backoffice/media'; import { UmbMemberItemRepository, UMB_MEMBER_ENTITY_TYPE } from '@umbraco-cms/backoffice/member'; -// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name @customElement('ufm-content-name') export class UmbUfmContentNameElement extends UmbUfmElementBase { @property() diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts index 5d828a4cfb4a..0c5f9e0b4d0d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/label-value/label-value.element.ts @@ -2,7 +2,6 @@ import { UMB_UFM_RENDER_CONTEXT } from '../ufm-render/ufm-render.context.js'; import { UmbUfmElementBase } from '../ufm-element-base.js'; import { customElement, property } from '@umbraco-cms/backoffice/external/lit'; -// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name @customElement('ufm-label-value') export class UmbUfmLabelValueElement extends UmbUfmElementBase { @property() diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts index b882beadeb5d..59b6540fd13a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/link/link.element.ts @@ -5,7 +5,6 @@ import { UmbDocumentItemRepository, UMB_DOCUMENT_ENTITY_TYPE } from '@umbraco-cm import { UmbMediaItemRepository, UMB_MEDIA_ENTITY_TYPE } from '@umbraco-cms/backoffice/media'; import type { UmbLinkPickerLink } from '@umbraco-cms/backoffice/multi-url-picker'; -// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name @customElement('ufm-link') export class UmbUfmLinkElement extends UmbUfmElementBase { @property() diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts index bd044dcb3cba..09ec97738c6c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/components/localize/localize.element.ts @@ -1,7 +1,6 @@ import { UmbUfmElementBase } from '../ufm-element-base.js'; import { customElement, property } from '@umbraco-cms/backoffice/external/lit'; -// eslint-disable-next-line local-rules/enforce-umb-prefix-on-element-name @customElement('ufm-localize') export class UmbUfmLocalizeElement extends UmbUfmElementBase { @property()