From 9fbdd270a14b62a29cffbbe659e3ff71d4c5873a Mon Sep 17 00:00:00 2001 From: leekelleher Date: Tue, 12 Mar 2024 11:22:55 +0000 Subject: [PATCH 01/13] Adds `UmbReferenceByUniqueAndType` interface --- src/Umbraco.Web.UI.Client/src/packages/core/models/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/models/index.ts index da63c4ae49..443a993919 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/models/index.ts @@ -23,3 +23,8 @@ export interface NumberRangeValueType { export interface UmbReferenceByUnique { unique: string; } + +export interface UmbReferenceByUniqueAndType { + type: string; + unique: string; +} From f72eba67506821bd1b7f2902a59bc1981033d755 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Tue, 12 Mar 2024 11:24:29 +0000 Subject: [PATCH 02/13] TreePicker: refactored workspace context retrieval As it is only being used to get the current entity's unique ID. --- .../property-editor-ui-tree-picker.element.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts index d1952c415c..f13df12ed8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts @@ -42,8 +42,6 @@ export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implemen #dynamicRootRepository = new UmbDynamicRootRepository(this); - #workspaceContext?: typeof UMB_WORKSPACE_CONTEXT.TYPE; - @property({ attribute: false }) public set config(config: UmbPropertyEditorConfigCollection | undefined) { const startNode: UmbTreePickerSource | undefined = config?.getValueByAlias('startNode'); @@ -62,14 +60,6 @@ export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implemen this.ignoreUserStartNodes = config?.getValueByAlias('ignoreUserStartNodes'); } - constructor() { - super(); - - this.consumeContext(UMB_WORKSPACE_CONTEXT, (workspaceContext) => { - this.#workspaceContext = workspaceContext; - }); - } - connectedCallback() { super.connectedCallback(); @@ -79,9 +69,10 @@ export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implemen async #setStartNodeId() { if (this.startNodeId) return; - const unique = this.#workspaceContext?.getUnique(); // TODO: Awaiting the workspace context to have a parent entity ID value. [LK] // e.g. const parentEntityId = this.#workspaceContext?.getParentEntityId(); + const workspaceContext = await this.getContext(UMB_WORKSPACE_CONTEXT); + const unique = workspaceContext.getUnique(); if (unique && this.#dynamicRoot) { const result = await this.#dynamicRootRepository.postDynamicRootQuery(this.#dynamicRoot, unique); if (result && result.length > 0) { From 7191f2173f014b114254bcc76cc276c58dd5881d Mon Sep 17 00:00:00 2001 From: leekelleher Date: Tue, 12 Mar 2024 11:26:30 +0000 Subject: [PATCH 03/13] TreePicker: refactored to use updated data structure value e.g. `[ { type: 'document', unique: 'a3a37004-139f-4254-ba56-3ed381b3007c' } ]` --- .../property-editor-ui-tree-picker.element.ts | 10 ++-- .../input-tree/input-tree.element.ts | 46 +++++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts index f13df12ed8..0a7819007b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tree-picker/property-editor-ui-tree-picker.element.ts @@ -11,11 +11,10 @@ import type { UmbTreePickerSource } from '@umbraco-cms/backoffice/components'; /** * @element umb-property-editor-ui-tree-picker */ - @customElement('umb-property-editor-ui-tree-picker') export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { - @property() - value = ''; + @property({ type: Array }) + value: UmbInputTreeElement['items'] = []; @state() type: UmbTreePickerSource['type'] = 'content'; @@ -82,13 +81,14 @@ export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implemen } #onChange(e: CustomEvent) { - this.value = (e.target as UmbInputTreeElement).value as string; + const input = e.target as UmbInputTreeElement; + this.value = input.items; this.dispatchEvent(new UmbPropertyValueChangeEvent()); } render() { return html`) { + this.#selectedIds = items?.map((item) => item.unique) ?? []; + this.value = items?.map((item) => item.unique).join(','); } - public get value(): string { - return super.value as string; + public get items(): Array { + return this.#selectedIds.map((id) => ({ type: this.#entityTypeLookup[this._type], unique: id })); } - selectedIds: Array = []; + #selectedIds: Array = []; #onChange(event: CustomEvent) { switch (this._type) { case 'content': - this.value = (event.target as UmbInputDocumentElement).selectedIds.join(','); + { + const input = event.target as UmbInputDocumentElement; + this.#selectedIds = input.selectedIds; + this.value = input.selectedIds.join(','); + } break; - case 'media': - this.value = (event.target as UmbInputMediaElement).selectedIds.join(','); + case 'media': { + const input = event.target as UmbInputMediaElement; + this.#selectedIds = input.selectedIds; + this.value = input.selectedIds.join(','); break; - case 'member': - this.value = (event.target as UmbInputMemberElement).selectedIds.join(','); + } + case 'member': { + const input = event.target as UmbInputMemberElement; + this.#selectedIds = input.selectedIds; + this.value = input.selectedIds.join(','); break; + } default: break; } @@ -102,7 +110,7 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) { #renderContentPicker() { return html` Date: Tue, 12 Mar 2024 11:26:53 +0000 Subject: [PATCH 04/13] TreePicker: Input element tidyup --- .../tree/components/input-tree/input-tree.element.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/components/input-tree/input-tree.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/components/input-tree/input-tree.element.ts index d9a568da77..b3abc71622 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/components/input-tree/input-tree.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/components/input-tree/input-tree.element.ts @@ -1,10 +1,11 @@ -import type { UmbInputMemberElement } from '@umbraco-cms/backoffice/member'; import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document'; import type { UmbInputMediaElement } from '@umbraco-cms/backoffice/media'; -import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import type { UmbInputMemberElement } from '@umbraco-cms/backoffice/member'; +import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; import type { UmbTreePickerSource } from '@umbraco-cms/backoffice/components'; @customElement('umb-input-tree') @@ -98,7 +99,7 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) { render() { switch (this._type) { case 'content': - return this.#renderContentPicker(); + return this.#renderDocumentPicker(); case 'media': return this.#renderMediaPicker(); case 'member': @@ -108,7 +109,7 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) { } } - #renderContentPicker() { + #renderDocumentPicker() { return html` Date: Thu, 14 Mar 2024 09:53:47 +0100 Subject: [PATCH 05/13] user --- .../packages/user/user/workspace/user-workspace.context.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts index 2b1a3249f4..b340b7fdb3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts @@ -45,7 +45,11 @@ export class UmbUserWorkspaceContext There might be a less manual way to do this. */ onUserStoreChanges(user: EntityType | undefined) { - if (!user) return; + if (!user) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r + history.pushState(null, '', 'section/user-management'); + return; + } this.#currentData.update({ state: user.state, avatarUrls: user.avatarUrls }); } From 7d76801654f15e16233168395a5e792768377654 Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:53:52 +0100 Subject: [PATCH 06/13] member --- .../members/member/workspace/member-workspace.context.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member-workspace.context.ts index 3202306a63..bfcd963786 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member-workspace.context.ts @@ -128,6 +128,7 @@ export class UmbMemberWorkspaceContext #onMemberStoreChange(member: EntityType | undefined) { if (!member) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r history.pushState(null, '', 'section/member-management'); } } From 39622a3efca7ffae6569c97c098edfade1fcc255 Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:53:58 +0100 Subject: [PATCH 07/13] member type --- .../member-type-workspace.context.ts | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/member-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/member-type-workspace.context.ts index a7f13d0df2..a60facd921 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/member-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/workspace/member-type-workspace.context.ts @@ -72,13 +72,25 @@ export class UmbMemberTypeWorkspaceContext } async load(unique: string) { - const { data } = await this.structure.loadType(unique); - if (!data) return undefined; this.resetState(); + const { data, asObservable } = await this.structure.loadType(unique); - this.setIsNew(false); - this.setIsSorting(false); - return { data } || undefined; + if (data) { + this.setIsNew(false); + this.setIsSorting(false); + this.#persistedData.update(data); + } + + if (asObservable) { + this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'umbMemberTypeStoreObserver'); + } + } + + #onStoreChange(entity: EntityType | undefined) { + if (!entity) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r + history.pushState(null, '', 'section/settings/workspace/member-type-root'); + } } async create(parent: { entityType: string; unique: string | null }) { From 046468d8e9fba0157083cb1024939fe4317e7e9c Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:54:04 +0100 Subject: [PATCH 08/13] media --- .../workspace/media-workspace.context.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts index bf13bd9675..9acbe98e67 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts @@ -125,13 +125,23 @@ export class UmbMediaWorkspaceContext async load(unique: string) { this.resetState(); this.#getDataPromise = this.repository.requestByUnique(unique); - const { data } = await this.#getDataPromise; - if (!data) return undefined; + type GetDataType = Awaited>; + const { data, asObservable } = (await this.#getDataPromise) as GetDataType; - this.setIsNew(false); - this.#persistedData.setValue(data); - this.#currentData.setValue(data); - return data || undefined; + if (data) { + this.setIsNew(false); + this.#persistedData.update(data); + this.#currentData.update(data); + } + + this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'umbMediaStoreObserver'); + } + + #onStoreChange(entity: EntityType | undefined) { + if (!entity) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r + history.pushState(null, '', 'section/media'); + } } async create(parent: { entityType: string; unique: string | null }, mediaTypeUnique: string) { From 5f4bd89c3d2906fc2a2edbc27bd9e7761753219b Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:54:10 +0100 Subject: [PATCH 09/13] media type --- .../workspace/media-type-workspace.context.ts | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts index 374818b70e..118eba2c76 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts @@ -127,15 +127,26 @@ export class UmbMediaTypeWorkspaceContext return data; } - async load(entityId: string) { + async load(unique: string) { this.resetState(); - const { data } = await this.structure.loadType(entityId); - if (!data) return undefined; + const { data, asObservable } = await this.structure.loadType(unique); - this.setIsNew(false); - this.setIsSorting(false); - this.#persistedData.setValue(data); - return data; + if (data) { + this.setIsNew(false); + this.setIsSorting(false); + this.#persistedData.update(data); + } + + if (asObservable) { + this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'umbMediaTypeStoreObserver'); + } + } + + #onStoreChange(entity: EntityType | undefined) { + if (!entity) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r + history.pushState(null, '', 'section/settings/workspace/media-type-root'); + } } /** From 8b44f4653405ff0265eccfa6aa8d99dc5aa5ef25 Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:54:17 +0100 Subject: [PATCH 10/13] document --- .../workspace/document-workspace.context.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 3b754584e3..5e09023145 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -141,13 +141,23 @@ export class UmbDocumentWorkspaceContext async load(unique: string) { this.resetState(); this.#getDataPromise = this.repository.requestByUnique(unique); - const { data } = await this.#getDataPromise; - if (!data) return undefined; + type GetDataType = Awaited>; + const { data, asObservable } = (await this.#getDataPromise) as GetDataType; - this.setIsNew(false); - this.#persistedData.setValue(data); - this.#currentData.setValue(data); - return data || undefined; + if (data) { + this.setIsNew(false); + this.#persistedData.update(data); + this.#currentData.update(data); + } + + this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'umbDocumentStoreObserver'); + } + + #onStoreChange(entity: EntityType | undefined) { + if (!entity) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r + history.pushState(null, '', 'section/content'); + } } async create(parent: { entityType: string; unique: string | null }, documentTypeUnique: string) { From debaf427faae3ae6a3572a278fce23efe0fe2ace Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:54:22 +0100 Subject: [PATCH 11/13] document type --- .../document-type-workspace.context.ts | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts index d2951889a3..7c1fb653a5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts @@ -166,13 +166,24 @@ export class UmbDocumentTypeWorkspaceContext async load(unique: string) { this.resetState(); - const { data } = await this.structure.loadType(unique); - if (!data) return undefined; + const { data, asObservable } = await this.structure.loadType(unique); - this.setIsNew(false); - this.setIsSorting(false); - this.#persistedData.setValue(data); - return data; + if (data) { + this.setIsNew(false); + this.setIsSorting(false); + this.#persistedData.update(data); + } + + if (asObservable) { + this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'umbDocumentTypeStoreObserver'); + } + } + + #onStoreChange(entity: EntityType | undefined) { + if (!entity) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r + history.pushState(null, '', 'section/settings/workspace/document-type-root'); + } } /** From 25737909cbd7e76e999ba98b401c3d2d5e761bbe Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:54:27 +0100 Subject: [PATCH 12/13] data type --- .../workspace/data-type-workspace.context.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts index 221f429d13..8748f9cfd9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/data-type/workspace/data-type-workspace.context.ts @@ -178,14 +178,27 @@ export class UmbDataTypeWorkspaceContext async load(unique: string) { this.resetState(); - const request = this.repository.requestByUnique(unique); - this.#getDataPromise = request; - const { data } = await request; + this.#getDataPromise = this.repository.requestByUnique(unique); + type GetDataType = Awaited>; + const { data, asObservable } = (await this.#getDataPromise) as GetDataType; if (!data) return undefined; - this.setIsNew(false); - this.#persistedData.setValue(data); - this.#currentData.setValue(data); + if (data) { + this.setIsNew(false); + this.#persistedData.setValue(data); + this.#currentData.setValue(data); + } + + if (asObservable) { + this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'umbDataTypeStoreObserver'); + } + } + + #onStoreChange(entity: EntityType | undefined) { + if (!entity) { + //TODO: This solution is alright for now. But reconsider when we introduce signal-r + history.pushState(null, '', 'section/settings/workspace/data-type-root'); + } } async create(parent: { entityType: string; unique: string | null }) { From dcce7ec7e1b932ef25fe3994884b2e43739e18e9 Mon Sep 17 00:00:00 2001 From: JesmoDev <26099018+JesmoDev@users.noreply.github.com> Date: Thu, 14 Mar 2024 09:54:38 +0100 Subject: [PATCH 13/13] add asObservable --- .../core/content-type/content-type-structure-manager.class.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts index 4bbc6e7abb..9b5db6402c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts @@ -129,11 +129,11 @@ export class UmbContentTypePropertyStructureManager