From 3baf57db07ed0be9d141db946bfe4a97e6af0173 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 25 Jul 2024 09:29:52 +0100 Subject: [PATCH 1/7] Introduced `UfmToken` interface type --- .../core/extension-registry/models/ufm-component.model.ts | 4 ++-- .../src/packages/ufm/plugins/marked-ufm.plugin.ts | 6 +++++- .../packages/ufm/ufm-components/label-value.component.ts | 5 +++-- .../src/packages/ufm/ufm-components/localize.component.ts | 5 +++-- .../src/packages/ufm/ufm-components/ufm-component-base.ts | 4 ++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/ufm-component.model.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/ufm-component.model.ts index 9c3a2afa14..9cf61264f4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/ufm-component.model.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/ufm-component.model.ts @@ -1,8 +1,8 @@ import type { ManifestApi, UmbApi } from '@umbraco-cms/backoffice/extension-api'; -import type { Tokens } from '@umbraco-cms/backoffice/external/marked'; +import type { UfmToken } from '@umbraco-cms/backoffice/ufm'; export interface UmbUfmComponentApi extends UmbApi { - render(token: Tokens.Generic): string | undefined; + render(token: UfmToken): string | undefined; } export interface MetaUfmComponent { diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts index 9ed749585d..6d2ee865a7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts @@ -3,7 +3,11 @@ import type { MarkedExtension, Tokens } from '@umbraco-cms/backoffice/external/m export interface UfmPlugin { alias: string; marker: string; - render?: (token: Tokens.Generic) => string | undefined; + render?: (token: UfmToken) => string | undefined; +} + +export interface UfmToken extends Tokens.Generic { + text?: string; } export function ufm(plugins: Array = []): MarkedExtension { diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.component.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.component.ts index 00c58d0027..7fa6b5d815 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.component.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.component.ts @@ -1,10 +1,11 @@ +import type { UfmToken } from '../plugins/marked-ufm.plugin.js'; import { UmbUfmComponentBase } from './ufm-component-base.js'; -import type { Tokens } from '@umbraco-cms/backoffice/external/marked'; import './label-value.element.js'; export class UmbUfmLabelValueComponent extends UmbUfmComponentBase { - render(token: Tokens.Generic) { + render(token: UfmToken) { + if (!token.text) return; return ``; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/localize.component.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/localize.component.ts index aacc2cd503..79890f75f5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/localize.component.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/localize.component.ts @@ -1,8 +1,9 @@ +import type { UfmToken } from '../plugins/marked-ufm.plugin.js'; import { UmbUfmComponentBase } from './ufm-component-base.js'; -import type { Tokens } from '@umbraco-cms/backoffice/external/marked'; export class UmbUfmLocalizeComponent extends UmbUfmComponentBase { - render(token: Tokens.Generic) { + render(token: UfmToken) { + if (!token.text) return; return ``; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/ufm-component-base.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/ufm-component-base.ts index 1109c69e76..71f552363e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/ufm-component-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/ufm-component-base.ts @@ -1,7 +1,7 @@ -import type { Tokens } from '@umbraco-cms/backoffice/external/marked'; +import type { UfmToken } from '../plugins/marked-ufm.plugin.js'; import type { UmbUfmComponentApi } from '@umbraco-cms/backoffice/extension-registry'; export abstract class UmbUfmComponentBase implements UmbUfmComponentApi { - abstract render(token: Tokens.Generic): string | undefined; + abstract render(token: UfmToken): string | undefined; destroy() {} } From b85d664ff2c713e47bedb959011a01aeac440baa Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 25 Jul 2024 09:30:47 +0100 Subject: [PATCH 2/7] UFM manifest amends --- .../src/packages/ufm/manifests.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/manifests.ts index b32b66dddf..ec604e0842 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/manifests.ts @@ -4,19 +4,15 @@ export const manifests: Array = [ { type: 'ufmComponent', alias: 'Umb.Markdown.LabelValue', - name: 'Label Value Markdown Component', + name: 'Label Value UFM Component', api: () => import('./ufm-components/label-value.component.js'), - meta: { - marker: '=', - }, + meta: { marker: '=' }, }, { type: 'ufmComponent', alias: 'Umb.Markdown.Localize', - name: 'Localize Markdown Component', + name: 'Localize UFM Component', api: () => import('./ufm-components/localize.component.js'), - meta: { - marker: '#', - }, + meta: { marker: '#' }, }, ]; From bca1d6fc140cff0da21b96b611c566cf27f528b8 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 25 Jul 2024 09:32:19 +0100 Subject: [PATCH 3/7] Added tests for UFM parsing --- .../ufm-render/ufm-render.element.ts | 2 +- .../packages/ufm/plugins/marked-ufm.test.ts | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts 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 65f33c51b4..56173caf27 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 @@ -28,7 +28,7 @@ UmbDomPurify.addHook('afterSanitizeAttributes', function (node) { } }); -const UmbMarked = new Marked({ +export const UmbMarked = new Marked({ async: true, gfm: true, breaks: true, diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts new file mode 100644 index 0000000000..ef01944675 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.test.ts @@ -0,0 +1,32 @@ +import { expect } from '@open-wc/testing'; +import { ufm } from './marked-ufm.plugin.js'; +import { UmbMarked } from '../index.js'; +import { UmbUfmLabelValueComponent } from '../ufm-components/label-value.component.js'; +import { UmbUfmLocalizeComponent } from '../ufm-components/localize.component.js'; + +describe('UmbMarkedUfm', () => { + describe('UFM parsing', () => { + const runs = [ + { ufm: '{=prop1}', expected: '' }, + { ufm: '{= prop1}', expected: '' }, + { ufm: '{= prop1 }', expected: '' }, + { ufm: '{{=prop1}}', expected: '{}' }, + { ufm: '{#general_add}', expected: '' }, + ]; + + // Manually configuring the UFM components for testing. + UmbMarked.use( + ufm([ + { alias: 'Umb.Markdown.LabelValue', marker: '=', render: new UmbUfmLabelValueComponent().render }, + { alias: 'Umb.Markdown.Localize', marker: '#', render: new UmbUfmLocalizeComponent().render }, + ]), + ); + + runs.forEach((run) => { + it(`Parsing "${run.ufm}"`, async () => { + const markup = await UmbMarked.parseInline(run.ufm); + expect(markup).to.equal(run.expected); + }); + }); + }); +}); From 933440bd966be8165151e0b6efebebe997db1263 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 25 Jul 2024 09:33:04 +0100 Subject: [PATCH 4/7] Simplified UFM regular expression --- .../src/packages/ufm/plugins/marked-ufm.plugin.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts index 6d2ee865a7..86c17cc4c9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/plugins/marked-ufm.plugin.ts @@ -16,13 +16,9 @@ export function ufm(plugins: Array = []): MarkedExtension { return { name: alias, level: 'inline', - start: (src: string) => { - const regex = new RegExp(`\\{${marker}`); - const match = src.match(regex); - return match ? match.index : -1; - }, - tokenizer(src: string): Tokens.Generic | undefined { - const pattern = `^(? src.indexOf(`{${marker}`), + tokenizer: (src: string) => { + const pattern = `^\\{${marker}([^}]*)\\}`; const regex = new RegExp(pattern); const match = src.match(regex); From 98e4ce70b0ef33b41bdc0ee22431960450bce4b2 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 25 Jul 2024 09:38:18 +0100 Subject: [PATCH 5/7] UFM LabelValue: allow non-undefined falsey values to be rendered `undefined` values will not be rendered --- .../src/packages/ufm/ufm-components/label-value.element.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.element.ts b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.element.ts index be54d466fc..cb28e01989 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/ufm/ufm-components/label-value.element.ts @@ -1,5 +1,5 @@ import { UMB_UFM_RENDER_CONTEXT } from '../components/ufm-render/index.js'; -import { customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { customElement, nothing, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; const elementName = 'ufm-label-value'; @@ -31,7 +31,7 @@ export class UmbUfmLabelValueElement extends UmbLitElement { } override render() { - return this._value ?? `{${this.alias}}`; + return this._value !== undefined ? this._value : nothing; } } From 37430141acfb9742b3e64f56a79c106b321cc0f9 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 25 Jul 2024 09:51:43 +0100 Subject: [PATCH 6/7] CollectionViews: sets UFM value inside object e.g. `{ value }` to render the value, use `{=value}`, other aliases will not work. --- .../core/components/table/table.element.ts | 2 +- .../document-grid-collection-view.element.ts | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts index cb2b5cbba9..299d8b0405 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts @@ -279,7 +279,7 @@ export class UmbTableElement extends LitElement { const element = document.createElement('umb-ufm-render') as UmbUfmRenderElement; element.inline = true; element.markdown = column.labelTemplate; - element.value = value; + element.value = { value }; return element; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts index d651ea1ce5..5218ca0e54 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/grid/document-grid-collection-view.element.ts @@ -172,26 +172,26 @@ export class UmbDocumentGridCollectionViewElement extends UmbLitElement { ${repeat( this._userDefinedProperties, (column) => column.alias, - (column) => html` -
  • - ${column.header}: - ${when( - column.nameTemplate, - () => html` - - `, - () => html`${getPropertyValueByAlias(item, column.alias)}`, - )} -
  • - `, + (column) => this.#renderProperty(item, column), )} `; } + #renderProperty(item: UmbDocumentCollectionItemModel, column: UmbCollectionColumnConfiguration) { + const value = getPropertyValueByAlias(item, column.alias); + return html` +
  • + ${column.header}: + ${when( + column.nameTemplate, + () => html``, + () => html`${value}`, + )} +
  • + `; + } + static override styles = [ UmbTextStyles, css` From 78a571705a31349399d7dd90dc5900bd762191a6 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:15:04 +0200 Subject: [PATCH 7/7] build: add sonar-project.properties to account for what are sources and test files (#2142) * build: add sonar-project.properties to account for what are sources and test files * docs: add project badges to github * build: also ignore .stories.ts files --- src/Umbraco.Web.UI.Client/.github/README.md | 2 ++ src/Umbraco.Web.UI.Client/sonar-project.properties | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/sonar-project.properties diff --git a/src/Umbraco.Web.UI.Client/.github/README.md b/src/Umbraco.Web.UI.Client/.github/README.md index c8ee810d64..d9f0f72c16 100644 --- a/src/Umbraco.Web.UI.Client/.github/README.md +++ b/src/Umbraco.Web.UI.Client/.github/README.md @@ -2,7 +2,9 @@ This is the working repository of the upcoming new Backoffice to Umbraco CMS. +[![Build and test](https://github.com/umbraco/Umbraco.CMS.Backoffice/actions/workflows/build_test.yml/badge.svg)](https://github.com/umbraco/Umbraco.CMS.Backoffice/actions/workflows/build_test.yml) [![Storybook](https://github.com/umbraco/Umbraco.CMS.Backoffice/actions/workflows/azure-static-web-apps-ambitious-stone-0033b3603.yml/badge.svg)](https://github.com/umbraco/Umbraco.CMS.Backoffice/actions/workflows/azure-static-web-apps-ambitious-stone-0033b3603.yml) +[![SonarCloud](https://sonarcloud.io/api/project_badges/measure?project=umbraco_Umbraco.CMS.Backoffice&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=umbraco_Umbraco.CMS.Backoffice) ## Installation instructions diff --git a/src/Umbraco.Web.UI.Client/sonar-project.properties b/src/Umbraco.Web.UI.Client/sonar-project.properties new file mode 100644 index 0000000000..44998fae7d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/sonar-project.properties @@ -0,0 +1,9 @@ +# Define the same root directory for sources and tests +sonar.sources = src/ +sonar.tests = src/ + +# Include test files in the test scope +sonar.test.inclusions = src/**/*.test.ts + +# Exclude test and stories files from the source scope +sonar.exclusions = src/**/*.test.ts, src/**/*.stories.ts