From 6b450ed8032ec8c275b032576aa1e1ec68dd7790 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Sep 2025 11:13:08 +0200 Subject: [PATCH 01/76] set property type unique on context --- .../property-type-based-property.context.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts index e1e101b4b71d..2e6980a4bbe3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts @@ -1,10 +1,13 @@ import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from './property-type-based-property.context-token.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; -import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; export class UmbPropertyTypeBasedPropertyContext extends UmbContextBase { + #unique = new UmbStringState(undefined); + unique = this.#unique.asObservable(); + #dataType = new UmbObjectState(undefined); dataType = this.#dataType.asObservable(); @@ -12,6 +15,22 @@ export class UmbPropertyTypeBasedPropertyContext extends UmbContextBase { super(host, UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT); } + /** + * Sets the unique identifier of the Property Type + * @param unique - The unique identifier of the Property Type + */ + setUnique(unique: string | undefined) { + this.#unique.setValue(unique); + } + + /** + * Gets the unique identifier of the Property Type + * @returns {string | undefined} The unique identifier of the Property Type + */ + getUnique(): string | undefined { + return this.#unique.getValue(); + } + setDataType(dataType: UmbPropertyTypeModel['dataType'] | undefined) { this.#dataType.setValue(dataType); } From 7affbcf54d1a05244ba3c4fef807e436117879a1 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Sep 2025 11:13:26 +0200 Subject: [PATCH 02/76] set the value --- .../property-type-based-property.element.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts index fea5d1fa3271..a74727636802 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts @@ -16,6 +16,9 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement { public set property(value: UmbPropertyTypeModel | undefined) { const oldProperty = this._property; this._property = value; + + this.#context.setUnique(this._property?.unique); + if (this._property?.dataType.unique !== oldProperty?.dataType.unique) { this._observeDataType(this._property?.dataType.unique); } From 46e76676314d0e473d33f2c6a9897b6a448d7be4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Sep 2025 11:14:49 +0200 Subject: [PATCH 03/76] observe property type unique from content picker property editor --- .../property-editor-ui-content-picker.element.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index f34caa2ca14c..4c425adfa192 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -18,6 +18,10 @@ import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; // import of local component import './components/input-content/index.js'; +import { UMB_PICKER_EXPANSION_CONTEXT } from 'src/packages/core/picker/expansion/picker-expansion.context.token.js'; +import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; +import { UMB_PROPERTY_TYPE_CONTEXT } from '@umbraco-cms/backoffice/content-type'; +import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; type UmbContentPickerValueType = UmbInputContentElement['selection']; @@ -65,6 +69,8 @@ export class UmbPropertyEditorUIContentPickerElement @state() private _invalidData?: UmbContentPickerValueType; + #propertyTypeUnique?: string; + #dynamicRoot?: UmbContentPickerSource['dynamicRoot']; #dynamicRootRepository = new UmbContentPickerDynamicRootRepository(this); @@ -105,6 +111,16 @@ export class UmbPropertyEditorUIContentPickerElement } } + constructor() { + super(); + + this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => { + this.observe(context?.unique, (propertyTypeUnique) => { + this.#propertyTypeUnique = propertyTypeUnique; + }); + }); + } + #parseInt(value: unknown, fallback: number): number { const num = Number(value); return !isNaN(num) && num > 0 ? num : fallback; From f275173fe6ba428171b288badaa8d6fb17bb9564 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Sep 2025 11:18:49 +0200 Subject: [PATCH 04/76] remove unused --- .../property-editor-ui-content-picker.element.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 4c425adfa192..f545b3ae2904 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -15,13 +15,10 @@ import type { UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; +import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; // import of local component import './components/input-content/index.js'; -import { UMB_PICKER_EXPANSION_CONTEXT } from 'src/packages/core/picker/expansion/picker-expansion.context.token.js'; -import { UMB_PROPERTY_CONTEXT, UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; -import { UMB_PROPERTY_TYPE_CONTEXT } from '@umbraco-cms/backoffice/content-type'; -import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; type UmbContentPickerValueType = UmbInputContentElement['selection']; From 73157149bbefff9db87744c62c73b0f9eb11c9b5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Sep 2025 12:18:46 +0200 Subject: [PATCH 05/76] observe data type unique --- .../property-editor-ui-content-picker.element.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index f545b3ae2904..e916d6f7d3a8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -67,6 +67,7 @@ export class UmbPropertyEditorUIContentPickerElement private _invalidData?: UmbContentPickerValueType; #propertyTypeUnique?: string; + #dataTypeUnique?: string; #dynamicRoot?: UmbContentPickerSource['dynamicRoot']; #dynamicRootRepository = new UmbContentPickerDynamicRootRepository(this); @@ -115,6 +116,10 @@ export class UmbPropertyEditorUIContentPickerElement this.observe(context?.unique, (propertyTypeUnique) => { this.#propertyTypeUnique = propertyTypeUnique; }); + + this.observe(context?.dataType, (dataType) => { + this.#dataTypeUnique = dataType?.unique; + }); }); } From 2d62fcb43a94119ceb092936137851f8b6f1c4be Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 09:03:26 +0200 Subject: [PATCH 06/76] wip picker memories --- .../src/packages/core/picker/constants.ts | 1 + .../src/packages/core/picker/index.ts | 3 +- .../packages/core/picker/memory/constants.ts | 1 + .../src/packages/core/picker/memory/index.ts | 1 + .../memory/picker-memory.context.token.ts | 4 ++ .../picker/memory/picker-memory.context.ts | 9 +++++ .../picker/memory/picker-memory.manager.ts | 28 ++++++++++++++ .../src/packages/core/picker/memory/types.ts | 4 ++ .../packages/core/picker/picker.context.ts | 7 +++- .../search/manager/picker-search.manager.ts | 37 ++++++++++++++++++- .../src/packages/core/picker/types.ts | 1 + 11 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts index f6d55f488f4b..080d5c3c1e3f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts @@ -1,2 +1,3 @@ export { UMB_PICKER_CONTEXT } from './picker.context.token.js'; export * from './search/constants.js'; +export * from './memory/constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts index d38d1310d8e2..52dfd81e98d3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts @@ -1,5 +1,6 @@ export * from './constants.js'; -export * from './search/index.js'; +export * from './memory/index.js'; export * from './picker.context.js'; export * from './picker.context.token.js'; +export * from './search/index.js'; export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts new file mode 100644 index 000000000000..7d477e01beeb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts @@ -0,0 +1 @@ +export * from './picker-memory.context.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts new file mode 100644 index 000000000000..1f70de15ccc5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts @@ -0,0 +1 @@ +export * from './picker-memory.manager.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts new file mode 100644 index 000000000000..a764fb4d33e2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts @@ -0,0 +1,4 @@ +import type { UmbPickerMemoryContext } from './picker-memory.context.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; + +export const UMB_PICKER_MEMORY_CONTEXT = new UmbContextToken('UmbPickerMemoryContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts new file mode 100644 index 000000000000..f5a245887e70 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts @@ -0,0 +1,9 @@ +import { UMB_PICKER_MEMORY_CONTEXT } from './picker-memory.context.token.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; + +export class UmbPickerMemoryContext extends UmbContextBase { + constructor(host: UmbControllerHost) { + super(host, UMB_PICKER_MEMORY_CONTEXT); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts new file mode 100644 index 000000000000..b7e756228b1a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts @@ -0,0 +1,28 @@ +import type { UmbPickerMemory } from './types.js'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; + +export class UmbPickerMemoryManager extends UmbControllerBase { + #memories = new UmbArrayState([], (x) => x.unique); + + constructor(host: UmbControllerHost) { + super(host); + } + + get(unique: string): UmbPickerMemory | undefined { + return this.#memories.getValue().find((x) => x.unique === unique); + } + + getAll() { + return this.#memories.getValue(); + } + + append(memory: UmbPickerMemory) { + this.#memories.appendOne(memory); + } + + delete(unique: string) { + this.#memories.remove([unique]); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts new file mode 100644 index 000000000000..8e8f5587497c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts @@ -0,0 +1,4 @@ +export interface UmbPickerMemory { + unique: string; + data: MemoryDataType; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index e606e79b0ffc..0938aaacf593 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -1,18 +1,23 @@ import { UMB_PICKER_CONTEXT } from './picker.context.token.js'; import { UmbPickerSearchManager } from './search/manager/picker-search.manager.js'; +import { UmbPickerMemoryManager } from './memory/index.js'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; export class UmbPickerContext extends UmbContextBase { + public readonly memory = new UmbPickerMemoryManager(this); public readonly selection = new UmbSelectionManager(this); - public readonly search = new UmbPickerSearchManager(this); + public readonly search = new UmbPickerSearchManager(this, { memory: this.memory }); + public dataType?: { unique: string }; constructor(host: UmbControllerHost) { super(host, UMB_PICKER_CONTEXT); + /* TODO: Move this implementation to another place. The generic picker context shouldn't be aware of property and data types. + It also gives an illegal import of content module */ this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => { this.observe(context?.dataType, (dataType) => { this.dataType = dataType; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index 9d73c0fdba2a..fdaca59468f9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -1,3 +1,5 @@ +import type { UmbPickerMemoryManager } from '../../memory/picker-memory.manager.js'; +import type { UmbPickerMemory } from '../../memory/types.js'; import type { UmbPickerSearchManagerConfig } from './types.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; @@ -6,6 +8,17 @@ import { UmbArrayState, UmbBooleanState, UmbNumberState, UmbObjectState } from ' import type { UmbSearchProvider, UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search'; import { debounce } from '@umbraco-cms/backoffice/utils'; +interface UmbPickerSearchMemory extends UmbPickerMemory { + unique: 'umbSearch'; + data: { + requestArgs: UmbSearchRequestArgs; + }; +} + +export interface UmbPickerSearchManagerArgs { + memory?: UmbPickerMemoryManager; +} + /** * A manager for searching items in a picker. * @exports @@ -36,13 +49,24 @@ export class UmbPickerSearchManager< #config?: UmbPickerSearchManagerConfig; #searchProvider?: UmbSearchProvider; + #memory?: UmbPickerMemoryManager; + #memoryUnique: string = 'umbSearch'; + /** * Creates an instance of UmbPickerSearchManager. * @param {UmbControllerHost} host The controller host for the search manager. + * @param args Optional arguments for the search manager. + * @param {UmbPickerMemoryManager} [args.memory] An optional memory manager to store selected items. * @memberof UmbPickerSearchManager */ - constructor(host: UmbControllerHost) { + constructor(host: UmbControllerHost, args?: UmbPickerSearchManagerArgs) { super(host); + + if (args?.memory) { + this.#memory = args.memory; + const searchMemory = this.#memory?.get(this.#memoryUnique); + debugger; + } } /** @@ -118,6 +142,7 @@ export class UmbPickerSearchManager< this.#resultItems.setValue([]); this.#searching.setValue(false); this.#resultTotalItems.setValue(0); + this.#memory?.delete(this.#memoryUnique); } /** @@ -187,9 +212,19 @@ export class UmbPickerSearchManager< // ensure that config params are always included ...this.#config?.queryParams, searchFrom: this.#config?.searchFrom, + // TODO: Move this implementation to another place. The generic picker search manager shouldn't be aware of data types. dataTypeUnique: this.#config?.dataTypeUnique, }; + const searchMemory: UmbPickerSearchMemory = { + unique: this.#memoryUnique, + data: { + requestArgs: args, + }, + }; + + this.#memory?.append(searchMemory); + const { data } = await this.#searchProvider.search(args); const items = (data?.items as ResultItemType[]) ?? []; this.#resultItems.setValue(items); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts index c537c39007e7..fc9c0f0beae1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts @@ -6,3 +6,4 @@ export interface UmbPickerContextConfig { } export type * from './search/types.js'; +export type * from './memory/types.js'; From e92ef186822057d081d8a1a6054a3735647c5521 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 09:04:00 +0200 Subject: [PATCH 07/76] append memory option to the picker data model --- src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 97b3ebb81ed2..65afca6005da 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -1,5 +1,6 @@ import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; +import type { UmbPickerMemory } from '@umbraco-cms/backoffice/picker'; export type * from './extensions/types.js'; @@ -8,6 +9,7 @@ export interface UmbPickerModalData { filter?: (item: ItemType) => boolean; pickableFilter?: (item: ItemType) => boolean; search?: UmbPickerModalSearchConfig; + memory?: Array; } export interface UmbPickerModalSearchConfig> { From a535abba7797b3d66265d5a2d182302309419205 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 10:19:09 +0200 Subject: [PATCH 08/76] split into methods --- .../search/manager/picker-search.manager.ts | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index fdaca59468f9..f3bf9ca11789 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -9,14 +9,13 @@ import type { UmbSearchProvider, UmbSearchRequestArgs, UmbSearchResultItemModel import { debounce } from '@umbraco-cms/backoffice/utils'; interface UmbPickerSearchMemory extends UmbPickerMemory { - unique: 'umbSearch'; data: { requestArgs: UmbSearchRequestArgs; }; } export interface UmbPickerSearchManagerArgs { - memory?: UmbPickerMemoryManager; + memoryManager?: UmbPickerMemoryManager; } /** @@ -49,8 +48,8 @@ export class UmbPickerSearchManager< #config?: UmbPickerSearchManagerConfig; #searchProvider?: UmbSearchProvider; - #memory?: UmbPickerMemoryManager; - #memoryUnique: string = 'umbSearch'; + #memoryManager?: UmbPickerMemoryManager; + #memoryUnique: string = 'UmbPickerSearch'; /** * Creates an instance of UmbPickerSearchManager. @@ -62,10 +61,9 @@ export class UmbPickerSearchManager< constructor(host: UmbControllerHost, args?: UmbPickerSearchManagerArgs) { super(host); - if (args?.memory) { - this.#memory = args.memory; - const searchMemory = this.#memory?.get(this.#memoryUnique); - debugger; + if (args?.memoryManager) { + this.#memoryManager = args.memoryManager; + this.#getAndApplyMemory(); } } @@ -142,7 +140,7 @@ export class UmbPickerSearchManager< this.#resultItems.setValue([]); this.#searching.setValue(false); this.#resultTotalItems.setValue(0); - this.#memory?.delete(this.#memoryUnique); + this.#memoryManager?.delete(this.#memoryUnique); } /** @@ -216,19 +214,31 @@ export class UmbPickerSearchManager< dataTypeUnique: this.#config?.dataTypeUnique, }; - const searchMemory: UmbPickerSearchMemory = { + this.#addMemory(args); + + const { data } = await this.#searchProvider.search(args); + const items = (data?.items as ResultItemType[]) ?? []; + this.#resultItems.setValue(items); + this.#resultTotalItems.setValue(data?.total ?? 0); + this.#searching.setValue(false); + } + + #addMemory(args: SearchRequestArgsType) { + const memory: UmbPickerSearchMemory = { unique: this.#memoryUnique, data: { requestArgs: args, }, }; - this.#memory?.append(searchMemory); + this.#memoryManager?.append(memory); + } - const { data } = await this.#searchProvider.search(args); - const items = (data?.items as ResultItemType[]) ?? []; - this.#resultItems.setValue(items); - this.#resultTotalItems.setValue(data?.total ?? 0); - this.#searching.setValue(false); + #getAndApplyMemory() { + const memory = this.#memoryManager?.get(this.#memoryUnique); + if (memory?.data?.requestArgs) { + this.#query.setValue(memory.data.requestArgs); + this.search(); + } } } From ca931a167f0f94b911a4eedc197de5ccbaefe846 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 10:19:43 +0200 Subject: [PATCH 09/76] initialize memory context --- src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts | 2 ++ .../src/packages/core/picker/memory/index.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts index d1236bc97bef..5e1f3d633b76 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts @@ -4,6 +4,7 @@ import { UmbActionEventContext } from './action/action-event.context.js'; import { manifests as coreManifests } from './manifests.js'; import { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; import { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; +import { UmbPickerMemoryContext } from '@umbraco-cms/backoffice/picker'; import { UmbExtensionsApiInitializer, type UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; import './property-action/components/index.js'; @@ -31,6 +32,7 @@ export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { new UmbNotificationContext(host); new UmbModalManagerContext(host); new UmbActionEventContext(host); + new UmbPickerMemoryContext(host); host.consumeContext(UMB_AUTH_CONTEXT, (authContext) => { // Initialize the auth context to let the app context know that the core module is ready diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts index 1f70de15ccc5..3e5b1671f748 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts @@ -1 +1,2 @@ export * from './picker-memory.manager.js'; +export * from './picker-memory.context.js'; From eb48cf205da2d2aa12409fe73f7c3fd5ba6bcbc7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 10:20:15 +0200 Subject: [PATCH 10/76] rename arg --- .../src/packages/core/picker/picker.context.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index 0938aaacf593..d40512bcd34c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -9,7 +9,7 @@ import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; export class UmbPickerContext extends UmbContextBase { public readonly memory = new UmbPickerMemoryManager(this); public readonly selection = new UmbSelectionManager(this); - public readonly search = new UmbPickerSearchManager(this, { memory: this.memory }); + public readonly search = new UmbPickerSearchManager(this, { memoryManager: this.memory }); public dataType?: { unique: string }; From 3b01d1882b21f671ffbcbac9211335b8c235207c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 20:30:51 +0200 Subject: [PATCH 11/76] make memory module --- src/Umbraco.Web.UI.Client/package.json | 1 + .../src/packages/core/entry-point.ts | 4 +-- .../src/packages/core/memory/constants.ts | 1 + .../src/packages/core/memory/index.ts | 4 +++ .../core/memory/memory.context.token.ts | 4 +++ .../packages/core/memory/memory.context.ts | 12 ++++++++ .../packages/core/memory/memory.manager.ts | 22 +++++++++++++++ .../src/packages/core/memory/types.ts | 10 +++++++ .../src/packages/core/modal/types.ts | 4 +-- .../src/packages/core/picker/index.ts | 1 - .../packages/core/picker/memory/constants.ts | 1 - .../src/packages/core/picker/memory/index.ts | 2 -- .../memory/picker-memory.context.token.ts | 4 --- .../picker/memory/picker-memory.context.ts | 9 ------ .../picker/memory/picker-memory.manager.ts | 28 ------------------- .../src/packages/core/picker/memory/types.ts | 4 --- .../packages/core/picker/picker.context.ts | 4 +-- .../src/packages/core/picker/types.ts | 1 - .../src/packages/core/vite.config.ts | 1 + src/Umbraco.Web.UI.Client/tsconfig.json | 1 + 20 files changed, 62 insertions(+), 56 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 7577e7a54441..35f89ac91c54 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -69,6 +69,7 @@ "./member-type": "./dist-cms/packages/members/member-type/index.js", "./member": "./dist-cms/packages/members/member/index.js", "./member-public-access": "./dist-cms/packages/members/member-public-access/index.js", + "./memory": "./dist-cms/packages/core/memory/index.js", "./menu": "./dist-cms/packages/core/menu/index.js", "./modal": "./dist-cms/packages/core/modal/index.js", "./models": "./dist-cms/packages/core/models/index.js", diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts index 5e1f3d633b76..3fa889e8a61d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts @@ -4,7 +4,7 @@ import { UmbActionEventContext } from './action/action-event.context.js'; import { manifests as coreManifests } from './manifests.js'; import { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; import { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; -import { UmbPickerMemoryContext } from '@umbraco-cms/backoffice/picker'; +import { UmbMemoryContext } from '@umbraco-cms/backoffice/memory'; import { UmbExtensionsApiInitializer, type UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; import './property-action/components/index.js'; @@ -32,7 +32,7 @@ export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { new UmbNotificationContext(host); new UmbModalManagerContext(host); new UmbActionEventContext(host); - new UmbPickerMemoryContext(host); + new UmbMemoryContext(host); host.consumeContext(UMB_AUTH_CONTEXT, (authContext) => { // Initialize the auth context to let the app context know that the core module is ready diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts new file mode 100644 index 000000000000..0b3c28b0399c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts @@ -0,0 +1 @@ +export * from './memory.context.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts new file mode 100644 index 000000000000..661dad428ceb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts @@ -0,0 +1,4 @@ +export * from './memory.manager.js'; +export * from './memory.context.js'; + +export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts new file mode 100644 index 000000000000..eddf34c10d32 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts @@ -0,0 +1,4 @@ +import type { UmbMemoryContext } from './memory.context.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; + +export const UMB_MEMORY_CONTEXT = new UmbContextToken('UmbMemoryContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts new file mode 100644 index 000000000000..b02a72304f03 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts @@ -0,0 +1,12 @@ +import { UMB_MEMORY_CONTEXT } from './memory.context.token.js'; +import { UmbMemoryManager } from './memory.manager.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; + +export class UmbMemoryContext extends UmbContextBase { + public readonly memory = new UmbMemoryManager(this); + + constructor(host: UmbControllerHost) { + super(host, UMB_MEMORY_CONTEXT); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts new file mode 100644 index 000000000000..354e5e816c76 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts @@ -0,0 +1,22 @@ +import type { UmbMemoryModel } from './types.js'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; + +export class UmbMemoryManager extends UmbControllerBase { + #memories = new Map(); + + get(unique: string): UmbMemoryModel | undefined { + return this.#memories.get(unique); + } + + getAll() { + return Array.from(this.#memories.values()); + } + + set(memory: UmbMemoryModel) { + this.#memories.set(memory.unique, memory); + } + + delete(unique: string) { + this.#memories.delete(unique); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts new file mode 100644 index 000000000000..d17cc3c041be --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts @@ -0,0 +1,10 @@ +export interface UmbMemoryModel { + clientTimestamp?: string; + values?: Array; + unique: string; +} + +export interface UmbMemoryValueModel { + unique: string; + [key: string]: unknown; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 65afca6005da..4cd9e8376030 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -1,6 +1,6 @@ import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; -import type { UmbPickerMemory } from '@umbraco-cms/backoffice/picker'; +import type { UmbMemoryModel } from '@umbraco-cms/backoffice/picker'; export type * from './extensions/types.js'; @@ -9,7 +9,7 @@ export interface UmbPickerModalData { filter?: (item: ItemType) => boolean; pickableFilter?: (item: ItemType) => boolean; search?: UmbPickerModalSearchConfig; - memory?: Array; + memory?: UmbMemoryModel; } export interface UmbPickerModalSearchConfig> { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts index 52dfd81e98d3..90220a711a72 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts @@ -1,5 +1,4 @@ export * from './constants.js'; -export * from './memory/index.js'; export * from './picker.context.js'; export * from './picker.context.token.js'; export * from './search/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts deleted file mode 100644 index 7d477e01beeb..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './picker-memory.context.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts deleted file mode 100644 index 3e5b1671f748..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './picker-memory.manager.js'; -export * from './picker-memory.context.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts deleted file mode 100644 index a764fb4d33e2..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.token.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { UmbPickerMemoryContext } from './picker-memory.context.js'; -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; - -export const UMB_PICKER_MEMORY_CONTEXT = new UmbContextToken('UmbPickerMemoryContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts deleted file mode 100644 index f5a245887e70..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.context.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { UMB_PICKER_MEMORY_CONTEXT } from './picker-memory.context.token.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; - -export class UmbPickerMemoryContext extends UmbContextBase { - constructor(host: UmbControllerHost) { - super(host, UMB_PICKER_MEMORY_CONTEXT); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts deleted file mode 100644 index b7e756228b1a..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/picker-memory.manager.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { UmbPickerMemory } from './types.js'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; - -export class UmbPickerMemoryManager extends UmbControllerBase { - #memories = new UmbArrayState([], (x) => x.unique); - - constructor(host: UmbControllerHost) { - super(host); - } - - get(unique: string): UmbPickerMemory | undefined { - return this.#memories.getValue().find((x) => x.unique === unique); - } - - getAll() { - return this.#memories.getValue(); - } - - append(memory: UmbPickerMemory) { - this.#memories.appendOne(memory); - } - - delete(unique: string) { - this.#memories.remove([unique]); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts deleted file mode 100644 index 8e8f5587497c..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/memory/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface UmbPickerMemory { - unique: string; - data: MemoryDataType; -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index d40512bcd34c..26b482fbf62e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -1,13 +1,13 @@ import { UMB_PICKER_CONTEXT } from './picker.context.token.js'; import { UmbPickerSearchManager } from './search/manager/picker-search.manager.js'; -import { UmbPickerMemoryManager } from './memory/index.js'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; +import { UmbMemoryManager } from '@umbraco-cms/backoffice/memory'; export class UmbPickerContext extends UmbContextBase { - public readonly memory = new UmbPickerMemoryManager(this); + public readonly memory = new UmbMemoryManager(this); public readonly selection = new UmbSelectionManager(this); public readonly search = new UmbPickerSearchManager(this, { memoryManager: this.memory }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts index fc9c0f0beae1..c537c39007e7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/types.ts @@ -6,4 +6,3 @@ export interface UmbPickerContextConfig { } export type * from './search/types.js'; -export type * from './memory/types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts b/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts index 6df35d3cd1ad..cbc2bf772056 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts @@ -37,6 +37,7 @@ export default defineConfig({ 'id/index': './id/index.ts', 'lit-element/index': './lit-element/index.ts', 'localization/index': './localization/index.ts', + 'memory/index': './memory/index.ts', 'menu/index': './menu/index.ts', 'modal/index': './modal/index.ts', 'models/index': './models/index.ts', diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index c2ec31a43d91..d5f89ef4e6a9 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -98,6 +98,7 @@ DON'T EDIT THIS FILE DIRECTLY. It is generated by /devops/tsconfig/index.js "@umbraco-cms/backoffice/member-type": ["./src/packages/members/member-type/index.ts"], "@umbraco-cms/backoffice/member": ["./src/packages/members/member/index.ts"], "@umbraco-cms/backoffice/member-public-access": ["./src/packages/members/member-public-access/index.ts"], + "@umbraco-cms/backoffice/memory": ["./src/packages/core/memory/index.ts"], "@umbraco-cms/backoffice/menu": ["./src/packages/core/menu/index.ts"], "@umbraco-cms/backoffice/modal": ["./src/packages/core/modal/index.ts"], "@umbraco-cms/backoffice/models": ["./src/packages/core/models/index.ts"], From b4bf867dad298bf35e5997a163a8941fa4ab0acf Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 21:27:32 +0200 Subject: [PATCH 12/76] export constants --- src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts index 661dad428ceb..da5f290af966 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts @@ -1,4 +1,5 @@ -export * from './memory.manager.js'; +export * from './constants.js'; export * from './memory.context.js'; +export * from './memory.manager.js'; export type * from './types.js'; From 77d77bd71ad57b1b83a2d693dcc759a810d8c9c4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 9 Sep 2025 21:27:41 +0200 Subject: [PATCH 13/76] allow nested memories --- src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts index d17cc3c041be..d5547f646d06 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts @@ -2,6 +2,7 @@ export interface UmbMemoryModel { clientTimestamp?: string; values?: Array; unique: string; + memories?: Array; } export interface UmbMemoryValueModel { From f72846d6682bab7aa69843711055a22a4c8f3e7e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 12:51:17 +0200 Subject: [PATCH 14/76] pass memory from input document to picker context --- .../packages/core/memory/memory.manager.ts | 2 +- .../core/modal/context/modal.context.ts | 12 ++++ .../src/packages/core/modal/types.ts | 2 +- .../core/picker-input/picker-input.context.ts | 29 +++++++-- .../src/packages/core/picker/constants.ts | 1 - .../search/manager/picker-search.manager.ts | 57 +++++++++------- .../tree-picker-modal.element.ts | 36 +++++++++- .../input-document/input-document.element.ts | 65 +++++++++++++++---- .../input-content/input-content.element.ts | 5 ++ 9 files changed, 165 insertions(+), 44 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts index 354e5e816c76..4540e3da928f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts @@ -1,7 +1,7 @@ import type { UmbMemoryModel } from './types.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -export class UmbMemoryManager extends UmbControllerBase { +export class UmbPickerMemoryManager extends UmbControllerBase { #memories = new Map(); get(unique: string): UmbMemoryModel | undefined { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index 3271d035d437..31aa8581bc7a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -8,6 +8,7 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { type UmbDeepPartialObject, umbDeepMerge } from '@umbraco-cms/backoffice/utils'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import { UMB_ROUTE_CONTEXT, type IRouterSlot } from '@umbraco-cms/backoffice/router'; +import type { UmbMemoryModel } from '@umbraco-cms/backoffice/picker'; export interface UmbModalRejectReason { type: string; @@ -59,6 +60,9 @@ export class UmbModalContext< #size = new UmbStringState('small'); public readonly size = this.#size.asObservable(); + #memory = new UmbObjectState(undefined); + public readonly memory = this.#memory.asObservable(); + constructor( host: UmbControllerHost, modalAlias: string | UmbModalToken, @@ -229,6 +233,14 @@ export class UmbModalContext< this.#size.setValue(size); } + public setMemory(memory: UmbMemoryModel | undefined) { + this.#memory.setValue(memory); + } + + public getMemory(): UmbMemoryModel | undefined { + return this.#memory.getValue(); + } + public override destroy(): void { this.dispatchEvent(new CustomEvent('umb:destroy')); this.#value.destroy(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 4cd9e8376030..a5937e147a16 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -1,6 +1,6 @@ import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; -import type { UmbMemoryModel } from '@umbraco-cms/backoffice/picker'; +import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; export type * from './extensions/types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index c6407d1c5498..e83881ecba14 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -2,11 +2,13 @@ import { UMB_PICKER_INPUT_CONTEXT } from './picker-input.context-token.js'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository'; -import { umbConfirmModal, umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; type PickerItemBaseType = { name: string; unique: string }; export class UmbPickerInputContext< @@ -21,8 +23,11 @@ export class UmbPickerInputContext< #itemManager; - selection; - selectedItems; + public readonly selection; + public readonly selectedItems; + + #memory = new UmbObjectState(undefined); + public readonly memory = this.#memory.asObservable(); /** * Define a minimum amount of selected items in this input, for this input to be valid. @@ -91,7 +96,13 @@ export class UmbPickerInputContext< async openPicker(pickerData?: Partial) { await this.#itemManager.init; - const modalValue = await umbOpenModal(this, this.modalAlias, { + + const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); + if (!modalManagerContext) { + throw new Error('Modal manager not found.'); + } + + const modalContext = modalManagerContext.open(this, this.modalAlias, { data: { multiple: this._max === 1 ? false : true, ...pickerData, @@ -99,7 +110,15 @@ export class UmbPickerInputContext< value: { selection: this.getSelection(), } as PickerModalValueType, - }).catch(() => undefined); + }); + + const modalValue = await modalContext.onSubmit().catch(() => undefined); + + /* Check if we have any memory from the modal, and if so, + apply it to the picker input context so it can be reached from the input element. */ + const modalMemory = modalContext?.getMemory(); + this.#memory.setValue(modalMemory); + if (!modalValue) return; this.setSelection(modalValue.selection); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts index 080d5c3c1e3f..f6d55f488f4b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/constants.ts @@ -1,3 +1,2 @@ export { UMB_PICKER_CONTEXT } from './picker.context.token.js'; export * from './search/constants.js'; -export * from './memory/constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index f3bf9ca11789..d8dcc03bf3fd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -1,5 +1,5 @@ -import type { UmbPickerMemoryManager } from '../../memory/picker-memory.manager.js'; -import type { UmbPickerMemory } from '../../memory/types.js'; +import type { UmbMemoryManager } from '../../../memory/memory.manager.js'; +import type { UmbMemoryModel } from '../../types.js'; import type { UmbPickerSearchManagerConfig } from './types.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; @@ -8,14 +8,8 @@ import { UmbArrayState, UmbBooleanState, UmbNumberState, UmbObjectState } from ' import type { UmbSearchProvider, UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search'; import { debounce } from '@umbraco-cms/backoffice/utils'; -interface UmbPickerSearchMemory extends UmbPickerMemory { - data: { - requestArgs: UmbSearchRequestArgs; - }; -} - export interface UmbPickerSearchManagerArgs { - memoryManager?: UmbPickerMemoryManager; + memoryManager?: UmbMemoryManager; } /** @@ -48,22 +42,21 @@ export class UmbPickerSearchManager< #config?: UmbPickerSearchManagerConfig; #searchProvider?: UmbSearchProvider; - #memoryManager?: UmbPickerMemoryManager; + #memoryManager?: UmbMemoryManager; #memoryUnique: string = 'UmbPickerSearch'; /** * Creates an instance of UmbPickerSearchManager. * @param {UmbControllerHost} host The controller host for the search manager. * @param args Optional arguments for the search manager. - * @param {UmbPickerMemoryManager} [args.memory] An optional memory manager to store selected items. + * @param {UmbMemoryManager} [args.memory] An optional memory manager to store selected items. * @memberof UmbPickerSearchManager */ constructor(host: UmbControllerHost, args?: UmbPickerSearchManagerArgs) { super(host); - if (args?.memoryManager) { this.#memoryManager = args.memoryManager; - this.#getAndApplyMemory(); + this.#observeMemory(); } } @@ -214,7 +207,7 @@ export class UmbPickerSearchManager< dataTypeUnique: this.#config?.dataTypeUnique, }; - this.#addMemory(args); + this.#setSearchRequestMemory(args); const { data } = await this.#searchProvider.search(args); const items = (data?.items as ResultItemType[]) ?? []; @@ -223,21 +216,37 @@ export class UmbPickerSearchManager< this.#searching.setValue(false); } - #addMemory(args: SearchRequestArgsType) { - const memory: UmbPickerSearchMemory = { + #observeMemory() { + this.observe(this.#memoryManager?.memory(this.#memoryUnique), (memory) => { + console.log(memory); + + if (memory) { + this.#getAndApplySearchRequestMemory(); + } + }); + } + + #setSearchRequestMemory(args: SearchRequestArgsType) { + // Add a memory entry with the latest request args + const memory: UmbMemoryModel = { unique: this.#memoryUnique, - data: { - requestArgs: args, - }, + values: [ + { + unique: this.#memoryUnique + 'LatestRequestArgs', + requestArgs: args, + }, + ], }; - this.#memoryManager?.append(memory); + this.#memoryManager?.setMemory(memory); } - #getAndApplyMemory() { - const memory = this.#memoryManager?.get(this.#memoryUnique); - if (memory?.data?.requestArgs) { - this.#query.setValue(memory.data.requestArgs); + #getAndApplySearchRequestMemory() { + const memory = this.#memoryManager?.getMemory(this.#memoryUnique); + const memoryData = memory?.values?.find((x) => x.unique === `${this.#memoryUnique}LatestRequestArgs`); + + if (memoryData?.requestArgs) { + this.#query.setValue(memoryData.requestArgs); this.search(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index bbd95cd19c6e..f7575b36c9c3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -3,10 +3,11 @@ import { UmbTreeItemPickerContext } from '../tree-item-picker/index.js'; import type { UmbTreePickerModalData, UmbTreePickerModalValue } from './tree-picker-modal.token.js'; import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; import { html, customElement, state, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit'; -import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; +import { UmbModalBaseElement, type UmbModalRejectReason } from '@umbraco-cms/backoffice/modal'; import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event'; +import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; @customElement('umb-tree-picker-modal') export class UmbTreePickerModalElement extends UmbModalBaseElement< @@ -68,6 +69,16 @@ export class UmbTreePickerModalElement memory.unique === 'UmbTreeItemPickerModal', + ); + + pickerModalMemory?.memories?.forEach((memory) => this.#pickerContext.memory.setMemory(memory)); + } } if (_changedProperties.has('value')) { @@ -149,6 +160,29 @@ export class UmbTreePickerModalElement diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 3767445c56fa..297501967817 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -8,6 +8,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type'; +import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; @customElement('umb-input-document') export class UmbInputDocumentElement extends UmbFormControlMixin( @@ -37,10 +38,10 @@ export class UmbInputDocumentElement extends UmbFormControlMixin) { - this.#pickerContext.setSelection(ids); + this.#pickerInputContext.setSelection(ids); this.#sorter.setModel(ids); } public get selection(): Array { - return this.#pickerContext.getSelection(); + return this.#pickerInputContext.getSelection(); } @property({ type: Object, attribute: false }) @@ -122,10 +123,26 @@ export class UmbInputDocumentElement extends UmbFormControlMixin memory.unique === this.#memoryUnique); + } + + #memoryUnique = 'UmbInputDocument'; + #memory?: UmbMemoryModel; + #inputDocumentMemory?: UmbMemoryModel; + @state() private _items?: Array; - #pickerContext = new UmbDocumentPickerInputContext(this); + #pickerInputContext = new UmbDocumentPickerInputContext(this); constructor() { super(); @@ -142,15 +159,41 @@ export class UmbInputDocumentElement extends UmbFormControlMixin !!this.max && this.selection.length > this.max, ); - this.observe(this.#pickerContext.selection, (selection) => (this.value = selection.join(',')), '_observeSelection'); - this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems), '_observerItems'); + this.observe( + this.#pickerInputContext.selection, + (selection) => (this.value = selection.join(',')), + '_observeSelection', + ); + + this.observe( + this.#pickerInputContext.selectedItems, + (selectedItems) => (this._items = selectedItems), + '_observerItems', + ); + + this.observe( + this.#pickerInputContext.memory, + (memory) => { + if (!memory) return; + + const inputDocumentMemory: UmbMemoryModel = { + unique: 'UmbInputDocument', + memories: [memory], + }; + + this.#inputDocumentMemory = inputDocumentMemory; + console.log('Input Document Memory:', inputDocumentMemory); + }, + 'umbObservePickerInputMemory', + ); } #openPicker() { - this.#pickerContext.openPicker( + this.#pickerInputContext.openPicker( { hideTreeRoot: true, startNode: this.startNode, + memory: this.#inputDocumentMemory, }, { allowedContentTypes: this.allowedContentTypeIds?.map((id) => ({ @@ -163,7 +206,7 @@ export class UmbInputDocumentElement extends UmbFormControlMixin( @@ -74,6 +75,9 @@ export class UmbInputContentElement extends UmbFormControlMixin = []; @@ -111,6 +115,7 @@ export class UmbInputContentElement extends UmbFormControlMixin `; From 2e4682e6b55a0821acd1acefea83f09d2c3f90a0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 12:51:48 +0200 Subject: [PATCH 15/76] Update property-editor-ui-content-picker.element.ts --- ...operty-editor-ui-content-picker.element.ts | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index e916d6f7d3a8..5f9281388b3e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -16,6 +16,7 @@ import type { } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; +import { UMB_MEMORY_CONTEXT, type UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; // import of local component import './components/input-content/index.js'; @@ -66,8 +67,11 @@ export class UmbPropertyEditorUIContentPickerElement @state() private _invalidData?: UmbContentPickerValueType; - #propertyTypeUnique?: string; + @state() + private _memory?: UmbMemoryModel; + #dataTypeUnique?: string; + #memoryContext?: typeof UMB_MEMORY_CONTEXT.TYPE; #dynamicRoot?: UmbContentPickerSource['dynamicRoot']; #dynamicRootRepository = new UmbContentPickerDynamicRootRepository(this); @@ -113,14 +117,16 @@ export class UmbPropertyEditorUIContentPickerElement super(); this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => { - this.observe(context?.unique, (propertyTypeUnique) => { - this.#propertyTypeUnique = propertyTypeUnique; - }); - this.observe(context?.dataType, (dataType) => { this.#dataTypeUnique = dataType?.unique; + this.#getMemory(); }); }); + + this.consumeContext(UMB_MEMORY_CONTEXT, (context) => { + this.#memoryContext = context; + this.#getMemory(); + }); } #parseInt(value: unknown, fallback: number): number { @@ -178,6 +184,45 @@ export class UmbPropertyEditorUIContentPickerElement this.readonly = false; } + #onInputContentMemoryChange(event: UmbChangeEvent) { + const target = event.target as UmbInputContentElement; + const memory = target?.memory; + + if (memory) { + this.#setMemory(memory); + } + } + + #getMemory() { + const memoryUnique = this.#getMemoryUnique(); + if (!memoryUnique) return; + if (!this.#memoryContext) return; + + this._memory = this.#memoryContext.memory.get(memoryUnique); + console.log('Memory', memoryUnique, this._memory); + } + + #setMemory(memory: UmbMemoryModel) { + const memoryUnique = this.#getMemoryUnique(); + if (!memoryUnique) return; + if (!this.#memoryContext) return; + + // Set up memory for this context which includes all memories from the input + const inputMemory: UmbMemoryModel = { + unique: memoryUnique, + memories: memory.memories, + }; + + this.#memoryContext.memory.set(inputMemory); + } + + #getMemoryUnique() { + if (!this.#memoryContext) return; + if (!this.#dataTypeUnique) return; + + return `UmbContentPickerPropertyEditorUi-${this._type}-${this.#dataTypeUnique}`; + } + override render() { const startNode: UmbTreeStartNode | undefined = this._rootUnique && this._rootEntityType @@ -194,8 +239,10 @@ export class UmbPropertyEditorUIContentPickerElement .maxMessage=${this._maxMessage} .startNode=${startNode} .allowedContentTypeIds=${this._allowedContentTypeUniques ?? ''} + .memory=${this._memory} ?readonly=${this.readonly} - @change=${this.#onChange}> + @change=${this.#onChange} + @memory-change=${this.#onInputContentMemoryChange}> ${this.#renderInvalidData()} `; From 369d0fb27cbcb1ebfec6a7c6ec43d2b96de7d6aa Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 12:52:53 +0200 Subject: [PATCH 16/76] fix import --- .../components/input-content/input-content.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 9c4dd09f2473..446d6d14d192 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -6,7 +6,7 @@ import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import type { UmbMemoryModel } from '@umbraco-cms/backoffice/picker'; +import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; @customElement('umb-input-content') export class UmbInputContentElement extends UmbFormControlMixin( From edb457fb6ed8ce46200efdd8785f1f871e844860 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 13:08:36 +0200 Subject: [PATCH 17/76] prefix with interaction --- .../src/packages/core/entry-point.ts | 4 +- .../core/interaction-memory/constants.ts | 1 + .../packages/core/interaction-memory/index.ts | 5 +++ .../interaction-memory.context.token.ts | 6 +++ .../interaction-memory.context.ts | 12 ++++++ .../interaction-memory.manager.ts | 28 +++++++++++++ .../packages/core/interaction-memory/types.ts | 11 +++++ .../src/packages/core/memory/constants.ts | 1 - .../src/packages/core/memory/index.ts | 5 --- .../core/memory/memory.context.token.ts | 4 -- .../packages/core/memory/memory.context.ts | 12 ------ .../packages/core/memory/memory.manager.ts | 22 ---------- .../src/packages/core/memory/types.ts | 11 ----- .../src/packages/core/modal/types.ts | 4 +- .../core/picker-input/picker-input.context.ts | 4 +- .../packages/core/picker/picker.context.ts | 2 +- .../search/manager/picker-search.manager.ts | 42 +++++++++---------- .../tree-picker-modal.element.ts | 4 +- .../input-document/input-document.element.ts | 12 +++--- .../input-content/input-content.element.ts | 4 +- ...operty-editor-ui-content-picker.element.ts | 16 +++---- src/Umbraco.Web.UI.Client/tsconfig.json | 2 +- 22 files changed, 109 insertions(+), 103 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.token.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts index 3fa889e8a61d..44476da4984f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts @@ -4,7 +4,7 @@ import { UmbActionEventContext } from './action/action-event.context.js'; import { manifests as coreManifests } from './manifests.js'; import { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; import { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; -import { UmbMemoryContext } from '@umbraco-cms/backoffice/memory'; +import { UmbInteractionMemoryContext } from 'src/packages/core/interaction-memory/index.js'; import { UmbExtensionsApiInitializer, type UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; import './property-action/components/index.js'; @@ -32,7 +32,7 @@ export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { new UmbNotificationContext(host); new UmbModalManagerContext(host); new UmbActionEventContext(host); - new UmbMemoryContext(host); + new UmbInteractionMemoryContext(host); host.consumeContext(UMB_AUTH_CONTEXT, (authContext) => { // Initialize the auth context to let the app context know that the core module is ready diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/constants.ts new file mode 100644 index 000000000000..9641d5013b62 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/constants.ts @@ -0,0 +1 @@ +export * from './interaction-memory.context.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts new file mode 100644 index 000000000000..a534dbd4bd9d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts @@ -0,0 +1,5 @@ +export * from './constants.js'; +export * from './interaction-memory.context.js'; +export * from './interaction-memory.manager.js'; + +export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.token.ts new file mode 100644 index 000000000000..d37a64fe99f0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.token.ts @@ -0,0 +1,6 @@ +import type { UmbInteractionMemoryContext } from './interaction-memory.context.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; + +export const UMB_INTERACTION_MEMORY_CONTEXT = new UmbContextToken( + 'UmbInteractionMemoryContext', +); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts new file mode 100644 index 000000000000..63d036364fc5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts @@ -0,0 +1,12 @@ +import { UMB_INTERACTION_MEMORY_CONTEXT } from './interaction-memory.context.token.js'; +import { UmbInteractionMemoryManager } from './interaction-memory.manager.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; + +export class UmbInteractionMemoryContext extends UmbContextBase { + public readonly memory = new UmbInteractionMemoryManager(this); + + constructor(host: UmbControllerHost) { + super(host, UMB_INTERACTION_MEMORY_CONTEXT); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts new file mode 100644 index 000000000000..88afc792199e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts @@ -0,0 +1,28 @@ +import type { UmbInteractionMemoryModel } from './types.js'; +import { UmbArrayState, type Observable } from '@umbraco-cms/backoffice/observable-api'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; + +export class UmbInteractionMemoryManager extends UmbControllerBase { + #memories = new UmbArrayState([], (x) => x.unique); + memories = this.#memories.asObservable(); + + memory(unique: string): Observable { + return this.#memories.asObservablePart((items) => items.find((item) => item.unique === unique)); + } + + getMemory(unique: string): UmbInteractionMemoryModel | undefined { + return this.#memories.getValue().find((item) => item.unique === unique); + } + + setMemory(memory: UmbInteractionMemoryModel) { + this.#memories.appendOne(memory); + } + + deleteMemory(unique: string) { + this.#memories.removeOne(unique); + } + + getAllMemories() { + return this.#memories.getValue(); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts new file mode 100644 index 000000000000..bdb840e33130 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts @@ -0,0 +1,11 @@ +export interface UmbInteractionMemoryModel { + clientTimestamp?: string; + values?: Array; + unique: string; + memories?: Array; +} + +export interface UmbInteractionMemoryValueModel { + unique: string; + [key: string]: unknown; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts deleted file mode 100644 index 0b3c28b0399c..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './memory.context.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts deleted file mode 100644 index da5f290af966..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './constants.js'; -export * from './memory.context.js'; -export * from './memory.manager.js'; - -export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts deleted file mode 100644 index eddf34c10d32..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.token.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { UmbMemoryContext } from './memory.context.js'; -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; - -export const UMB_MEMORY_CONTEXT = new UmbContextToken('UmbMemoryContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts deleted file mode 100644 index b02a72304f03..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.context.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { UMB_MEMORY_CONTEXT } from './memory.context.token.js'; -import { UmbMemoryManager } from './memory.manager.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; - -export class UmbMemoryContext extends UmbContextBase { - public readonly memory = new UmbMemoryManager(this); - - constructor(host: UmbControllerHost) { - super(host, UMB_MEMORY_CONTEXT); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts deleted file mode 100644 index 4540e3da928f..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/memory.manager.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { UmbMemoryModel } from './types.js'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; - -export class UmbPickerMemoryManager extends UmbControllerBase { - #memories = new Map(); - - get(unique: string): UmbMemoryModel | undefined { - return this.#memories.get(unique); - } - - getAll() { - return Array.from(this.#memories.values()); - } - - set(memory: UmbMemoryModel) { - this.#memories.set(memory.unique, memory); - } - - delete(unique: string) { - this.#memories.delete(unique); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts deleted file mode 100644 index d5547f646d06..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/memory/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface UmbMemoryModel { - clientTimestamp?: string; - values?: Array; - unique: string; - memories?: Array; -} - -export interface UmbMemoryValueModel { - unique: string; - [key: string]: unknown; -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index a5937e147a16..ff9b182267fa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -1,6 +1,6 @@ import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; -import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; export type * from './extensions/types.js'; @@ -9,7 +9,7 @@ export interface UmbPickerModalData { filter?: (item: ItemType) => boolean; pickableFilter?: (item: ItemType) => boolean; search?: UmbPickerModalSearchConfig; - memory?: UmbMemoryModel; + memory?: UmbInteractionMemoryModel; } export interface UmbPickerModalSearchConfig> { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index e83881ecba14..b2c0f1118e1e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -8,7 +8,7 @@ import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; -import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; type PickerItemBaseType = { name: string; unique: string }; export class UmbPickerInputContext< @@ -26,7 +26,7 @@ export class UmbPickerInputContext< public readonly selection; public readonly selectedItems; - #memory = new UmbObjectState(undefined); + #memory = new UmbObjectState(undefined); public readonly memory = this.#memory.asObservable(); /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index 26b482fbf62e..9ba386b539a6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -4,7 +4,7 @@ import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; -import { UmbMemoryManager } from '@umbraco-cms/backoffice/memory'; +import { UmbMemoryManager } from 'src/packages/core/interaction-memory/index.js'; export class UmbPickerContext extends UmbContextBase { public readonly memory = new UmbMemoryManager(this); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index d8dcc03bf3fd..130c5841c63e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -1,15 +1,14 @@ -import type { UmbMemoryManager } from '../../../memory/memory.manager.js'; -import type { UmbMemoryModel } from '../../types.js'; import type { UmbPickerSearchManagerConfig } from './types.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; +import type { UmbInteractionMemoryManager, UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; import { UmbArrayState, UmbBooleanState, UmbNumberState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import type { UmbSearchProvider, UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search'; import { debounce } from '@umbraco-cms/backoffice/utils'; export interface UmbPickerSearchManagerArgs { - memoryManager?: UmbMemoryManager; + interactionMemoryManager?: UmbInteractionMemoryManager; } /** @@ -42,21 +41,21 @@ export class UmbPickerSearchManager< #config?: UmbPickerSearchManagerConfig; #searchProvider?: UmbSearchProvider; - #memoryManager?: UmbMemoryManager; - #memoryUnique: string = 'UmbPickerSearch'; + #interactionMemoryManager?: UmbInteractionMemoryManager; + #interactionMemoryUnique: string = 'UmbPickerSearch'; /** * Creates an instance of UmbPickerSearchManager. * @param {UmbControllerHost} host The controller host for the search manager. * @param args Optional arguments for the search manager. - * @param {UmbMemoryManager} [args.memory] An optional memory manager to store selected items. + * @param {UmbInteractionMemoryManager} [args.interactionMemoryManager] An optional memory manager to store selected items. * @memberof UmbPickerSearchManager */ constructor(host: UmbControllerHost, args?: UmbPickerSearchManagerArgs) { super(host); - if (args?.memoryManager) { - this.#memoryManager = args.memoryManager; - this.#observeMemory(); + if (args?.interactionMemoryManager) { + this.#interactionMemoryManager = args.interactionMemoryManager; + this.#observeInteractionMemory(); } } @@ -133,7 +132,7 @@ export class UmbPickerSearchManager< this.#resultItems.setValue([]); this.#searching.setValue(false); this.#resultTotalItems.setValue(0); - this.#memoryManager?.delete(this.#memoryUnique); + this.#interactionMemoryManager?.deleteMemory(this.#interactionMemoryUnique); } /** @@ -216,37 +215,36 @@ export class UmbPickerSearchManager< this.#searching.setValue(false); } - #observeMemory() { - this.observe(this.#memoryManager?.memory(this.#memoryUnique), (memory) => { + #observeInteractionMemory() { + this.observe(this.#interactionMemoryManager?.memory(this.#interactionMemoryUnique), (memory) => { console.log(memory); if (memory) { - this.#getAndApplySearchRequestMemory(); + this.#applySearchRequestInteractionMemory(memory); } }); } #setSearchRequestMemory(args: SearchRequestArgsType) { // Add a memory entry with the latest request args - const memory: UmbMemoryModel = { - unique: this.#memoryUnique, + const memory: UmbInteractionMemoryModel = { + unique: this.#interactionMemoryUnique, values: [ { - unique: this.#memoryUnique + 'LatestRequestArgs', + unique: this.#interactionMemoryUnique + 'LatestRequestArgs', requestArgs: args, }, ], }; - this.#memoryManager?.setMemory(memory); + this.#interactionMemoryManager?.setMemory(memory); } - #getAndApplySearchRequestMemory() { - const memory = this.#memoryManager?.getMemory(this.#memoryUnique); - const memoryData = memory?.values?.find((x) => x.unique === `${this.#memoryUnique}LatestRequestArgs`); + #applySearchRequestInteractionMemory(memory: UmbInteractionMemoryModel) { + const memoryValue = memory?.values?.find((x) => x.unique === this.#interactionMemoryUnique + 'LatestRequestArgs'); - if (memoryData?.requestArgs) { - this.#query.setValue(memoryData.requestArgs); + if (memoryValue?.requestArgs) { + this.#query.setValue(memoryValue.requestArgs); this.search(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index f7575b36c9c3..9d230974dbdb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -7,7 +7,7 @@ import { UmbModalBaseElement, type UmbModalRejectReason } from '@umbraco-cms/bac import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event'; -import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; @customElement('umb-tree-picker-modal') export class UmbTreePickerModalElement extends UmbModalBaseElement< @@ -175,7 +175,7 @@ export class UmbTreePickerModalElement( @@ -124,10 +124,10 @@ export class UmbInputDocumentElement extends UmbFormControlMixin; @@ -176,7 +176,7 @@ export class UmbInputDocumentElement extends UmbFormControlMixin { if (!memory) return; - const inputDocumentMemory: UmbMemoryModel = { + const inputDocumentMemory: UmbInteractionMemoryModel = { unique: 'UmbInputDocument', memories: [memory], }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 446d6d14d192..3ce23910d8b9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -6,7 +6,7 @@ import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import type { UmbMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; @customElement('umb-input-content') export class UmbInputContentElement extends UmbFormControlMixin( @@ -76,7 +76,7 @@ export class UmbInputContentElement extends UmbFormControlMixin { + this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { this.#memoryContext = context; this.#getMemory(); }); @@ -198,22 +198,22 @@ export class UmbPropertyEditorUIContentPickerElement if (!memoryUnique) return; if (!this.#memoryContext) return; - this._memory = this.#memoryContext.memory.get(memoryUnique); + this._memory = this.#memoryContext.memory.getMemory(memoryUnique); console.log('Memory', memoryUnique, this._memory); } - #setMemory(memory: UmbMemoryModel) { + #setMemory(memory: UmbInteractionMemoryModel) { const memoryUnique = this.#getMemoryUnique(); if (!memoryUnique) return; if (!this.#memoryContext) return; // Set up memory for this context which includes all memories from the input - const inputMemory: UmbMemoryModel = { + const inputMemory: UmbInteractionMemoryModel = { unique: memoryUnique, memories: memory.memories, }; - this.#memoryContext.memory.set(inputMemory); + this.#memoryContext.memory.setMemory(inputMemory); } #getMemoryUnique() { diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index d5f89ef4e6a9..17c60f44fa2c 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -98,7 +98,7 @@ DON'T EDIT THIS FILE DIRECTLY. It is generated by /devops/tsconfig/index.js "@umbraco-cms/backoffice/member-type": ["./src/packages/members/member-type/index.ts"], "@umbraco-cms/backoffice/member": ["./src/packages/members/member/index.ts"], "@umbraco-cms/backoffice/member-public-access": ["./src/packages/members/member-public-access/index.ts"], - "@umbraco-cms/backoffice/memory": ["./src/packages/core/memory/index.ts"], + "@umbraco-cms/backoffice/memory": ["src/packages/core/interaction-memory/index.ts"], "@umbraco-cms/backoffice/menu": ["./src/packages/core/menu/index.ts"], "@umbraco-cms/backoffice/modal": ["./src/packages/core/modal/index.ts"], "@umbraco-cms/backoffice/models": ["./src/packages/core/models/index.ts"], From 7634e58ff059a671bc8b7d5f04694c4bc4fa59be Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 13:13:18 +0200 Subject: [PATCH 18/76] clean up --- .../src/packages/core/modal/context/modal.context.ts | 8 ++++---- .../src/packages/core/picker/picker.context.ts | 6 +++--- .../tree/tree-picker-modal/tree-picker-modal.element.ts | 4 ++-- .../components/input-content/input-content.element.ts | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index 31aa8581bc7a..46786c36ae55 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -8,7 +8,7 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { type UmbDeepPartialObject, umbDeepMerge } from '@umbraco-cms/backoffice/utils'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import { UMB_ROUTE_CONTEXT, type IRouterSlot } from '@umbraco-cms/backoffice/router'; -import type { UmbMemoryModel } from '@umbraco-cms/backoffice/picker'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; export interface UmbModalRejectReason { type: string; @@ -60,7 +60,7 @@ export class UmbModalContext< #size = new UmbStringState('small'); public readonly size = this.#size.asObservable(); - #memory = new UmbObjectState(undefined); + #memory = new UmbObjectState(undefined); public readonly memory = this.#memory.asObservable(); constructor( @@ -233,11 +233,11 @@ export class UmbModalContext< this.#size.setValue(size); } - public setMemory(memory: UmbMemoryModel | undefined) { + public setMemory(memory: UmbInteractionMemoryModel | undefined) { this.#memory.setValue(memory); } - public getMemory(): UmbMemoryModel | undefined { + public getMemory(): UmbInteractionMemoryModel | undefined { return this.#memory.getValue(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index 9ba386b539a6..a90cda6b4e37 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -3,13 +3,13 @@ import { UmbPickerSearchManager } from './search/manager/picker-search.manager.j import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/memory'; import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; -import { UmbMemoryManager } from 'src/packages/core/interaction-memory/index.js'; export class UmbPickerContext extends UmbContextBase { - public readonly memory = new UmbMemoryManager(this); + public readonly interactionMemory = new UmbInteractionMemoryManager(this); public readonly selection = new UmbSelectionManager(this); - public readonly search = new UmbPickerSearchManager(this, { memoryManager: this.memory }); + public readonly search = new UmbPickerSearchManager(this, { interactionMemoryManager: this.interactionMemory }); public dataType?: { unique: string }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 9d230974dbdb..9fe771d29ee9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -77,7 +77,7 @@ export class UmbTreePickerModalElement memory.unique === 'UmbTreeItemPickerModal', ); - pickerModalMemory?.memories?.forEach((memory) => this.#pickerContext.memory.setMemory(memory)); + pickerModalMemory?.memories?.forEach((memory) => this.#pickerContext.interactionMemory.setMemory(memory)); } } @@ -172,7 +172,7 @@ export class UmbTreePickerModalElement( From 9dd022569502c758b23d4cf9f1e07ed95c90c510 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 13:13:37 +0200 Subject: [PATCH 19/76] fix import --- .../core/tree/tree-picker-modal/tree-picker-modal.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 9fe771d29ee9..c4c57973a84b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -7,7 +7,7 @@ import { UmbModalBaseElement, type UmbModalRejectReason } from '@umbraco-cms/bac import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event'; -import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; @customElement('umb-tree-picker-modal') export class UmbTreePickerModalElement extends UmbModalBaseElement< From cbb4097d6a66c775b7bbd155e1c3939f508d20ed Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 13:15:31 +0200 Subject: [PATCH 20/76] rename module --- src/Umbraco.Web.UI.Client/package.json | 2 +- src/Umbraco.Web.UI.Client/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 35f89ac91c54..c3e3c7973e61 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -57,6 +57,7 @@ "./icon": "./dist-cms/packages/core/icon-registry/index.js", "./id": "./dist-cms/packages/core/id/index.js", "./imaging": "./dist-cms/packages/media/imaging/index.js", + "./interaction-memory": "./dist-cms/packages/core/interaction-memory/index.js", "./language": "./dist-cms/packages/language/index.js", "./lit-element": "./dist-cms/packages/core/lit-element/index.js", "./localization": "./dist-cms/packages/core/localization/index.js", @@ -69,7 +70,6 @@ "./member-type": "./dist-cms/packages/members/member-type/index.js", "./member": "./dist-cms/packages/members/member/index.js", "./member-public-access": "./dist-cms/packages/members/member-public-access/index.js", - "./memory": "./dist-cms/packages/core/memory/index.js", "./menu": "./dist-cms/packages/core/menu/index.js", "./modal": "./dist-cms/packages/core/modal/index.js", "./models": "./dist-cms/packages/core/models/index.js", diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 17c60f44fa2c..f99389051c88 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -86,6 +86,7 @@ DON'T EDIT THIS FILE DIRECTLY. It is generated by /devops/tsconfig/index.js "@umbraco-cms/backoffice/icon": ["./src/packages/core/icon-registry/index.ts"], "@umbraco-cms/backoffice/id": ["./src/packages/core/id/index.ts"], "@umbraco-cms/backoffice/imaging": ["./src/packages/media/imaging/index.ts"], + "@umbraco-cms/backoffice/interaction-memory": ["./src/packages/core/interaction-memory/index.ts"], "@umbraco-cms/backoffice/language": ["./src/packages/language/index.ts"], "@umbraco-cms/backoffice/lit-element": ["./src/packages/core/lit-element/index.ts"], "@umbraco-cms/backoffice/localization": ["./src/packages/core/localization/index.ts"], @@ -98,7 +99,6 @@ DON'T EDIT THIS FILE DIRECTLY. It is generated by /devops/tsconfig/index.js "@umbraco-cms/backoffice/member-type": ["./src/packages/members/member-type/index.ts"], "@umbraco-cms/backoffice/member": ["./src/packages/members/member/index.ts"], "@umbraco-cms/backoffice/member-public-access": ["./src/packages/members/member-public-access/index.ts"], - "@umbraco-cms/backoffice/memory": ["src/packages/core/interaction-memory/index.ts"], "@umbraco-cms/backoffice/menu": ["./src/packages/core/menu/index.ts"], "@umbraco-cms/backoffice/modal": ["./src/packages/core/modal/index.ts"], "@umbraco-cms/backoffice/models": ["./src/packages/core/models/index.ts"], From 4ec1a9806e3956e8adff062c431448e0fba49218 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 13:16:35 +0200 Subject: [PATCH 21/76] Update vite.config.ts --- src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts b/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts index cbc2bf772056..35aa800b95c7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/vite.config.ts @@ -37,7 +37,7 @@ export default defineConfig({ 'id/index': './id/index.ts', 'lit-element/index': './lit-element/index.ts', 'localization/index': './localization/index.ts', - 'memory/index': './memory/index.ts', + 'interaction-memory/index': './interaction-memory/index.ts', 'menu/index': './menu/index.ts', 'modal/index': './modal/index.ts', 'models/index': './models/index.ts', From 67271717ccb566a2922f4e4d30ee3fcb0a31f81b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 13:24:23 +0200 Subject: [PATCH 22/76] update module name --- .../src/packages/core/modal/context/modal.context.ts | 2 +- .../src/packages/core/picker/picker.context.ts | 2 +- .../core/picker/search/manager/picker-search.manager.ts | 5 ++++- .../core/tree/tree-picker-modal/tree-picker-modal.element.ts | 2 +- .../components/input-content/input-content.element.ts | 2 +- .../property-editor-ui-content-picker.element.ts | 5 ++++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index 46786c36ae55..bdaf9eed6406 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -8,7 +8,7 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { type UmbDeepPartialObject, umbDeepMerge } from '@umbraco-cms/backoffice/utils'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import { UMB_ROUTE_CONTEXT, type IRouterSlot } from '@umbraco-cms/backoffice/router'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; export interface UmbModalRejectReason { type: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index a90cda6b4e37..e985afd65a2b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -3,7 +3,7 @@ import { UmbPickerSearchManager } from './search/manager/picker-search.manager.j import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/memory'; +import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; export class UmbPickerContext extends UmbContextBase { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index 130c5841c63e..2af03bcf93ad 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -2,7 +2,10 @@ import type { UmbPickerSearchManagerConfig } from './types.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; -import type { UmbInteractionMemoryManager, UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { + UmbInteractionMemoryManager, + UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; import { UmbArrayState, UmbBooleanState, UmbNumberState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import type { UmbSearchProvider, UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search'; import { debounce } from '@umbraco-cms/backoffice/utils'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index c4c57973a84b..77805c0c9ff7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -7,7 +7,7 @@ import { UmbModalBaseElement, type UmbModalRejectReason } from '@umbraco-cms/bac import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-tree-picker-modal') export class UmbTreePickerModalElement extends UmbModalBaseElement< diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 8d027b81cf8c..94dd0c0ee172 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -6,7 +6,7 @@ import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-input-content') export class UmbInputContentElement extends UmbFormControlMixin( diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 9b5c20428bbd..b7dc9090dd8f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -16,7 +16,10 @@ import type { } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; -import { UMB_INTERACTION_MEMORY_CONTEXT, type UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/memory'; +import { + UMB_INTERACTION_MEMORY_CONTEXT, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; // import of local component import './components/input-content/index.js'; From 141b06763d718718c2941f23bdb63111d1fbc9cf Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 13:45:10 +0200 Subject: [PATCH 23/76] observe after search is initialized --- .../core/picker/search/manager/picker-search.manager.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index 2af03bcf93ad..fa8493844e8e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -58,7 +58,6 @@ export class UmbPickerSearchManager< super(host); if (args?.interactionMemoryManager) { this.#interactionMemoryManager = args.interactionMemoryManager; - this.#observeInteractionMemory(); } } @@ -186,6 +185,8 @@ export class UmbPickerSearchManager< } this.setSearchable(true); + + this.#observeInteractionMemory(); } #debouncedSearch = debounce(this.#search, 300); @@ -218,9 +219,11 @@ export class UmbPickerSearchManager< this.#searching.setValue(false); } + #muteMemoryObservation = false; + #observeInteractionMemory() { this.observe(this.#interactionMemoryManager?.memory(this.#interactionMemoryUnique), (memory) => { - console.log(memory); + if (this.#muteMemoryObservation) return; if (memory) { this.#applySearchRequestInteractionMemory(memory); @@ -240,7 +243,9 @@ export class UmbPickerSearchManager< ], }; + this.#muteMemoryObservation = true; this.#interactionMemoryManager?.setMemory(memory); + this.#muteMemoryObservation = false; } #applySearchRequestInteractionMemory(memory: UmbInteractionMemoryModel) { From 8fde5391dee2d9dd5adda819f00327f240eec0e5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 16:32:34 +0200 Subject: [PATCH 24/76] use memory manager in all places --- .../interaction-memory.manager.ts | 4 ++ .../core/modal/context/modal.context.ts | 19 ++++----- .../src/packages/core/modal/types.ts | 4 +- .../core/picker-input/picker-input.context.ts | 13 +++--- .../tree-picker-modal.element.ts | 34 +++++++++++----- .../input-document/input-document.context.ts | 2 + .../input-document/input-document.element.ts | 40 +++++-------------- 7 files changed, 56 insertions(+), 60 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts index 88afc792199e..05dbe6bd5961 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts @@ -25,4 +25,8 @@ export class UmbInteractionMemoryManager extends UmbControllerBase { getAllMemories() { return this.#memories.getValue(); } + + clear() { + this.#memories.clear(); + } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index bdaf9eed6406..7caa52134298 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -8,7 +8,10 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { type UmbDeepPartialObject, umbDeepMerge } from '@umbraco-cms/backoffice/utils'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import { UMB_ROUTE_CONTEXT, type IRouterSlot } from '@umbraco-cms/backoffice/router'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import { + UmbInteractionMemoryManager, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; export interface UmbModalRejectReason { type: string; @@ -60,8 +63,7 @@ export class UmbModalContext< #size = new UmbStringState('small'); public readonly size = this.#size.asObservable(); - #memory = new UmbObjectState(undefined); - public readonly memory = this.#memory.asObservable(); + public readonly interactionMemory = new UmbInteractionMemoryManager(this); constructor( host: UmbControllerHost, @@ -89,6 +91,9 @@ export class UmbModalContext< this.#size.setValue(size); + // Pass any provided memories to the interaction memory manager + args.data?.interactionMemories?.forEach((memory) => this.interactionMemory.setMemory(memory)); + const defaultData = this.alias instanceof UmbModalToken ? this.alias.getDefaultData() : undefined; this.data = Object.freeze( // If we have both data and defaultData perform a deep merge @@ -233,14 +238,6 @@ export class UmbModalContext< this.#size.setValue(size); } - public setMemory(memory: UmbInteractionMemoryModel | undefined) { - this.#memory.setValue(memory); - } - - public getMemory(): UmbInteractionMemoryModel | undefined { - return this.#memory.getValue(); - } - public override destroy(): void { this.dispatchEvent(new CustomEvent('umb:destroy')); this.#value.destroy(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index ff9b182267fa..881a5f07bbd8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -1,6 +1,6 @@ import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; -import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; export type * from './extensions/types.js'; @@ -9,7 +9,7 @@ export interface UmbPickerModalData { filter?: (item: ItemType) => boolean; pickableFilter?: (item: ItemType) => boolean; search?: UmbPickerModalSearchConfig; - memory?: UmbInteractionMemoryModel; + interactionMemories?: Array; } export interface UmbPickerModalSearchConfig> { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index b2c0f1118e1e..8720de607713 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -8,7 +8,10 @@ import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; -import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; +import { + UmbInteractionMemoryManager, + type UmbInteractionMemoryModel, +} from 'src/packages/core/interaction-memory/index.js'; type PickerItemBaseType = { name: string; unique: string }; export class UmbPickerInputContext< @@ -25,9 +28,7 @@ export class UmbPickerInputContext< public readonly selection; public readonly selectedItems; - - #memory = new UmbObjectState(undefined); - public readonly memory = this.#memory.asObservable(); + public readonly interactionMemory = new UmbInteractionMemoryManager(this); /** * Define a minimum amount of selected items in this input, for this input to be valid. @@ -116,8 +117,8 @@ export class UmbPickerInputContext< /* Check if we have any memory from the modal, and if so, apply it to the picker input context so it can be reached from the input element. */ - const modalMemory = modalContext?.getMemory(); - this.#memory.setValue(modalMemory); + const modalMemories = modalContext?.interactionMemory.getAllMemories(); + modalMemories.forEach((memory) => this.interactionMemory.setMemory(memory)); if (!modalValue) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 77805c0c9ff7..3d3afb3c66ba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -70,14 +70,8 @@ export class UmbTreePickerModalElement memory.unique === 'UmbTreeItemPickerModal', - ); - - pickerModalMemory?.memories?.forEach((memory) => this.#pickerContext.interactionMemory.setMemory(memory)); + if (this.data?.treeAlias) { + this.#observeInteractionMemories(); } } @@ -170,17 +164,37 @@ export class UmbTreePickerModalElement { + debugger; + memory?.memories?.forEach((memory) => this.#pickerContext.interactionMemory.setMemory(memory)); + }, + 'umbModalInteractionMemoryObserver', + ); + } + #setTreeItemPickerModalMemory() { // Get all memories from the picker context and set them as on combined memory for the picker modal const pickerMemories = this.#pickerContext.interactionMemory.getAllMemories(); if (pickerMemories?.length === 0) return; + const unique = this.#getInteractionMemoryUnique(this.data?.treeAlias); + if (!unique) return; const pickerModalMemory: UmbInteractionMemoryModel = { - unique: 'UmbTreeItemPickerModal', + unique, memories: pickerMemories, }; - this.modalContext?.setMemory(pickerModalMemory); + this.modalContext?.interactionMemory.setMemory(pickerModalMemory); } override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts index 11afa59568ee..627b7171b7ea 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts @@ -53,6 +53,8 @@ export class UmbDocumentPickerInputContext extends UmbPickerInputContext< ...pickerData?.search?.queryParams, }; + combinedPickerData.interactionMemories = this.interactionMemory.getAllMemories(); + await super.openPicker(combinedPickerData); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 0ba0aaa76329..2cfe11a4bee4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -8,7 +8,10 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type'; -import type { UmbInteractionMemoryModel } from 'src/packages/core/interaction-memory/index.js'; +import { + UmbInteractionMemoryManager, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-input-document') export class UmbInputDocumentElement extends UmbFormControlMixin( @@ -123,22 +126,14 @@ export class UmbInputDocumentElement extends UmbFormControlMixin | undefined { + return this.#pickerInputContext.interactionMemory.getAllMemories(); } - public set memory(value: UmbInteractionMemoryModel | undefined) { - this.#memory = value; - - // Check if we have a memory for this input, by looking for a memory with the same unique as this input. - // If we find one, we set it as the inputDocumentMemory, which is then passed to the picker modal when opened. - this.#inputDocumentMemory = value?.memories?.find((memory) => memory.unique === this.#memoryUnique); + public set interactionMemories(value: Array | undefined) { + value?.forEach((memory) => this.#pickerInputContext.interactionMemory.setMemory(memory)); } - #memoryUnique = 'UmbInputDocument'; - #memory?: UmbInteractionMemoryModel; - #inputDocumentMemory?: UmbInteractionMemoryModel; - @state() private _items?: Array; @@ -170,22 +165,6 @@ export class UmbInputDocumentElement extends UmbFormControlMixin (this._items = selectedItems), '_observerItems', ); - - this.observe( - this.#pickerInputContext.memory, - (memory) => { - if (!memory) return; - - const inputDocumentMemory: UmbInteractionMemoryModel = { - unique: 'UmbInputDocument', - memories: [memory], - }; - - this.#inputDocumentMemory = inputDocumentMemory; - console.log('Input Document Memory:', inputDocumentMemory); - }, - 'umbObservePickerInputMemory', - ); } #openPicker() { @@ -193,7 +172,6 @@ export class UmbInputDocumentElement extends UmbFormControlMixin ({ From 49ec3145f2084afead82ee19be3afc9f9e75f90b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 21:20:06 +0200 Subject: [PATCH 25/76] make picker modal base element --- .../src/packages/core/picker/index.ts | 1 + .../src/packages/core/picker/modal/index.ts | 1 + .../picker/modal/picker-modal-base.element.ts | 64 ++++++++++++++++ .../tree-picker-modal.element.ts | 74 ++++--------------- 4 files changed, 79 insertions(+), 61 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts index 90220a711a72..fb3be7e1556f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/index.ts @@ -1,4 +1,5 @@ export * from './constants.js'; +export * from './modal/index.js'; export * from './picker.context.js'; export * from './picker.context.token.js'; export * from './search/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/index.ts new file mode 100644 index 000000000000..762dc5e74cf6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/index.ts @@ -0,0 +1 @@ +export * from './picker-modal-base.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts new file mode 100644 index 000000000000..d2434c7522b5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -0,0 +1,64 @@ +import type { UmbPickerContext } from '../picker.context.js'; +import { property } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import { + UmbModalBaseElement, + type ManifestModal, + type UmbModalContext, + type UmbModalRejectReason, +} from '@umbraco-cms/backoffice/modal'; + +export abstract class UmbPickerModalBaseElement< + ModalDataType extends object = object, + ModalValueType = unknown, + ModalManifestType extends ManifestModal = ManifestModal, +> extends UmbModalBaseElement { + protected abstract _pickerContext: UmbPickerContext; + + @property({ attribute: false }) + public override set modalContext(context: UmbModalContext | undefined) { + super.modalContext = context; + this.#observeInteractionMemories(); + } + public override get modalContext(): UmbModalContext | undefined { + return super.modalContext; + } + + protected override _submitModal() { + this.#setTreeItemPickerModalMemory(); + super._submitModal(); + } + + protected override _rejectModal(reason?: UmbModalRejectReason) { + this.#setTreeItemPickerModalMemory(); + super._rejectModal(reason); + } + + #getInteractionMemoryUnique() { + // TODO: we need a unique key (id/label) from the element to append to the memory unique key + return 'UmbPickerModalMemory'; + } + + #observeInteractionMemories() { + this.observe( + this.modalContext?.interactionMemory.memory(this.#getInteractionMemoryUnique()), + (memory) => { + memory?.memories?.forEach((memory) => this._pickerContext.interactionMemory.setMemory(memory)); + }, + 'umbModalInteractionMemoryObserver', + ); + } + + #setTreeItemPickerModalMemory() { + // Get all memories from the picker context and set them as on combined memory for the picker modal + const pickerMemories = this._pickerContext.interactionMemory.getAllMemories(); + if (pickerMemories?.length === 0) return; + + const pickerModalMemory: UmbInteractionMemoryModel = { + unique: this.#getInteractionMemoryUnique(), + memories: pickerMemories, + }; + + this.modalContext?.interactionMemory.setMemory(pickerModalMemory); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 3d3afb3c66ba..8512217a2b16 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -3,14 +3,13 @@ import { UmbTreeItemPickerContext } from '../tree-item-picker/index.js'; import type { UmbTreePickerModalData, UmbTreePickerModalValue } from './tree-picker-modal.token.js'; import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; import { html, customElement, state, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit'; -import { UmbModalBaseElement, type UmbModalRejectReason } from '@umbraco-cms/backoffice/modal'; import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; @customElement('umb-tree-picker-modal') -export class UmbTreePickerModalElement extends UmbModalBaseElement< +export class UmbTreePickerModalElement extends UmbPickerModalBaseElement< UmbTreePickerModalData, UmbTreePickerModalValue > { @@ -33,12 +32,12 @@ export class UmbTreePickerModalElement { + this._pickerContext.selection.setSelectable(true); + this.observe(this._pickerContext.selection.hasSelection, (hasSelection) => { this._hasSelection = hasSelection; }); this.#observePickerSelection(); @@ -55,29 +54,25 @@ export class UmbTreePickerModalElement { this.updateValue({ selection }); this.requestUpdate(); @@ -98,7 +93,7 @@ export class UmbTreePickerModalElement { this._searchQuery = query?.query; }, @@ -109,13 +104,13 @@ export class UmbTreePickerModalElement { - debugger; - memory?.memories?.forEach((memory) => this.#pickerContext.interactionMemory.setMemory(memory)); - }, - 'umbModalInteractionMemoryObserver', - ); - } - - #setTreeItemPickerModalMemory() { - // Get all memories from the picker context and set them as on combined memory for the picker modal - const pickerMemories = this.#pickerContext.interactionMemory.getAllMemories(); - if (pickerMemories?.length === 0) return; - const unique = this.#getInteractionMemoryUnique(this.data?.treeAlias); - if (!unique) return; - - const pickerModalMemory: UmbInteractionMemoryModel = { - unique, - memories: pickerMemories, - }; - - this.modalContext?.interactionMemory.setMemory(pickerModalMemory); - } - override render() { return html` From a8ea47ba2ec8c6bd965bd412a7fa5353fdbccc73 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 21:29:41 +0200 Subject: [PATCH 26/76] update types --- .../packages/core/picker/modal/picker-modal-base.element.ts | 5 ++++- .../core/tree/tree-picker-modal/tree-picker-modal.element.ts | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index d2434c7522b5..9c25f35e637d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -1,4 +1,5 @@ import type { UmbPickerContext } from '../picker.context.js'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { property } from '@umbraco-cms/backoffice/external/lit'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import { @@ -6,10 +7,12 @@ import { type ManifestModal, type UmbModalContext, type UmbModalRejectReason, + type UmbPickerModalData, } from '@umbraco-cms/backoffice/modal'; export abstract class UmbPickerModalBaseElement< - ModalDataType extends object = object, + ItemType = UmbEntityModel, + ModalDataType extends UmbPickerModalData = UmbPickerModalData, ModalValueType = unknown, ModalManifestType extends ManifestModal = ManifestModal, > extends UmbModalBaseElement { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 8512217a2b16..037c82d09b92 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -10,6 +10,7 @@ import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; @customElement('umb-tree-picker-modal') export class UmbTreePickerModalElement extends UmbPickerModalBaseElement< + TreeItemType, UmbTreePickerModalData, UmbTreePickerModalValue > { From b36dddd91a12517969248714dba13069fb5ac41f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 10 Sep 2025 22:09:47 +0200 Subject: [PATCH 27/76] add memory for document picker property editor --- .../event/interaction-memory-change.event.ts | 8 ++ .../packages/core/interaction-memory/index.ts | 1 + .../core/picker-input/picker-input.context.ts | 6 +- .../input-document/input-document.element.ts | 14 +++- ...perty-editor-ui-document-picker.element.ts | 78 ++++++++++++++++++- 5 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts new file mode 100644 index 000000000000..d9005af164cd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts @@ -0,0 +1,8 @@ +export class UmbInteractionMemoryChangeEvent extends Event { + public static readonly TYPE = 'interaction-memory-change'; + + public constructor() { + // mimics the native change event + super(UmbInteractionMemoryChangeEvent.TYPE, { bubbles: true, composed: false, cancelable: false }); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts index a534dbd4bd9d..e23c10411cc9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts @@ -1,4 +1,5 @@ export * from './constants.js'; +export * from './event/interaction-memory-change.event.js'; export * from './interaction-memory.context.js'; export * from './interaction-memory.manager.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index 8720de607713..fc98614c5e8e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -7,11 +7,7 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; -import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; -import { - UmbInteractionMemoryManager, - type UmbInteractionMemoryModel, -} from 'src/packages/core/interaction-memory/index.js'; +import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; type PickerItemBaseType = { name: string; unique: string }; export class UmbPickerInputContext< diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 2cfe11a4bee4..b08419cbc08e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -9,7 +9,7 @@ import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type'; import { - UmbInteractionMemoryManager, + UmbInteractionMemoryChangeEvent, type UmbInteractionMemoryModel, } from '@umbraco-cms/backoffice/interaction-memory'; @@ -131,9 +131,12 @@ export class UmbInputDocumentElement extends UmbFormControlMixin | undefined) { + this.#interactionMemories = value; value?.forEach((memory) => this.#pickerInputContext.interactionMemory.setMemory(memory)); } + #interactionMemories?: Array = []; + @state() private _items?: Array; @@ -165,6 +168,15 @@ export class UmbInputDocumentElement extends UmbFormControlMixin (this._items = selectedItems), '_observerItems', ); + + this.observe( + this.#pickerInputContext.interactionMemory.memories, + (memories) => { + this.#interactionMemories = memories; + this.dispatchEvent(new UmbInteractionMemoryChangeEvent()); + }, + '_observeMemories', + ); } #openPicker() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 567d59739cdb..2df0d55ee3cc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -1,5 +1,6 @@ import type { UmbInputDocumentElement } from '../../components/input-document/input-document.element.js'; import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js'; +import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @@ -9,6 +10,10 @@ import type { UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; +import { + UMB_INTERACTION_MEMORY_CONTEXT, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-property-editor-ui-document-picker') export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { @@ -47,11 +52,80 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl @state() private _startNodeId?: string; + @state() + private _interactionMemories: Array = []; + + #dataTypeUnique?: string; + #memoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; + + constructor() { + super(); + + this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => { + this.observe(context?.dataType, (dataType) => { + this.#dataTypeUnique = dataType?.unique; + this.#getMemory(); + }); + }); + + this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { + this.#memoryContext = context; + this.#getMemory(); + }); + } + #onChange(event: CustomEvent & { target: UmbInputDocumentElement }) { this.value = event.target.value; this.dispatchEvent(new UmbChangeEvent()); } + #getMemoryUnique() { + if (!this.#dataTypeUnique) return; + return `UmbDocumentPickerPropertyEditorUi-${this.#dataTypeUnique}`; + } + + #getMemory() { + const memoryUnique = this.#getMemoryUnique(); + if (!memoryUnique) return; + if (!this.#memoryContext) return; + + const memory = this.#memoryContext.memory.getMemory(memoryUnique); + this._interactionMemories = memory?.memories ?? []; + } + + #setMemory(memories: Array) { + const memoryUnique = this.#getMemoryUnique(); + if (!memoryUnique) return; + if (!this.#memoryContext) return; + + // Set up memory for the Property Editor + Data Type context which includes all memories from the input + const dataTypeMemory: UmbInteractionMemoryModel = { + unique: memoryUnique, + memories, + }; + + this.#memoryContext.memory.setMemory(dataTypeMemory); + } + + #deleteMemory() { + const unique = this.#getMemoryUnique(); + if (!unique) { + throw new Error('Memory is unique is missing'); + } + this.#memoryContext?.memory.deleteMemory(unique); + } + + #onInteractionMemoriesChange(event: UmbChangeEvent) { + const target = event.target as UmbInputDocumentElement; + const interactionMemories = target.interactionMemories; + + if (interactionMemories && interactionMemories.length > 0) { + this.#setMemory(interactionMemories); + } else { + this.#deleteMemory(); + } + } + override render() { const startNode: UmbTreeStartNode | undefined = this._startNodeId ? { unique: this._startNodeId, entityType: UMB_DOCUMENT_ENTITY_TYPE } @@ -64,7 +138,9 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl .startNode=${startNode} .value=${this.value} @change=${this.#onChange} - ?readonly=${this.readonly}> + ?readonly=${this.readonly} + .interactionMemories=${this._interactionMemories} + @interaction-memory-change=${this.#onInteractionMemoriesChange}> `; } From f7aec47e645f86d90ce310dec4cb0f75e4505043 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 10:18:16 +0200 Subject: [PATCH 28/76] store tree item picker expansion state in interaction memory --- .../tree-item-picker-expansion.manager.ts | 85 +++++++++++++++++++ .../tree-item-picker.context.ts | 8 +- .../tree-picker-modal.element.ts | 26 +++++- 3 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts new file mode 100644 index 000000000000..e54268e1cbfe --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts @@ -0,0 +1,85 @@ +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { + UmbInteractionMemoryManager, + UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbEntityExpansionManager, type UmbEntityExpansionModel } from '@umbraco-cms/backoffice/utils'; + +export interface UmbTreeItemPickerExpansionManagerArgs { + interactionMemoryManager?: UmbInteractionMemoryManager; +} + +export class UmbTreeItemPickerExpansionManager extends UmbControllerBase { + #manager = new UmbEntityExpansionManager(this); + public readonly expansion = this.#manager.expansion; + + #interactionMemoryManager?: UmbInteractionMemoryManager; + #interactionMemoryUnique: string = 'UmbTreeItemPickerExpansion'; + #muteMemoryObservation = false; + + constructor(host: UmbControllerHost, args?: UmbTreeItemPickerExpansionManagerArgs) { + super(host); + this.#interactionMemoryManager = args?.interactionMemoryManager; + + if (this.#interactionMemoryManager) { + this.#observeInteractionMemory(); + } + } + + /** + * Sets the full expansion state + * @param {UmbEntityExpansionModel} expansion - The full expansion state to set + * @memberof UmbTreeItemPickerExpansionManager + */ + setExpansion(expansion: UmbEntityExpansionModel): void { + this.#manager.setExpansion(expansion); + // Store the latest expansion state in interaction memory + this.#setExpansionMemory(); + } + + /** + * Gets the current expansion state + * @returns {UmbEntityExpansionModel} The full expansion state + * @memberof UmbTreeItemPickerExpansionManager + */ + getExpansion(): UmbEntityExpansionModel { + return this.#manager.getExpansion(); + } + + #observeInteractionMemory() { + this.observe(this.#interactionMemoryManager?.memory(this.#interactionMemoryUnique), (memory) => { + if (this.#muteMemoryObservation) return; + + if (memory) { + this.#applyExpansionInteractionMemory(memory); + } + }); + } + + #setExpansionMemory() { + // Add a memory entry with the latest expansion state + const memory: UmbInteractionMemoryModel = { + unique: this.#interactionMemoryUnique, + values: [ + { + unique: this.#interactionMemoryUnique, + expansion: this.getExpansion(), + }, + ], + }; + + this.#muteMemoryObservation = true; + this.#interactionMemoryManager?.setMemory(memory); + this.#muteMemoryObservation = false; + } + + #applyExpansionInteractionMemory(memory: UmbInteractionMemoryModel) { + const memoryValue = memory?.values?.find((x) => x.unique === this.#interactionMemoryUnique); + const memoryExpansion = memoryValue?.expansion as UmbEntityExpansionModel | undefined; + + if (memoryExpansion) { + this.#manager.setExpansion(memoryExpansion); + } + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker.context.ts index 99f163c25cb4..bd30dcf6385b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker.context.ts @@ -1,10 +1,10 @@ +import { UmbTreeItemPickerExpansionManager } from './tree-item-picker-expansion.manager.js'; import { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; export class UmbTreeItemPickerContext extends UmbPickerContext { - constructor(host: UmbControllerHost) { - super(host); - } + public readonly expansion = new UmbTreeItemPickerExpansionManager(this, { + interactionMemoryManager: this.interactionMemory, + }); } export { UmbTreeItemPickerContext as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 037c82d09b92..4d6e4d94b2e1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -1,5 +1,6 @@ import type { UmbTreeItemModelBase, UmbTreeSelectionConfiguration } from '../types.js'; import { UmbTreeItemPickerContext } from '../tree-item-picker/index.js'; +import type { UmbTreeElement } from '../tree.element.js'; import type { UmbTreePickerModalData, UmbTreePickerModalValue } from './tree-picker-modal.token.js'; import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; import { html, customElement, state, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit'; @@ -7,6 +8,7 @@ import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event'; import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; +import type { UmbEntityExpansionModel, UmbExpansionChangeEvent } from '@umbraco-cms/backoffice/utils'; @customElement('umb-tree-picker-modal') export class UmbTreePickerModalElement extends UmbPickerModalBaseElement< @@ -33,6 +35,9 @@ export class UmbTreePickerModalElement { + this._treeExpansion = value; + }, + 'umbTreeItemPickerExpansionObserver', + ); + } + // Tree Selection #onTreeItemSelected(event: UmbSelectedEvent) { event.stopPropagation(); @@ -150,6 +166,12 @@ export class UmbTreePickerModalElement @@ -182,9 +204,11 @@ export class UmbTreePickerModalElement + @deselected=${this.#onTreeItemDeselected} + @expansion-change=${this.#onTreeItemExpansionChange}> `; } From e98369a68bdc8e3db06b6180aa6fec259f0b2a7f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 10:21:18 +0200 Subject: [PATCH 29/76] Update picker-modal-base.element.ts --- .../src/packages/core/picker/modal/picker-modal-base.element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index 9c25f35e637d..68fe3f8e89d7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -38,7 +38,6 @@ export abstract class UmbPickerModalBaseElement< } #getInteractionMemoryUnique() { - // TODO: we need a unique key (id/label) from the element to append to the memory unique key return 'UmbPickerModalMemory'; } From 533cbfa14784178b525337dd58b8811d4b4001d6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 10:25:30 +0200 Subject: [PATCH 30/76] remove the memory if we have no expansion state --- .../tree-item-picker-expansion.manager.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts index e54268e1cbfe..b48912df7cfe 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts @@ -34,8 +34,13 @@ export class UmbTreeItemPickerExpansionManager extends UmbControllerBase { */ setExpansion(expansion: UmbEntityExpansionModel): void { this.#manager.setExpansion(expansion); + // Store the latest expansion state in interaction memory - this.#setExpansionMemory(); + if (expansion.length > 0) { + this.#setExpansionMemory(); + } else { + this.#removeExpansionMemory(); + } } /** @@ -58,6 +63,8 @@ export class UmbTreeItemPickerExpansionManager extends UmbControllerBase { } #setExpansionMemory() { + if (!this.#interactionMemoryManager) return; + // Add a memory entry with the latest expansion state const memory: UmbInteractionMemoryModel = { unique: this.#interactionMemoryUnique, @@ -74,6 +81,11 @@ export class UmbTreeItemPickerExpansionManager extends UmbControllerBase { this.#muteMemoryObservation = false; } + #removeExpansionMemory() { + if (!this.#interactionMemoryManager) return; + this.#interactionMemoryManager.deleteMemory(this.#interactionMemoryUnique); + } + #applyExpansionInteractionMemory(memory: UmbInteractionMemoryModel) { const memoryValue = memory?.values?.find((x) => x.unique === this.#interactionMemoryUnique); const memoryExpansion = memoryValue?.expansion as UmbEntityExpansionModel | undefined; From 482b81f0f2b0846eff0f8c0d23c01d454e3e8246 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 10:37:24 +0200 Subject: [PATCH 31/76] delete memory if it doesn't include anything --- .../picker/modal/picker-modal-base.element.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index 68fe3f8e89d7..68bb5da55267 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -54,13 +54,16 @@ export abstract class UmbPickerModalBaseElement< #setTreeItemPickerModalMemory() { // Get all memories from the picker context and set them as on combined memory for the picker modal const pickerMemories = this._pickerContext.interactionMemory.getAllMemories(); - if (pickerMemories?.length === 0) return; - const pickerModalMemory: UmbInteractionMemoryModel = { - unique: this.#getInteractionMemoryUnique(), - memories: pickerMemories, - }; + if (pickerMemories?.length > 0) { + const pickerModalMemory: UmbInteractionMemoryModel = { + unique: this.#getInteractionMemoryUnique(), + memories: pickerMemories, + }; - this.modalContext?.interactionMemory.setMemory(pickerModalMemory); + this.modalContext?.interactionMemory.setMemory(pickerModalMemory); + } else { + this.modalContext?.interactionMemory.deleteMemory(this.#getInteractionMemoryUnique()); + } } } From 1845e395fb4e12a207f9e024794da045fe79c670 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 10:49:49 +0200 Subject: [PATCH 32/76] clear picker input memories if nothing comes from the modal --- .../core/picker-input/picker-input.context.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index fc98614c5e8e..3e6b1ec8b18d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -7,7 +7,10 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; -import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; +import { + UmbInteractionMemoryManager, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; type PickerItemBaseType = { name: string; unique: string }; export class UmbPickerInputContext< @@ -111,10 +114,7 @@ export class UmbPickerInputContext< const modalValue = await modalContext.onSubmit().catch(() => undefined); - /* Check if we have any memory from the modal, and if so, - apply it to the picker input context so it can be reached from the input element. */ - const modalMemories = modalContext?.interactionMemory.getAllMemories(); - modalMemories.forEach((memory) => this.interactionMemory.setMemory(memory)); + this.#handleModalMemories(modalContext?.interactionMemory.getAllMemories() ?? []); if (!modalValue) return; @@ -141,4 +141,14 @@ export class UmbPickerInputContext< this.setSelection(newSelection); this.getHostElement().dispatchEvent(new UmbChangeEvent()); } + + #handleModalMemories(modalMemories: Array) { + /* Check if we have any memories from the modal, and if so, + apply it to the picker input context so it can be reached from the input element. */ + if (modalMemories.length > 0) { + modalMemories.forEach((memory) => this.interactionMemory.setMemory(memory)); + } else { + this.interactionMemory.clear(); + } + } } From 5976f0badf57518b8058cc18f493fa1ef897a320 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 10:56:44 +0200 Subject: [PATCH 33/76] Refactor interaction memory handling in picker input Moved the passing of interaction memories from the document picker input context to the core picker input context. Renamed the method for setting memories from the modal for clarity and consistency. --- .../src/packages/core/picker-input/picker-input.context.ts | 5 +++-- .../components/input-document/input-document.context.ts | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index 3e6b1ec8b18d..f4b5b18f1fa8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -105,6 +105,7 @@ export class UmbPickerInputContext< const modalContext = modalManagerContext.open(this, this.modalAlias, { data: { multiple: this._max === 1 ? false : true, + interactionMemories: this.interactionMemory.getAllMemories(), ...pickerData, }, value: { @@ -114,7 +115,7 @@ export class UmbPickerInputContext< const modalValue = await modalContext.onSubmit().catch(() => undefined); - this.#handleModalMemories(modalContext?.interactionMemory.getAllMemories() ?? []); + this.#setMemoriesFromModal(modalContext?.interactionMemory.getAllMemories() ?? []); if (!modalValue) return; @@ -142,7 +143,7 @@ export class UmbPickerInputContext< this.getHostElement().dispatchEvent(new UmbChangeEvent()); } - #handleModalMemories(modalMemories: Array) { + #setMemoriesFromModal(modalMemories: Array) { /* Check if we have any memories from the modal, and if so, apply it to the picker input context so it can be reached from the input element. */ if (modalMemories.length > 0) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts index 627b7171b7ea..11afa59568ee 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts @@ -53,8 +53,6 @@ export class UmbDocumentPickerInputContext extends UmbPickerInputContext< ...pickerData?.search?.queryParams, }; - combinedPickerData.interactionMemories = this.interactionMemory.getAllMemories(); - await super.openPicker(combinedPickerData); } From 69d420c6044dafb53f45f027333a0454f11ebe29 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 11:12:18 +0200 Subject: [PATCH 34/76] only dispatch an event if the value changes --- .../components/input-document/input-document.element.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index b08419cbc08e..f66b44665929 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -12,6 +12,7 @@ import { UmbInteractionMemoryChangeEvent, type UmbInteractionMemoryModel, } from '@umbraco-cms/backoffice/interaction-memory'; +import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; @customElement('umb-input-document') export class UmbInputDocumentElement extends UmbFormControlMixin( @@ -172,8 +173,14 @@ export class UmbInputDocumentElement extends UmbFormControlMixin { + // only dispatch the event if the interaction memories have actually changed + const isIdentical = jsonStringComparison(memories, this.#interactionMemories); + + if (!isIdentical) { + this.dispatchEvent(new UmbInteractionMemoryChangeEvent()); + } + this.#interactionMemories = memories; - this.dispatchEvent(new UmbInteractionMemoryChangeEvent()); }, '_observeMemories', ); From 5fbeea83060379b1cfbee06815cb446576302929 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 11:21:22 +0200 Subject: [PATCH 35/76] remove unused --- .../src/packages/core/modal/context/modal.context.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index 7caa52134298..8ee66df425ed 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -8,10 +8,7 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { type UmbDeepPartialObject, umbDeepMerge } from '@umbraco-cms/backoffice/utils'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import { UMB_ROUTE_CONTEXT, type IRouterSlot } from '@umbraco-cms/backoffice/router'; -import { - UmbInteractionMemoryManager, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; export interface UmbModalRejectReason { type: string; From c5a10e569ae575fc1a56b744d7f9ea54af960631 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 12:14:19 +0200 Subject: [PATCH 36/76] observe to support close on escape --- .../picker/modal/picker-modal-base.element.ts | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index 68bb5da55267..caf3bb86cc01 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -6,7 +6,6 @@ import { UmbModalBaseElement, type ManifestModal, type UmbModalContext, - type UmbModalRejectReason, type UmbPickerModalData, } from '@umbraco-cms/backoffice/modal'; @@ -21,27 +20,28 @@ export abstract class UmbPickerModalBaseElement< @property({ attribute: false }) public override set modalContext(context: UmbModalContext | undefined) { super.modalContext = context; - this.#observeInteractionMemories(); + this.#observeModalInteractionMemories(); } public override get modalContext(): UmbModalContext | undefined { return super.modalContext; } - protected override _submitModal() { - this.#setTreeItemPickerModalMemory(); - super._submitModal(); + override connectedCallback(): void { + super.connectedCallback(); + this.#observePickerModalInteractionMemories(); } - protected override _rejectModal(reason?: UmbModalRejectReason) { - this.#setTreeItemPickerModalMemory(); - super._rejectModal(reason); + #observePickerModalInteractionMemories() { + this.observe(this._pickerContext.interactionMemory.memories, (memories) => { + this.#setTreeItemPickerModalMemory(memories); + }); } #getInteractionMemoryUnique() { return 'UmbPickerModalMemory'; } - #observeInteractionMemories() { + #observeModalInteractionMemories() { this.observe( this.modalContext?.interactionMemory.memory(this.#getInteractionMemoryUnique()), (memory) => { @@ -51,10 +51,7 @@ export abstract class UmbPickerModalBaseElement< ); } - #setTreeItemPickerModalMemory() { - // Get all memories from the picker context and set them as on combined memory for the picker modal - const pickerMemories = this._pickerContext.interactionMemory.getAllMemories(); - + #setTreeItemPickerModalMemory(pickerMemories: Array) { if (pickerMemories?.length > 0) { const pickerModalMemory: UmbInteractionMemoryModel = { unique: this.#getInteractionMemoryUnique(), From bfd122b45b10c4faba1c13d198bd9ac580a82b6c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 12:20:29 +0200 Subject: [PATCH 37/76] add comments --- .../packages/core/picker/modal/picker-modal-base.element.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index caf3bb86cc01..8aaed83ce8c3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -28,6 +28,8 @@ export abstract class UmbPickerModalBaseElement< override connectedCallback(): void { super.connectedCallback(); + // We need to observe the picker memories to be able to update the modal memory. + // We observe the memories to support close with esc key or clicking outside the modal. this.#observePickerModalInteractionMemories(); } @@ -38,7 +40,8 @@ export abstract class UmbPickerModalBaseElement< } #getInteractionMemoryUnique() { - return 'UmbPickerModalMemory'; + // TODO: consider appending with a picker unique when we have that implemented. + return `UmbPickerModalMemory`; } #observeModalInteractionMemories() { From 82e584daadaf59bf73b63976f5e4a778507eebf7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 12:22:21 +0200 Subject: [PATCH 38/76] fix type error --- .../core/picker/search/manager/picker-search.manager.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index fa8493844e8e..f8b927557d70 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -250,9 +250,10 @@ export class UmbPickerSearchManager< #applySearchRequestInteractionMemory(memory: UmbInteractionMemoryModel) { const memoryValue = memory?.values?.find((x) => x.unique === this.#interactionMemoryUnique + 'LatestRequestArgs'); + const requestArgs = memoryValue?.requestArgs as SearchRequestArgsType | undefined; - if (memoryValue?.requestArgs) { - this.#query.setValue(memoryValue.requestArgs); + if (requestArgs) { + this.#query.setValue(requestArgs); this.search(); } } From 71dc79fe1682756bd03fbb6c288d73cd8172825f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 12:24:54 +0200 Subject: [PATCH 39/76] fix typings --- .../src/packages/core/modal/context/modal.context.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index 8ee66df425ed..ebf0aa5c4e88 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -8,7 +8,10 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { type UmbDeepPartialObject, umbDeepMerge } from '@umbraco-cms/backoffice/utils'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import { UMB_ROUTE_CONTEXT, type IRouterSlot } from '@umbraco-cms/backoffice/router'; -import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; +import { + UmbInteractionMemoryManager, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; export interface UmbModalRejectReason { type: string; @@ -89,7 +92,8 @@ export class UmbModalContext< this.#size.setValue(size); // Pass any provided memories to the interaction memory manager - args.data?.interactionMemories?.forEach((memory) => this.interactionMemory.setMemory(memory)); + const memories = ((args.data?.interactionMemories as Array) || undefined) ?? []; + memories.forEach((memory) => this.interactionMemory.setMemory(memory)); const defaultData = this.alias instanceof UmbModalToken ? this.alias.getDefaultData() : undefined; this.data = Object.freeze( From 072df2c868c79a5764eae41b7cfc9c0fbc4abae6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 13:51:30 +0200 Subject: [PATCH 40/76] Replaces data type-based memory keys with config hash-based keys --- ...perty-editor-ui-document-picker.element.ts | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 2df0d55ee3cc..3693fbe7a1bc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -14,6 +14,7 @@ import { UMB_INTERACTION_MEMORY_CONTEXT, type UmbInteractionMemoryModel, } from '@umbraco-cms/backoffice/interaction-memory'; +import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; @customElement('umb-property-editor-ui-document-picker') export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { @@ -21,6 +22,8 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl public value?: string; public set config(config: UmbPropertyEditorConfigCollection | undefined) { + this.#setConfigHash(config); + if (!config) return; const minMax = config.getValueByAlias('validationLimit'); @@ -30,6 +33,8 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl } this._startNodeId = config.getValueByAlias('startNodeId'); + + this.#getInteractionMemory(); } /** @@ -55,48 +60,46 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl @state() private _interactionMemories: Array = []; - #dataTypeUnique?: string; - #memoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; + #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; + #configHashCode?: number; constructor() { super(); - this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => { - this.observe(context?.dataType, (dataType) => { - this.#dataTypeUnique = dataType?.unique; - this.#getMemory(); - }); - }); - this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { - this.#memoryContext = context; - this.#getMemory(); + this.#interactionMemoryContext = context; + this.#getInteractionMemory(); }); } + #setConfigHash(config: UmbPropertyEditorConfigCollection | undefined) { + const configString = config ? JSON.stringify(config.toObject()) : ''; + const hashCode = simpleHashCode(configString); + this.#configHashCode = hashCode; + } + #onChange(event: CustomEvent & { target: UmbInputDocumentElement }) { this.value = event.target.value; this.dispatchEvent(new UmbChangeEvent()); } - #getMemoryUnique() { - if (!this.#dataTypeUnique) return; - return `UmbDocumentPickerPropertyEditorUi-${this.#dataTypeUnique}`; + #getInteractionMemoryUnique() { + return `UmbDocumentPickerPropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; } - #getMemory() { - const memoryUnique = this.#getMemoryUnique(); + #getInteractionMemory() { + const memoryUnique = this.#getInteractionMemoryUnique(); if (!memoryUnique) return; - if (!this.#memoryContext) return; + if (!this.#interactionMemoryContext) return; - const memory = this.#memoryContext.memory.getMemory(memoryUnique); + const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); this._interactionMemories = memory?.memories ?? []; } - #setMemory(memories: Array) { - const memoryUnique = this.#getMemoryUnique(); + #setInteractionMemory(memories: Array) { + const memoryUnique = this.#getInteractionMemoryUnique(); if (!memoryUnique) return; - if (!this.#memoryContext) return; + if (!this.#interactionMemoryContext) return; // Set up memory for the Property Editor + Data Type context which includes all memories from the input const dataTypeMemory: UmbInteractionMemoryModel = { @@ -104,15 +107,15 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl memories, }; - this.#memoryContext.memory.setMemory(dataTypeMemory); + this.#interactionMemoryContext.memory.setMemory(dataTypeMemory); } - #deleteMemory() { - const unique = this.#getMemoryUnique(); + #deleteInteractionMemory() { + const unique = this.#getInteractionMemoryUnique(); if (!unique) { throw new Error('Memory is unique is missing'); } - this.#memoryContext?.memory.deleteMemory(unique); + this.#interactionMemoryContext?.memory.deleteMemory(unique); } #onInteractionMemoriesChange(event: UmbChangeEvent) { @@ -120,9 +123,9 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl const interactionMemories = target.interactionMemories; if (interactionMemories && interactionMemories.length > 0) { - this.#setMemory(interactionMemories); + this.#setInteractionMemory(interactionMemories); } else { - this.#deleteMemory(); + this.#deleteInteractionMemory(); } } From 1f1a56ebef9c8154e326297c02e9ad3b11800715 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 15:03:50 +0200 Subject: [PATCH 41/76] dont store picker search in interaction memory --- .../search/manager/picker-search.manager.ts | 70 ------------------- 1 file changed, 70 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index f8b927557d70..cd0b232b4168 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -1,19 +1,10 @@ import type { UmbPickerSearchManagerConfig } from './types.js'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; -import type { - UmbInteractionMemoryManager, - UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; import { UmbArrayState, UmbBooleanState, UmbNumberState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import type { UmbSearchProvider, UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search'; import { debounce } from '@umbraco-cms/backoffice/utils'; -export interface UmbPickerSearchManagerArgs { - interactionMemoryManager?: UmbInteractionMemoryManager; -} - /** * A manager for searching items in a picker. * @exports @@ -44,23 +35,6 @@ export class UmbPickerSearchManager< #config?: UmbPickerSearchManagerConfig; #searchProvider?: UmbSearchProvider; - #interactionMemoryManager?: UmbInteractionMemoryManager; - #interactionMemoryUnique: string = 'UmbPickerSearch'; - - /** - * Creates an instance of UmbPickerSearchManager. - * @param {UmbControllerHost} host The controller host for the search manager. - * @param args Optional arguments for the search manager. - * @param {UmbInteractionMemoryManager} [args.interactionMemoryManager] An optional memory manager to store selected items. - * @memberof UmbPickerSearchManager - */ - constructor(host: UmbControllerHost, args?: UmbPickerSearchManagerArgs) { - super(host); - if (args?.interactionMemoryManager) { - this.#interactionMemoryManager = args.interactionMemoryManager; - } - } - /** * Set the configuration for the search manager. * @param {UmbPickerSearchManagerConfig} config The configuration for the search manager. @@ -134,7 +108,6 @@ export class UmbPickerSearchManager< this.#resultItems.setValue([]); this.#searching.setValue(false); this.#resultTotalItems.setValue(0); - this.#interactionMemoryManager?.deleteMemory(this.#interactionMemoryUnique); } /** @@ -185,8 +158,6 @@ export class UmbPickerSearchManager< } this.setSearchable(true); - - this.#observeInteractionMemory(); } #debouncedSearch = debounce(this.#search, 300); @@ -210,51 +181,10 @@ export class UmbPickerSearchManager< dataTypeUnique: this.#config?.dataTypeUnique, }; - this.#setSearchRequestMemory(args); - const { data } = await this.#searchProvider.search(args); const items = (data?.items as ResultItemType[]) ?? []; this.#resultItems.setValue(items); this.#resultTotalItems.setValue(data?.total ?? 0); this.#searching.setValue(false); } - - #muteMemoryObservation = false; - - #observeInteractionMemory() { - this.observe(this.#interactionMemoryManager?.memory(this.#interactionMemoryUnique), (memory) => { - if (this.#muteMemoryObservation) return; - - if (memory) { - this.#applySearchRequestInteractionMemory(memory); - } - }); - } - - #setSearchRequestMemory(args: SearchRequestArgsType) { - // Add a memory entry with the latest request args - const memory: UmbInteractionMemoryModel = { - unique: this.#interactionMemoryUnique, - values: [ - { - unique: this.#interactionMemoryUnique + 'LatestRequestArgs', - requestArgs: args, - }, - ], - }; - - this.#muteMemoryObservation = true; - this.#interactionMemoryManager?.setMemory(memory); - this.#muteMemoryObservation = false; - } - - #applySearchRequestInteractionMemory(memory: UmbInteractionMemoryModel) { - const memoryValue = memory?.values?.find((x) => x.unique === this.#interactionMemoryUnique + 'LatestRequestArgs'); - const requestArgs = memoryValue?.requestArgs as SearchRequestArgsType | undefined; - - if (requestArgs) { - this.#query.setValue(requestArgs); - this.search(); - } - } } From 6578e6cd715945a7c38a4769b5c8abed9b0c0856 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 16:13:37 +0200 Subject: [PATCH 42/76] Rename interaction memory key in picker modal base --- .../src/packages/core/picker/modal/picker-modal-base.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index 8aaed83ce8c3..5433e0e28b7a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -41,7 +41,7 @@ export abstract class UmbPickerModalBaseElement< #getInteractionMemoryUnique() { // TODO: consider appending with a picker unique when we have that implemented. - return `UmbPickerModalMemory`; + return `UmbPickerModal`; } #observeModalInteractionMemories() { From ef70022e728f5f59c723a2da4dec74516e847a9f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 16:13:51 +0200 Subject: [PATCH 43/76] Remove error throw for missing interaction memory --- .../property-editor-ui-document-picker.element.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 3693fbe7a1bc..651052077a6c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -1,6 +1,5 @@ import type { UmbInputDocumentElement } from '../../components/input-document/input-document.element.js'; import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js'; -import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @@ -112,9 +111,7 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl #deleteInteractionMemory() { const unique = this.#getInteractionMemoryUnique(); - if (!unique) { - throw new Error('Memory is unique is missing'); - } + if (!unique) return; this.#interactionMemoryContext?.memory.deleteMemory(unique); } From c7f7aaa37592d713de0cdfd535c75654b3ce730c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 16:14:24 +0200 Subject: [PATCH 44/76] Refactor interaction memory handling in content picker Replaces the single 'memory' property with an 'interactionMemories' array and updates event handling to support multiple interaction memories. Adjusts property types, event listeners, and child component bindings to accommodate this change. --- .../input-content/input-content.element.ts | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 94dd0c0ee172..8465134a0f2c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -6,7 +6,10 @@ import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import { + UmbInteractionMemoryChangeEvent, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-input-content') export class UmbInputContentElement extends UmbFormControlMixin( @@ -73,10 +76,17 @@ export class UmbInputContentElement extends UmbFormControlMixin | undefined { + return this.#interactionMemories; + } + public set interactionMemories(value: Array | undefined) { + this.#interactionMemories = value; + } + + #interactionMemories: Array | undefined; #entityTypeLookup = { content: 'document', media: 'media', member: 'member' }; @@ -92,6 +102,15 @@ export class UmbInputContentElement extends UmbFormControlMixin + @change=${this.#onChange} + .interactionMemories=${this.#interactionMemories} + @interaction-memory-change=${this.#onInteractionMemoriesChange}> `; } From aaa7503c1f17a4c3a411034044dea6770b853633 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 16:14:48 +0200 Subject: [PATCH 45/76] Refactor content picker to use interaction memories Replaces the previous memory handling with a new approach using interaction memories, including unique hash generation based on config. Updates event handling and property names to align with the new interaction memory model, improving state management and consistency. --- ...operty-editor-ui-content-picker.element.ts | 83 ++++++++++++------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index b7dc9090dd8f..95746bcd5098 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -15,7 +15,6 @@ import type { UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import { UMB_INTERACTION_MEMORY_CONTEXT, type UmbInteractionMemoryModel, @@ -23,6 +22,7 @@ import { // import of local component import './components/input-content/index.js'; +import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; type UmbContentPickerValueType = UmbInputContentElement['selection']; @@ -71,10 +71,10 @@ export class UmbPropertyEditorUIContentPickerElement private _invalidData?: UmbContentPickerValueType; @state() - private _memory?: UmbInteractionMemoryModel; + private _interactionMemories: Array = []; - #dataTypeUnique?: string; - #memoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; + #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; + #configHashCode?: number; #dynamicRoot?: UmbContentPickerSource['dynamicRoot']; #dynamicRootRepository = new UmbContentPickerDynamicRootRepository(this); @@ -86,6 +86,8 @@ export class UmbPropertyEditorUIContentPickerElement }; public set config(config: UmbPropertyEditorConfigCollection | undefined) { + this.#setConfigHash(config); + if (!config) return; const startNode = config.getValueByAlias('startNode'); @@ -119,16 +121,9 @@ export class UmbPropertyEditorUIContentPickerElement constructor() { super(); - this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => { - this.observe(context?.dataType, (dataType) => { - this.#dataTypeUnique = dataType?.unique; - this.#getMemory(); - }); - }); - this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { - this.#memoryContext = context; - this.#getMemory(); + this.#interactionMemoryContext = context; + this.#getInteractionMemory(); }); } @@ -154,6 +149,12 @@ export class UmbPropertyEditorUIContentPickerElement return this.shadowRoot?.querySelector('umb-input-content')?.focus(); } + #setConfigHash(config: UmbPropertyEditorConfigCollection | undefined) { + const configString = config ? JSON.stringify(config.toObject()) : ''; + const hashCode = simpleHashCode(configString); + this.#configHashCode = hashCode; + } + async #setPickerRootUnique() { // If we have a root unique value, we don't need to fetch it from the dynamic root if (this._rootUnique) return; @@ -192,38 +193,56 @@ export class UmbPropertyEditorUIContentPickerElement const memory = target?.memory; if (memory) { - this.#setMemory(memory); + this.#setInteractionMemory(memory); } } - #getMemory() { - const memoryUnique = this.#getMemoryUnique(); + #getInteractionMemoryUnique() { + return `UmbContentPickerPropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; + } + + #getInteractionMemory() { + const memoryUnique = this.#getInteractionMemoryUnique(); if (!memoryUnique) return; - if (!this.#memoryContext) return; + if (!this.#interactionMemoryContext) return; - this._memory = this.#memoryContext.memory.getMemory(memoryUnique); - console.log('Memory', memoryUnique, this._memory); + const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); + this._interactionMemories = memory?.memories ?? []; + debugger; } - #setMemory(memory: UmbInteractionMemoryModel) { - const memoryUnique = this.#getMemoryUnique(); + #setInteractionMemory(memories: Array) { + const memoryUnique = this.#getInteractionMemoryUnique(); if (!memoryUnique) return; - if (!this.#memoryContext) return; + if (!this.#interactionMemoryContext) return; - // Set up memory for this context which includes all memories from the input - const inputMemory: UmbInteractionMemoryModel = { + // Set up memory for the Property Editor + Data Type context which includes all memories from the input + const dataTypeMemory: UmbInteractionMemoryModel = { unique: memoryUnique, - memories: memory.memories, + memories, }; - this.#memoryContext.memory.setMemory(inputMemory); + this.#interactionMemoryContext.memory.setMemory(dataTypeMemory); + } + + #deleteInteractionMemory() { + const unique = this.#getInteractionMemoryUnique(); + if (!unique) { + throw new Error('Memory is unique is missing'); + } + this.#interactionMemoryContext?.memory.deleteMemory(unique); } - #getMemoryUnique() { - if (!this.#memoryContext) return; - if (!this.#dataTypeUnique) return; + #onInteractionMemoriesChange(event: UmbChangeEvent) { + const target = event.target as UmbInputContentElement; + const interactionMemories = target.interactionMemories; + debugger; - return `UmbContentPickerPropertyEditorUi-${this._type}-${this.#dataTypeUnique}`; + if (interactionMemories && interactionMemories.length > 0) { + this.#setInteractionMemory(interactionMemories); + } else { + this.#deleteInteractionMemory(); + } } override render() { @@ -242,10 +261,10 @@ export class UmbPropertyEditorUIContentPickerElement .maxMessage=${this._maxMessage} .startNode=${startNode} .allowedContentTypeIds=${this._allowedContentTypeUniques ?? ''} - .memory=${this._memory} ?readonly=${this.readonly} @change=${this.#onChange} - @memory-change=${this.#onInputContentMemoryChange}> + .interactionMemories=${this._interactionMemories} + @interaction-memory-change=${this.#onInteractionMemoriesChange}> ${this.#renderInvalidData()} `; From f36c5b866ffea0b048fa7f7bd163f592e9814398 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 19:07:06 +0200 Subject: [PATCH 46/76] remove debugger --- .../content-picker/property-editor-ui-content-picker.element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 95746bcd5098..b435f95986df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -236,7 +236,6 @@ export class UmbPropertyEditorUIContentPickerElement #onInteractionMemoriesChange(event: UmbChangeEvent) { const target = event.target as UmbInputContentElement; const interactionMemories = target.interactionMemories; - debugger; if (interactionMemories && interactionMemories.length > 0) { this.#setInteractionMemory(interactionMemories); From f0875a1592f239884373a09b470a31e9c335acd4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 20:20:53 +0200 Subject: [PATCH 47/76] rename const --- .../property-editor-ui-document-picker.element.ts | 4 ++-- .../property-editor-ui-content-picker.element.ts | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 651052077a6c..0e911a08d2f2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -101,12 +101,12 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl if (!this.#interactionMemoryContext) return; // Set up memory for the Property Editor + Data Type context which includes all memories from the input - const dataTypeMemory: UmbInteractionMemoryModel = { + const propertyEditorMemory: UmbInteractionMemoryModel = { unique: memoryUnique, memories, }; - this.#interactionMemoryContext.memory.setMemory(dataTypeMemory); + this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); } #deleteInteractionMemory() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index b435f95986df..52bacd23cfbc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -208,7 +208,6 @@ export class UmbPropertyEditorUIContentPickerElement const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); this._interactionMemories = memory?.memories ?? []; - debugger; } #setInteractionMemory(memories: Array) { @@ -217,12 +216,12 @@ export class UmbPropertyEditorUIContentPickerElement if (!this.#interactionMemoryContext) return; // Set up memory for the Property Editor + Data Type context which includes all memories from the input - const dataTypeMemory: UmbInteractionMemoryModel = { + const propertyEditorMemory: UmbInteractionMemoryModel = { unique: memoryUnique, memories, }; - this.#interactionMemoryContext.memory.setMemory(dataTypeMemory); + this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); } #deleteInteractionMemory() { From afadcfbc5ca4f79e536bfdde71eebb44cf3219b6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 20:21:16 +0200 Subject: [PATCH 48/76] wip media picker memories --- .../input-rich-media.element.ts | 42 +++++++++-- .../media-picker-modal.element.ts | 36 ++++++++- ...property-editor-ui-media-picker.element.ts | 74 ++++++++++++++++++- 3 files changed, 145 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts index 353400e6860c..3871e4b5ef07 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts @@ -18,6 +18,11 @@ import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository'; import { UMB_MEDIA_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/media-type'; import '@umbraco-cms/backoffice/imaging'; +import { + UmbInteractionMemoryChangeEvent, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; +import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; type UmbRichMediaCardModel = { unique: string; @@ -102,7 +107,7 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< public override set value(value: Array | undefined) { super.value = value; this.#sorter.setModel(value); - this.#pickerContext.setSelection(value?.map((item) => item.mediaKey) ?? []); + this.#pickerInputContext.setSelection(value?.map((item) => item.mediaKey) ?? []); this.#itemManager.setUniques(value?.map((x) => x.mediaKey)); // Maybe the new value is using an existing media, and there we need to update the cards despite no repository update. this.#populateCards(); @@ -171,6 +176,17 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< } #readonly = false; + @property({ type: Array, attribute: false }) + public get interactionMemories(): Array | undefined { + return this.#pickerInputContext.interactionMemory.getAllMemories(); + } + public set interactionMemories(value: Array | undefined) { + this.#interactionMemories = value; + value?.forEach((memory) => this.#pickerInputContext.interactionMemory.setMemory(memory)); + } + + #interactionMemories?: Array = []; + @state() private _cards: Array = []; @@ -179,7 +195,7 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< readonly #itemManager = new UmbRepositoryItemsManager(this, UMB_MEDIA_ITEM_REPOSITORY_ALIAS); - readonly #pickerContext = new UmbMediaPickerInputContext(this); + readonly #pickerInputContext = new UmbMediaPickerInputContext(this); constructor() { super(); @@ -234,7 +250,7 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< this._routeBuilder = routeBuilder; }); - this.observe(this.#pickerContext.selection, (selection) => { + this.observe(this.#pickerInputContext.selection, (selection) => { this.#addItems(selection); }); @@ -263,6 +279,22 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< () => this.maxMessage, () => !this.readonly && !!this.value && !!this.max && this.value?.length > this.max, ); + + this.observe( + this.#pickerInputContext.interactionMemory.memories, + (memories) => { + // only dispatch the event if the interaction memories have actually changed + const isIdentical = jsonStringComparison(memories, this.#interactionMemories); + + if (!isIdentical) { + debugger; + this.dispatchEvent(new UmbInteractionMemoryChangeEvent()); + } + + this.#interactionMemories = memories; + }, + '_observeMemories', + ); } protected override getFormElement() { @@ -312,7 +344,7 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< } #openPicker() { - this.#pickerContext.openPicker( + this.#pickerInputContext.openPicker( { multiple: this.multiple, startNode: this.startNode, @@ -330,7 +362,7 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< async #onRemove(item: UmbRichMediaCardModel) { try { - await this.#pickerContext.requestRemoveItem(item.media); + await this.#pickerInputContext.requestRemoveItem(item.media); this.value = this.value?.filter((x) => x.key !== item.unique); this.dispatchEvent(new UmbChangeEvent()); } catch { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index 3ac92136f98b..7d81495c3f29 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -28,6 +28,10 @@ import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { UMB_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/variant'; import '@umbraco-cms/backoffice/imaging'; +import { + UmbInteractionMemoryManager, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; const root: UmbMediaPathModel = { name: 'Media', unique: null, entityType: UMB_MEDIA_ROOT_ENTITY_TYPE }; @@ -37,6 +41,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement x.unique == selectedItems[0].unique); if (selectedItem) { @@ -172,7 +179,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index d2e5d0a576bf..7b9d12a602db 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -14,6 +14,11 @@ import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umb import '../../components/input-rich-media/input-rich-media.element.js'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { + UMB_INTERACTION_MEMORY_CONTEXT, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; +import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; const elementName = 'umb-property-editor-ui-media-picker'; @@ -26,6 +31,8 @@ export class UmbPropertyEditorUIMediaPickerElement implements UmbPropertyEditorUiElement { public set config(config: UmbPropertyEditorConfigCollection | undefined) { + this.#setConfigHash(config); + if (!config) return; this._allowedMediaTypes = config.getValueByAlias('filter')?.split(',') ?? []; @@ -39,6 +46,8 @@ export class UmbPropertyEditorUIMediaPickerElement const minMax = config.getValueByAlias('validationLimit'); this._min = minMax?.min ?? 0; this._max = minMax?.max ?? Infinity; + + this.#getInteractionMemory(); } /** @@ -87,6 +96,12 @@ export class UmbPropertyEditorUIMediaPickerElement @state() private _variantId?: string; + @state() + private _interactionMemories: Array = []; + + #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; + #configHashCode?: number; + constructor() { super(); @@ -94,6 +109,17 @@ export class UmbPropertyEditorUIMediaPickerElement this.observe(context?.alias, (alias) => (this._alias = alias)); this.observe(context?.variantId, (variantId) => (this._variantId = variantId?.toString() || 'invariant')); }); + + this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { + this.#interactionMemoryContext = context; + this.#getInteractionMemory(); + }); + } + + #setConfigHash(config: UmbPropertyEditorConfigCollection | undefined) { + const configString = config ? JSON.stringify(config.toObject()) : ''; + const hashCode = simpleHashCode(configString); + this.#configHashCode = hashCode; } override firstUpdated() { @@ -110,6 +136,50 @@ export class UmbPropertyEditorUIMediaPickerElement this.dispatchEvent(new UmbChangeEvent()); } + #getInteractionMemoryUnique() { + return `UmbMediaPickerPropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; + } + + #getInteractionMemory() { + const memoryUnique = this.#getInteractionMemoryUnique(); + if (!memoryUnique) return; + if (!this.#interactionMemoryContext) return; + + const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); + this._interactionMemories = memory?.memories ?? []; + } + + #setInteractionMemory(memories: Array) { + const memoryUnique = this.#getInteractionMemoryUnique(); + if (!memoryUnique) return; + if (!this.#interactionMemoryContext) return; + + // Set up memory for the Property Editor + Data Type context which includes all memories from the input + const propertyEditorMemory: UmbInteractionMemoryModel = { + unique: memoryUnique, + memories, + }; + + this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); + } + + #deleteInteractionMemory() { + const unique = this.#getInteractionMemoryUnique(); + if (!unique) return; + this.#interactionMemoryContext?.memory.deleteMemory(unique); + } + + #onInteractionMemoriesChange(event: UmbChangeEvent) { + const target = event.target as UmbInputRichMediaElement; + const interactionMemories = target.interactionMemories; + + if (interactionMemories && interactionMemories.length > 0) { + this.#setInteractionMemory(interactionMemories); + } else { + this.#deleteInteractionMemory(); + } + } + override render() { return html` + ?readonly=${this.readonly} + .interactionMemories=${this._interactionMemories} + @interaction-memory-change=${this.#onInteractionMemoriesChange}> `; } From fa5883bdf5d771d7e3ea9939a12c8ff996501147 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 20:27:44 +0200 Subject: [PATCH 49/76] remove args --- .../src/packages/core/picker/picker.context.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index e985afd65a2b..843aaa40eb09 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -9,7 +9,7 @@ import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; export class UmbPickerContext extends UmbContextBase { public readonly interactionMemory = new UmbInteractionMemoryManager(this); public readonly selection = new UmbSelectionManager(this); - public readonly search = new UmbPickerSearchManager(this, { interactionMemoryManager: this.interactionMemory }); + public readonly search = new UmbPickerSearchManager(this); public dataType?: { unique: string }; From 51d30a2fa13ca08a10ac1e675697afc810117f8b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 20:30:48 +0200 Subject: [PATCH 50/76] simplify memory model --- .../src/packages/core/interaction-memory/types.ts | 3 +-- .../tree-item-picker-expansion.manager.ts | 12 ++++-------- .../media-picker/media-picker-modal.element.ts | 15 ++++++--------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts index bdb840e33130..66a2660e877d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts @@ -1,11 +1,10 @@ export interface UmbInteractionMemoryModel { clientTimestamp?: string; - values?: Array; + value?: UmbInteractionMemoryValueModel; unique: string; memories?: Array; } export interface UmbInteractionMemoryValueModel { - unique: string; [key: string]: unknown; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts index b48912df7cfe..4b8eece06ff8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts @@ -68,12 +68,9 @@ export class UmbTreeItemPickerExpansionManager extends UmbControllerBase { // Add a memory entry with the latest expansion state const memory: UmbInteractionMemoryModel = { unique: this.#interactionMemoryUnique, - values: [ - { - unique: this.#interactionMemoryUnique, - expansion: this.getExpansion(), - }, - ], + value: { + expansion: this.getExpansion(), + }, }; this.#muteMemoryObservation = true; @@ -87,8 +84,7 @@ export class UmbTreeItemPickerExpansionManager extends UmbControllerBase { } #applyExpansionInteractionMemory(memory: UmbInteractionMemoryModel) { - const memoryValue = memory?.values?.find((x) => x.unique === this.#interactionMemoryUnique); - const memoryExpansion = memoryValue?.expansion as UmbEntityExpansionModel | undefined; + const memoryExpansion = memory?.value?.expansion as UmbEntityExpansionModel | undefined; if (memoryExpansion) { this.#manager.setExpansion(memoryExpansion); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index 7d81495c3f29..6b70f200664c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -309,17 +309,14 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement Date: Mon, 15 Sep 2025 21:06:31 +0200 Subject: [PATCH 51/76] update internal value before dispatching event --- .../components/input-document/input-document.element.ts | 3 +-- .../components/input-rich-media/input-rich-media.element.ts | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index f66b44665929..3a363b7a6f79 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -177,10 +177,9 @@ export class UmbInputDocumentElement extends UmbFormControlMixin Date: Mon, 15 Sep 2025 21:31:46 +0200 Subject: [PATCH 52/76] remove unused --- .../property-type-based-property.context.ts | 21 +------------------ .../property-type-based-property.element.ts | 2 -- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts index 2e6980a4bbe3..e1e101b4b71d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.context.ts @@ -1,13 +1,10 @@ import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from './property-type-based-property.context-token.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; -import { UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; export class UmbPropertyTypeBasedPropertyContext extends UmbContextBase { - #unique = new UmbStringState(undefined); - unique = this.#unique.asObservable(); - #dataType = new UmbObjectState(undefined); dataType = this.#dataType.asObservable(); @@ -15,22 +12,6 @@ export class UmbPropertyTypeBasedPropertyContext extends UmbContextBase { super(host, UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT); } - /** - * Sets the unique identifier of the Property Type - * @param unique - The unique identifier of the Property Type - */ - setUnique(unique: string | undefined) { - this.#unique.setValue(unique); - } - - /** - * Gets the unique identifier of the Property Type - * @returns {string | undefined} The unique identifier of the Property Type - */ - getUnique(): string | undefined { - return this.#unique.getValue(); - } - setDataType(dataType: UmbPropertyTypeModel['dataType'] | undefined) { this.#dataType.setValue(dataType); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts index a74727636802..bf7ad096193d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts @@ -17,8 +17,6 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement { const oldProperty = this._property; this._property = value; - this.#context.setUnique(this._property?.unique); - if (this._property?.dataType.unique !== oldProperty?.dataType.unique) { this._observeDataType(this._property?.dataType.unique); } From b0985b040fcaa5b1d494abb2414c2aac1ab61950 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 15 Sep 2025 21:32:22 +0200 Subject: [PATCH 53/76] Update property-type-based-property.element.ts --- .../property-type-based-property.element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts index bf7ad096193d..fea5d1fa3271 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content/components/property-type-based-property/property-type-based-property.element.ts @@ -16,7 +16,6 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement { public set property(value: UmbPropertyTypeModel | undefined) { const oldProperty = this._property; this._property = value; - if (this._property?.dataType.unique !== oldProperty?.dataType.unique) { this._observeDataType(this._property?.dataType.unique); } From 44bbd238cd0e2540dfd59cf95de96241a15cd0aa Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 12:25:01 +0200 Subject: [PATCH 54/76] rename method --- .../packages/core/picker/modal/picker-modal-base.element.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index 5433e0e28b7a..e3849c09ddc2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -35,7 +35,7 @@ export abstract class UmbPickerModalBaseElement< #observePickerModalInteractionMemories() { this.observe(this._pickerContext.interactionMemory.memories, (memories) => { - this.#setTreeItemPickerModalMemory(memories); + this.#setPickerModalMemory(memories); }); } @@ -54,7 +54,7 @@ export abstract class UmbPickerModalBaseElement< ); } - #setTreeItemPickerModalMemory(pickerMemories: Array) { + #setPickerModalMemory(pickerMemories: Array) { if (pickerMemories?.length > 0) { const pickerModalMemory: UmbInteractionMemoryModel = { unique: this.#getInteractionMemoryUnique(), From 3c0e8f1f48092956421e0d37ee331c9a8f52a206 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 13:36:03 +0200 Subject: [PATCH 55/76] simplify types --- .../src/packages/core/interaction-memory/types.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts index 66a2660e877d..5996a8279bc4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts @@ -1,10 +1,6 @@ export interface UmbInteractionMemoryModel { clientTimestamp?: string; - value?: UmbInteractionMemoryValueModel; + value?: any; unique: string; memories?: Array; } - -export interface UmbInteractionMemoryValueModel { - [key: string]: unknown; -} From eea696249719fd2627b47b856aaa502548422678 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 13:39:09 +0200 Subject: [PATCH 56/76] implement location memory for media picker --- .../media-picker-modal.element.ts | 67 +++++++++++++------ .../media-picker.context.token.ts | 8 +++ .../media-picker/media-picker.context.ts | 18 +++++ 3 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.token.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index 6b70f200664c..4a79c0176471 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -7,6 +7,7 @@ import type { UmbDropzoneMediaElement } from '../../dropzone/index.js'; import type { UmbMediaPathModel } from './types.js'; import type { UmbMediaPickerFolderPathElement } from './components/media-picker-folder-path.element.js'; import type { UmbMediaPickerModalData, UmbMediaPickerModalValue } from './media-picker-modal.token.js'; +import { UmbMediaPickerContext } from './media-picker.context.js'; import type { UmbDropzoneChangeEvent, UmbUploadableItem } from '@umbraco-cms/backoffice/dropzone'; import { css, @@ -20,28 +21,30 @@ import { nothing, } from '@umbraco-cms/backoffice/external/lit'; import { debounce, UmbPaginationManager } from '@umbraco-cms/backoffice/utils'; -import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import type { UUIInputEvent, UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui'; import { isUmbracoFolder } from '@umbraco-cms/backoffice/media-type'; import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { UMB_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/variant'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; import '@umbraco-cms/backoffice/imaging'; -import { - UmbInteractionMemoryManager, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; const root: UmbMediaPathModel = { name: 'Media', unique: null, entityType: UMB_MEDIA_ROOT_ENTITY_TYPE }; // TODO: investigate how we can reuse the picker-search-field element, picker context etc. @customElement('umb-media-picker-modal') -export class UmbMediaPickerModalElement extends UmbModalBaseElement { +export class UmbMediaPickerModalElement extends UmbPickerModalBaseElement< + UmbMediaItemModel, + UmbMediaPickerModalData, + UmbMediaPickerModalValue +> { #mediaTreeRepository = new UmbMediaTreeRepository(this); #mediaItemRepository = new UmbMediaItemRepository(this); #mediaSearchProvider = new UmbMediaSearchProvider(this); - #interactionMemoryManager = new UmbInteractionMemoryManager(this); + + protected override _pickerContext = new UmbMediaPickerContext(this); #dataType?: { unique: string }; @@ -83,6 +86,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement(); #contextCulture?: string | null; + #locationInteractionMemoryUnique: string = 'UmbMediaItemPickerLocation'; constructor() { super(); @@ -127,9 +131,28 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement) { const key = this._currentMediaEntity.entityType + this._currentMediaEntity.unique; let paginationManager = this.#pagingMap.get(key); @@ -158,8 +181,6 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement x.unique == selectedItems[0].unique); if (selectedItem) { @@ -173,6 +194,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement { this.#searchMedia(); }, 500); + // TODO: move to search manager in context #onSearch(e: UUIInputEvent) { this._searchQuery = (e.target.value as string).toLocaleLowerCase(); this._searching = true; @@ -290,6 +318,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement( + 'UmbPickerContext', + undefined, + (context): context is UmbMediaPickerContext => context.IS_MEDIA_PICKER_CONTEXT, +); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts new file mode 100644 index 000000000000..df235ee2961c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts @@ -0,0 +1,18 @@ +import { UMB_MEDIA_PICKER_CONTEXT } from './media-picker.context.token.js'; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; + +// TODO: extend UmbTreeItemPickerContext +export class UmbMediaPickerContext extends UmbContextBase { + // For context token safety: + public readonly IS_MEDIA_PICKER_CONTEXT = true; + + public readonly interactionMemory = new UmbInteractionMemoryManager(this); + + constructor(host: UmbControllerHost) { + super(host, UMB_MEDIA_PICKER_CONTEXT); + } +} + +export { UmbMediaPickerContext as api }; From 13816cf379c2e7e8ed3662409fefd3015bcc61c5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 13:43:31 +0200 Subject: [PATCH 57/76] temp type cast --- .../media/modals/media-picker/media-picker-modal.element.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index 4a79c0176471..439b736eeb57 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -27,6 +27,7 @@ import { isUmbracoFolder } from '@umbraco-cms/backoffice/media-type'; import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { UMB_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/variant'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import type { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; import '@umbraco-cms/backoffice/imaging'; @@ -44,7 +45,9 @@ export class UmbMediaPickerModalElement extends UmbPickerModalBaseElement< #mediaItemRepository = new UmbMediaItemRepository(this); #mediaSearchProvider = new UmbMediaSearchProvider(this); - protected override _pickerContext = new UmbMediaPickerContext(this); + /* TODO: We currently only rely on the interactionMemory manager in the picker interface which is correctly implemented in the Media Picker + Remove this type cast when MediaPicker has implemented the full PickerContext interface */ + protected override _pickerContext = new UmbMediaPickerContext(this) as unknown as UmbPickerContext; #dataType?: { unique: string }; From 25383d8b1c01cd8b43f270ba0a89218585e5c248 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 13:47:03 +0200 Subject: [PATCH 58/76] set location memory when using the breadcrumb --- .../media/modals/media-picker/media-picker-modal.element.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index 439b736eeb57..b3b1a85ecdc4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -298,6 +298,8 @@ export class UmbMediaPickerModalElement extends UmbPickerModalBaseElement< this._searchFrom = undefined; } + this.#setLocationInInteractionMemory(); + this.#loadChildrenOfCurrentMediaItem(); } From d900b7c5f645a4693844f87e5b4d002931175f2a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 14:05:28 +0200 Subject: [PATCH 59/76] remove code duplication --- .../media-picker-modal.element.ts | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index b3b1a85ecdc4..be7b88c5285e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -118,37 +118,29 @@ export class UmbMediaPickerModalElement extends UmbPickerModalBaseElement< super.firstUpdated(_changedProperties); const startNode = this.data?.startNode; + const locationFromMemory = this.#getLocationFromInteractionMemory(); - if (startNode) { - const { data } = await this.#mediaItemRepository.requestItems([startNode.unique]); - this._startNode = data?.[0]; - - if (this._startNode) { - this._currentMediaEntity = { - name: this._startNode.name, - unique: this._startNode.unique, - entityType: this._startNode.entityType, - }; + const uniquesToRequest = [startNode?.unique, locationFromMemory?.entity.unique].filter( + (x) => x !== null && x !== undefined, + ); - this._searchFrom = { unique: this._startNode.unique, entityType: this._startNode.entityType }; - } - } + if (uniquesToRequest.length > 0) { + const { data } = await this.#mediaItemRepository.requestItems(uniquesToRequest); - const locationFromMemory = this.#getLocationFromInteractionMemory(); - const locationEntityUnique = locationFromMemory?.entity.unique; + this._startNode = data?.find((x) => x.unique === startNode?.unique); + const locationMemoryItem = data?.find((x) => x.unique === locationFromMemory?.entity.unique); - if (locationEntityUnique) { - const { data } = await this.#mediaItemRepository.requestItems([locationEntityUnique]); - const mediaItem = data?.[0]; + // TODO: We probably need to check if the location item is within the start node. If not then fall back to start node. + const source = locationMemoryItem || this._startNode; - if (mediaItem) { + if (source) { this._currentMediaEntity = { - name: mediaItem.name, - unique: mediaItem.unique, - entityType: mediaItem.entityType, + name: source.name, + unique: source.unique, + entityType: source.entityType, }; - this._searchFrom = { unique: mediaItem.unique, entityType: mediaItem.entityType }; + this._searchFrom = { unique: source.unique, entityType: source.entityType }; } } From 4c64290f6b057fc37ee340119a911be494c78d6b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 14:17:52 +0200 Subject: [PATCH 60/76] bubble memories from input media to input content --- .../input-media/input-media.element.ts | 52 +++++++++++++++---- .../input-rich-media.element.ts | 28 +++++----- .../input-content/input-content.element.ts | 4 +- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index dc2bfcbf1b48..a49b74e08459 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -21,6 +21,11 @@ import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_MEDIA_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/media-type'; import '@umbraco-cms/backoffice/imaging'; +import { + UmbInteractionMemoryChangeEvent, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; +import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; const elementName = 'umb-input-media'; @customElement(elementName) @@ -61,10 +66,10 @@ export class UmbInputMediaElement extends UmbFormControlMixin) { - this.#pickerContext.setSelection(ids); + this.#pickerInputContext.setSelection(ids); this.#sorter.setModel(ids); } public get selection(): Array { - return this.#pickerContext.getSelection(); + return this.#pickerInputContext.getSelection(); } @property({ type: Array }) @@ -146,13 +151,24 @@ export class UmbInputMediaElement extends UmbFormControlMixin | undefined { + return this.#pickerInputContext.interactionMemory.getAllMemories(); + } + public set interactionMemories(value: Array | undefined) { + this.#interactionMemories = value; + value?.forEach((memory) => this.#pickerInputContext.interactionMemory.setMemory(memory)); + } + + #interactionMemories?: Array = []; + @state() private _editMediaPath = ''; @state() private _cards: Array = []; - #pickerContext = new UmbMediaPickerInputContext(this); + #pickerInputContext = new UmbMediaPickerInputContext(this); constructor() { super(); @@ -166,15 +182,29 @@ export class UmbInputMediaElement extends UmbFormControlMixin (this.value = selection.join(','))); + this.observe(this.#pickerInputContext.selection, (selection) => (this.value = selection.join(','))); - this.observe(this.#pickerContext.selectedItems, async (selectedItems) => { + this.observe(this.#pickerInputContext.selectedItems, async (selectedItems) => { const missingCards = selectedItems.filter((item) => !this._cards.find((card) => card.unique === item.unique)); if (selectedItems?.length && !missingCards.length) return; this._cards = selectedItems ?? []; }); + this.observe( + this.#pickerInputContext.interactionMemory.memories, + (memories) => { + // only dispatch the event if the interaction memories have actually changed + const isIdentical = jsonStringComparison(memories, this.#interactionMemories); + + if (!isIdentical) { + this.#interactionMemories = memories; + this.dispatchEvent(new UmbInteractionMemoryChangeEvent()); + } + }, + '_observeMemories', + ); + this.addValidator( 'rangeUnderflow', () => this.minMessage, @@ -188,7 +218,7 @@ export class UmbInputMediaElement extends UmbFormControlMixin 1, startNode: this.startNode, @@ -204,7 +234,7 @@ export class UmbInputMediaElement extends UmbFormControlMixin x.unique !== item.unique); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts index 8d9a5d559092..f8462f181418 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts @@ -254,6 +254,20 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< this.#addItems(selection); }); + this.observe( + this.#pickerInputContext.interactionMemory.memories, + (memories) => { + // only dispatch the event if the interaction memories have actually changed + const isIdentical = jsonStringComparison(memories, this.#interactionMemories); + + if (!isIdentical) { + this.#interactionMemories = memories; + this.dispatchEvent(new UmbInteractionMemoryChangeEvent()); + } + }, + '_observeMemories', + ); + this.addValidator( 'valueMissing', () => this.requiredMessage ?? UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, @@ -279,20 +293,6 @@ export class UmbInputRichMediaElement extends UmbFormControlMixin< () => this.maxMessage, () => !this.readonly && !!this.value && !!this.max && this.value?.length > this.max, ); - - this.observe( - this.#pickerInputContext.interactionMemory.memories, - (memories) => { - // only dispatch the event if the interaction memories have actually changed - const isIdentical = jsonStringComparison(memories, this.#interactionMemories); - - if (!isIdentical) { - this.#interactionMemories = memories; - this.dispatchEvent(new UmbInteractionMemoryChangeEvent()); - } - }, - '_observeMemories', - ); } protected override getFormElement() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 8465134a0f2c..004893182bc8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -151,7 +151,9 @@ export class UmbInputContentElement extends UmbFormControlMixin + @change=${this.#onChange} + .interactionMemories=${this.#interactionMemories} + @interaction-memory-change=${this.#onInteractionMemoriesChange}> `; } From 93787c3f1e1a59958f3dbcb6bb0963a6c6733613 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 14:26:18 +0200 Subject: [PATCH 61/76] Update src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../content-picker/property-editor-ui-content-picker.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 52bacd23cfbc..305f0fb9b794 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -227,7 +227,7 @@ export class UmbPropertyEditorUIContentPickerElement #deleteInteractionMemory() { const unique = this.#getInteractionMemoryUnique(); if (!unique) { - throw new Error('Memory is unique is missing'); + throw new Error('Memory unique is missing'); } this.#interactionMemoryContext?.memory.deleteMemory(unique); } From 4cb413362c8e34b6aa2e49808617e4ee448f55b5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 14:29:18 +0200 Subject: [PATCH 62/76] fix import --- src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts index 44476da4984f..3499d1e9c638 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts @@ -2,9 +2,9 @@ import { UMB_AUTH_CONTEXT } from './auth/auth.context.token.js'; import { UmbBackofficeNotificationContainerElement, UmbBackofficeModalContainerElement } from './components/index.js'; import { UmbActionEventContext } from './action/action-event.context.js'; import { manifests as coreManifests } from './manifests.js'; +import { UmbInteractionMemoryContext } from './interaction-memory/index.js'; import { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; import { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; -import { UmbInteractionMemoryContext } from 'src/packages/core/interaction-memory/index.js'; import { UmbExtensionsApiInitializer, type UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; import './property-action/components/index.js'; From bfaf0ec6ca82cd627d658d2a5281e2287e207489 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 14:31:30 +0200 Subject: [PATCH 63/76] remove unused method --- .../property-editor-ui-content-picker.element.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 305f0fb9b794..250f2c0da826 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -19,10 +19,10 @@ import { UMB_INTERACTION_MEMORY_CONTEXT, type UmbInteractionMemoryModel, } from '@umbraco-cms/backoffice/interaction-memory'; +import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; // import of local component import './components/input-content/index.js'; -import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; type UmbContentPickerValueType = UmbInputContentElement['selection']; @@ -188,15 +188,6 @@ export class UmbPropertyEditorUIContentPickerElement this.readonly = false; } - #onInputContentMemoryChange(event: UmbChangeEvent) { - const target = event.target as UmbInputContentElement; - const memory = target?.memory; - - if (memory) { - this.#setInteractionMemory(memory); - } - } - #getInteractionMemoryUnique() { return `UmbContentPickerPropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; } From 68c4b136466c66f459d69c6affa20292d58c00ef Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 15:18:44 +0200 Subject: [PATCH 64/76] Refactor content picker interaction memory management Introduced UmbPropertyEditorUiInteractionMemoryManager to encapsulate interaction memory logic for property editors. Updated the content picker property editor to use this new manager, removing duplicated memory management code and improving maintainability. --- .../packages/core/property-editor/index.ts | 1 + .../interaction-memory/index.ts | 1 + ...ty-editor-ui-interaction-memory.manager.ts | 92 +++++++++++++++++++ ...operty-editor-ui-content-picker.element.ts | 88 +++++------------- 4 files changed, 116 insertions(+), 66 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/index.ts index 6f36bd603767..016483412b66 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/index.ts @@ -2,5 +2,6 @@ export * from './components/index.js'; export * from './config/index.js'; export * from './constants.js'; export * from './events/index.js'; +export * from './interaction-memory/index.js'; export * from './ui-picker-modal/index.js'; export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/index.ts new file mode 100644 index 000000000000..835e4df1982b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/index.ts @@ -0,0 +1 @@ +export * from './property-editor-ui-interaction-memory.manager.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts new file mode 100644 index 000000000000..e2924a334e3a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts @@ -0,0 +1,92 @@ +import type { UmbPropertyEditorConfigCollection } from '../config/index.js'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { + UMB_INTERACTION_MEMORY_CONTEXT, + type UmbInteractionMemoryModel, +} from '@umbraco-cms/backoffice/interaction-memory'; +import { simpleHashCode, UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; + +export interface UmbPropertyEditorUiInteractionMemoryManagerArgs { + memoryUniquePrefix: string; +} + +export class UmbPropertyEditorUiInteractionMemoryManager extends UmbControllerBase { + #memories = new UmbArrayState([], (x) => x.unique); + memories = this.#memories.asObservable(); + + #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; + #configHashCode?: number; + #memoryUniquePrefix: string; + + constructor(host: UmbControllerHost, args: UmbPropertyEditorUiInteractionMemoryManagerArgs) { + super(host); + + this.#memoryUniquePrefix = args.memoryUniquePrefix; + + this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { + this.#interactionMemoryContext = context; + this.#getInteractionMemory(); + }); + } + + /** + * Sets the property editor config, used to create a unique hash for the interaction memory. + * @param {(UmbPropertyEditorConfigCollection | undefined)} config + * @memberof UmbPropertyEditorUiInteractionMemoryManager + */ + setPropertyEditorConfig(config: UmbPropertyEditorConfigCollection | undefined) { + this.#setConfigHash(config); + this.#getInteractionMemory(); + } + + /** + * Creates or updates an interaction memory for this property editor based on the provided memories. + * @param {Array} memories - The memories to include for this property editor. + * @returns {void} + * @memberof UmbPropertyEditorUiInteractionMemoryManager + */ + setMemory(memories: Array): void { + const memoryUnique = this.#getInteractionMemoryUnique(); + if (!memoryUnique) return; + if (!this.#interactionMemoryContext) return; + + const propertyEditorMemory: UmbInteractionMemoryModel = { + unique: memoryUnique, + memories, + }; + + this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); + } + + /** + * Deletes the interaction memory for this property editor. + * @memberof UmbPropertyEditorUiInteractionMemoryManager + */ + deleteMemory() { + const unique = this.#getInteractionMemoryUnique(); + if (!unique) { + throw new Error('Memory unique is missing'); + } + this.#interactionMemoryContext?.memory.deleteMemory(unique); + } + + #getInteractionMemoryUnique() { + return `${this.#memoryUniquePrefix + this.#configHashCode ? '-' + this.#configHashCode : ''}`; + } + + #getInteractionMemory() { + const memoryUnique = this.#getInteractionMemoryUnique(); + if (!memoryUnique) return; + if (!this.#interactionMemoryContext) return; + + const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); + this.#memories.setValue(memory?.memories ?? []); + } + + #setConfigHash(config: UmbPropertyEditorConfigCollection | undefined) { + const configString = config ? JSON.stringify(config.toObject()) : ''; + const hashCode = simpleHashCode(configString); + this.#configHashCode = hashCode; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 250f2c0da826..1e46c58567ee 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -10,16 +10,13 @@ import { UMB_ANCESTORS_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; import { UMB_DOCUMENT_ENTITY_TYPE } from '@umbraco-cms/backoffice/document'; import { UMB_MEDIA_ENTITY_TYPE } from '@umbraco-cms/backoffice/media'; import { UMB_MEMBER_ENTITY_TYPE } from '@umbraco-cms/backoffice/member'; -import type { - UmbPropertyEditorConfigCollection, - UmbPropertyEditorUiElement, +import { + UmbPropertyEditorUiInteractionMemoryManager, + type UmbPropertyEditorConfigCollection, + type UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import { - UMB_INTERACTION_MEMORY_CONTEXT, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; -import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; // import of local component import './components/input-content/index.js'; @@ -73,9 +70,6 @@ export class UmbPropertyEditorUIContentPickerElement @state() private _interactionMemories: Array = []; - #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; - #configHashCode?: number; - #dynamicRoot?: UmbContentPickerSource['dynamicRoot']; #dynamicRootRepository = new UmbContentPickerDynamicRootRepository(this); @@ -85,8 +79,20 @@ export class UmbPropertyEditorUIContentPickerElement member: UMB_MEMBER_ENTITY_TYPE, }; + #interactionMemoryManager = new UmbPropertyEditorUiInteractionMemoryManager(this, { + memoryUniquePrefix: 'UmbContentPickerPropertyEditorUi', + }); + + constructor() { + super(); + + this.observe(this.#interactionMemoryManager.memories, (interactionMemories) => { + this._interactionMemories = interactionMemories ?? []; + }); + } + public set config(config: UmbPropertyEditorConfigCollection | undefined) { - this.#setConfigHash(config); + this.#interactionMemoryManager.setPropertyEditorConfig(config); if (!config) return; @@ -118,15 +124,6 @@ export class UmbPropertyEditorUIContentPickerElement } } - constructor() { - super(); - - this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { - this.#interactionMemoryContext = context; - this.#getInteractionMemory(); - }); - } - #parseInt(value: unknown, fallback: number): number { const num = Number(value); return !isNaN(num) && num > 0 ? num : fallback; @@ -149,12 +146,6 @@ export class UmbPropertyEditorUIContentPickerElement return this.shadowRoot?.querySelector('umb-input-content')?.focus(); } - #setConfigHash(config: UmbPropertyEditorConfigCollection | undefined) { - const configString = config ? JSON.stringify(config.toObject()) : ''; - const hashCode = simpleHashCode(configString); - this.#configHashCode = hashCode; - } - async #setPickerRootUnique() { // If we have a root unique value, we don't need to fetch it from the dynamic root if (this._rootUnique) return; @@ -188,49 +179,14 @@ export class UmbPropertyEditorUIContentPickerElement this.readonly = false; } - #getInteractionMemoryUnique() { - return `UmbContentPickerPropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; - } - - #getInteractionMemory() { - const memoryUnique = this.#getInteractionMemoryUnique(); - if (!memoryUnique) return; - if (!this.#interactionMemoryContext) return; - - const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); - this._interactionMemories = memory?.memories ?? []; - } - - #setInteractionMemory(memories: Array) { - const memoryUnique = this.#getInteractionMemoryUnique(); - if (!memoryUnique) return; - if (!this.#interactionMemoryContext) return; - - // Set up memory for the Property Editor + Data Type context which includes all memories from the input - const propertyEditorMemory: UmbInteractionMemoryModel = { - unique: memoryUnique, - memories, - }; - - this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); - } - - #deleteInteractionMemory() { - const unique = this.#getInteractionMemoryUnique(); - if (!unique) { - throw new Error('Memory unique is missing'); - } - this.#interactionMemoryContext?.memory.deleteMemory(unique); - } - - #onInteractionMemoriesChange(event: UmbChangeEvent) { + #onInputInteractionMemoriesChange(event: UmbChangeEvent) { const target = event.target as UmbInputContentElement; const interactionMemories = target.interactionMemories; if (interactionMemories && interactionMemories.length > 0) { - this.#setInteractionMemory(interactionMemories); + this.#interactionMemoryManager.setMemory(interactionMemories); } else { - this.#deleteInteractionMemory(); + this.#interactionMemoryManager.deleteMemory(); } } @@ -253,7 +209,7 @@ export class UmbPropertyEditorUIContentPickerElement ?readonly=${this.readonly} @change=${this.#onChange} .interactionMemories=${this._interactionMemories} - @interaction-memory-change=${this.#onInteractionMemoriesChange}> + @interaction-memory-change=${this.#onInputInteractionMemoriesChange}> ${this.#renderInvalidData()} `; From b963a3a25f97f3b80a20d6ef79a90138f210a070 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 15:30:48 +0200 Subject: [PATCH 65/76] Refactor interaction memory management in pickers Replaces custom interaction memory logic in document and media picker property editors with the shared UmbPropertyEditorUiInteractionMemoryManager. Updates unique memory key prefixes for consistency and simplifies related event handling. This improves maintainability and standardizes memory management across property editors. --- ...ty-editor-ui-interaction-memory.manager.ts | 2 +- ...perty-editor-ui-document-picker.element.ts | 74 ++++------------- ...property-editor-ui-media-picker.element.ts | 83 ++++--------------- ...operty-editor-ui-content-picker.element.ts | 2 +- 4 files changed, 35 insertions(+), 126 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts index e2924a334e3a..d8d4e3cdc172 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts @@ -72,7 +72,7 @@ export class UmbPropertyEditorUiInteractionMemoryManager extends UmbControllerBa } #getInteractionMemoryUnique() { - return `${this.#memoryUniquePrefix + this.#configHashCode ? '-' + this.#configHashCode : ''}`; + return `${this.#memoryUniquePrefix}PropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; } #getInteractionMemory() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 0e911a08d2f2..37a220ff5ea0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -4,16 +4,13 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models'; -import type { - UmbPropertyEditorConfigCollection, - UmbPropertyEditorUiElement, +import { + UmbPropertyEditorUiInteractionMemoryManager, + type UmbPropertyEditorConfigCollection, + type UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import { - UMB_INTERACTION_MEMORY_CONTEXT, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; -import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-property-editor-ui-document-picker') export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { @@ -21,7 +18,7 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl public value?: string; public set config(config: UmbPropertyEditorConfigCollection | undefined) { - this.#setConfigHash(config); + this.#interactionMemoryManager.setPropertyEditorConfig(config); if (!config) return; @@ -32,8 +29,6 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl } this._startNodeId = config.getValueByAlias('startNodeId'); - - this.#getInteractionMemory(); } /** @@ -59,70 +54,31 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl @state() private _interactionMemories: Array = []; - #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; - #configHashCode?: number; + #interactionMemoryManager = new UmbPropertyEditorUiInteractionMemoryManager(this, { + memoryUniquePrefix: 'UmbDocumentPicker', + }); constructor() { super(); - this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { - this.#interactionMemoryContext = context; - this.#getInteractionMemory(); + this.observe(this.#interactionMemoryManager.memories, (interactionMemories) => { + this._interactionMemories = interactionMemories ?? []; }); } - #setConfigHash(config: UmbPropertyEditorConfigCollection | undefined) { - const configString = config ? JSON.stringify(config.toObject()) : ''; - const hashCode = simpleHashCode(configString); - this.#configHashCode = hashCode; - } - #onChange(event: CustomEvent & { target: UmbInputDocumentElement }) { this.value = event.target.value; this.dispatchEvent(new UmbChangeEvent()); } - #getInteractionMemoryUnique() { - return `UmbDocumentPickerPropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; - } - - #getInteractionMemory() { - const memoryUnique = this.#getInteractionMemoryUnique(); - if (!memoryUnique) return; - if (!this.#interactionMemoryContext) return; - - const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); - this._interactionMemories = memory?.memories ?? []; - } - - #setInteractionMemory(memories: Array) { - const memoryUnique = this.#getInteractionMemoryUnique(); - if (!memoryUnique) return; - if (!this.#interactionMemoryContext) return; - - // Set up memory for the Property Editor + Data Type context which includes all memories from the input - const propertyEditorMemory: UmbInteractionMemoryModel = { - unique: memoryUnique, - memories, - }; - - this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); - } - - #deleteInteractionMemory() { - const unique = this.#getInteractionMemoryUnique(); - if (!unique) return; - this.#interactionMemoryContext?.memory.deleteMemory(unique); - } - - #onInteractionMemoriesChange(event: UmbChangeEvent) { + #onInputInteractionMemoriesChange(event: UmbChangeEvent) { const target = event.target as UmbInputDocumentElement; const interactionMemories = target.interactionMemories; if (interactionMemories && interactionMemories.length > 0) { - this.#setInteractionMemory(interactionMemories); + this.#interactionMemoryManager.setMemory(interactionMemories); } else { - this.#deleteInteractionMemory(); + this.#interactionMemoryManager.deleteMemory(); } } @@ -140,7 +96,7 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl @change=${this.#onChange} ?readonly=${this.readonly} .interactionMemories=${this._interactionMemories} - @interaction-memory-change=${this.#onInteractionMemoriesChange}> + @interaction-memory-change=${this.#onInputInteractionMemoriesChange}> `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index 7b9d12a602db..9d97c7a56051 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -5,33 +5,27 @@ import { customElement, html, property, state } from '@umbraco-cms/backoffice/ex import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property'; import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models'; -import type { - UmbPropertyEditorConfigCollection, - UmbPropertyEditorUiElement, +import { + UmbPropertyEditorUiInteractionMemoryManager, + type UmbPropertyEditorConfigCollection, + type UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; - -import '../../components/input-rich-media/input-rich-media.element.js'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; -import { - UMB_INTERACTION_MEMORY_CONTEXT, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; -import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; - -const elementName = 'umb-property-editor-ui-media-picker'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import '../../components/input-rich-media/input-rich-media.element.js'; /** * @element umb-property-editor-ui-media-picker */ -@customElement(elementName) +@customElement('umb-property-editor-ui-media-picker') export class UmbPropertyEditorUIMediaPickerElement extends UmbFormControlMixin(UmbLitElement) implements UmbPropertyEditorUiElement { public set config(config: UmbPropertyEditorConfigCollection | undefined) { - this.#setConfigHash(config); + this.#interactionMemoryManager.setPropertyEditorConfig(config); if (!config) return; @@ -46,8 +40,6 @@ export class UmbPropertyEditorUIMediaPickerElement const minMax = config.getValueByAlias('validationLimit'); this._min = minMax?.min ?? 0; this._max = minMax?.max ?? Infinity; - - this.#getInteractionMemory(); } /** @@ -99,8 +91,9 @@ export class UmbPropertyEditorUIMediaPickerElement @state() private _interactionMemories: Array = []; - #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; - #configHashCode?: number; + #interactionMemoryManager = new UmbPropertyEditorUiInteractionMemoryManager(this, { + memoryUniquePrefix: 'UmbMediaPicker', + }); constructor() { super(); @@ -110,18 +103,11 @@ export class UmbPropertyEditorUIMediaPickerElement this.observe(context?.variantId, (variantId) => (this._variantId = variantId?.toString() || 'invariant')); }); - this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { - this.#interactionMemoryContext = context; - this.#getInteractionMemory(); + this.observe(this.#interactionMemoryManager.memories, (interactionMemories) => { + this._interactionMemories = interactionMemories ?? []; }); } - #setConfigHash(config: UmbPropertyEditorConfigCollection | undefined) { - const configString = config ? JSON.stringify(config.toObject()) : ''; - const hashCode = simpleHashCode(configString); - this.#configHashCode = hashCode; - } - override firstUpdated() { this.addFormControlElement(this.shadowRoot!.querySelector('umb-input-rich-media')!); } @@ -136,47 +122,14 @@ export class UmbPropertyEditorUIMediaPickerElement this.dispatchEvent(new UmbChangeEvent()); } - #getInteractionMemoryUnique() { - return `UmbMediaPickerPropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; - } - - #getInteractionMemory() { - const memoryUnique = this.#getInteractionMemoryUnique(); - if (!memoryUnique) return; - if (!this.#interactionMemoryContext) return; - - const memory = this.#interactionMemoryContext.memory.getMemory(memoryUnique); - this._interactionMemories = memory?.memories ?? []; - } - - #setInteractionMemory(memories: Array) { - const memoryUnique = this.#getInteractionMemoryUnique(); - if (!memoryUnique) return; - if (!this.#interactionMemoryContext) return; - - // Set up memory for the Property Editor + Data Type context which includes all memories from the input - const propertyEditorMemory: UmbInteractionMemoryModel = { - unique: memoryUnique, - memories, - }; - - this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); - } - - #deleteInteractionMemory() { - const unique = this.#getInteractionMemoryUnique(); - if (!unique) return; - this.#interactionMemoryContext?.memory.deleteMemory(unique); - } - - #onInteractionMemoriesChange(event: UmbChangeEvent) { + #onInputInteractionMemoriesChange(event: UmbChangeEvent) { const target = event.target as UmbInputRichMediaElement; const interactionMemories = target.interactionMemories; if (interactionMemories && interactionMemories.length > 0) { - this.#setInteractionMemory(interactionMemories); + this.#interactionMemoryManager.setMemory(interactionMemories); } else { - this.#deleteInteractionMemory(); + this.#interactionMemoryManager.deleteMemory(); } } @@ -198,7 +151,7 @@ export class UmbPropertyEditorUIMediaPickerElement @change=${this.#onChange} ?readonly=${this.readonly} .interactionMemories=${this._interactionMemories} - @interaction-memory-change=${this.#onInteractionMemoriesChange}> + @interaction-memory-change=${this.#onInputInteractionMemoriesChange}> `; } @@ -208,6 +161,6 @@ export { UmbPropertyEditorUIMediaPickerElement as element }; declare global { interface HTMLElementTagNameMap { - [elementName]: UmbPropertyEditorUIMediaPickerElement; + ['umb-property-editor-ui-media-picker']: UmbPropertyEditorUIMediaPickerElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 1e46c58567ee..42e5fce1e96d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -80,7 +80,7 @@ export class UmbPropertyEditorUIContentPickerElement }; #interactionMemoryManager = new UmbPropertyEditorUiInteractionMemoryManager(this, { - memoryUniquePrefix: 'UmbContentPickerPropertyEditorUi', + memoryUniquePrefix: 'UmbContentPicker', }); constructor() { From 933ad19e4733cc4e8ed07ed0e8317ac176923ea4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 15:48:51 +0200 Subject: [PATCH 66/76] export context token --- .../src/packages/media/media/modals/constants.ts | 3 ++- .../src/packages/media/media/modals/media-picker/constants.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/constants.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/constants.ts index 7ad378394b73..4274263cda7f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/constants.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/constants.ts @@ -1,3 +1,4 @@ export { UMB_IMAGE_CROPPER_EDITOR_MODAL } from './image-cropper-editor/index.js'; -export * from './media-caption-alt-text/constants.js'; export { UMB_MEDIA_PICKER_MODAL } from './media-picker/index.js'; +export * from './media-caption-alt-text/constants.js'; +export * from './media-picker/constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/constants.ts new file mode 100644 index 000000000000..252317b0597f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/constants.ts @@ -0,0 +1 @@ +export * from './media-picker.context.token.js'; From 46380d41d65e4d53afe4d1e6337dddbba157c6b7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 15:54:05 +0200 Subject: [PATCH 67/76] add js docs --- .../interaction-memory.manager.ts | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts index 05dbe6bd5961..3f029ae24076 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts @@ -2,30 +2,68 @@ import type { UmbInteractionMemoryModel } from './types.js'; import { UmbArrayState, type Observable } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +/** + * A manager for handling interaction memory items. + * @exports + * @class UmbInteractionMemoryManager + * @augments {UmbControllerBase} + */ export class UmbInteractionMemoryManager extends UmbControllerBase { #memories = new UmbArrayState([], (x) => x.unique); + /** Observable for all memory items. */ memories = this.#memories.asObservable(); + /** + * Observable for a specific memory item by its unique identifier. + * @param {string} unique - The unique identifier of the memory item. + * @returns {(Observable)} An observable that emits the memory item or undefined if not found. + * @memberof UmbInteractionMemoryManager + */ memory(unique: string): Observable { return this.#memories.asObservablePart((items) => items.find((item) => item.unique === unique)); } + /** + * Get a specific memory item by its unique identifier. + * @param {string} unique - The unique identifier of the memory item. + * @returns {(UmbInteractionMemoryModel | undefined)} The memory item or undefined if not found. + * @memberof UmbInteractionMemoryManager + */ getMemory(unique: string): UmbInteractionMemoryModel | undefined { return this.#memories.getValue().find((item) => item.unique === unique); } + /** + * Add or update a memory item. + * @param {UmbInteractionMemoryModel} memory - The memory item to add or update. + * @memberof UmbInteractionMemoryManager + */ setMemory(memory: UmbInteractionMemoryModel) { this.#memories.appendOne(memory); } + /** + * Delete a memory item by its unique identifier. + * @param {string} unique - The unique identifier of the memory item. + * @memberof UmbInteractionMemoryManager + */ deleteMemory(unique: string) { this.#memories.removeOne(unique); } - getAllMemories() { + /** + * Get all memory items from the manager. + * @returns {Array} An array of all memory items. + * @memberof UmbInteractionMemoryManager + */ + getAllMemories(): Array { return this.#memories.getValue(); } + /** + * Clear all memory items from the manager. + * @memberof UmbInteractionMemoryManager + */ clear() { this.#memories.clear(); } From 5e5d15be0d43a11a12812d5b87339ee4e3e0424b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 15:59:00 +0200 Subject: [PATCH 68/76] remove timestamp --- .../src/packages/core/interaction-memory/types.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts index 5996a8279bc4..7f3d18c5314c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/types.ts @@ -1,6 +1,5 @@ export interface UmbInteractionMemoryModel { - clientTimestamp?: string; - value?: any; unique: string; + value?: any; memories?: Array; } From 71cf680b4143f1ec3068678985413d1d492c2b15 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 18:23:22 +0200 Subject: [PATCH 69/76] add tests for interaction memory manager --- .../interaction-memory.manager.test.ts | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts new file mode 100644 index 000000000000..14cdd2e2446b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts @@ -0,0 +1,103 @@ +import { UmbInteractionMemoryManager } from './interaction-memory.manager.js'; +import { expect } from '@open-wc/testing'; +import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; +import { customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbControllerHostElementMixin } from '@umbraco-cms/backoffice/controller-api'; + +@customElement('test-my-controller-host') +class UmbTestControllerHostElement extends UmbControllerHostElementMixin(HTMLElement) {} + +describe('UmbInteractionMemoryManager', () => { + let manager: UmbInteractionMemoryManager; + const nestedMemory1 = { unique: 'nestedMemory1', value: 'Nested Memory 1' }; + const nestedMemory2 = { unique: 'nestedMemory2', value: 'Nested Memory 2' }; + const memory1 = { unique: '1', value: 'Memory 1' }; + const memory2 = { unique: '2', value: 'Memory 2', memories: [nestedMemory1, nestedMemory2] }; + + beforeEach(() => { + const hostElement = new UmbTestControllerHostElement(); + manager = new UmbInteractionMemoryManager(hostElement); + manager.setMemory(memory1); + manager.setMemory(memory2); + }); + + describe('Public API', () => { + describe('properties', () => { + it('has a memories property', () => { + expect(manager).to.have.property('memories').to.be.an.instanceOf(Observable); + }); + }); + + describe('methods', () => { + it('has a memory method', () => { + expect(manager).to.have.property('memory').that.is.a('function'); + }); + + it('has a getMemory method', () => { + expect(manager).to.have.property('getMemory').that.is.a('function'); + }); + + it('has a setMemory method', () => { + expect(manager).to.have.property('setMemory').that.is.a('function'); + }); + + it('has a deleteMemory method', () => { + expect(manager).to.have.property('deleteMemory').that.is.a('function'); + }); + + it('has a getAllMemories method', () => { + expect(manager).to.have.property('getAllMemories').that.is.a('function'); + }); + + it('has a clear method', () => { + expect(manager).to.have.property('clear').that.is.a('function'); + }); + }); + }); + + describe('getMemory()', () => { + it('returns the correct memory item by unique identifier', () => { + const result = manager.getMemory('1'); + expect(result).to.deep.equal(memory1); + }); + }); + + describe('setMemory()', () => { + it('create a new memory unique identifier', () => { + const newMemory = { unique: 'newMemory', value: 'New Memory' }; + manager.setMemory(newMemory); + const result = manager.getMemory('newMemory'); + expect(result).to.deep.equal(newMemory); + }); + + it('update an existing memory item by unique identifier', () => { + const updatedMemory = { unique: '1', value: 'Updated Memory 1' }; + manager.setMemory(updatedMemory); + const result = manager.getMemory('1'); + expect(result).to.deep.equal(updatedMemory); + }); + }); + + describe('deleteMemory()', () => { + it('deletes an existing memory item by unique identifier', () => { + manager.deleteMemory('1'); + const result = manager.getMemory('1'); + expect(result).to.be.undefined; + }); + }); + + describe('getAllMemories()', () => { + it('returns all memory items', () => { + const result = manager.getAllMemories(); + expect(result).to.deep.equal([memory1, memory2]); + }); + }); + + describe('clear()', () => { + it('clears all memory items', () => { + manager.clear(); + const result = manager.getAllMemories(); + expect(result.length).to.equal(0); + }); + }); +}); From b9df29506cbfc7e482bb48946754a636146c029a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 20:45:33 +0200 Subject: [PATCH 70/76] Added tests for the property editor ui interaction memory manager --- ...itor-ui-interaction-memory.manager.test.ts | 128 ++++++++++++++++++ ...ty-editor-ui-interaction-memory.manager.ts | 27 ++-- ...perty-editor-ui-document-picker.element.ts | 6 +- ...property-editor-ui-media-picker.element.ts | 6 +- ...operty-editor-ui-content-picker.element.ts | 6 +- 5 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts new file mode 100644 index 000000000000..26c234007f7f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts @@ -0,0 +1,128 @@ +import { expect } from '@open-wc/testing'; +import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; +import { customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbControllerHostElementMixin } from '@umbraco-cms/backoffice/controller-api'; +import { UmbPropertyEditorUiInteractionMemoryManager } from './property-editor-ui-interaction-memory.manager.js'; +import { UmbInteractionMemoryContext } from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbPropertyEditorConfigCollection } from '../config/index.js'; + +@customElement('test-my-controller-host') +class UmbTestControllerHostElement extends UmbControllerHostElementMixin(HTMLElement) { + constructor() { + super(); + new UmbInteractionMemoryContext(this); + } +} + +describe('UmbPropertyEditorUiInteractionMemoryManager', () => { + let manager: UmbPropertyEditorUiInteractionMemoryManager; + let childMemories = [ + { unique: '1', value: 'Value 1' }, + { unique: '2', value: 'Value 2' }, + ]; + + beforeEach(() => { + const hostElement = new UmbTestControllerHostElement(); + document.body.appendChild(hostElement); + + manager = new UmbPropertyEditorUiInteractionMemoryManager(hostElement, { + memoryUniquePrefix: 'TestPrefix', + }); + + // A random config to generate a hash code from + const config = new UmbPropertyEditorConfigCollection([ + { + alias: 'someAlias', + value: 'someValue', + }, + ]); + + manager.setPropertyEditorConfig(config); + }); + + describe('Public API', () => { + describe('properties', () => { + it('has a memories property', () => { + expect(manager).to.have.property('memories').to.be.an.instanceOf(Observable); + }); + }); + + describe('methods', () => { + it('has a setPropertyEditorConfig method', () => { + expect(manager).to.have.property('setPropertyEditorConfig').that.is.a('function'); + }); + + it('has a saveMemoriesForPropertyEditor method', () => { + expect(manager).to.have.property('saveMemoriesForPropertyEditor').that.is.a('function'); + }); + + it('has a deleteMemoriesForPropertyEditor method', () => { + expect(manager).to.have.property('deleteMemoriesForPropertyEditor').that.is.a('function'); + }); + }); + + describe('saveMemoriesForPropertyEditor', () => { + it('creates a property editor memory based on the provided data', (done) => { + manager.memories.subscribe((memories) => { + if (memories.length > 0) { + expect(memories).to.have.lengthOf(2); + expect(memories).to.deep.equal(childMemories); + done(); + } + }); + + manager.saveMemoriesForPropertyEditor(childMemories); + }); + + it('updates the property editor memory based on the provided data', (done) => { + const updatedChildMemories = [ + { unique: '1', value: 'Updated Value 1' }, + { unique: '2', value: 'Updated Value 2' }, + { unique: '3', value: 'New Value 3' }, + ]; + + // We start at -1 because the first call is the initial empty array + let callCount = -1; + manager.memories.subscribe((memories) => { + callCount++; + if (callCount === 1) { + // First call, after initial save + expect(memories).to.have.lengthOf(2); + expect(memories).to.deep.equal(childMemories); + } else if (callCount === 2) { + // Second call, after update + expect(memories).to.have.lengthOf(3); + expect(memories).to.deep.equal(updatedChildMemories); + done(); + } + }); + + manager.saveMemoriesForPropertyEditor(childMemories); + manager.saveMemoriesForPropertyEditor(updatedChildMemories); + }); + }); + + describe('deleteMemoriesForPropertyEditor', () => { + it('deletes all memories for this property editor', (done) => { + // We start at -1 because the first call is the initial empty array + let callCount = -1; + manager.memories.subscribe((memories) => { + callCount++; + if (callCount === 1) { + // First call, after initial save + expect(memories).to.have.lengthOf(2); + expect(memories).to.deep.equal(childMemories); + } else if (callCount === 2) { + // Second call, after delete + expect(memories).to.have.lengthOf(0); + expect(memories).to.deep.equal([]); + done(); + } + }); + + manager.saveMemoriesForPropertyEditor(childMemories); + manager.deleteMemoriesForPropertyEditor(); + }); + }); + }); +}); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts index d8d4e3cdc172..52d57558b2d1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts @@ -18,16 +18,18 @@ export class UmbPropertyEditorUiInteractionMemoryManager extends UmbControllerBa #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; #configHashCode?: number; #memoryUniquePrefix: string; + #init?: Promise; constructor(host: UmbControllerHost, args: UmbPropertyEditorUiInteractionMemoryManagerArgs) { super(host); this.#memoryUniquePrefix = args.memoryUniquePrefix; - this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { - this.#interactionMemoryContext = context; - this.#getInteractionMemory(); - }); + this.#init = Promise.all([ + this.consumeContext(UMB_INTERACTION_MEMORY_CONTEXT, (context) => { + this.#interactionMemoryContext = context; + }).asPromise(), + ]); } /** @@ -43,12 +45,12 @@ export class UmbPropertyEditorUiInteractionMemoryManager extends UmbControllerBa /** * Creates or updates an interaction memory for this property editor based on the provided memories. * @param {Array} memories - The memories to include for this property editor. - * @returns {void} + * @returns {Promise} * @memberof UmbPropertyEditorUiInteractionMemoryManager */ - setMemory(memories: Array): void { + async saveMemoriesForPropertyEditor(memories: Array): Promise { + await this.#init; const memoryUnique = this.#getInteractionMemoryUnique(); - if (!memoryUnique) return; if (!this.#interactionMemoryContext) return; const propertyEditorMemory: UmbInteractionMemoryModel = { @@ -57,25 +59,26 @@ export class UmbPropertyEditorUiInteractionMemoryManager extends UmbControllerBa }; this.#interactionMemoryContext.memory.setMemory(propertyEditorMemory); + this.#memories.setValue(memories); } /** * Deletes the interaction memory for this property editor. * @memberof UmbPropertyEditorUiInteractionMemoryManager */ - deleteMemory() { + async deleteMemoriesForPropertyEditor(): Promise { + await this.#init; const unique = this.#getInteractionMemoryUnique(); - if (!unique) { - throw new Error('Memory unique is missing'); - } this.#interactionMemoryContext?.memory.deleteMemory(unique); + this.#memories.setValue([]); } #getInteractionMemoryUnique() { return `${this.#memoryUniquePrefix}PropertyEditorUi${this.#configHashCode ? '-' + this.#configHashCode : ''}`; } - #getInteractionMemory() { + async #getInteractionMemory() { + await this.#init; const memoryUnique = this.#getInteractionMemoryUnique(); if (!memoryUnique) return; if (!this.#interactionMemoryContext) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 37a220ff5ea0..46d94065f0a5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -71,14 +71,14 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl this.dispatchEvent(new UmbChangeEvent()); } - #onInputInteractionMemoriesChange(event: UmbChangeEvent) { + async #onInputInteractionMemoriesChange(event: UmbChangeEvent) { const target = event.target as UmbInputDocumentElement; const interactionMemories = target.interactionMemories; if (interactionMemories && interactionMemories.length > 0) { - this.#interactionMemoryManager.setMemory(interactionMemories); + await this.#interactionMemoryManager.saveMemoriesForPropertyEditor(interactionMemories); } else { - this.#interactionMemoryManager.deleteMemory(); + await this.#interactionMemoryManager.deleteMemoriesForPropertyEditor(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index 9d97c7a56051..3b223736f3c9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -122,14 +122,14 @@ export class UmbPropertyEditorUIMediaPickerElement this.dispatchEvent(new UmbChangeEvent()); } - #onInputInteractionMemoriesChange(event: UmbChangeEvent) { + async #onInputInteractionMemoriesChange(event: UmbChangeEvent) { const target = event.target as UmbInputRichMediaElement; const interactionMemories = target.interactionMemories; if (interactionMemories && interactionMemories.length > 0) { - this.#interactionMemoryManager.setMemory(interactionMemories); + await this.#interactionMemoryManager.saveMemoriesForPropertyEditor(interactionMemories); } else { - this.#interactionMemoryManager.deleteMemory(); + await this.#interactionMemoryManager.deleteMemoriesForPropertyEditor(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 42e5fce1e96d..21942491e4e8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -179,14 +179,14 @@ export class UmbPropertyEditorUIContentPickerElement this.readonly = false; } - #onInputInteractionMemoriesChange(event: UmbChangeEvent) { + async #onInputInteractionMemoriesChange(event: UmbChangeEvent) { const target = event.target as UmbInputContentElement; const interactionMemories = target.interactionMemories; if (interactionMemories && interactionMemories.length > 0) { - this.#interactionMemoryManager.setMemory(interactionMemories); + await this.#interactionMemoryManager.saveMemoriesForPropertyEditor(interactionMemories); } else { - this.#interactionMemoryManager.deleteMemory(); + await this.#interactionMemoryManager.deleteMemoriesForPropertyEditor(); } } From 3d801eded80725713e35702fb54d5f1bfa5e890b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 16 Sep 2025 21:00:48 +0200 Subject: [PATCH 71/76] Rename memories to memoriesForPropertyEditor Renamed the 'memories' property to 'memoriesForPropertyEditor' in the interaction memory manager and updated all references in related property editor components and tests for clarity and consistency. --- ...operty-editor-ui-interaction-memory.manager.test.ts | 10 +++++----- .../property-editor-ui-interaction-memory.manager.ts | 2 +- .../property-editor-ui-document-picker.element.ts | 2 +- .../property-editor-ui-media-picker.element.ts | 2 +- .../property-editor-ui-content-picker.element.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts index 26c234007f7f..a62d64d19f30 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts @@ -42,8 +42,8 @@ describe('UmbPropertyEditorUiInteractionMemoryManager', () => { describe('Public API', () => { describe('properties', () => { - it('has a memories property', () => { - expect(manager).to.have.property('memories').to.be.an.instanceOf(Observable); + it('has a memoriesForPropertyEditor property', () => { + expect(manager).to.have.property('memoriesForPropertyEditor').to.be.an.instanceOf(Observable); }); }); @@ -63,7 +63,7 @@ describe('UmbPropertyEditorUiInteractionMemoryManager', () => { describe('saveMemoriesForPropertyEditor', () => { it('creates a property editor memory based on the provided data', (done) => { - manager.memories.subscribe((memories) => { + manager.memoriesForPropertyEditor.subscribe((memories) => { if (memories.length > 0) { expect(memories).to.have.lengthOf(2); expect(memories).to.deep.equal(childMemories); @@ -83,7 +83,7 @@ describe('UmbPropertyEditorUiInteractionMemoryManager', () => { // We start at -1 because the first call is the initial empty array let callCount = -1; - manager.memories.subscribe((memories) => { + manager.memoriesForPropertyEditor.subscribe((memories) => { callCount++; if (callCount === 1) { // First call, after initial save @@ -106,7 +106,7 @@ describe('UmbPropertyEditorUiInteractionMemoryManager', () => { it('deletes all memories for this property editor', (done) => { // We start at -1 because the first call is the initial empty array let callCount = -1; - manager.memories.subscribe((memories) => { + manager.memoriesForPropertyEditor.subscribe((memories) => { callCount++; if (callCount === 1) { // First call, after initial save diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts index 52d57558b2d1..a466352a2f8c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts @@ -13,7 +13,7 @@ export interface UmbPropertyEditorUiInteractionMemoryManagerArgs { export class UmbPropertyEditorUiInteractionMemoryManager extends UmbControllerBase { #memories = new UmbArrayState([], (x) => x.unique); - memories = this.#memories.asObservable(); + memoriesForPropertyEditor = this.#memories.asObservable(); #interactionMemoryContext?: typeof UMB_INTERACTION_MEMORY_CONTEXT.TYPE; #configHashCode?: number; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 46d94065f0a5..41a5ca694c86 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -61,7 +61,7 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl constructor() { super(); - this.observe(this.#interactionMemoryManager.memories, (interactionMemories) => { + this.observe(this.#interactionMemoryManager.memoriesForPropertyEditor, (interactionMemories) => { this._interactionMemories = interactionMemories ?? []; }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index 3b223736f3c9..9aa3a7cb6671 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -103,7 +103,7 @@ export class UmbPropertyEditorUIMediaPickerElement this.observe(context?.variantId, (variantId) => (this._variantId = variantId?.toString() || 'invariant')); }); - this.observe(this.#interactionMemoryManager.memories, (interactionMemories) => { + this.observe(this.#interactionMemoryManager.memoriesForPropertyEditor, (interactionMemories) => { this._interactionMemories = interactionMemories ?? []; }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index 21942491e4e8..a1b5aca83ece 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -86,7 +86,7 @@ export class UmbPropertyEditorUIContentPickerElement constructor() { super(); - this.observe(this.#interactionMemoryManager.memories, (interactionMemories) => { + this.observe(this.#interactionMemoryManager.memoriesForPropertyEditor, (interactionMemories) => { this._interactionMemories = interactionMemories ?? []; }); } From 94865c7647311571de3843d05c6d2edde62b14b0 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Wed, 17 Sep 2025 10:41:32 +0100 Subject: [PATCH 72/76] Separated out `import type`s + ordering --- .../src/packages/core/entry-point.ts | 9 +++---- .../interaction-memory.context.ts | 2 +- .../interaction-memory.manager.test.ts | 2 +- .../interaction-memory.manager.ts | 3 ++- .../core/modal/context/modal.context.ts | 14 +++++------ .../src/packages/core/modal/types.ts | 2 +- .../core/picker-input/picker-input.context.ts | 10 ++++---- .../picker/modal/picker-modal-base.element.ts | 10 +++----- .../packages/core/picker/picker.context.ts | 4 ++-- .../search/manager/picker-search.manager.ts | 4 ++-- ...itor-ui-interaction-memory.manager.test.ts | 6 ++--- ...ty-editor-ui-interaction-memory.manager.ts | 8 +++---- .../tree-item-picker-expansion.manager.ts | 3 ++- .../tree-picker-modal.element.ts | 10 ++++---- .../input-document/input-document.element.ts | 10 ++++---- ...perty-editor-ui-document-picker.element.ts | 14 +++++------ .../input-media/input-media.element.ts | 12 ++++------ .../media-picker-modal.element.ts | 24 +++++++++---------- .../media-picker/media-picker.context.ts | 2 +- ...property-editor-ui-media-picker.element.ts | 16 ++++++------- .../input-content/input-content.element.ts | 8 +++---- ...operty-editor-ui-content-picker.element.ts | 10 ++++---- 22 files changed, 86 insertions(+), 97 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts index 3499d1e9c638..89763284e8c2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entry-point.ts @@ -1,11 +1,12 @@ +import { manifests as coreManifests } from './manifests.js'; import { UMB_AUTH_CONTEXT } from './auth/auth.context.token.js'; -import { UmbBackofficeNotificationContainerElement, UmbBackofficeModalContainerElement } from './components/index.js'; import { UmbActionEventContext } from './action/action-event.context.js'; -import { manifests as coreManifests } from './manifests.js'; +import { UmbBackofficeNotificationContainerElement, UmbBackofficeModalContainerElement } from './components/index.js'; import { UmbInteractionMemoryContext } from './interaction-memory/index.js'; -import { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; +import { UmbExtensionsApiInitializer } from '@umbraco-cms/backoffice/extension-api'; import { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; -import { UmbExtensionsApiInitializer, type UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; +import { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; +import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; import './property-action/components/index.js'; import './menu/components/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts index 63d036364fc5..32e267129af4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.context.ts @@ -1,7 +1,7 @@ import { UMB_INTERACTION_MEMORY_CONTEXT } from './interaction-memory.context.token.js'; import { UmbInteractionMemoryManager } from './interaction-memory.manager.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; export class UmbInteractionMemoryContext extends UmbContextBase { public readonly memory = new UmbInteractionMemoryManager(this); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts index 14cdd2e2446b..6c506732d6ad 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.test.ts @@ -1,7 +1,7 @@ import { UmbInteractionMemoryManager } from './interaction-memory.manager.js'; +import { customElement } from '@umbraco-cms/backoffice/external/lit'; import { expect } from '@open-wc/testing'; import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; -import { customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbControllerHostElementMixin } from '@umbraco-cms/backoffice/controller-api'; @customElement('test-my-controller-host') diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts index 3f029ae24076..a385e4a59c49 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/interaction-memory.manager.ts @@ -1,6 +1,7 @@ import type { UmbInteractionMemoryModel } from './types.js'; -import { UmbArrayState, type Observable } from '@umbraco-cms/backoffice/observable-api'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { Observable } from '@umbraco-cms/backoffice/observable-api'; /** * A manager for handling interaction memory items. diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index ebf0aa5c4e88..4f4b16d78d10 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -2,16 +2,16 @@ import { UmbModalToken } from '../token/modal-token.js'; import type { UmbModalConfig, UmbModalType } from '../types.js'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; +import { umbDeepMerge } from '@umbraco-cms/backoffice/utils'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { UmbId } from '@umbraco-cms/backoffice/id'; +import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import { type UmbDeepPartialObject, umbDeepMerge } from '@umbraco-cms/backoffice/utils'; +import { UMB_ROUTE_CONTEXT } from '@umbraco-cms/backoffice/router'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; -import { UMB_ROUTE_CONTEXT, type IRouterSlot } from '@umbraco-cms/backoffice/router'; -import { - UmbInteractionMemoryManager, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; +import type { IRouterSlot } from '@umbraco-cms/backoffice/router'; +import type { UmbDeepPartialObject } from '@umbraco-cms/backoffice/utils'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; export interface UmbModalRejectReason { type: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 881a5f07bbd8..6509d86f3e29 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -1,6 +1,6 @@ -import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; export type * from './extensions/types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index f4b5b18f1fa8..39955981fd02 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -1,16 +1,14 @@ import { UMB_PICKER_INPUT_CONTEXT } from './picker-input.context-token.js'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; +import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; +import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository'; import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; -import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; -import { - UmbInteractionMemoryManager, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; type PickerItemBaseType = { name: string; unique: string }; export class UmbPickerInputContext< @@ -144,7 +142,7 @@ export class UmbPickerInputContext< } #setMemoriesFromModal(modalMemories: Array) { - /* Check if we have any memories from the modal, and if so, + /* Check if we have any memories from the modal, and if so, apply it to the picker input context so it can be reached from the input element. */ if (modalMemories.length > 0) { modalMemories.forEach((memory) => this.interactionMemory.setMemory(memory)); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index e3849c09ddc2..2284bf705121 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -1,13 +1,9 @@ import type { UmbPickerContext } from '../picker.context.js'; -import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import { property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; -import { - UmbModalBaseElement, - type ManifestModal, - type UmbModalContext, - type UmbPickerModalData, -} from '@umbraco-cms/backoffice/modal'; +import type { ManifestModal, UmbModalContext, UmbPickerModalData } from '@umbraco-cms/backoffice/modal'; export abstract class UmbPickerModalBaseElement< ItemType = UmbEntityModel, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts index 843aaa40eb09..63a16f123ad4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/picker.context.ts @@ -1,10 +1,10 @@ import { UMB_PICKER_CONTEXT } from './picker.context.token.js'; import { UmbPickerSearchManager } from './search/manager/picker-search.manager.js'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; -import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils'; +import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; export class UmbPickerContext extends UmbContextBase { public readonly interactionMemory = new UmbInteractionMemoryManager(this); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index cd0b232b4168..35a44053645d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -1,9 +1,9 @@ import type { UmbPickerSearchManagerConfig } from './types.js'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; +import { debounce } from '@umbraco-cms/backoffice/utils'; import { UmbArrayState, UmbBooleanState, UmbNumberState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbSearchProvider, UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search'; -import { debounce } from '@umbraco-cms/backoffice/utils'; /** * A manager for searching items in a picker. diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts index a62d64d19f30..4f775c857837 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.test.ts @@ -1,10 +1,10 @@ +import { UmbPropertyEditorUiInteractionMemoryManager } from './property-editor-ui-interaction-memory.manager.js'; +import { UmbPropertyEditorConfigCollection } from '../config/index.js'; +import { customElement } from '@umbraco-cms/backoffice/external/lit'; import { expect } from '@open-wc/testing'; import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; -import { customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbControllerHostElementMixin } from '@umbraco-cms/backoffice/controller-api'; -import { UmbPropertyEditorUiInteractionMemoryManager } from './property-editor-ui-interaction-memory.manager.js'; import { UmbInteractionMemoryContext } from '@umbraco-cms/backoffice/interaction-memory'; -import { UmbPropertyEditorConfigCollection } from '../config/index.js'; @customElement('test-my-controller-host') class UmbTestControllerHostElement extends UmbControllerHostElementMixin(HTMLElement) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts index a466352a2f8c..8d86e21b767e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/interaction-memory/property-editor-ui-interaction-memory.manager.ts @@ -1,11 +1,9 @@ import type { UmbPropertyEditorConfigCollection } from '../config/index.js'; +import { simpleHashCode, UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import { UMB_INTERACTION_MEMORY_CONTEXT } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { - UMB_INTERACTION_MEMORY_CONTEXT, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; -import { simpleHashCode, UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; export interface UmbPropertyEditorUiInteractionMemoryManagerArgs { memoryUniquePrefix: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts index 4b8eece06ff8..7d4d3f7070e6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-picker/tree-item-picker-expansion.manager.ts @@ -1,10 +1,11 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import { UmbEntityExpansionManager } from '@umbraco-cms/backoffice/utils'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbEntityExpansionModel } from '@umbraco-cms/backoffice/utils'; import type { UmbInteractionMemoryManager, UmbInteractionMemoryModel, } from '@umbraco-cms/backoffice/interaction-memory'; -import { UmbEntityExpansionManager, type UmbEntityExpansionModel } from '@umbraco-cms/backoffice/utils'; export interface UmbTreeItemPickerExpansionManagerArgs { interactionMemoryManager?: UmbInteractionMemoryManager; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 4d6e4d94b2e1..fb71dd349de7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -1,13 +1,13 @@ -import type { UmbTreeItemModelBase, UmbTreeSelectionConfiguration } from '../types.js'; import { UmbTreeItemPickerContext } from '../tree-item-picker/index.js'; import type { UmbTreeElement } from '../tree.element.js'; +import type { UmbTreeItemModelBase, UmbTreeSelectionConfiguration } from '../types.js'; import type { UmbTreePickerModalData, UmbTreePickerModalValue } from './tree-picker-modal.token.js'; -import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; -import { html, customElement, state, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit'; -import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; -import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; +import { customElement, html, ifDefined, nothing, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event'; +import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; +import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; +import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; import type { UmbEntityExpansionModel, UmbExpansionChangeEvent } from '@umbraco-cms/backoffice/utils'; @customElement('umb-tree-picker-modal') diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 3a363b7a6f79..c652c538eee5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -1,18 +1,16 @@ import type { UmbDocumentItemModel } from '../../item/types.js'; import { UmbDocumentPickerInputContext } from './input-document.context.js'; import { css, customElement, html, nothing, property, repeat, state, when } from '@umbraco-cms/backoffice/external/lit'; +import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UmbInteractionMemoryChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; -import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type'; -import { - UmbInteractionMemoryChangeEvent, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; -import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-input-document') export class UmbInputDocumentElement extends UmbFormControlMixin( diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 41a5ca694c86..49420115d3ef 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -1,16 +1,16 @@ -import type { UmbInputDocumentElement } from '../../components/input-document/input-document.element.js'; import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js'; +import type { UmbInputDocumentElement } from '../../components/input-document/input-document.element.js'; +import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; -import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbPropertyEditorUiInteractionMemoryManager } from '@umbraco-cms/backoffice/property-editor'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models'; -import { - UmbPropertyEditorUiInteractionMemoryManager, - type UmbPropertyEditorConfigCollection, - type UmbPropertyEditorUiElement, +import type { + UmbPropertyEditorConfigCollection, + UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-property-editor-ui-document-picker') export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index a49b74e08459..2dd5f30d4c68 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -10,22 +10,20 @@ import { repeat, state, } from '@umbraco-cms/backoffice/external/lit'; +import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UmbInteractionMemoryChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbSorterController, UmbSorterResolvePlacementAsGrid } from '@umbraco-cms/backoffice/sorter'; +import { UMB_MEDIA_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/media-type'; import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; -import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import { UMB_MEDIA_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/media-type'; import '@umbraco-cms/backoffice/imaging'; -import { - UmbInteractionMemoryChangeEvent, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; -import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; const elementName = 'umb-input-media'; @customElement(elementName) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index be7b88c5285e..a9a70f8f33e3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -1,34 +1,34 @@ import { UmbMediaItemRepository } from '../../repository/index.js'; import { UmbMediaTreeRepository } from '../../tree/media-tree.repository.js'; import { UMB_MEDIA_ROOT_ENTITY_TYPE } from '../../entity.js'; -import type { UmbMediaTreeItemModel, UmbMediaSearchItemModel, UmbMediaItemModel } from '../../types.js'; import { UmbMediaSearchProvider } from '../../search/index.js'; import type { UmbDropzoneMediaElement } from '../../dropzone/index.js'; +import type { UmbMediaTreeItemModel, UmbMediaSearchItemModel, UmbMediaItemModel } from '../../types.js'; +import { UmbMediaPickerContext } from './media-picker.context.js'; import type { UmbMediaPathModel } from './types.js'; import type { UmbMediaPickerFolderPathElement } from './components/media-picker-folder-path.element.js'; import type { UmbMediaPickerModalData, UmbMediaPickerModalValue } from './media-picker-modal.token.js'; -import { UmbMediaPickerContext } from './media-picker.context.js'; -import type { UmbDropzoneChangeEvent, UmbUploadableItem } from '@umbraco-cms/backoffice/dropzone'; import { css, - html, customElement, - state, - repeat, + html, ifDefined, - query, - type PropertyValues, nothing, + query, + repeat, + state, } from '@umbraco-cms/backoffice/external/lit'; import { debounce, UmbPaginationManager } from '@umbraco-cms/backoffice/utils'; -import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; -import type { UUIInputEvent, UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui'; import { isUmbracoFolder } from '@umbraco-cms/backoffice/media-type'; -import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; +import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; +import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/content'; import { UMB_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/variant'; +import type { PropertyValues } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbDropzoneChangeEvent, UmbUploadableItem } from '@umbraco-cms/backoffice/dropzone'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbPickerContext } from '@umbraco-cms/backoffice/picker'; -import { UmbPickerModalBaseElement } from '@umbraco-cms/backoffice/picker'; +import type { UUIInputEvent, UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui'; import '@umbraco-cms/backoffice/imaging'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts index df235ee2961c..88ef119fdcc4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker.context.ts @@ -1,7 +1,7 @@ import { UMB_MEDIA_PICKER_CONTEXT } from './media-picker.context.token.js'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; // TODO: extend UmbTreeItemPickerContext export class UmbMediaPickerContext extends UmbContextBase { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index 9aa3a7cb6671..fe10e921525b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -2,18 +2,18 @@ import type { UmbInputRichMediaElement } from '../../components/input-rich-media import type { UmbCropModel, UmbMediaPickerValueModel } from '../types.js'; import { UMB_MEDIA_ENTITY_TYPE } from '../../entity.js'; import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbPropertyEditorUiInteractionMemoryManager } from '@umbraco-cms/backoffice/property-editor'; import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property'; -import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models'; -import { - UmbPropertyEditorUiInteractionMemoryManager, - type UmbPropertyEditorConfigCollection, - type UmbPropertyEditorUiElement, -} from '@umbraco-cms/backoffice/property-editor'; -import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; -import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import type { + UmbPropertyEditorConfigCollection, + UmbPropertyEditorUiElement, +} from '@umbraco-cms/backoffice/property-editor'; +import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models'; +import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; import '../../components/input-rich-media/input-rich-media.element.js'; /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 004893182bc8..314b22016ba8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -1,15 +1,13 @@ import type { UmbContentPickerSource } from '../../types.js'; -import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import { css, customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UmbInteractionMemoryChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import { - UmbInteractionMemoryChangeEvent, - type UmbInteractionMemoryModel, -} from '@umbraco-cms/backoffice/interaction-memory'; @customElement('umb-input-content') export class UmbInputContentElement extends UmbFormControlMixin( diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index a1b5aca83ece..fb4824c7ac44 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -10,13 +10,13 @@ import { UMB_ANCESTORS_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; import { UMB_DOCUMENT_ENTITY_TYPE } from '@umbraco-cms/backoffice/document'; import { UMB_MEDIA_ENTITY_TYPE } from '@umbraco-cms/backoffice/media'; import { UMB_MEMBER_ENTITY_TYPE } from '@umbraco-cms/backoffice/member'; -import { - UmbPropertyEditorUiInteractionMemoryManager, - type UmbPropertyEditorConfigCollection, - type UmbPropertyEditorUiElement, +import { UmbPropertyEditorUiInteractionMemoryManager } from '@umbraco-cms/backoffice/property-editor'; +import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; +import type { + UmbPropertyEditorConfigCollection, + UmbPropertyEditorUiElement, } from '@umbraco-cms/backoffice/property-editor'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; // import of local component import './components/input-content/index.js'; From bf59f3dcde791acc710bfbe635f2261b781346e2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 18 Sep 2025 15:52:10 +0200 Subject: [PATCH 73/76] remove interaction memory implementation in modal context --- .../core/modal/context/modal.context.ts | 8 ---- .../core/picker-input/picker-input.context.ts | 14 ------- .../picker/modal/picker-modal-base.element.ts | 39 +++++++++---------- 3 files changed, 19 insertions(+), 42 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts index 4f4b16d78d10..b27388d406e3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/context/modal.context.ts @@ -5,13 +5,11 @@ import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffi import { umbDeepMerge } from '@umbraco-cms/backoffice/utils'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import { UmbId } from '@umbraco-cms/backoffice/id'; -import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import { UMB_ROUTE_CONTEXT } from '@umbraco-cms/backoffice/router'; import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; import type { IRouterSlot } from '@umbraco-cms/backoffice/router'; import type { UmbDeepPartialObject } from '@umbraco-cms/backoffice/utils'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; export interface UmbModalRejectReason { type: string; @@ -63,8 +61,6 @@ export class UmbModalContext< #size = new UmbStringState('small'); public readonly size = this.#size.asObservable(); - public readonly interactionMemory = new UmbInteractionMemoryManager(this); - constructor( host: UmbControllerHost, modalAlias: string | UmbModalToken, @@ -91,10 +87,6 @@ export class UmbModalContext< this.#size.setValue(size); - // Pass any provided memories to the interaction memory manager - const memories = ((args.data?.interactionMemories as Array) || undefined) ?? []; - memories.forEach((memory) => this.interactionMemory.setMemory(memory)); - const defaultData = this.alias instanceof UmbModalToken ? this.alias.getDefaultData() : undefined; this.data = Object.freeze( // If we have both data and defaultData perform a deep merge diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index 39955981fd02..3619c88b2b8d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -6,7 +6,6 @@ import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository'; import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; @@ -112,9 +111,6 @@ export class UmbPickerInputContext< }); const modalValue = await modalContext.onSubmit().catch(() => undefined); - - this.#setMemoriesFromModal(modalContext?.interactionMemory.getAllMemories() ?? []); - if (!modalValue) return; this.setSelection(modalValue.selection); @@ -140,14 +136,4 @@ export class UmbPickerInputContext< this.setSelection(newSelection); this.getHostElement().dispatchEvent(new UmbChangeEvent()); } - - #setMemoriesFromModal(modalMemories: Array) { - /* Check if we have any memories from the modal, and if so, - apply it to the picker input context so it can be reached from the input element. */ - if (modalMemories.length > 0) { - modalMemories.forEach((memory) => this.interactionMemory.setMemory(memory)); - } else { - this.interactionMemory.clear(); - } - } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts index 2284bf705121..85aa28e4807a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/modal/picker-modal-base.element.ts @@ -1,9 +1,9 @@ import type { UmbPickerContext } from '../picker.context.js'; -import { property } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; -import type { ManifestModal, UmbModalContext, UmbPickerModalData } from '@umbraco-cms/backoffice/modal'; +import type { ManifestModal, UmbPickerModalData } from '@umbraco-cms/backoffice/modal'; +import { UMB_PICKER_INPUT_CONTEXT } from '@umbraco-cms/backoffice/picker-input'; export abstract class UmbPickerModalBaseElement< ItemType = UmbEntityModel, @@ -13,36 +13,35 @@ export abstract class UmbPickerModalBaseElement< > extends UmbModalBaseElement { protected abstract _pickerContext: UmbPickerContext; - @property({ attribute: false }) - public override set modalContext(context: UmbModalContext | undefined) { - super.modalContext = context; - this.#observeModalInteractionMemories(); - } - public override get modalContext(): UmbModalContext | undefined { - return super.modalContext; + #pickerInputContext?: typeof UMB_PICKER_INPUT_CONTEXT.TYPE; + + constructor() { + super(); + this.consumeContext(UMB_PICKER_INPUT_CONTEXT, (pickerInputContext) => { + this.#pickerInputContext = pickerInputContext; + this.#observeMemoriesFromInputContext(); + }); } override connectedCallback(): void { super.connectedCallback(); - // We need to observe the picker memories to be able to update the modal memory. - // We observe the memories to support close with esc key or clicking outside the modal. - this.#observePickerModalInteractionMemories(); + this.#observeMemoriesFromPicker(); } - #observePickerModalInteractionMemories() { + #observeMemoriesFromPicker() { this.observe(this._pickerContext.interactionMemory.memories, (memories) => { - this.#setPickerModalMemory(memories); + this.#setMemoriesOnInputContext(memories); }); } #getInteractionMemoryUnique() { - // TODO: consider appending with a picker unique when we have that implemented. + // TODO: consider appending with a unique when we have that implemented. return `UmbPickerModal`; } - #observeModalInteractionMemories() { + #observeMemoriesFromInputContext() { this.observe( - this.modalContext?.interactionMemory.memory(this.#getInteractionMemoryUnique()), + this.#pickerInputContext?.interactionMemory.memory(this.#getInteractionMemoryUnique()), (memory) => { memory?.memories?.forEach((memory) => this._pickerContext.interactionMemory.setMemory(memory)); }, @@ -50,16 +49,16 @@ export abstract class UmbPickerModalBaseElement< ); } - #setPickerModalMemory(pickerMemories: Array) { + #setMemoriesOnInputContext(pickerMemories: Array) { if (pickerMemories?.length > 0) { const pickerModalMemory: UmbInteractionMemoryModel = { unique: this.#getInteractionMemoryUnique(), memories: pickerMemories, }; - this.modalContext?.interactionMemory.setMemory(pickerModalMemory); + this.#pickerInputContext?.interactionMemory.setMemory(pickerModalMemory); } else { - this.modalContext?.interactionMemory.deleteMemory(this.#getInteractionMemoryUnique()); + this.#pickerInputContext?.interactionMemory.deleteMemory(this.#getInteractionMemoryUnique()); } } } From 6dc88f89a7d0b060e5f51d082c561a40bb613eb6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 18 Sep 2025 15:55:02 +0200 Subject: [PATCH 74/76] remove interactionMemories from modal interface --- src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 6509d86f3e29..3fe706855006 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -1,5 +1,4 @@ import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api'; -import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; export type * from './extensions/types.js'; @@ -9,7 +8,6 @@ export interface UmbPickerModalData { filter?: (item: ItemType) => boolean; pickableFilter?: (item: ItemType) => boolean; search?: UmbPickerModalSearchConfig; - interactionMemories?: Array; } export interface UmbPickerModalSearchConfig> { From 245e6eb535c3e30a9a789f7bfc065d19a31dc406 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 18 Sep 2025 16:02:22 +0200 Subject: [PATCH 75/76] revert to using the umbOpenModal helper --- .../core/picker-input/picker-input.context.ts | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts index 3619c88b2b8d..11d3bdeeb221 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker-input/picker-input.context.ts @@ -4,10 +4,15 @@ import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UmbDeprecation } from '@umbraco-cms/backoffice/utils'; import { UmbInteractionMemoryManager } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository'; -import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository'; -import type { UmbModalToken, UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; +import { + umbConfirmModal, + umbOpenModal, + type UmbModalToken, + type UmbPickerModalData, + type UmbPickerModalValue, +} from '@umbraco-cms/backoffice/modal'; type PickerItemBaseType = { name: string; unique: string }; export class UmbPickerInputContext< @@ -93,24 +98,16 @@ export class UmbPickerInputContext< async openPicker(pickerData?: Partial) { await this.#itemManager.init; - - const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT); - if (!modalManagerContext) { - throw new Error('Modal manager not found.'); - } - - const modalContext = modalManagerContext.open(this, this.modalAlias, { + const modalValue = await umbOpenModal(this, this.modalAlias, { data: { multiple: this._max === 1 ? false : true, - interactionMemories: this.interactionMemory.getAllMemories(), ...pickerData, }, value: { selection: this.getSelection(), } as PickerModalValueType, - }); + }).catch(() => undefined); - const modalValue = await modalContext.onSubmit().catch(() => undefined); if (!modalValue) return; this.setSelection(modalValue.selection); From 7030ba07b762882c914413ae6154f558f2c1d387 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 18 Sep 2025 16:11:37 +0200 Subject: [PATCH 76/76] align property and event name --- .../event/interaction-memories-change.event.ts | 8 ++++++++ .../event/interaction-memory-change.event.ts | 8 -------- .../src/packages/core/interaction-memory/index.ts | 2 +- .../input-document/input-document.element.ts | 4 ++-- .../property-editor-ui-document-picker.element.ts | 2 +- .../components/input-media/input-media.element.ts | 4 ++-- .../input-rich-media/input-rich-media.element.ts | 4 ++-- .../property-editor-ui-media-picker.element.ts | 2 +- .../components/input-content/input-content.element.ts | 10 +++++----- .../property-editor-ui-content-picker.element.ts | 2 +- 10 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memories-change.event.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memories-change.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memories-change.event.ts new file mode 100644 index 000000000000..e9d65ff06538 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memories-change.event.ts @@ -0,0 +1,8 @@ +export class UmbInteractionMemoriesChangeEvent extends Event { + public static readonly TYPE = 'interaction-memories-change'; + + public constructor() { + // mimics the native change event + super(UmbInteractionMemoriesChangeEvent.TYPE, { bubbles: true, composed: false, cancelable: false }); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts deleted file mode 100644 index d9005af164cd..000000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/event/interaction-memory-change.event.ts +++ /dev/null @@ -1,8 +0,0 @@ -export class UmbInteractionMemoryChangeEvent extends Event { - public static readonly TYPE = 'interaction-memory-change'; - - public constructor() { - // mimics the native change event - super(UmbInteractionMemoryChangeEvent.TYPE, { bubbles: true, composed: false, cancelable: false }); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts index e23c10411cc9..175b537a068f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/interaction-memory/index.ts @@ -1,5 +1,5 @@ export * from './constants.js'; -export * from './event/interaction-memory-change.event.js'; +export * from './event/interaction-memories-change.event.js'; export * from './interaction-memory.context.js'; export * from './interaction-memory.manager.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index c652c538eee5..4e848125fbed 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -5,7 +5,7 @@ import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; -import { UmbInteractionMemoryChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbInteractionMemoriesChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type'; @@ -176,7 +176,7 @@ export class UmbInputDocumentElement extends UmbFormControlMixin + @interaction-memories-change=${this.#onInputInteractionMemoriesChange}> `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index 2dd5f30d4c68..177fd5e022ec 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -14,7 +14,7 @@ import { jsonStringComparison } from '@umbraco-cms/backoffice/observable-api'; import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; -import { UmbInteractionMemoryChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbInteractionMemoriesChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbSorterController, UmbSorterResolvePlacementAsGrid } from '@umbraco-cms/backoffice/sorter'; @@ -197,7 +197,7 @@ export class UmbInputMediaElement extends UmbFormControlMixin + @interaction-memories-change=${this.#onInputInteractionMemoriesChange}> `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts index 314b22016ba8..a557488c1e4a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/components/input-content/input-content.element.ts @@ -3,7 +3,7 @@ import { css, customElement, html, property } from '@umbraco-cms/backoffice/exte import { splitStringToArray } from '@umbraco-cms/backoffice/utils'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; -import { UmbInteractionMemoryChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; +import { UmbInteractionMemoriesChangeEvent } from '@umbraco-cms/backoffice/interaction-memory'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbInteractionMemoryModel } from '@umbraco-cms/backoffice/interaction-memory'; import type { UmbReferenceByUniqueAndType } from '@umbraco-cms/backoffice/models'; @@ -100,13 +100,13 @@ export class UmbInputContentElement extends UmbFormControlMixin + @interaction-memories-change=${this.#onInteractionMemoriesChange}> `; } @@ -151,7 +151,7 @@ export class UmbInputContentElement extends UmbFormControlMixin + @interaction-memories-change=${this.#onInteractionMemoriesChange}> `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts index fb4824c7ac44..a80582396006 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/property-editors/content-picker/property-editor-ui-content-picker.element.ts @@ -209,7 +209,7 @@ export class UmbPropertyEditorUIContentPickerElement ?readonly=${this.readonly} @change=${this.#onChange} .interactionMemories=${this._interactionMemories} - @interaction-memory-change=${this.#onInputInteractionMemoriesChange}> + @interaction-memories-change=${this.#onInputInteractionMemoriesChange}> ${this.#renderInvalidData()} `;