diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-content-no-router.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-content-no-router.element.ts index 06108fe2c6..c1fd3ba231 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-content-no-router.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-content-no-router.element.ts @@ -4,7 +4,7 @@ import { css, html, customElement, state, repeat, nothing } from '@umbraco-cms/b import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import type { UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbPropertyTypeContainerMergedModel } from '@umbraco-cms/backoffice/content-type'; import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/workspace'; /** @@ -20,10 +20,10 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme private _hasRootGroups = false; @state() - private _tabs?: Array; + private _tabs?: Array; @state() - private _activeTabId?: string | null | undefined; + private _activeTabKey?: string | null | undefined; //@state() //private _activeTabName?: string | null | undefined; @@ -36,7 +36,7 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme this.#tabsStructureHelper.setIsRoot(true); this.#tabsStructureHelper.setContainerChildType('Tab'); - this.observe(this.#tabsStructureHelper.mergedContainers, (tabs) => { + this.observe(this.#tabsStructureHelper.childContainers, (tabs) => { this._tabs = tabs; this.#checkDefaultTabName(); }); @@ -68,20 +68,20 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme if (!this._tabs || !this.#blockWorkspace) return; // Find the default tab to grab: - if (this._activeTabId === undefined) { + if (this._activeTabKey === undefined) { if (this._hasRootGroups) { //this._activeTabName = null; - this._activeTabId = null; + this._activeTabKey = null; } else if (this._tabs.length > 0) { //this._activeTabName = this._tabs[0].name; - this._activeTabId = this._tabs[0].id; + this._activeTabKey = this._tabs[0].key; } } } - #setTabName(tabName: string | undefined | null, tabId: string | null | undefined) { + #setTabName(tabName: string | undefined | null, tabKey: string | null | undefined) { //this._activeTabName = tabName; - this._activeTabId = tabId; + this._activeTabKey = tabKey; } override render() { @@ -93,7 +93,7 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme ? html` this.#setTabName(null, null)} >Content @@ -105,19 +105,19 @@ export class UmbBlockWorkspaceViewEditContentNoRouterElement extends UmbLitEleme (tab) => { return html` this.#setTabName(tab.name, tab.id)} + .active=${tab.key === this._activeTabKey} + @click=${() => this.#setTabName(tab.name, tab.key)} >${tab.name}`; }, )} ` : nothing} - ${this._activeTabId !== undefined + ${this._activeTabKey !== undefined ? html` + .containerId=${this._activeTabKey}> ` : nothing} `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts index 8bbd9cec4d..986598b50c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts @@ -1,7 +1,7 @@ import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js'; import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { UmbContentTypeModel, UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbContentTypeModel, UmbPropertyTypeContainerMergedModel } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @@ -42,7 +42,7 @@ export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { hideSingleGroup = false; @state() - private _groups: Array = []; + private _groups: Array = []; @state() private _hasProperties = false; @@ -60,7 +60,7 @@ export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { if (!this.#blockWorkspace || !this.#managerName) return; this.#groupStructureHelper.setStructureManager(this.#blockWorkspace[this.#managerName].structure); this.observe( - this.#groupStructureHelper.mergedContainers, + this.#groupStructureHelper.childContainers, (groups) => { this._groups = groups; }, @@ -89,18 +89,18 @@ export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { ? this.renderGroup(this._groups[0]) : repeat( this._groups, - (group) => group.id, + (group) => group.key, (group) => html` ${this.renderGroup(group)}`, )} `; } - renderGroup(group: UmbPropertyTypeContainerModel) { + renderGroup(group: UmbPropertyTypeContainerMergedModel) { return html` + .containerId=${group.ids[0]}> `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts index de633b326b..cd0ba81f9f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit.element.ts @@ -3,7 +3,7 @@ import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token import type { UmbBlockWorkspaceViewEditTabElement } from './block-workspace-view-edit-tab.element.js'; import { css, html, customElement, state, repeat, property } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { UmbContentTypeModel, UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbContentTypeModel, UmbPropertyTypeContainerMergedModel } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; import type { UmbRoute, UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router'; import { encodeFolderName } from '@umbraco-cms/backoffice/router'; @@ -34,7 +34,7 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U private _routes: UmbRoute[] = []; @state() - private _tabs?: Array; + private _tabs?: Array; @state() private _routerPath?: string; @@ -48,7 +48,7 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U this.#tabsStructureHelper.setIsRoot(true); this.#tabsStructureHelper.setContainerChildType('Tab'); this.observe( - this.#tabsStructureHelper.mergedContainers, + this.#tabsStructureHelper.childContainers, (tabs) => { this._tabs = tabs; this.#createRoutes(); @@ -102,7 +102,7 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U component: () => import('./block-workspace-view-edit-tab.element.js'), setup: (component) => { (component as UmbBlockWorkspaceViewEditTabElement).managerName = this.#managerName; - (component as UmbBlockWorkspaceViewEditTabElement).containerId = tab.id; + (component as UmbBlockWorkspaceViewEditTabElement).containerId = tab.ids[0]; }, }); }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-container-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-container-structure-helper.class.ts index 58afbe2cb0..9558578e39 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-container-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-container-structure-helper.class.ts @@ -1,8 +1,13 @@ -import type { UmbContentTypeModel, UmbPropertyContainerTypes, UmbPropertyTypeContainerModel } from '../types.js'; +import type { + UmbContentTypeModel, + UmbPropertyContainerTypes, + UmbPropertyTypeContainerMergedModel, + UmbPropertyTypeContainerModel, +} from '../types.js'; import type { UmbContentTypeStructureManager } from './content-type-structure-manager.class.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState, UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; /** * This class is a helper class for managing the structure of containers in a content type. @@ -11,6 +16,7 @@ import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; export class UmbContentTypeContainerStructureHelper extends UmbControllerBase { #init; #initResolver?: (value: unknown) => void; + #initRejector?: () => void; #containerId?: string | null; #childType?: UmbPropertyContainerTypes = 'Group'; @@ -21,31 +27,55 @@ export class UmbContentTypeContainerStructureHelper([], (x) => x.id); - readonly containers = this.#childContainers.asObservable(); + get containers() { + this.#startLegacy(); + return this.#childContainers.asObservable(); + } // State containing the merged containers (only one pr. name): - #mergedChildContainers = new UmbArrayState([], (x) => x.id); - readonly mergedContainers = this.#mergedChildContainers.asObservable(); + #legacyMergedChildContainers = new UmbArrayState([], (x) => x.id); + get mergedContainers() { + this.#startLegacy(); + return this.#legacyMergedChildContainers.asObservable(); + } + + #childContainersMerged = new UmbArrayState([], (x) => x.path); + public readonly childContainers = this.#childContainersMerged.asObservable(); // Owner containers are containers owned by the owner Content Type (The specific one up for editing) #ownerChildContainers: UmbPropertyTypeContainerModel[] = []; - #hasProperties = new UmbArrayState<{ id: string | null; has: boolean }>([], (x) => x.id); - readonly hasProperties = this.#hasProperties.asObservablePart((x) => x.some((y) => y.has)); + #hasProperties = new UmbBooleanState(false); + readonly hasProperties = this.#hasProperties.asObservable(); constructor(host: UmbControllerHost) { super(host); - this.#init = new Promise((resolve) => { + this.#init = new Promise((resolve, reject) => { this.#initResolver = resolve; + this.#initRejector = reject; }); - this.#mergedChildContainers.sortBy((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)); - this.observe(this.containers, this.#performContainerMerge, null); + this.#legacyMergedChildContainers.sortBy((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)); + } + + // TODO: Implement UmbDeprecated and Obsolete this from v.17 [NL] + #legacyMergeLogic = false; + #startLegacy() { + if (this.#legacyMergeLogic) return; + console.log( + "Pst. we will be deprecating 'mergedContainers' and 'containers' in v.17.0, feel free to use them until v.18.0. But please use 'childContainers'", + ); + this.#legacyMergeLogic = true; + this.#legacyObserveContainers(); + this.observe(this.containers, this.#legacyPerformContainerMerge, null); } public setStructureManager(structure: UmbContentTypeStructureManager | undefined) { if (this.#structure === structure || !structure) return; if (this.#structure && !structure) { + this.#initRejector?.(); + this.#initResolver = undefined; + this.#initRejector = undefined; throw new Error( 'Structure manager is already set, the helpers are not designed to be re-setup with new managers', ); @@ -53,7 +83,9 @@ export class UmbContentTypeContainerStructureHelper { + this.#childContainersMerged.setValue(childContainers ?? []); + }, + 'observeChildContainers', + ); + + if (this.#containerId === null) { + this.removeUmbControllerByAlias('observeParentContainer'); + // Observe root properties: + this.observe( + this.#structure?.hasPropertyStructuresOfRoot(), + (has) => { + this.#hasProperties.setValue(has ?? false); + }, + 'observeProperties', + ); + } else { + // Observe properties of the parent container and matching containers (therefor getting the merged container of the parent id): [NL] + const parentObservable = + this.#containerId !== undefined && this.#childType + ? this.#structure?.mergedContainersOfId(this.#containerId) + : undefined; + + this.observe( + parentObservable, + (parentContainer) => { + this.observe( + parentContainer ? this.#structure?.hasPropertyStructuresOfGroupIds(parentContainer.ids ?? []) : undefined, + (has) => { + this.#hasProperties.setValue(has ?? false); + }, + 'observeProperties', + ); + }, + 'observeParentContainer', + ); + } + } + + // LEGACY properties: #containerName?: string; #containerType?: UmbPropertyContainerTypes; #parentName?: string | null; #parentType?: UmbPropertyContainerTypes; - #observeContainers() { + // LEGACY method: + #legacyObserveContainers() { + if (!this.#legacyMergeLogic) return; if (!this.#structure || this.#containerId === undefined) return; if (this.#containerId === null) { - this.#observeHasPropertiesOf(null); - this.#observeRootContainers(); + //this.#observeHasPropertiesOf(null); + this.#legacyObserveRootContainers(); this.removeUmbControllerByAlias('_observeContainers'); } else { this.observe( @@ -133,8 +218,7 @@ export class UmbContentTypeContainerStructureHelper { - this.#hasProperties.setValue([]); + //this.#hasProperties.setValue([]); this.#childContainers.setValue([]); this.#containerObservers.forEach((x) => x.destroy()); this.#containerObservers = []; containers.forEach((container) => { - this.#observeHasPropertiesOf(container.id); + //this.#observeHasPropertiesOf(container.id); this.#containerObservers.push( this.observe( @@ -184,7 +269,8 @@ export class UmbContentTypeContainerStructureHelper) { + // LEGACY method: + #legacyFilterNonOwnerContainers(containers: Array) { return this.#ownerChildContainers.length > 0 ? containers.filter( (anyCon) => @@ -226,22 +315,23 @@ export class UmbContentTypeContainerStructureHelper) => { + // LEGACY method: + #legacyPerformContainerMerge = (containers: Array) => { // Remove containers that matches with a owner container: - let merged = this.#filterNonOwnerContainers(containers); + let merged = this.#legacyFilterNonOwnerContainers(containers); // Remove containers of same name and type: // This only works cause we are dealing with a single level of containers in this Helper, if we had more levels we would need to be more clever about the parent as well. [NL] merged = merged.filter((x, i, cons) => i === cons.findIndex((y) => y.name === x.name && y.type === x.type)); - this.#mergedChildContainers.setValue(merged); + this.#legacyMergedChildContainers.setValue(merged); }; /** * Returns true if the container is an owner container. * @param containerId */ - isOwnerChildContainer(containerId?: string) { + isOwnerChildContainer(containerId?: string): boolean | undefined { if (!this.#structure || !containerId) return; - return this.#ownerChildContainers.some((x) => x.id === containerId); + return this.#structure.isOwnerContainer(containerId); } getContentTypeOfContainer(containerId?: string) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts index 10237041bf..be18514559 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-property-structure-helper.class.ts @@ -47,7 +47,7 @@ export class UmbContentTypePropertyStructureHelper { 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 ffb224e144..6d97aaef57 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 @@ -497,19 +497,38 @@ export class UmbContentTypeStructureManager< makeEmptyContainerName( containerId: string, - containerType: UmbPropertyContainerTypes, - parentId: string | null = null, + legacyContainerType?: UmbPropertyContainerTypes, + legacyParentId?: string | null, ): string { return ( - this.makeContainerNameUniqueForOwnerContentType(containerId, 'Unnamed', containerType, parentId) ?? 'Unnamed' + this.makeContainerNameUniqueForOwnerContentType(containerId, 'Unnamed', legacyContainerType, legacyParentId) ?? + 'Unnamed' ); } + /** + * + * @param {string} containerId - The id of the container to make unique + * @param {string} newName - The new name to make unique + * @param {never} _legacyContainerType - do not use, has no effect. Is deprecated and will be removed in v.17 + * @param {never} _legacyParentId - do not use, has no effect. Is deprecated and will be removed in v.17 + * @returns + */ makeContainerNameUniqueForOwnerContentType( containerId: string, newName: string, - containerType: UmbPropertyContainerTypes, - parentId: string | null = null, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _legacyContainerType?: UmbPropertyContainerTypes, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _legacyParentId?: string | null, ) { + const container = this.getOwnerContainerById(containerId); + if (!container) { + console.warn(`Container with id ${containerId} not found in owner content type.`); + return null; + } + const containerType = container.type; + const parentId = container.parent?.id ?? null; + const ownerRootContainers = this.getOwnerContainers(containerType, parentId); //getRootContainers() can't differentiates between compositions and locals if (!ownerRootContainers) { return null; @@ -749,6 +768,26 @@ export class UmbContentTypeStructureManager< }); } + hasPropertyStructuresOfGroupIds(groupIds: Array) { + return this.#contentTypes.asObservablePart((docTypes) => { + return docTypes.some((docType) => { + return docType.properties?.some((property) => { + return property.container?.id && groupIds.includes(property.container.id); + }); + }); + }); + } + + hasPropertyStructuresOfRoot() { + return this.#contentTypes.asObservablePart((docTypes) => { + return docTypes.some((docType) => { + return docType.properties?.some((property) => { + return !property.container; + }); + }); + }); + } + rootContainers(containerType: UmbPropertyContainerTypes) { return createObservablePart(this.#contentTypeContainers, (data) => { return data.filter((x) => x.parent === null && x.type === containerType); diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-group.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-group.element.ts index 2745074f62..68f83dac68 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-group.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-group.element.ts @@ -1,4 +1,4 @@ -import type { UmbContentTypeModel, UmbPropertyTypeContainerModel } from '../../../types.js'; +import type { UmbContentTypeModel, UmbPropertyTypeContainerMergedModel } from '../../../types.js'; import type { UmbContentTypeContainerStructureHelper } from '../../../structure/index.js'; import { css, customElement, html, nothing, property, repeat, state, when } from '@umbraco-cms/backoffice/external/lit'; import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; @@ -11,16 +11,16 @@ import './content-type-design-editor-properties.element.js'; @customElement('umb-content-type-design-editor-group') export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement { @property({ attribute: false }) - public set group(value: UmbPropertyTypeContainerModel | undefined) { + public set group(value: UmbPropertyTypeContainerMergedModel | undefined) { if (value === this._group) return; this._group = value; - this._groupId = value?.id; + this._groupId = value?.ownerId ?? value?.ids[0]; this.#checkInherited(); } - public get group(): UmbPropertyTypeContainerModel | undefined { + public get group(): UmbPropertyTypeContainerMergedModel | undefined { return this._group; } - private _group?: UmbPropertyTypeContainerModel | undefined; + private _group?: UmbPropertyTypeContainerMergedModel | undefined; @property({ attribute: false }) public set groupStructureHelper(value: UmbContentTypeContainerStructureHelper | undefined) { @@ -45,7 +45,8 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement { @state() private _hasOwnerContainer?: boolean; - @state() + // attrbute is used by Sorter Controller in parent scope. + @property({ type: Boolean, reflect: true, attribute: 'inherited' }) private _inherited?: boolean; @state() @@ -54,48 +55,46 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement { #checkInherited() { if (this.groupStructureHelper && this.group) { // Check is this container matches with any other group. If so it is inherited aka. merged with others. [NL] - if (this.group.name) { - // We can first match with something if we have a name [NL] - this.observe( - this.groupStructureHelper.containersByNameAndType(this.group.name, 'Group'), - (containers) => { - const ownerContainer = containers.find((con) => this.groupStructureHelper!.isOwnerChildContainer(con.id)); - const hasAOwnerContainer = !!ownerContainer; - const pureOwnerContainer = hasAOwnerContainer && containers.length === 1; - - this._hasOwnerContainer = hasAOwnerContainer; - this._inherited = !pureOwnerContainer; - this._inheritedFrom = containers - .filter((con) => con.id !== ownerContainer?.id) - .map((con) => this.groupStructureHelper!.getContentTypeOfContainer(con.id)) - .filter((contentType) => contentType !== undefined) as Array; - }, - 'observeGroupContainers', - ); - } else { - // We use name match to determine inheritance, so no name cannot inherit. - this._inherited = false; + if (this.group.ownerId) { this._hasOwnerContainer = true; - this.removeUmbControllerByAlias('observeGroupContainers'); + } + + const notOwnerContainerIds = this.group.ids.filter((id) => id !== this.group!.ownerId); + + if (notOwnerContainerIds.length > 0) { + this._inheritedFrom = notOwnerContainerIds + .map((id) => this.groupStructureHelper!.getContentTypeOfContainer(id)) + .filter((contentType) => contentType !== undefined) as Array; + this._inherited = true; + } else { + this._inheritedFrom = undefined; + this._inherited = false; } } } #singleValueUpdate(propertyName: string, value: string | number | boolean | null | undefined) { - if (!this._groupStructureHelper || !this.group) return; + if (!this._groupStructureHelper || !this._group) return; + + const ownerId = this._group.ownerId; + if (!ownerId) return; const partialObject = {} as any; partialObject[propertyName] = value; - this._groupStructureHelper.partialUpdateContainer(this.group.id, partialObject); + this._groupStructureHelper.partialUpdateContainer(ownerId, partialObject); } #renameGroup(e: InputEvent) { if (!this.groupStructureHelper || !this._group) return; + const ownerId = this._group.ownerId; + if (!ownerId) return; let newName = (e.target as HTMLInputElement).value; + // TODO: This does not seem right, the detection of a unique name requires better awareness on the level of the change. [NL] + // This seem to use check for root containers. const changedName = this.groupStructureHelper .getStructureManager()! - .makeContainerNameUniqueForOwnerContentType(this._group.id, newName, 'Group', this._group.parent?.id ?? null); + .makeContainerNameUniqueForOwnerContentType(ownerId, newName); if (changedName) { newName = changedName; } @@ -105,11 +104,11 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement { #blurGroup(e: InputEvent) { if (!this.groupStructureHelper || !this._group) return; + const ownerId = this._group.ownerId; + if (!ownerId) return; const newName = (e.target as HTMLInputElement).value; if (newName === '') { - const changedName = this.groupStructureHelper - .getStructureManager()! - .makeEmptyContainerName(this._group.id, 'Group', this._group.parent?.id ?? null); + const changedName = this.groupStructureHelper.getStructureManager()!.makeEmptyContainerName(ownerId); this.#singleValueUpdate('name', changedName); (e.target as HTMLInputElement).value = changedName; } @@ -119,21 +118,22 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement { e.preventDefault(); e.stopImmediatePropagation(); if (!this.groupStructureHelper || !this._group) return; + if (this._group.ownerId === undefined) return; // TODO: Do proper localization here: [NL] await umbConfirmModal(this, { headline: `${this.localize.term('actions_delete')} group`, content: html` - Are you sure you want to delete the group ${this._group.name ?? this._group.id} + Are you sure you want to delete the group ${this._group.name ?? this._group.ownerId} `, confirmLabel: this.localize.term('actions_delete'), color: 'danger', }); - this.groupStructureHelper.removeContainer(this._group.id); + this.groupStructureHelper.removeContainer(this._group.ownerId); } override render() { @@ -277,6 +277,10 @@ export class UmbContentTypeWorkspaceViewEditGroupElement extends UmbLitElement { padding: var(--uui-size-space-4) var(--uui-size-space-5); } + :host([inherited]) div[slot='header'] { + cursor: default; + } + div[slot='header'] > div { display: flex; align-items: center; diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts index 49adf60673..75b3f5b8c8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-property.element.ts @@ -456,6 +456,10 @@ export class UmbContentTypeDesignEditorPropertyElement extends UmbLitElement { height: min-content; } + #header i { + opacity: 0.55; + } + #editor { position: relative; --uui-button-background-color: var(--uui-color-background); diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-tab.element.ts index 051f6caffc..34e8ddf56c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor-tab.element.ts @@ -1,5 +1,9 @@ import { UMB_CONTENT_TYPE_WORKSPACE_CONTEXT } from '../../content-type-workspace.context-token.js'; -import type { UmbContentTypeModel, UmbPropertyTypeContainerModel } from '../../../types.js'; +import type { + UmbContentTypeModel, + UmbPropertyTypeContainerMergedModel, + UmbPropertyTypeContainerModel, +} from '../../../types.js'; import { UmbContentTypeContainerStructureHelper } from '../../../structure/index.js'; import { UMB_CONTENT_TYPE_DESIGN_EDITOR_CONTEXT } from './content-type-design-editor.context-token.js'; import type { UmbContentTypeWorkspaceViewEditGroupElement } from './content-type-design-editor-group.element.js'; @@ -13,95 +17,122 @@ import type { UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; import './content-type-design-editor-properties.element.js'; import './content-type-design-editor-group.element.js'; -const SORTER_CONFIG: UmbSorterConfig = { - getUniqueOfElement: (element) => element.group?.id, - getUniqueOfModel: (modelEntry) => modelEntry.id, - // TODO: Make specific to the current owner document. [NL] - identifier: 'content-type-container-sorter', - itemSelector: 'umb-content-type-design-editor-group', - handleSelector: '.drag-handle', - containerSelector: '.container-list', -}; +const SORTER_CONFIG: UmbSorterConfig = + { + getUniqueOfElement: (element) => element.group?.key, + getUniqueOfModel: (modelEntry) => modelEntry.key, + // TODO: Make specific to the current owner document. [NL] + identifier: 'content-type-container-sorter', + itemSelector: 'umb-content-type-design-editor-group', + handleSelector: '.drag-handle', + disabledItemSelector: '[inherited]', // Inherited attribute is set by the umb-content-type-design-editor-group. + containerSelector: '.container-list', + }; @customElement('umb-content-type-design-editor-tab') export class UmbContentTypeDesignEditorTabElement extends UmbLitElement { - #sorter = new UmbSorterController(this, { - ...SORTER_CONFIG, - onChange: ({ model }) => { - this._groups = model; - }, - onEnd: ({ item }) => { - /*if (this._inherited === undefined) { + #sorter = new UmbSorterController( + this, + { + ...SORTER_CONFIG, + onChange: ({ model }) => { + this._groups = model; + }, + onEnd: ({ item }) => { + /*if (this._inherited === undefined) { throw new Error('OwnerTabId is not set, we have not made a local duplicated of this container.'); return; }*/ - /** - * Explanation: If the item is the first in list, we compare it to the item behind it to set a sortOrder. - * If it's not the first in list, we will compare to the item in before it, and check the following item to see if it caused overlapping sortOrder, then update - * the overlap if true, which may cause another overlap, so we loop through them till no more overlaps... - */ - const model = this._groups; - const newIndex = model.findIndex((entry) => entry.id === item.id); + /** + * Explanation: If the item is the first in list, we compare it to the item behind it to set a sortOrder. + * If it's not the first in list, we will compare to the item in before it, and check the following item to see if it caused overlapping sortOrder, then update + * the overlap if true, which may cause another overlap, so we loop through them till no more overlaps... + */ + const model = this._groups; + const newIndex = model.findIndex((entry) => entry.key === item.key); - // Doesn't exist in model - if (newIndex === -1) return; + // Doesn't exist in model + if (newIndex === -1) return; - // As origin we set prev sort order to -1, so if no other then our item will become 0 - let prevSortOrder = -1; + // As origin we set prev sort order to -1, so if no other then our item will become 0 + let prevSortOrder = -1; - // Not first in list - if (newIndex > 0 && model.length > 0) { - prevSortOrder = model[newIndex - 1].sortOrder; - } + // Not first in list + if (newIndex > 0 && model.length > 0) { + prevSortOrder = model[newIndex - 1].sortOrder; + } - // increase the prevSortOrder and use it for the moved item, - this.#groupStructureHelper.partialUpdateContainer(item.id, { - sortOrder: ++prevSortOrder, - }); + const ownerId = item.ownerId; - // Adjust everyone right after, meaning until there is a gap between the sortOrders: - let i = newIndex + 1; - let entry: UmbPropertyTypeContainerModel | undefined; - // As long as there is an item with the index & the sortOrder is less or equal to the prevSortOrder, we will update the sortOrder: - while ((entry = model[i]) !== undefined && entry.sortOrder <= prevSortOrder) { - // Increase the prevSortOrder and use it for the item: - this.#groupStructureHelper.partialUpdateContainer(entry.id, { + if (ownerId === undefined) { + // This may be possible later, but for now this is not possible. [NL] + throw new Error( + 'OwnerId is not set for the given container, we cannot move containers that are not owned by the current Document.', + ); + } + + // increase the prevSortOrder and use it for the moved item, + this.#groupStructureHelper.partialUpdateContainer(ownerId, { sortOrder: ++prevSortOrder, }); - i++; - } + // Adjust everyone right after, meaning until there is a gap between the sortOrders: + let i = newIndex + 1; + let entry: UmbPropertyTypeContainerMergedModel | undefined; + // As long as there is an item with the index & the sortOrder is less or equal to the prevSortOrder, we will update the sortOrder: + while ((entry = model[i]) !== undefined && entry.sortOrder <= prevSortOrder) { + // Only updated owned containers: + if (entry.ownerId) { + // Increase the prevSortOrder and use it for the item: + this.#groupStructureHelper.partialUpdateContainer(entry.ownerId, { + sortOrder: ++prevSortOrder, + }); + + i++; + } + } + }, + onRequestDrop: async ({ unique }) => { + const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT); + if (!context) { + throw new Error('Could not get Workspace Context'); + } + return context.structure.getMergedContainerById(unique) as UmbPropertyTypeContainerMergedModel | undefined; + }, + requestExternalRemove: async ({ item }) => { + const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT); + if (!context) { + throw new Error('Could not get Workspace Context'); + } + return await context.structure.removeContainer(null, item.ownerId, { preventRemovingProperties: true }).then( + () => true, + () => false, + ); + }, + requestExternalInsert: async ({ item }) => { + const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT); + if (!context) { + throw new Error('Could not get Workspace Context'); + } + if (item.ownerId === undefined) { + // This may be possible later, but for now this is not possible. [NL] + throw new Error('OwnerId is not set, we cannot move containers that are not owned by the current Document.'); + } + const parent = this.#containerId ? { id: this.#containerId } : null; + const containerModelItem: UmbPropertyTypeContainerModel = { + id: item.ownerId, + name: item.name, + sortOrder: item.sortOrder, + type: item.type, + parent, + }; + return await context.structure.insertContainer(null, containerModelItem).then( + () => true, + () => false, + ); + }, }, - onRequestDrop: async ({ unique }) => { - const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT); - if (!context) { - throw new Error('Could not get Workspace Context'); - } - return context.structure.getOwnerContainerById(unique); - }, - requestExternalRemove: async ({ item }) => { - const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT); - if (!context) { - throw new Error('Could not get Workspace Context'); - } - return await context.structure.removeContainer(null, item.id, { preventRemovingProperties: true }).then( - () => true, - () => false, - ); - }, - requestExternalInsert: async ({ item }) => { - const context = await this.getContext(UMB_CONTENT_TYPE_WORKSPACE_CONTEXT); - if (!context) { - throw new Error('Could not get Workspace Context'); - } - const parent = this.#containerId ? { id: this.#containerId } : null; - const updatedItem = { ...item, parent }; - return await context.structure.insertContainer(null, updatedItem).then( - () => true, - () => false, - ); - }, - }); + ); #workspaceModal?: UmbModalRouteRegistrationController< typeof UMB_WORKSPACE_MODAL.DATA, @@ -122,7 +153,7 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement { } @state() - private _groups: Array = []; + private _groups: Array = []; @state() private _hasProperties = false; @@ -170,7 +201,7 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement { }); this.observe( - this.#groupStructureHelper.mergedContainers, + this.#groupStructureHelper.childContainers, (groups) => { this._groups = groups; this.#sorter.setModel(this._groups); @@ -212,14 +243,14 @@ export class UmbContentTypeDesignEditorTabElement extends UmbLitElement {
${repeat( this._groups, - (group) => group.id, + (group) => group.ids[0], (group) => html` `, diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts index d37eef19a0..9f632ab6fc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts @@ -2,7 +2,7 @@ import { UMB_CONTENT_TYPE_WORKSPACE_CONTEXT } from '../../content-type-workspace import type { UmbContentTypeCompositionModel, UmbContentTypeModel, - UmbPropertyTypeContainerModel, + UmbPropertyTypeContainerMergedModel, } from '../../../types.js'; import { UmbContentTypeContainerStructureHelper, @@ -33,9 +33,9 @@ import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @customElement('umb-content-type-design-editor') export class UmbContentTypeDesignEditorElement extends UmbLitElement implements UmbWorkspaceViewElement { - #sorter = new UmbSorterController(this, { - getUniqueOfElement: (element) => element.getAttribute('data-umb-tab-id'), - getUniqueOfModel: (tab) => tab.id, + #sorter = new UmbSorterController(this, { + getUniqueOfElement: (element) => element.getAttribute('data-umb-tab-key'), + getUniqueOfModel: (tab) => tab.key, identifier: 'content-type-tabs-sorter', itemSelector: 'uui-tab', containerSelector: 'uui-tab-group', @@ -51,7 +51,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements * the overlap if true, which may cause another overlap, so we loop through them till no more overlaps... */ const model = this._tabs ?? []; - const newIndex = model.findIndex((entry) => entry.id === item.id); + const newIndex = model.findIndex((entry) => entry.key === item.key); // Doesn't exist in model if (newIndex === -1) return; @@ -64,20 +64,32 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements prevSortOrder = model[newIndex - 1].sortOrder; } + const ownerId = item.ownerId; + + if (ownerId === undefined) { + // This may be possible later, but for now this is not possible. [NL] + throw new Error( + 'OwnerId is not set for the given container, we cannot move containers that are not owned by the current Document.', + ); + } + // increase the prevSortOrder and use it for the moved item, - this.#tabsStructureHelper.partialUpdateContainer(item.id, { + this.#tabsStructureHelper.partialUpdateContainer(ownerId, { sortOrder: ++prevSortOrder, }); // Adjust everyone right after, until there is a gap between the sortOrders: [NL] let i = newIndex + 1; - let entry: UmbPropertyTypeContainerModel | undefined; + let entry: UmbPropertyTypeContainerMergedModel | undefined; // As long as there is an item with the index & the sortOrder is less or equal to the prevSortOrder, we will update the sortOrder: while ((entry = model[i]) !== undefined && entry.sortOrder <= prevSortOrder) { - // Increase the prevSortOrder and use it for the item: - this.#tabsStructureHelper.partialUpdateContainer(entry.id, { - sortOrder: ++prevSortOrder, - }); + // Only updated owned containers: + if (entry.ownerId) { + // Increase the prevSortOrder and use it for the item: + this.#tabsStructureHelper.partialUpdateContainer(entry.ownerId, { + sortOrder: ++prevSortOrder, + }); + } i++; } @@ -105,7 +117,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements private _routes: UmbRoute[] = []; @state() - private _tabs?: Array; + private _tabs?: Array; @state() private _routerPath?: string; @@ -136,7 +148,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements this.#tabsStructureHelper.setContainerChildType('Tab'); this.#tabsStructureHelper.setIsRoot(true); - this.observe(this.#tabsStructureHelper.mergedContainers, (tabs) => { + this.observe(this.#tabsStructureHelper.childContainers, (tabs) => { this._tabs = tabs; this.#sorter.setModel(tabs); this.#createRoutes(); @@ -180,7 +192,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements if (this._tabs.length > 0) { this._tabs?.forEach((tab) => { const tabName = tab.name && tab.name !== '' ? tab.name : '-'; - if (tab.id === this.#processingTabId) { + if (tab.ownerId && tab.ownerId === this.#processingTabId) { activeTabName = tabName; } routes.push({ @@ -188,7 +200,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements component: () => import('./content-type-design-editor-tab.element.js'), setup: (component) => { this.#currentTabComponent = component as UmbContentTypeDesignEditorTabElement; - this.#currentTabComponent.containerId = tab.id; + this.#currentTabComponent.containerId = tab.ownerId ?? tab.ids[0]; }, }); }); @@ -265,8 +277,8 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements } } - async #requestDeleteTab(tab: UmbPropertyTypeContainerModel | undefined) { - if (!tab) return; + async #requestDeleteTab(tab: UmbPropertyTypeContainerMergedModel | undefined) { + if (!tab || !tab.ownerId) return; // TODO: Localize this: const tabName = tab.name === '' ? 'Unnamed' : tab.name; // TODO: Localize this: @@ -288,10 +300,9 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements await umbConfirmModal(this, modalData); - this.#deleteTab(tab?.id); + this.#deleteTab(tab.ownerId); } - #deleteTab(tabId?: string) { - if (!tabId) return; + #deleteTab(tabId: string) { this.#workspaceContext?.structure.removeContainer(null, tabId); if (this.#processingTabId === tabId) { this.#processingTabId = undefined; @@ -332,12 +343,13 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements }, 100); } - async #tabNameChanged(event: InputEvent, tab: UmbPropertyTypeContainerModel) { - this.#processingTabId = tab.id; + async #tabNameChanged(event: InputEvent, tab: UmbPropertyTypeContainerMergedModel) { + if (!this.#workspaceContext || !tab.ownerId) return; + this.#processingTabId = tab.ownerId; let newName = (event.target as HTMLInputElement).value; - const changedName = this.#workspaceContext?.structure.makeContainerNameUniqueForOwnerContentType( - tab.id, + const changedName = this.#workspaceContext.structure.makeContainerNameUniqueForOwnerContentType( + tab.ownerId, newName, 'Tab', ); @@ -349,20 +361,20 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements (event.target as HTMLInputElement).value = newName; } - this.#tabsStructureHelper.partialUpdateContainer(tab.id!, { + this.#tabsStructureHelper.partialUpdateContainer(tab.ownerId, { name: newName, }); } - async #tabNameBlur(event: FocusEvent, tab: UmbPropertyTypeContainerModel) { - if (!this.#processingTabId) return; + async #tabNameBlur(event: FocusEvent, tab: UmbPropertyTypeContainerMergedModel) { + if (!this.#processingTabId || !tab.ownerId) return; const newName = (event.target as HTMLInputElement | undefined)?.value; if (newName === '') { const changedName = this.#workspaceContext!.structure.makeEmptyContainerName(this.#processingTabId, 'Tab'); (event.target as HTMLInputElement).value = changedName; - this.#tabsStructureHelper.partialUpdateContainer(tab.id!, { + this.#tabsStructureHelper.partialUpdateContainer(tab.ownerId, { name: changedName, }); } @@ -506,7 +518,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements ${this.renderRootTab()} ${repeat( this._tabs, - (tab) => tab.id, + (tab) => tab.ownerId ?? tab.ids[0], (tab) => this.renderTab(tab), )} @@ -535,16 +547,17 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements `; } - renderTab(tab: UmbPropertyTypeContainerModel) { + renderTab(tab: UmbPropertyTypeContainerMergedModel) { const path = this._routerPath + '/tab/' + encodeFolderName(tab.name && tab.name !== '' ? tab.name : '-'); const tabActive = path === this._activePath; - const ownedTab = this.#tabsStructureHelper.isOwnerChildContainer(tab.id!) ?? false; + const ownedTab = tab.ownerId ? true : false; return html` this.#onDragOver(event, path)}> @@ -552,14 +565,15 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements `; } - renderTabInner(tab: UmbPropertyTypeContainerModel, tabActive: boolean, ownedTab: boolean) { + renderTabInner(tab: UmbPropertyTypeContainerMergedModel, tabActive: boolean, ownedTab: boolean) { // TODO: Localize this: const hasTabName = tab.name && tab.name !== ''; const tabName = hasTabName ? tab.name : 'Unnamed'; + const tabId = tab.ownerId ?? tab.ids[0]; if (this._sortModeActive) { return html`
${ownedTab - ? html` ${tabName} + ? html` ${tabName} (this); @state() - private _groups: Array = []; + private _groups: Array = []; @state() private _hasProperties = false; @@ -42,7 +42,7 @@ export class UmbContentWorkspaceViewEditTabElement extends UmbLitElement { workspaceContext?.structure as unknown as UmbContentTypeStructureManager, ); }); - this.observe(this.#groupStructureHelper.mergedContainers, (groups) => { + this.observe(this.#groupStructureHelper.childContainers, (groups) => { this._groups = groups; }); this.observe(this.#groupStructureHelper.hasProperties, (hasProperties) => { @@ -63,12 +63,12 @@ export class UmbContentWorkspaceViewEditTabElement extends UmbLitElement { : ''} ${repeat( this._groups, - (group) => group.id, + (group) => group.key, (group) => html` + .containerId=${group.ids[0]}> `, )} `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts index dce11b6601..f5b9941d44 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor.element.ts @@ -4,7 +4,7 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbContentTypeModel, UmbContentTypeStructureManager, - UmbPropertyTypeContainerModel, + UmbPropertyTypeContainerMergedModel, } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypeContainerStructureHelper, @@ -34,7 +34,7 @@ export class UmbContentWorkspaceViewEditElement extends UmbLitElement implements private _routes: UmbRoute[] = []; @state() - private _tabs?: Array; + private _tabs?: Array; @state() private _routerPath?: string; @@ -64,7 +64,7 @@ export class UmbContentWorkspaceViewEditElement extends UmbLitElement implements this._tabsStructureHelper.setIsRoot(true); this._tabsStructureHelper.setContainerChildType('Tab'); this.observe( - this._tabsStructureHelper.mergedContainers, + this._tabsStructureHelper.childContainers, (tabs) => { this._tabs = tabs; this.#createRoutes(); @@ -117,7 +117,7 @@ export class UmbContentWorkspaceViewEditElement extends UmbLitElement implements path, component: () => import('./content-editor-tab.element.js'), setup: (component) => { - (component as UmbContentWorkspaceViewEditTabElement).containerId = tab.id; + (component as UmbContentWorkspaceViewEditTabElement).containerId = tab.ownerId ?? tab.ids[0]; }, }); this.#createViewContext(path); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/stored-path.function.ts b/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/stored-path.function.ts index e143ee3920..6f485bf991 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/stored-path.function.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/stored-path.function.ts @@ -35,7 +35,7 @@ export function setStoredPath(path: string): void { * Redirect the user to the stored path or the base path if not available. * If the basePath matches the start of the stored path, the browser will replace the state instead of redirecting. * @param {string} basePath - The base path to redirect to if no stored path is available. - * @param {boolean} [force] - If true, will redirect using Location + * @param {boolean} force - If true, will redirect using Location */ export function redirectToStoredPath(basePath: string, force = false): void { const url = retrieveStoredPath(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-editor/workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-editor/workspace-editor.element.ts index da8ecccf87..72276e6ac8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-editor/workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-editor/workspace-editor.element.ts @@ -213,8 +213,9 @@ export class UmbWorkspaceEditorElement extends UmbLitElement { } #renderRoutes() { - if (!this._routes || this._routes.length === 0 || !this._workspaceViews || this._workspaceViews.length === 0) + if (!this._routes || this._routes.length === 0 || !this._workspaceViews || this._workspaceViews.length === 0) { return nothing; + } return html`