diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts index 072b9d347c..fcb3cf1843 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/structure/content-type-container-structure-helper.class.ts @@ -12,21 +12,21 @@ export class UmbContentTypeContainerStructureHelper void; - _containerId?: string | null; - _childType?: UmbPropertyContainerTypes = 'Group'; + #containerId?: string | null; + #childType?: UmbPropertyContainerTypes = 'Group'; #structure?: UmbContentTypeStructureManager; // State containing the all containers defined in the data: - #containers = new UmbArrayState([], (x) => x.id); - readonly containers = this.#containers.asObservable(); + #childContainers = new UmbArrayState([], (x) => x.id); + readonly containers = this.#childContainers.asObservable(); // State containing the merged containers (only one pr. name): - #mergedContainers = new UmbArrayState([], (x) => x.id); - readonly mergedContainers = this.#mergedContainers.asObservable(); + #mergedChildContainers = new UmbArrayState([], (x) => x.id); + readonly mergedContainers = this.#mergedChildContainers.asObservable(); // Owner containers are containers owned by the owner Content Type (The specific one up for editing) - private _ownerContainers: UmbPropertyTypeContainerModel[] = []; + #ownerChildContainers: UmbPropertyTypeContainerModel[] = []; #hasProperties = new UmbBooleanState(false); readonly hasProperties = this.#hasProperties.asObservable(); @@ -37,7 +37,7 @@ export class UmbContentTypeContainerStructureHelper (a.sortOrder || 0) - (b.sortOrder || 0)); + this.#mergedChildContainers.sortBy((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)); this.observe(this.containers, this.#performContainerMerge, null); } @@ -64,73 +64,73 @@ export class UmbContentTypeContainerStructureHelper { if (container) { - this._containerName = container.name ?? ''; - this._containerType = container.type; + this.#containerName = container.name ?? ''; + this.#containerType = container.type; if (container.parent) { // We have a parent for our main container, so lets observe that one as well: this.observe( this.#structure!.containerById(container.parent.id), (parent) => { if (parent) { - this._parentName = parent.name ?? ''; - this._parentType = parent.type; + this.#parentName = parent.name ?? ''; + this.#parentType = parent.type; this.#observeSimilarContainers(); } else { this.removeUmbControllerByAlias('_observeContainers'); - this._parentName = undefined; - this._parentType = undefined; + this.#parentName = undefined; + this.#parentType = undefined; } }, '_observeMainParentContainer', ); } else { this.removeUmbControllerByAlias('_observeMainParentContainer'); - this._parentName = null; //In this way we want to look for one without a parent. [NL] - this._parentType = undefined; + this.#parentName = null; //In this way we want to look for one without a parent. [NL] + this.#parentType = undefined; this.#observeSimilarContainers(); } } else { this.removeUmbControllerByAlias('_observeContainers'); - this._containerName = undefined; - this._containerType = undefined; + this.#containerName = undefined; + this.#containerType = undefined; // TODO: reset has Properties. this.#hasProperties.setValue(false); } @@ -141,30 +141,37 @@ export class UmbContentTypeContainerStructureHelper { // We want to remove hasProperties of groups that does not exist anymore.: // this.#removeHasPropertiesOfGroup() this.#hasProperties.setValue(false); - this.#containers.setValue([]); + this.#childContainers.setValue([]); containers.forEach((container) => { this.#observeHasPropertiesOf(container.id); this.observe( - this.#structure!.containersOfParentId(container.id, this._childType!), + this.#structure!.containersOfParentId(container.id, this.#childType!), (containers) => { - // Remove existing containers that are not the parent of the new containers: - this.#containers.filter((x) => x.parent?.id !== container.id || containers.some((y) => y.id === x.id)); + // observe direct owner containers of this container id: + this.#ownerChildContainers = + this.#structure!.getOwnerContainers(this.#childType!, this.#containerId!) ?? []; + // TODO: Maybe check for dif before setting it? - this.#containers.append(containers); + // Remove existing containers that are not the parent of the new containers: + this.#childContainers.filter( + (x) => x.parent?.id !== container.id || containers.some((y) => y.id === x.id), + ); + + this.#childContainers.append(containers); }, '_observeGroupsOf_' + container.id, ); @@ -175,16 +182,16 @@ export class UmbContentTypeContainerStructureHelper { // Here (When getting root containers) we get containers from all ContentTypes. It also means we need to do an extra filtering to ensure we only get one of each containers. [NL] // For that we get the owner containers first (We do not need to observe as this observation will be triggered if one of the owner containers change) [NL] - this._ownerContainers = this.#structure!.getOwnerContainers(this._childType!, this._containerId!) ?? []; - this.#containers.setValue(rootContainers); + this.#ownerChildContainers = this.#structure!.getOwnerContainers(this.#childType!, this.#containerId!) ?? []; + this.#childContainers.setValue(rootContainers); }, '_observeRootContainers', ); @@ -204,10 +211,10 @@ export class UmbContentTypeContainerStructureHelper) { - return this._ownerContainers.length > 0 + return this.#ownerChildContainers.length > 0 ? containers.filter( (anyCon) => - !this._ownerContainers.some( + !this.#ownerChildContainers.some( (ownerCon) => // Then if this is not the owner container but matches one by name & type, then we do not want it. ownerCon.id !== anyCon.id && ownerCon.name === anyCon.name && ownerCon.type === anyCon.type, @@ -222,7 +229,7 @@ export class UmbContentTypeContainerStructureHelper i === cons.findIndex((y) => y.name === x.name && y.type === x.type)); - this.#mergedContainers.setValue(merged); + this.#mergedChildContainers.setValue(merged); }; /** @@ -230,11 +237,11 @@ export class UmbContentTypeContainerStructureHelper x.id === containerId); + return this.#ownerChildContainers.some((x) => x.id === containerId); } containersByNameAndType(name: string, type: UmbPropertyContainerTypes) { - return this.#containers.asObservablePart((cons) => cons.filter((x) => x.name === name && x.type === type)); + return this.#childContainers.asObservablePart((cons) => cons.filter((x) => x.name === name && x.type === type)); } /** Manipulate methods: */ @@ -252,7 +259,7 @@ export class UmbContentTypeContainerStructureHelper x.unique === contentTypeUnique)?.containers ?? []; - const containers = frozenContainers.filter((x) => x.id !== containerId); + const contentType = this.#contentTypes.getValue().find((x) => x.unique === contentTypeUnique); + if (!contentType) { + throw new Error('Could not find the Content Type to remove container from'); + } + const frozenContainers = contentType.containers ?? []; + const containers = frozenContainers.filter((x) => x.id !== containerId || x.parent?.id !== containerId); + + const frozenProperties = contentType.properties ?? []; + const properties = frozenProperties.filter((x) => x.container?.id !== containerId); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore // TODO: fix TS partial complaint - this.#contentTypes.updateOne(contentTypeUnique, { containers }); + this.#contentTypes.updateOne(contentTypeUnique, { containers, properties }); } createPropertyScaffold(containerId: string | null = null) { @@ -424,7 +430,7 @@ export class UmbContentTypeStructureManager< await this.#init; contentTypeUnique = contentTypeUnique ?? this.#ownerContentTypeUnique!; - // If we have a container, we need to ensure it exists, and then update the container with the new parent id. + // If we have a container, we need to ensure it exists, and then update the container with the new parent id. [NL] if (containerId) { const container = await this.ensureContainerOf(containerId, contentTypeUnique); if (!container) { @@ -455,7 +461,7 @@ export class UmbContentTypeStructureManager< await this.#init; contentTypeUnique = contentTypeUnique ?? this.#ownerContentTypeUnique!; - // If we have a container, we need to ensure it exists, and then update the container with the new parent id. + // If we have a container, we need to ensure it exists, and then update the container with the new parent id. [NL] if (property.container) { const container = await this.ensureContainerOf(property.container.id, contentTypeUnique); if (!container) { @@ -501,7 +507,6 @@ export class UmbContentTypeStructureManager< const frozenProperties = this.#contentTypes.getValue().find((x) => x.unique === contentTypeUnique)?.properties ?? []; - const properties = partialUpdateFrozenArray(frozenProperties, partialUpdate, (x) => x.id === propertyId); // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts index 989c770b23..02bfa20407 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/workspace/views/design/content-type-design-editor.element.ts @@ -167,7 +167,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements if (!this.#workspaceContext || !this._tabs || this._hasRootGroups === undefined) return; const routes: UmbRoute[] = []; - // We gather the activeTab name to check for rename, this is a bit hacky way to redirect the user without noticing to the new name [NL] + // We gather the activeTab name to check for rename, this is a bit hacky way to redirect the user without noticing the url changes to the new name [NL] let activeTabName: string | undefined = undefined; if (this._tabs.length > 0) { @@ -180,8 +180,6 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements path: `tab/${encodeFolderName(tabName).toString()}`, component: () => import('./content-type-design-editor-tab.element.js'), setup: (component) => { - // Or just cache the current view here, and use it if the same is begin requested?. [NL] - //(component as UmbContentTypeDesignEditorTabElement).tabName = tabName; (component as UmbContentTypeDesignEditorTabElement).containerId = tab.id; }, }); @@ -192,7 +190,6 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements path: 'root', component: () => import('./content-type-design-editor-tab.element.js'), setup: (component) => { - //(component as UmbContentTypeDesignEditorTabElement).noTabName = true; (component as UmbContentTypeDesignEditorTabElement).containerId = null; }, }); @@ -220,7 +217,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements if (oldPath !== newPath) { // Lets cheat a bit and update the activePath already, in this way our input does not loose focus [NL] this._activePath = this._routerPath + newPath; - // Update the current URL, so we are still on this specific tab: + // Update the current URL, so we are still on this specific tab: [NL] window.history.replaceState(null, '', this._activePath); // TODO: We have some flickering when renaming, this could potentially be fixed if we cache the view and re-use it if the same is requested [NL] // Or maybe its just about we just send the updated tabName to the view, and let it handle the update itself [NL] @@ -247,7 +244,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements color: 'danger', }; - // TODO: If this tab is composed of other tabs, then notify that it will only delete the local tab. + // TODO: If this tab is composed of other tabs, then notify that it will only delete the local tab. [NL] await umbConfirmModal(this, modalData); @@ -256,13 +253,13 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements #remove(tabId?: string) { if (!tabId) return; this.#workspaceContext?.structure.removeContainer(null, tabId); - // TODO: We should only navigate away if it was the last tab and if it was the active one... + // TODO: We should only navigate away if it was the last tab and if it was the active one... [NL] this._tabsStructureHelper?.isOwnerChildContainer(tabId) ? window.history.replaceState(null, '', this._routerPath + (this._routes[0]?.path ?? '/root')) : ''; } async #addTab() { - // If there is already a Tab with no name, then focus it instead of adding a new one: + // If there is already a Tab with no name, then focus it instead of adding a new one: [NL] // TODO: Optimize this so it looks at the data instead of the DOM [NL] const inputEl = this.shadowRoot?.querySelector('uui-tab[active] uui-input') as UUIInputElement; if (inputEl?.value === '') { @@ -456,7 +453,7 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements value=${ifDefined(tab.sortOrder)} style="width:50px" @change=${(e: UUIInputEvent) => this.#changeOrderNumber(tab, e)}>` - : html`${tab.name!}`} + : html`${tab.name!}`} `; }