From 7ecc6ece7e9f11305d01dc9d0ebc4d420a38cc11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 8 Oct 2025 17:40:42 +0200 Subject: [PATCH] Block Workspace: dynamic headline & browser title (#20424) * get content type name method * use local virtual render for the workspace headline and browser title --- .../block-workspace-editor.element.ts | 5 +- .../workspace/block-workspace.context.ts | 70 ++++++++++++++----- .../content-type-structure-manager.class.ts | 4 ++ 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts index 9c2e1b9a38..a76ed3ea2f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace-editor.element.ts @@ -11,10 +11,7 @@ export class UmbBlockWorkspaceEditorElement extends UmbLitElement { this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (context) => { if (context) { this.observe( - observeMultiple([ - context.isNew, - context.content.structure.ownerContentTypeObservablePart((contentType) => contentType?.name), - ]), + observeMultiple([context.isNew, context.name]), ([isNew, name]) => { this._headline = this.localize.term(isNew ? 'general_add' : 'general_edit') + ' ' + this.localize.string(name); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index 770ef5fd19..4a8fcbb12f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -1,5 +1,5 @@ -import type { UmbBlockDataModel, UmbBlockLayoutBaseModel } from '../types.js'; -import { UMB_BLOCK_ENTRIES_CONTEXT, UMB_BLOCK_ENTRY_CONTEXT, UMB_BLOCK_MANAGER_CONTEXT } from '../context/index.js'; +import type { UmbBlockDataModel, UmbBlockDataValueModel, UmbBlockLayoutBaseModel } from '../types.js'; +import { UMB_BLOCK_ENTRIES_CONTEXT, UMB_BLOCK_MANAGER_CONTEXT } from '../context/index.js'; import { UmbBlockWorkspaceEditorElement } from './block-workspace-editor.element.js'; import { UmbBlockElementManager } from './block-element-manager.js'; import type { UmbBlockWorkspaceOriginData } from './block-workspace.modal-token.js'; @@ -24,6 +24,7 @@ import { decodeFilePath, UmbReadOnlyVariantGuardManager } from '@umbraco-cms/bac import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; +import { UmbUfmVirtualRenderController } from '@umbraco-cms/backoffice/ufm'; export type UmbBlockWorkspaceElementManagerNames = 'content' | 'settings'; @@ -66,6 +67,8 @@ export class UmbBlockWorkspaceContext(undefined); readonly name = this.#name.asObservable(); + #labelRender = new UmbUfmVirtualRenderController(this); + #variantId = new UmbClassState(undefined); readonly variantId = this.#variantId.asObservable(); @@ -99,14 +102,22 @@ export class UmbBlockWorkspaceContext { - this.#name.setValue(context?.getName()); - }); + this.observe( + this.variantId, + (variantId) => { + this.content.setVariantId(variantId); + this.settings.setVariantId(variantId); + }, + null, + ); - this.observe(this.variantId, (variantId) => { - this.content.setVariantId(variantId); - this.settings.setVariantId(variantId); - }); + this.observe( + observeMultiple([this.content.values, this.settings.values]), + async ([contentValues]) => { + this.#renderLabel(contentValues); + }, + 'observeContentForLabelRender', + ); this.routes.setRoutes([ { @@ -210,15 +221,17 @@ export class UmbBlockWorkspaceContext { this.observe( contentTypeId ? manager.blockTypeOf(contentTypeId) : undefined, - (blockType) => { - if (!blockType?.editorSize) return; - - const editorConfig = manager.getEditorConfiguration(); - const useInlineEditing = editorConfig?.find((x) => x.alias === 'useInlineEditingAsDefault')?.value; - - if (!useInlineEditing) { - this.setEditorSize(blockType.editorSize); + async (blockType) => { + if (blockType?.editorSize) { + const editorConfig = manager.getEditorConfiguration(); + const useInlineEditing = editorConfig?.find((x) => x.alias === 'useInlineEditingAsDefault')?.value; + if (!useInlineEditing) { + this.setEditorSize(blockType.editorSize); + } } + + await this.content.structure.whenLoaded(); + this.#gotLabel(blockType?.label ?? this.content.structure.getOwnerContentTypeName()); }, 'observeBlockType', ); @@ -227,6 +240,29 @@ export class UmbBlockWorkspaceContext | undefined) { + const valueObject = {} as Record; + if (contentValues) { + for (const property of contentValues) { + valueObject[property.alias] = property.value; + } + } + + this.#labelRender.value = valueObject; + // Await one animation frame: + await new Promise((resolve) => requestAnimationFrame(() => resolve(true))); + const result = this.#labelRender.toString(); + this.#name.setValue(result); + this.view.setTitle(result); + } + #allowNavigateAway = false; #onWillNavigate = async (e: CustomEvent) => { const newUrl = e.detail.url; diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-structure-manager.class.ts index 4c1ad32a4d..b55e8b88dd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-structure-manager.class.ts @@ -314,6 +314,10 @@ export class UmbContentTypeStructureManager< return this.#contentTypes.getValue().find((y) => y.unique === this.#ownerContentTypeUnique); } + getOwnerContentTypeName() { + return this.getOwnerContentType()?.name; + } + getOwnerContentTypeUnique() { return this.#ownerContentTypeUnique; }