From 60ad1c383569f50508022eebd85fbde839f296fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 13 Feb 2023 14:23:53 +0100 Subject: [PATCH] Feature/tree store base (#514) * out comment temprorary for development * initial prep * comment * change port number for dev generate api * generated new apis * document-type repository * rename to item * rename to document * use ItemType * not name detail for full models * correct token * imports * correct imports * use DocumentTypeTreeItem * mega type adapt commit * move DataType import * rename document detail store * add document * new mock data * partialUpdateFrozenArray * imports * document context work * document and document type in context * data-type stores + data-sources * byKey document + data-type * remove type * comment * data-type repository * data-type context adjustments * data-type data observable * fix model import * use ContentTypeCompositionType * correct mock data * . * split treedata / data * correct mock endpoints * new models * update model usage * correct models * imports * correct models * update model imports * update models * update type * update docuemnt models * use DocumentModel * DocumentModel * import lit/decorators.js * lint fixes * remove console.logs * implementation of tree store base class --------- Co-authored-by: Mads Rasmussen --- .../libs/observable-api/array-state.ts | 60 ++++++++++----- src/Umbraco.Web.UI.Client/libs/store/index.ts | 1 + .../libs/store/tree-store-base.ts | 68 +++++++++++++++++ .../repository/document-type.tree.store.ts | 72 +----------------- .../repository/document.tree.store.ts | 75 +------------------ .../repository/data-type.tree.store.ts | 72 +----------------- .../tree/data/template.tree.store.ts | 73 +----------------- .../src/core/mocks/data/document.data.ts | 2 +- 8 files changed, 121 insertions(+), 302 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/store/tree-store-base.ts 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 303e3b3874..5da5dbcfc8 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 { pushToUniqueArray } from "./push-to-unique-array.method"; +import { DeepState } from './deep-state'; +import { pushToUniqueArray } from './push-to-unique-array.method'; /** * @export @@ -12,14 +12,41 @@ import { pushToUniqueArray } from "./push-to-unique-array.method"; */ export class ArrayState extends DeepState { - - constructor(initialData: T[], private _getUnique?: (entry: T) => unknown) { super(initialData); } /** - * @method append + * @method remove + * @param {unknown[]} uniques - The unique values to remove. + * @return {ArrayState} Reference to it self. + * @description - Remove some new data of this Subject. + * @example Example remove entry with key '1' and '2' + * const data = [ + * { key: 1, value: 'foo'}, + * { key: 2, value: 'bar'} + * ]; + * const myState = new ArrayState(data, (x) => x.key); + * myState.remove([1, 2]); + */ + remove(uniques: unknown[]) { + let next = this.getValue(); + if (this._getUnique) { + uniques.forEach((unique) => { + next = next.filter((x) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return this._getUnique(x) !== unique; + }); + }); + + this.next(next); + } + return this; + } + + /** + * @method removeOne * @param {unknown} unique - The unique value to remove. * @return {ArrayState} Reference to it self. * @description - Remove some new data of this Subject. @@ -29,19 +56,16 @@ export class ArrayState extends DeepState { * { key: 2, value: 'bar'} * ]; * const myState = new ArrayState(data, (x) => x.key); - * myState.remove([1]); + * myState.removeOne(1); */ - remove(uniques: unknown[]) { + removeOne(unique: unknown) { let next = this.getValue(); if (this._getUnique) { - uniques.forEach( unique => { - next = next.filter(x => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return this._getUnique(x) !== unique; - }) - } - ); + next = next.filter((x) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return this._getUnique(x) !== unique; + }); this.next(next); } @@ -89,7 +113,7 @@ export class ArrayState extends DeepState { */ appendOne(entry: T) { const next = [...this.getValue()]; - if(this._getUnique) { + if (this._getUnique) { pushToUniqueArray(next, entry, this._getUnique); } else { next.push(entry); @@ -115,9 +139,9 @@ export class ArrayState extends DeepState { * ]); */ append(entries: T[]) { - if(this._getUnique) { + if (this._getUnique) { const next = [...this.getValue()]; - entries.forEach(entry => { + entries.forEach((entry) => { pushToUniqueArray(next, entry, this._getUnique!); }); this.next(next); diff --git a/src/Umbraco.Web.UI.Client/libs/store/index.ts b/src/Umbraco.Web.UI.Client/libs/store/index.ts index 2c8f2e1e80..fbda429a4b 100644 --- a/src/Umbraco.Web.UI.Client/libs/store/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/store/index.ts @@ -1,3 +1,4 @@ export * from './icon/icon.store'; export * from './store'; export * from './store-base'; +export * from './tree-store-base'; diff --git a/src/Umbraco.Web.UI.Client/libs/store/tree-store-base.ts b/src/Umbraco.Web.UI.Client/libs/store/tree-store-base.ts new file mode 100644 index 0000000000..feab80cb01 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/store/tree-store-base.ts @@ -0,0 +1,68 @@ +import { EntityTreeItemModel } from '@umbraco-cms/backend-api'; +import { ArrayState, partialUpdateFrozenArray } from '@umbraco-cms/observable-api'; +import { UmbStoreBase } from '@umbraco-cms/store'; + +/** + * @export + * @class UmbTreeStoreBase + * @extends {UmbStoreBase} + * @description - General Tree Data Store + */ +// TODO: consider if tree store could be turned into a general EntityTreeStore class? +export class UmbTreeStoreBase extends UmbStoreBase { + #data = new ArrayState([], (x) => x.key); + + /** + * Appends items to the store + * @param {Array} items + * @memberof UmbTreeStoreBase + */ + appendItems(items: Array) { + this.#data.append(items); + } + + /** + * Updates an item in the store + * @param {string} key + * @param {Partial} data + * @memberof UmbTreeStoreBase + */ + updateItem(key: string, data: Partial) { + this.#data.next(partialUpdateFrozenArray(this.#data.getValue(), data, (entry) => entry.key === key)); + } + + /** + * Removes an item from the store + * @param {string} key + * @memberof UmbTreeStoreBase + */ + removeItem(key: string) { + this.#data.removeOne(key); + } + + /** + * An observable to observe the root items + * @memberof UmbTreeStoreBase + */ + rootItems = this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null)); + + /** + * Returns an observable to observe the children of a given parent + * @param {(string | null)} parentKey + * @return {*} + * @memberof UmbTreeStoreBase + */ + childrenOf(parentKey: string | null) { + return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === parentKey)); + } + + /** + * Returns an observable to observe the items with the given keys + * @param {Array} keys + * @return {*} + * @memberof UmbTreeStoreBase + */ + items(keys: Array) { + return this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? ''))); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.tree.store.ts index becaa5def9..b18c51f11a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/repository/document-type.tree.store.ts @@ -1,7 +1,5 @@ -import { EntityTreeItemModel } from '@umbraco-cms/backend-api'; import { UmbContextToken } from '@umbraco-cms/context-api'; -import { ArrayState } from '@umbraco-cms/observable-api'; -import { UmbStoreBase } from '@umbraco-cms/store'; +import { UmbTreeStoreBase } from '@umbraco-cms/store'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; /** @@ -11,9 +9,7 @@ import { UmbControllerHostInterface } from '@umbraco-cms/controller'; * @description - Tree Data Store for Document-Types */ // TODO: consider if tree store could be turned into a general EntityTreeStore class? -export class UmbDocumentTypeTreeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.key); - +export class UmbDocumentTypeTreeStore extends UmbTreeStoreBase { /** * Creates an instance of UmbDocumentTypeTreeStore. * @param {UmbControllerHostInterface} host @@ -22,70 +18,6 @@ export class UmbDocumentTypeTreeStore extends UmbStoreBase { constructor(host: UmbControllerHostInterface) { super(host, UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN.toString()); } - - /** - * Appends items to the store - * @param {Array} items - * @memberof UmbDocumentTypeTreeStore - */ - appendItems(items: Array) { - this.#data.append(items); - } - - /** - * Updates an item in the store - * @param {string} key - * @param {Partial} data - * @memberof UmbDocumentTypeTreeStore - */ - updateItem(key: string, data: Partial) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.appendOne({ ...entry, ...data }); - } - } - - /** - * Removes an item from the store - * @param {string} key - * @memberof UmbDocumentTypeTreeStore - */ - removeItem(key: string) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.remove([key]); - } - } - - /** - * An observable to observe the root items - * @memberof UmbDocumentTypeTreeStore - */ - rootItems = this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null)); - - /** - * Returns an observable to observe the children of a given parent - * @param {(string | null)} parentKey - * @return {*} - * @memberof UmbDocumentTypeTreeStore - */ - childrenOf(parentKey: string | null) { - return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === parentKey)); - } - - /** - * Returns an observable to observe the items with the given keys - * @param {Array} keys - * @return {*} - * @memberof UmbDocumentTypeTreeStore - */ - items(keys: Array) { - return this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? ''))); - } } export const UMB_DOCUMENT_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken( diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.tree.store.ts index 076bdfd652..8cc4cd5aa3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/repository/document.tree.store.ts @@ -1,19 +1,14 @@ -import { EntityTreeItemModel } from '@umbraco-cms/backend-api'; import { UmbContextToken } from '@umbraco-cms/context-api'; -import { ArrayState } from '@umbraco-cms/observable-api'; -import { UmbStoreBase } from '@umbraco-cms/store'; +import { UmbTreeStoreBase } from '@umbraco-cms/store'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; /** * @export * @class UmbDocumentTreeStore - * @extends {UmbStoreBase} + * @extends {UmbTreeStoreBase} * @description - Tree Data Store for Templates */ -// TODO: consider if tree store could be turned into a general EntityTreeStore class? -export class UmbDocumentTreeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.key); - +export class UmbDocumentTreeStore extends UmbTreeStoreBase { /** * Creates an instance of UmbDocumentTreeStore. * @param {UmbControllerHostInterface} host @@ -22,70 +17,6 @@ export class UmbDocumentTreeStore extends UmbStoreBase { constructor(host: UmbControllerHostInterface) { super(host, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN.toString()); } - - /** - * Appends items to the store - * @param {Array} items - * @memberof UmbDocumentTreeStore - */ - appendItems(items: Array) { - this.#data.append(items); - } - - /** - * Updates an item in the store - * @param {string} key - * @param {Partial} data - * @memberof UmbDocumentTreeStore - */ - updateItem(key: string, data: Partial) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.appendOne({ ...entry, ...data }); - } - } - - /** - * Removes an item from the store - * @param {string} key - * @memberof UmbDocumentTreeStore - */ - removeItem(key: string) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.remove([key]); - } - } - - /** - * An observable to observe the root items - * @memberof UmbDocumentTreeStore - */ - rootItems = this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null)); - - /** - * Returns an observable to observe the children of a given parent - * @param {(string | null)} parentKey - * @return {*} - * @memberof UmbDocumentTreeStore - */ - childrenOf(parentKey: string | null) { - return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === parentKey)); - } - - /** - * Returns an observable to observe the items with the given keys - * @param {Array} keys - * @return {*} - * @memberof UmbDocumentTreeStore - */ - items(keys: Array) { - return this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? ''))); - } } export const UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken( diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.tree.store.ts index 3f1a440f1e..6cf869e5e1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/repository/data-type.tree.store.ts @@ -1,8 +1,6 @@ -import { EntityTreeItemModel } from '@umbraco-cms/backend-api'; import { UmbContextToken } from '@umbraco-cms/context-api'; -import { ArrayState } from '@umbraco-cms/observable-api'; -import { UmbStoreBase } from '@umbraco-cms/store'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; +import { UmbTreeStoreBase } from '@umbraco-cms/store'; /** * @export @@ -11,9 +9,7 @@ import { UmbControllerHostInterface } from '@umbraco-cms/controller'; * @description - Tree Data Store for Data-Types */ // TODO: consider if tree store could be turned into a general EntityTreeStore class? -export class UmbDataTypeTreeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.key); - +export class UmbDataTypeTreeStore extends UmbTreeStoreBase { /** * Creates an instance of UmbDataTypeTreeStore. * @param {UmbControllerHostInterface} host @@ -22,70 +18,6 @@ export class UmbDataTypeTreeStore extends UmbStoreBase { constructor(host: UmbControllerHostInterface) { super(host, UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN.toString()); } - - /** - * Appends items to the store - * @param {Array} items - * @memberof UmbDataTypeTreeStore - */ - appendItems(items: Array) { - this.#data.append(items); - } - - /** - * Updates an item in the store - * @param {string} key - * @param {Partial} data - * @memberof UmbDataTypeTreeStore - */ - updateItem(key: string, data: Partial) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.appendOne({ ...entry, ...data }); - } - } - - /** - * Removes an item from the store - * @param {string} key - * @memberof UmbDataTypeTreeStore - */ - removeItem(key: string) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.remove([key]); - } - } - - /** - * An observable to observe the root items - * @memberof UmbDataTypeTreeStore - */ - rootItems = this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null)); - - /** - * Returns an observable to observe the children of a given parent - * @param {(string | null)} parentKey - * @return {*} - * @memberof UmbDataTypeTreeStore - */ - childrenOf(parentKey: string | null) { - return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === parentKey)); - } - - /** - * Returns an observable to observe the items with the given keys - * @param {Array} keys - * @return {*} - * @memberof UmbDataTypeTreeStore - */ - items(keys: Array) { - return this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? ''))); - } } export const UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken( diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/tree/data/template.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/tree/data/template.tree.store.ts index 55e5468271..e2fc0588da 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/tree/data/template.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/tree/data/template.tree.store.ts @@ -1,7 +1,5 @@ -import type { EntityTreeItemModel } from '@umbraco-cms/backend-api'; import { UmbContextToken } from '@umbraco-cms/context-api'; -import { ArrayState } from '@umbraco-cms/observable-api'; -import { UmbStoreBase } from '@umbraco-cms/store'; +import { UmbTreeStoreBase } from '@umbraco-cms/store'; import type { UmbControllerHostInterface } from '@umbraco-cms/controller'; /** @@ -10,9 +8,7 @@ import type { UmbControllerHostInterface } from '@umbraco-cms/controller'; * @extends {UmbStoreBase} * @description - Tree Data Store for Templates */ -export class UmbTemplateTreeStore extends UmbStoreBase { - #data = new ArrayState([], (x) => x.key); - +export class UmbTemplateTreeStore extends UmbTreeStoreBase { /** * Creates an instance of UmbTemplateTreeStore. * @param {UmbControllerHostInterface} host @@ -21,71 +17,6 @@ export class UmbTemplateTreeStore extends UmbStoreBase { constructor(host: UmbControllerHostInterface) { super(host, UMB_TEMPLATE_TREE_STORE_CONTEXT_TOKEN.toString()); } - - /** - * Appends items to the store - * @param {Array} items - * @memberof UmbTemplateTreeStore - */ - appendItems(items: Array) { - this.#data.append(items); - } - - /** - * Updates an item in the store - * @param {string} key - * @param {Partial} data - * @memberof UmbTemplateTreeStore - */ - updateItem(key: string, data: Partial) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.appendOne({ ...entry, ...data }); - } - } - - /** - * Removes an item from the store - * @param {string} key - * @memberof UmbTemplateTreeStore - */ - removeItem(key: string) { - const entries = this.#data.getValue(); - const entry = entries.find((entry) => entry.key === key); - - if (entry) { - this.#data.remove([key]); - } - } - - /** - * Returns an observable to observe the root items - * @return {*} - * @memberof UmbTemplateTreeStore - */ - rootItems = this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null)); - - /** - * Returns an observable to observe the children of a given parent - * @param {(string | null)} parentKey - * @return {*} - * @memberof UmbTemplateTreeStore - */ - childrenOf(parentKey: string | null) { - return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === parentKey)); - } - - /** - * Returns an observable to observe the items with the given keys - * @param {Array} keys - * @return {*} - * @memberof UmbTemplateTreeStore - */ - items(keys: Array) { - return this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? ''))); - } } export const UMB_TEMPLATE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken( diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts index 8eaf0ea55e..4fbac76d2a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/document.data.ts @@ -379,7 +379,7 @@ export const treeData: Array = [ name: 'All property editors', type: 'document', icon: 'icon-item-arrangement', - hasChildren: false, + hasChildren: true, }, { isProtected: false,