From 090e2fbc2cd14e81e5d2aca595d1bacf31db68bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 23 Jan 2023 15:47:46 +0100 Subject: [PATCH] data type --- .../documents/document.detail.store.ts | 2 +- .../documents/document.tree.store.ts | 3 +- .../media/media/media.detail.store.ts | 2 +- .../media/media/media.tree.store.ts | 2 +- .../data-types/data-type.detail.store.ts | 99 +++++++++++++++++++ .../data-types/data-type.tree.store.ts | 96 ++++++++++++++++++ .../unique-array-behavior-subject.ts | 17 ++-- 7 files changed, 209 insertions(+), 12 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.detail.store.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.tree.store.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.detail.store.ts index 3a03b40656..ce52e59454 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.detail.store.ts @@ -12,7 +12,7 @@ export const UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken} + * @extends {UmbStoreBase} * @description - Data Store for Documents */ export class UmbDocumentDetailStore extends UmbStoreBase implements UmbContentStore { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.tree.store.ts index b6015d47ff..43d53ad842 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.tree.store.ts @@ -1,4 +1,3 @@ -import type { Observable } from 'rxjs'; import { DocumentResource, DocumentTreeItem } from '@umbraco-cms/backend-api'; import { tryExecuteAndNotify } from '@umbraco-cms/resources'; import { UmbContextToken } from '@umbraco-cms/context-api'; @@ -13,7 +12,7 @@ export const UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken} + * @extends {UmbStoreBase} * @description - Data Store for Documents */ export class UmbDocumentTreeStore extends UmbStoreBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.detail.store.ts index 646dc36273..5a9403138a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.detail.store.ts @@ -12,7 +12,7 @@ export const UMB_MEDIA_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken} + * @extends {UmbStoreBase} * @description - Data Store for Media */ export class UmbMediaDetailStore extends UmbStoreBase implements UmbContentStore { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.tree.store.ts index c6801c3794..36f1a3c9cd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/media.tree.store.ts @@ -15,7 +15,7 @@ type MediaTreeItem = ContentTreeItem; /** * @export * @class UmbMediaTreeStore - * @extends {UmbStoreBase} + * @extends {UmbStoreBase} * @description - Data Store for Media */ export class UmbMediaTreeStore extends UmbStoreBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.detail.store.ts new file mode 100644 index 0000000000..31b5035a34 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.detail.store.ts @@ -0,0 +1,99 @@ +import type { DataTypeDetails } from '@umbraco-cms/models'; +import { UmbContextToken } from '@umbraco-cms/context-api'; +import { createObservablePart, UniqueArrayBehaviorSubject } from '@umbraco-cms/observable-api'; +import { UmbStoreBase } from '@umbraco-cms/stores/store-base'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; +import { DataTypeResource } from '@umbraco-cms/backend-api'; + + +export const UMB_DATA_TYPE_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbDataTypeDetailStore'); + + +/** + * @export + * @class UmbDataTypeDetailStore + * @extends {UmbStoreBase} + * @description - Details Data Store for Data Types + */ +export class UmbDataTypeDetailStore extends UmbStoreBase { + + + private _data = new UniqueArrayBehaviorSubject([], (x) => x.key); + + + constructor(host: UmbControllerHostInterface) { + super(host, UMB_DATA_TYPE_DETAIL_STORE_CONTEXT_TOKEN.toString()); + } + + /** + * @description - Request a Data Type by key. The Data Type is added to the store and is returned as an Observable. + * @param {string} key + * @return {*} {(Observable)} + * @memberof UmbDataTypesStore + */ + getByKey(key: string) { + // TODO: use backend cli when available. + fetch(`/umbraco/management/api/v1/document/data-type/${key}`) + .then((res) => res.json()) + .then((data) => { + this._data.append(data); + }); + + return createObservablePart(this._data, (documents) => + documents.find((document) => document.key === key) + ); + } + + // TODO: make sure UI somehow can follow the status of this action. + /** + * @description - Save a Data Type. + * @param {Array} dataTypes + * @memberof UmbDataTypesStore + * @return {*} {Promise} + */ + save(data: DataTypeDetails[]) { + // fetch from server and update store + // TODO: use Fetcher API. + let body: string; + + try { + body = JSON.stringify(data); + } catch (error) { + console.error(error); + return Promise.reject(); + } + + // TODO: use backend cli when available. + return fetch('/umbraco/management/api/v1/data-type/save', { + method: 'POST', + body: body, + headers: { + 'Content-Type': 'application/json', + }, + }) + .then((res) => res.json()) + .then((data: Array) => { + this._data.append(data); + }); + } + + // TODO: How can we avoid having this in both stores? + /** + * @description - Delete a Data Type. + * @param {string[]} keys + * @memberof UmbDataTypesStore + * @return {*} {Promise} + */ + async delete(keys: string[]) { + // TODO: use backend cli when available. + await fetch('/umbraco/backoffice/data-type/delete', { + method: 'POST', + body: JSON.stringify(keys), + headers: { + 'Content-Type': 'application/json', + }, + }); + + this._data.remove(keys); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.tree.store.ts new file mode 100644 index 0000000000..2e8b6aaa47 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/data-type.tree.store.ts @@ -0,0 +1,96 @@ +import { DataTypeResource, DocumentTreeItem } from '@umbraco-cms/backend-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/resources'; +import { UmbContextToken } from '@umbraco-cms/context-api'; +import { createObservablePart, UniqueArrayBehaviorSubject } from '@umbraco-cms/observable-api'; +import { UmbStoreBase } from '@umbraco-cms/stores/store-base'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; + + +export const UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbDocumentTreeStore'); + + +/** + * @export + * @class UmbDocumentStore + * @extends {UmbStoreBase} + * @description - Tree Data Store for Data Types + */ +export class UmbDocumentTreeStore extends UmbStoreBase { + + + private _data = new UniqueArrayBehaviorSubject([], (x) => x.key); + + + constructor(host: UmbControllerHostInterface) { + super(host, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN.toString()); + } + + // TODO: How can we avoid having this in both stores? + /** + * @description - Delete a Data Type. + * @param {string[]} keys + * @memberof UmbDataTypesStore + * @return {*} {Promise} + */ + async delete(keys: string[]) { + // TODO: use backend cli when available. + await fetch('/umbraco/backoffice/data-type/delete', { + method: 'POST', + body: JSON.stringify(keys), + headers: { + 'Content-Type': 'application/json', + }, + }); + + this._data.remove(keys); + } + + getTreeRoot() { + tryExecuteAndNotify(this._host, DataTypeResource.getTreeDataTypeRoot({})).then(({ data }) => { + if (data) { + // TODO: how do we handle if an item has been removed during this session(like in another tab or by another user)? + this._data.append(data.items); + } + }); + + // TODO: how do we handle trashed items? + // TODO: remove ignore when we know how to handle trashed items. + return createObservablePart(this._data, (items) => items.filter((item) => item.parentKey === null && !item.isTrashed)); + } + + getTreeItemChildren(key: string) { + tryExecuteAndNotify( + this._host, + DataTypeResource.getTreeDataTypeChildren({ + parentKey: key, + }) + ).then(({ data }) => { + if (data) { + // TODO: how do we handle if an item has been removed during this session(like in another tab or by another user)? + this._data.append(data.items); + } + }); + + // TODO: how do we handle trashed items? + // TODO: remove ignore when we know how to handle trashed items. + return createObservablePart(this._data, (items) => items.filter((item) => item.parentKey === key && !item.isTrashed)); + } + + getTreeItems(keys: Array) { + if (keys?.length > 0) { + tryExecuteAndNotify( + this._host, + DataTypeResource.getTreeDataTypeItem({ + key: keys, + }) + ).then(({ data }) => { + if (data) { + // TODO: how do we handle if an item has been removed during this session(like in another tab or by another user)? + this._data.append(data); + } + }); + } + + return createObservablePart(this._data, (items) => items.filter((item) => keys.includes(item.key ?? ''))); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/core/observable-api/unique-array-behavior-subject.ts b/src/Umbraco.Web.UI.Client/src/core/observable-api/unique-array-behavior-subject.ts index 20519fc7b9..94267f6379 100644 --- a/src/Umbraco.Web.UI.Client/src/core/observable-api/unique-array-behavior-subject.ts +++ b/src/Umbraco.Web.UI.Client/src/core/observable-api/unique-array-behavior-subject.ts @@ -28,16 +28,19 @@ export class UniqueArrayBehaviorSubject extends UniqueBehaviorSubject { * { key: 2, value: 'bar'} * ]; * const mySubject = new UniqueArrayBehaviorSubject(data, (x) => x.key); - * mySubject.remove(1); + * mySubject.remove([1]); */ - remove(unique: unknown) { + remove(uniques: unknown[]) { const unFrozenDataSet = [...this.getValue()]; if (this._getUnique) { - unFrozenDataSet.filter(x => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return this._getUnique(x) !== unique; - }); + uniques.forEach( unique => + unFrozenDataSet.filter(x => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return this._getUnique(x) !== unique; + }) + ); + this.next(unFrozenDataSet); } }