diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts index e24fcb66c4..303e3b3874 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/array-state.ts @@ -1,5 +1,5 @@ import { DeepState } from "./deep-state"; -import { appendToFrozenArray } from "./append-to-frozen-array.method"; +import { pushToUniqueArray } from "./push-to-unique-array.method"; /** * @export @@ -21,15 +21,15 @@ export class ArrayState extends DeepState { /** * @method append * @param {unknown} unique - The unique value to remove. - * @returns ArrayState + * @return {ArrayState} Reference to it self. * @description - Remove some new data of this Subject. * @example Example remove entry with key '1' * const data = [ * { key: 1, value: 'foo'}, * { key: 2, value: 'bar'} * ]; - * const mySubject = new ArrayState(data, (x) => x.key); - * mySubject.remove([1]); + * const myState = new ArrayState(data, (x) => x.key); + * myState.remove([1]); */ remove(uniques: unknown[]) { let next = this.getValue(); @@ -51,7 +51,7 @@ export class ArrayState extends DeepState { /** * @method filter * @param {unknown} filterMethod - The unique value to remove. - * @returns ArrayState + * @return {ArrayState} Reference to it self. * @description - Remove some new data of this Subject. * @example Example remove entry with key '1' * const data = [ @@ -59,8 +59,8 @@ export class ArrayState extends DeepState { * { key: 2, value: 'bar'}, * { key: 3, value: 'poo'} * ]; - * const mySubject = new ArrayState(data, (x) => x.key); - * mySubject.filter((entry) => entry.key !== 1); + * const myState = new ArrayState(data, (x) => x.key); + * myState.filter((entry) => entry.key !== 1); * * Result: * [ @@ -75,48 +75,55 @@ export class ArrayState extends DeepState { } /** - * @method append - * @param {Partial} partialData - A object containing some of the data for this Subject. - * @returns ArrayState + * @method appendOne + * @param {T} entry - new data to be added in this Subject. + * @return {ArrayState} Reference to it self. * @description - Append some new data to this Subject. * @example Example append some data. * const data = [ * { key: 1, value: 'foo'}, * { key: 2, value: 'bar'} * ]; - * const mySubject = new ArrayState(data); - * mySubject.append({ key: 1, value: 'replaced-foo'}); + * const myState = new ArrayState(data); + * myState.append({ key: 1, value: 'replaced-foo'}); */ appendOne(entry: T) { - this.next(appendToFrozenArray(this.getValue(), entry, this._getUnique)) + const next = [...this.getValue()]; + if(this._getUnique) { + pushToUniqueArray(next, entry, this._getUnique); + } else { + next.push(entry); + } + this.next(next); return this; } /** * @method append * @param {T[]} entries - A array of new data to be added in this Subject. - * @returns ArrayState + * @return {ArrayState} Reference to it self. * @description - Append some new data to this Subject, if it compares to existing data it will replace it. * @example Example append some data. * const data = [ * { key: 1, value: 'foo'}, * { key: 2, value: 'bar'} * ]; - * const mySubject = new ArrayState(data); - * mySubject.append([ + * const myState = new ArrayState(data); + * myState.append([ * { key: 1, value: 'replaced-foo'}, * { key: 3, value: 'another-bla'} * ]); */ append(entries: T[]) { - // TODO: stop calling appendOne for each but make sure to handle this in one. - entries.forEach(x => this.appendOne(x)) - - /* - const unFrozenDataSet = [...this.getValue()]; - - this.next(unFrozenDataSet); - */ + if(this._getUnique) { + const next = [...this.getValue()]; + entries.forEach(entry => { + pushToUniqueArray(next, entry, this._getUnique!); + }); + this.next(next); + } else { + this.next([...this.getValue(), ...entries]); + } return this; } } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts index 5175616f20..e726a075bb 100644 --- a/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/object-state.ts @@ -12,15 +12,17 @@ import { DeepState } from "./deep-state"; export class ObjectState extends DeepState { /** - * @method append - * @param {Partial} partialData - A object containing some of the data for this Subject. + * @method update + * @param {Partial} partialData - A object containing some of the data to update in this Subject. * @description - Append some new data to this Object. + * @return {ObjectState} Reference to it self. * @example Example append some data. * const data = {key: 'myKey', value: 'myInitialValue'}; - * const mySubject = new ObjectState(data) - * mySubject.append({value: 'myNewValue'}) + * const myState = new ObjectState(data); + * myState.update({value: 'myNewValue'}); */ update(partialData: Partial) { this.next({ ...this.getValue(), ...partialData }); + return this; } } diff --git a/src/Umbraco.Web.UI.Client/libs/observable-api/push-to-unique-array.method.ts b/src/Umbraco.Web.UI.Client/libs/observable-api/push-to-unique-array.method.ts new file mode 100644 index 0000000000..35e4e3169c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/observable-api/push-to-unique-array.method.ts @@ -0,0 +1,22 @@ +/** + * @export + * @method pushToUniqueArray + * @param {T[]} data - An array of objects. + * @param {T} entry - The object to insert or replace with. + * @param {getUniqueMethod: (entry: T) => unknown} [getUniqueMethod] - Method to get the unique value of an entry. + * @description - Append or replaces an item of an Array. + * @example Example append new entry for a Array. Where the key is unique and the item will be updated if matched with existing. + * const entry = {key: 'myKey', value: 'myValue'}; + * const newDataSet = pushToUniqueArray([], entry, x => x.key === key); + * mySubject.next(newDataSet); + */ +export function pushToUniqueArray(data: T[], entry: T, getUniqueMethod: (entry: T) => unknown): T[] { + const unique = getUniqueMethod(entry); + const indexToReplace = data.findIndex((x) => getUniqueMethod(x) === unique); + if (indexToReplace !== -1) { + data[indexToReplace] = entry; + } else { + data.push(entry); + } + return data; +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts index b76b29f580..3f89ad1f4b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts @@ -46,9 +46,9 @@ export class UmbWorkspaceDocumentContext extends UmbWorkspaceContentContext x.alias); + const newDataSet = appendToFrozenArray(this._data.getValue().data, entry, x => x.alias); - this.update({data: newDataSet}); + this._data.update({data: newDataSet}); } /* diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/workspace-content.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/workspace-content.context.ts index 76852a829f..b55c24255e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/workspace-content.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/workspace-content.context.ts @@ -2,7 +2,7 @@ import { v4 as uuidv4 } from 'uuid'; import { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN, UmbNotificationDefaultData } from '@umbraco-cms/notification'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextConsumerController, UmbContextProviderController } from '@umbraco-cms/context-api'; -import { DeepState, UmbObserverController, createObservablePart } from '@umbraco-cms/observable-api'; +import { ObjectState, UmbObserverController, createObservablePart } from '@umbraco-cms/observable-api'; import { UmbContentStore } from '@umbraco-cms/store'; import type { ContentTreeItem } from '@umbraco-cms/backend-api'; @@ -33,7 +33,7 @@ export abstract class UmbWorkspaceContentContext< constructor(host: UmbControllerHostInterface, defaultData: ContentTypeType, storeAlias: string, entityType: string) { this._host = host; - this._data = new DeepState(defaultData); + this._data = new ObjectState(defaultData); this.data = this._data.asObservable(); this.name = createObservablePart(this._data, (data) => data.name); diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index e82a3ad7e7..5490e9632e 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -20,6 +20,7 @@ "resolveJsonModule": true, "baseUrl": ".", "paths": { + "@umbraco-cms/modal": ["src/core/modal"], "@umbraco-cms/models": ["libs/models"], "@umbraco-cms/backend-api": ["libs/backend-api"], "@umbraco-cms/context-api": ["libs/context-api"],