diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts index 2712f528bc..241cab9d39 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -18,7 +18,7 @@ import { } from './documents/document-types/document-type.store'; import { UmbMediaTypeStore, UMB_MEDIA_TYPE_STORE_CONTEXT_TOKEN } from './media/media-types/media-type.store'; import { UmbMemberTypeStore, UMB_MEMBER_TYPE_STORE_CONTEXT_TOKEN } from './members/member-types/member-type.store'; -import { UmbDocumentStore, UMB_DOCUMENT_STORE_CONTEXT_TOKEN } from './documents/documents/document.store'; +import { UmbDocumentStore, UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN } from './documents/documents/document.detail.store'; import { UmbMediaStore, UMB_MEDIA_STORE_CONTEXT_TOKEN } from './media/media/media.store'; import { UmbMemberGroupStore, UMB_MEMBER_GROUP_STORE_CONTEXT_TOKEN } from './members/member-groups/member-group.store'; import { UmbDictionaryStore, UMB_DICTIONARY_STORE_CONTEXT_TOKEN } from './translation/dictionary/dictionary.store'; @@ -67,7 +67,9 @@ export class UmbBackofficeElement extends UmbLitElement { // TODO: find a way this is possible outside this element. It needs to be possible to register stores in extensions this.provideContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, new UmbCurrentUserStore()); - this.provideContext(UMB_DOCUMENT_STORE_CONTEXT_TOKEN, new UmbDocumentStore(this)); + + new UmbDocumentStore(this); + this.provideContext(UMB_MEDIA_STORE_CONTEXT_TOKEN, new UmbMediaStore(this)); this.provideContext(UMB_DATA_TYPE_STORE_CONTEXT_TOKEN, new UmbDataTypeStore(this)); this.provideContext(UMB_DOCUMENT_TYPE_STORE_CONTEXT_TOKEN, new UmbDocumentTypeStore(this)); 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 new file mode 100644 index 0000000000..452c7bee12 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.detail.store.ts @@ -0,0 +1,83 @@ +import { map, Observable } from 'rxjs'; +import type { DocumentDetails } from '@umbraco-cms/models'; +import { DocumentResource, DocumentTreeItem, FolderTreeItem } 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_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbDocumentDetailStore'); + + +/** + * @export + * @class UmbDocumentStore + * @extends {UmbStoreBase} + * @description - Data Store for Documents + */ +export class UmbDocumentDetailStore extends UmbStoreBase { + + + private _data = new UniqueArrayBehaviorSubject([], (a, b) => a.key === b.key); + + + constructor(host: UmbControllerHostInterface) { + super(host, UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN.toString()); + } + + getByKey(key: string): Observable { + // TODO: use backend cli when available. + fetch(`/umbraco/management/api/v1/document/details/${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. + save(data: DocumentDetails[]): Promise { + // 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/document/save', { + method: 'POST', + body: body, + headers: { + 'Content-Type': 'application/json', + }, + }) + .then((res) => res.json()) + .then((data: Array) => { + this._data.append(data); + }); + } + + // TODO: how do we handle trashed items? + async trash(keys: Array) { + // TODO: use backend cli when available. + const res = await fetch('/umbraco/management/api/v1/document/trash', { + method: 'POST', + body: JSON.stringify(keys), + headers: { + 'Content-Type': 'application/json', + }, + }); + const data = await res.json(); + this._data.next(data); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.store.ts deleted file mode 100644 index 57fdab43b5..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.store.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { map, Observable } from 'rxjs'; -import { UmbNodeStoreBase } from '../../../core/stores/store'; -import type { DocumentDetails } from '@umbraco-cms/models'; -import { DocumentResource, DocumentTreeItem, FolderTreeItem } from '@umbraco-cms/backend-api'; -import { tryExecuteAndNotify } from '@umbraco-cms/resources'; -import { UmbContextToken } from '@umbraco-cms/context-api'; -import { createObservablePart } from '@umbraco-cms/observable-api'; - -export const isDocumentDetails = (document: DocumentDetails | DocumentTreeItem): document is DocumentDetails => { - return (document as DocumentDetails).data !== undefined; -}; - -export type UmbDocumentStoreItemType = DocumentDetails | DocumentTreeItem; - -// TODO: research how we write names of global consts. -export const STORE_ALIAS = 'UmbDocumentStore'; - -/** - * @export - * @class UmbDocumentStore - * @extends {UmbDocumentStoreBase} - * @description - Data Store for Documents - */ -export class UmbDocumentStore extends UmbNodeStoreBase { - public readonly storeAlias = STORE_ALIAS; - - getByKey(key: string): Observable { - // TODO: use backend cli when available. - fetch(`/umbraco/management/api/v1/document/details/${key}`) - .then((res) => res.json()) - .then((data) => { - this.updateItems(data); - }); - - /* - return this.items.pipe( - map( - (documents) => - (documents.find((document) => document.key === key && isDocumentDetails(document)) as DocumentDetails) || null - ) - ); - */ - - return createObservablePart(this.items, (documents) => - (documents.find((document) => document.key === key && isDocumentDetails(document)) as DocumentDetails) - ); - } - - // TODO: make sure UI somehow can follow the status of this action. - save(data: DocumentDetails[]): Promise { - // 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/document/save', { - method: 'POST', - body: body, - headers: { - 'Content-Type': 'application/json', - }, - }) - .then((res) => res.json()) - .then((data: Array) => { - this.updateItems(data); - }); - } - - // TODO: how do we handle trashed items? - async trash(keys: Array) { - // TODO: use backend cli when available. - const res = await fetch('/umbraco/management/api/v1/document/trash', { - method: 'POST', - body: JSON.stringify(keys), - headers: { - 'Content-Type': 'application/json', - }, - }); - const data = await res.json(); - this.updateItems(data); - } - - getTreeRoot(): Observable> { - tryExecuteAndNotify(this.host, DocumentResource.getTreeDocumentRoot({})).then(({ data }) => { - if (data) { - this.updateItems(data.items); - } - }); - - // TODO: how do we handle trashed items? - // TODO: remove ignore when we know how to handle trashed items. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return this.items.pipe(map((items) => items.filter((item) => item.parentKey === null && !item.isTrashed))); - } - - getTreeItemChildren(key: string): Observable> { - tryExecuteAndNotify( - this.host, - DocumentResource.getTreeDocumentChildren({ - parentKey: key, - }) - ).then(({ data }) => { - if (data) { - this.updateItems(data.items); - } - }); - - // TODO: how do we handle trashed items? - // TODO: remove ignore when we know how to handle trashed items. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return this.items.pipe(map((items) => items.filter((item) => item.parentKey === key && !item.isTrashed))); - } - - getTreeItems(keys: Array): Observable> { - if (keys?.length > 0) { - tryExecuteAndNotify( - this.host, - DocumentResource.getTreeDocumentItem({ - key: keys, - }) - ).then(({ data }) => { - if (data) { - this.updateItems(data); - } - }); - } - - return this.items.pipe(map((items) => items.filter((item) => keys.includes(item.key ?? '')))); - } -} - -export const UMB_DOCUMENT_STORE_CONTEXT_TOKEN = new UmbContextToken(STORE_ALIAS); 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 new file mode 100644 index 0000000000..3fb2f4d645 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/document.tree.store.ts @@ -0,0 +1,91 @@ +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'; +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('UmbDocumentDetailStore'); + + +/** + * @export + * @class UmbDocumentStore + * @extends {UmbStoreBase} + * @description - Data Store for Documents + */ +export class UmbDocumentTreeStore extends UmbStoreBase { + + + private _data = new UniqueArrayBehaviorSubject([], (a, b) => a.key === b.key); + + + constructor(host: UmbControllerHostInterface) { + super(host, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN.toString()); + } + + // TODO: how do we handle trashed items? + async trash(keys: Array) { + // TODO: use backend cli when available. + const res = await fetch('/umbraco/management/api/v1/document/trash', { + method: 'POST', + body: JSON.stringify(keys), + headers: { + 'Content-Type': 'application/json', + }, + }); + const data = await res.json(); + this._data.next(data); + } + + getTreeRoot(): Observable> { + tryExecuteAndNotify(this._host, DocumentResource.getTreeDocumentRoot({})).then(({ data }) => { + if (data) { + this._data.append(data.items); + } + }); + + // TODO: how do we handle if an item has been removed during this session(like in another tab or by another user)? + // 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): Observable> { + tryExecuteAndNotify( + this._host, + DocumentResource.getTreeDocumentChildren({ + parentKey: key, + }) + ).then(({ data }) => { + if (data) { + this._data.append(data.items); + } + }); + + // TODO: how do we handle if an item has been removed during this session(like in another tab or by another user)? + // 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): Observable> { + if (keys?.length > 0) { + tryExecuteAndNotify( + this._host, + DocumentResource.getTreeDocumentItem({ + 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/backoffice/documents/documents/tree/actions/action-document-delete.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/tree/actions/action-document-delete.element.ts index 9c635f9d6e..34a5180f84 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/tree/actions/action-document-delete.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/tree/actions/action-document-delete.element.ts @@ -2,7 +2,8 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html } from 'lit'; import { customElement } from 'lit/decorators.js'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '../../../../../core/modal'; -import { UmbDocumentStore, UMB_DOCUMENT_STORE_CONTEXT_TOKEN } from '../../document.store'; +import type { UmbDocumentDetailStore } from '../../document.detail.store'; +import { UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN } from '../../document.detail.store'; import UmbTreeItemActionElement from '../../../../shared/components/tree/action/tree-item-action.element'; @customElement('umb-tree-action-document-delete') @@ -10,7 +11,7 @@ export default class UmbTreeActionDocumentDeleteElement extends UmbTreeItemActio static styles = [UUITextStyles, css``]; private _modalService?: UmbModalService; - private _documentStore?: UmbDocumentStore; + private _documentStore?: UmbDocumentDetailStore; connectedCallback(): void { super.connectedCallback(); @@ -19,7 +20,7 @@ export default class UmbTreeActionDocumentDeleteElement extends UmbTreeItemActio this._modalService = modalService; }); - this.consumeContext(UMB_DOCUMENT_STORE_CONTEXT_TOKEN, (documentStore) => { + this.consumeContext(UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN, (documentStore) => { this._documentStore = documentStore; }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/tree/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/tree/manifests.ts index dd544de291..09a36620ae 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/tree/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/tree/manifests.ts @@ -1,4 +1,4 @@ -import { STORE_ALIAS } from '../document.store'; +import { STORE_ALIAS } from '../document.detail.store'; import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models'; const treeAlias = 'Umb.Tree.Documents'; 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 e8256d17cf..da50760cdf 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 @@ -1,6 +1,6 @@ import { UmbWorkspaceContentContext } from '../../../shared/components/workspace/workspace-content/workspace-content.context'; -import { STORE_ALIAS as DOCUMENT_STORE_ALIAS } from '../../../documents/documents/document.store'; -import type { UmbDocumentStore, UmbDocumentStoreItemType } from '../../../documents/documents/document.store'; +import { STORE_ALIAS as DOCUMENT_STORE_ALIAS } from '../document.detail.store'; +import type { UmbDocumentStore, UmbDocumentStoreItemType } from '../document.detail.store'; import type { UmbControllerHostInterface } from '@umbraco-cms/controller'; import type { DocumentDetails } from '@umbraco-cms/models'; import { appendToFrozenArray } from '@umbraco-cms/observable-api'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts index 8a23c626b1..3bdcfe9ebc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection.context.ts @@ -1,11 +1,11 @@ import { ContentTreeItem } from '@umbraco-cms/backend-api'; -import { UmbTreeDataStore } from '@umbraco-cms/stores/store'; +import { UmbTreeStore } from '@umbraco-cms/stores/store'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextToken, UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UniqueBehaviorSubject, UmbObserverController } from '@umbraco-cms/observable-api'; export class UmbCollectionContext< DataType extends ContentTreeItem, - StoreType extends UmbTreeDataStore = UmbTreeDataStore + StoreType extends UmbTreeStore = UmbTreeStore > { private _host: UmbControllerHostInterface; private _entityKey: string | null; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-document-picker/input-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-document-picker/input-document-picker.element.ts index 31432bdac6..5c1e5ddb40 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-document-picker/input-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-document-picker/input-document-picker.element.ts @@ -7,7 +7,8 @@ import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from 'src/core/modal import type { FolderTreeItem } from '@umbraco-cms/backend-api'; import { UmbLitElement } from '@umbraco-cms/element'; import type { UmbObserverController } from '@umbraco-cms/observable-api'; -import { UmbDocumentStore, UMB_DOCUMENT_STORE_CONTEXT_TOKEN } from 'src/backoffice/documents/documents/document.store'; +import type { UmbDocumentDetailStore } from 'src/backoffice/documents/documents/document.detail.store'; +import { UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN } from 'src/backoffice/documents/documents/document.detail.store'; @customElement('umb-input-document-picker') export class UmbInputDocumentPickerElement extends FormControlMixin(UmbLitElement) { @@ -77,7 +78,7 @@ export class UmbInputDocumentPickerElement extends FormControlMixin(UmbLitElemen private _items?: Array; private _modalService?: UmbModalService; - private _documentStore?: UmbDocumentStore; + private _documentStore?: UmbDocumentDetailStore; private _pickedItemsObserver?: UmbObserverController; constructor() { @@ -94,7 +95,7 @@ export class UmbInputDocumentPickerElement extends FormControlMixin(UmbLitElemen () => !!this.max && this._selectedKeys.length > this.max ); - this.consumeContext(UMB_DOCUMENT_STORE_CONTEXT_TOKEN, (instance) => { + this.consumeContext(UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN, (instance) => { this._documentStore = instance; this._observePickedDocuments(); }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts index 83d7affd20..e2080afd81 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree-item.element.ts @@ -11,7 +11,7 @@ import { UMB_TREE_CONTEXT_MENU_SERVICE_CONTEXT_TOKEN, } from './context-menu/tree-context-menu.service'; import type { Entity } from '@umbraco-cms/models'; -import { UmbTreeDataStore } from '@umbraco-cms/stores/store'; +import { UmbTreeStore } from '@umbraco-cms/stores/store'; import { UmbLitElement } from '@umbraco-cms/element'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; @@ -68,7 +68,7 @@ export class UmbTreeItem extends UmbLitElement { private _hasActions = false; private _treeContext?: UmbTreeContextBase; - private _store?: UmbTreeDataStore; + private _store?: UmbTreeStore; private _sectionContext?: UmbSectionContext; private _treeContextMenuService?: UmbTreeContextMenuService; @@ -81,7 +81,7 @@ export class UmbTreeItem extends UmbLitElement { this._observeIsSelected(); }); - this.consumeContext('umbStore', (store: UmbTreeDataStore) => { + this.consumeContext('umbStore', (store: UmbTreeStore) => { this._store = store; }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts index 9af9c01147..40b3bb7aff 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/tree/tree.element.ts @@ -5,7 +5,7 @@ import { repeat } from 'lit-html/directives/repeat.js'; import { UmbTreeContextBase } from './tree.context'; import type { Entity, ManifestTree } from '@umbraco-cms/models'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry'; -import { UmbTreeDataStore } from '@umbraco-cms/stores/store'; +import { UmbTreeStore } from '@umbraco-cms/stores/store'; import { UmbLitElement } from '@umbraco-cms/element'; import './tree-item.element'; @@ -66,7 +66,7 @@ export class UmbTreeElement extends UmbLitElement { private _loading = true; private _treeContext?: UmbTreeContextBase; - private _store?: UmbTreeDataStore; + private _store?: UmbTreeStore; connectedCallback(): void { super.connectedCallback(); @@ -108,7 +108,7 @@ export class UmbTreeElement extends UmbLitElement { if (!this._tree?.meta.storeAlias) return; - this.consumeContext(this._tree.meta.storeAlias, (store: UmbTreeDataStore) => { + this.consumeContext(this._tree.meta.storeAlias, (store: UmbTreeStore) => { this._store = store; this.provideContext('umbStore', store); }); 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 2ab466b647..a34aa895c8 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 @@ -49,6 +49,7 @@ export class UniqueArrayBehaviorSubject extends UniqueBehaviorSubject { * ]); */ append(entries: T[]) { + // TODO: stop calling appendOne for each but make sure to handle this in one. entries.forEach(x => this.appendOne(x)) } } diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/store-base.ts b/src/Umbraco.Web.UI.Client/src/core/stores/store-base.ts new file mode 100644 index 0000000000..97430508ce --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/stores/store-base.ts @@ -0,0 +1,11 @@ +import { UmbContextProviderController } from "../context-api/provide/context-provider.controller"; +import { UmbControllerHostInterface } from "../controller/controller-host.mixin"; + +export class UmbStoreBase { + + + constructor (protected _host: UmbControllerHostInterface, public readonly storeAlias: string) { + new UmbContextProviderController(_host, storeAlias, this); + } + +} diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts index 3720a2f01a..c37274b158 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts @@ -1,6 +1,4 @@ import type { Observable } from 'rxjs'; -import { UmbControllerHostInterface } from '../controller/controller-host.mixin'; -import { UniqueBehaviorSubject } from '../observable-api/unique-behavior-subject'; export interface UmbDataStoreIdentifiers { key?: string; @@ -9,80 +7,25 @@ export interface UmbDataStoreIdentifiers { export interface UmbDataStore { readonly storeAlias: string; + + // TODO: is items the right name? readonly items: Observable>; updateItems(items: Array): void; } -export interface UmbTreeDataStore extends UmbDataStore { +export interface UmbTreeStore extends UmbDataStore { getTreeRoot(): Observable>; getTreeItemChildren(key: string): Observable>; } -/** - * @export - * @class UmbDataStoreBase - * @implements {UmbDataStore} - * @template T - * @description - Base class for Data Stores - */ -export abstract class UmbDataStoreBase implements UmbDataStore { - public abstract readonly storeAlias: string; - - protected _items = new UniqueBehaviorSubject(>[]); - public readonly items = this._items.asObservable(); - - protected host: UmbControllerHostInterface; - - constructor(host: UmbControllerHostInterface) { - this.host = host; - } - - /** - * @description - Delete items from the store. - * @param {Array} keys - * @memberof UmbDataStoreBase - */ - public deleteItems(keys: Array): void { - const remainingItems = this._items.getValue().filter((item) => item.key && keys.includes(item.key) === false); - this._items.next(remainingItems); - } - - /** - * @description - Update the store with new items. Existing items are updated, new items are added, old are kept. Items are matched by the compareKey. - * @param {Array} items - * @param {keyof T} [compareKey='key'] - * @memberof UmbDataStoreBase - */ - public updateItems(items: Array, compareKey: keyof T = 'key'): void { - const newData = [...this._items.getValue()]; - items.forEach((newItem) => { - const storedItemIndex = newData.findIndex((item) => item[compareKey] === newItem[compareKey]); - if (storedItemIndex !== -1) { - newData[storedItemIndex] = newItem; - } else { - newData.push(newItem); - } - }); - - this._items.next(newData); - } -} - -/** - * @export - * @class UmbNodeStoreBase - * @implements {UmbDataStore} - * @template T - * @description - Base class for Data Stores - */ -export abstract class UmbNodeStoreBase extends UmbDataStoreBase { +export interface UmbContentStore extends UmbDataStore { /** * @description - Request data by key. The data is added to the store and is returned as an Observable. * @param {string} key - * @return {*} {(Observable)} + * @return {*} {(Observable)} * @memberof UmbDataStoreBase */ - abstract getByKey(key: string): Observable; + getByKey(key: string): Observable; /** * @description - Save data. @@ -90,5 +33,5 @@ export abstract class UmbNodeStoreBase extend * @return {*} {(Promise)} * @memberof UmbNodeStoreBase */ - abstract save(data: T[]): Promise; + save(data: T[]): Promise; }