document store split
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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>('UmbDocumentDetailStore');
|
||||
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbDocumentStore
|
||||
* @extends {UmbStoreBase<DocumentDetails>}
|
||||
* @description - Data Store for Documents
|
||||
*/
|
||||
export class UmbDocumentDetailStore extends UmbStoreBase {
|
||||
|
||||
|
||||
private _data = new UniqueArrayBehaviorSubject<DocumentDetails>([], (a, b) => a.key === b.key);
|
||||
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, UMB_DOCUMENT_DETAIL_STORE_CONTEXT_TOKEN.toString());
|
||||
}
|
||||
|
||||
getByKey(key: string): Observable<DocumentDetails | undefined> {
|
||||
// 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<void> {
|
||||
// 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<DocumentDetails>) => {
|
||||
this._data.append(data);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: how do we handle trashed items?
|
||||
async trash(keys: Array<string>) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -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<DocumentDetails | DocumentTreeItem>}
|
||||
* @description - Data Store for Documents
|
||||
*/
|
||||
export class UmbDocumentStore extends UmbNodeStoreBase<UmbDocumentStoreItemType> {
|
||||
public readonly storeAlias = STORE_ALIAS;
|
||||
|
||||
getByKey(key: string): Observable<DocumentDetails | undefined> {
|
||||
// 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<void> {
|
||||
// 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<DocumentDetails>) => {
|
||||
this.updateItems(data);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: how do we handle trashed items?
|
||||
async trash(keys: Array<string>) {
|
||||
// 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<Array<DocumentTreeItem>> {
|
||||
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<Array<FolderTreeItem>> {
|
||||
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<string>): Observable<Array<FolderTreeItem>> {
|
||||
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<UmbDocumentStore>(STORE_ALIAS);
|
||||
@@ -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<UmbDocumentTreeStore>('UmbDocumentDetailStore');
|
||||
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbDocumentStore
|
||||
* @extends {UmbStoreBase<DocumentTree>}
|
||||
* @description - Data Store for Documents
|
||||
*/
|
||||
export class UmbDocumentTreeStore extends UmbStoreBase {
|
||||
|
||||
|
||||
private _data = new UniqueArrayBehaviorSubject<DocumentTreeItem>([], (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<string>) {
|
||||
// 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<Array<DocumentTreeItem>> {
|
||||
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<Array<DocumentTreeItem>> {
|
||||
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<string>): Observable<Array<DocumentTreeItem>> {
|
||||
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 ?? '')));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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<DataType> = UmbTreeDataStore<DataType>
|
||||
StoreType extends UmbTreeStore<DataType> = UmbTreeStore<DataType>
|
||||
> {
|
||||
private _host: UmbControllerHostInterface;
|
||||
private _entityKey: string | null;
|
||||
|
||||
@@ -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<FolderTreeItem>;
|
||||
|
||||
private _modalService?: UmbModalService;
|
||||
private _documentStore?: UmbDocumentStore;
|
||||
private _documentStore?: UmbDocumentDetailStore;
|
||||
private _pickedItemsObserver?: UmbObserverController<FolderTreeItem>;
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
@@ -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<unknown>;
|
||||
private _store?: UmbTreeStore<unknown>;
|
||||
private _sectionContext?: UmbSectionContext;
|
||||
private _treeContextMenuService?: UmbTreeContextMenuService;
|
||||
|
||||
@@ -81,7 +81,7 @@ export class UmbTreeItem extends UmbLitElement {
|
||||
this._observeIsSelected();
|
||||
});
|
||||
|
||||
this.consumeContext('umbStore', (store: UmbTreeDataStore<unknown>) => {
|
||||
this.consumeContext('umbStore', (store: UmbTreeStore<unknown>) => {
|
||||
this._store = store;
|
||||
});
|
||||
|
||||
|
||||
@@ -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<Entity>;
|
||||
private _store?: UmbTreeStore<Entity>;
|
||||
|
||||
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<Entity>) => {
|
||||
this.consumeContext(this._tree.meta.storeAlias, (store: UmbTreeStore<Entity>) => {
|
||||
this._store = store;
|
||||
this.provideContext('umbStore', store);
|
||||
});
|
||||
|
||||
@@ -49,6 +49,7 @@ export class UniqueArrayBehaviorSubject<T> extends UniqueBehaviorSubject<T[]> {
|
||||
* ]);
|
||||
*/
|
||||
append(entries: T[]) {
|
||||
// TODO: stop calling appendOne for each but make sure to handle this in one.
|
||||
entries.forEach(x => this.appendOne(x))
|
||||
}
|
||||
}
|
||||
|
||||
11
src/Umbraco.Web.UI.Client/src/core/stores/store-base.ts
Normal file
11
src/Umbraco.Web.UI.Client/src/core/stores/store-base.ts
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<T> {
|
||||
readonly storeAlias: string;
|
||||
|
||||
// TODO: is items the right name?
|
||||
readonly items: Observable<Array<T>>;
|
||||
updateItems(items: Array<T>): void;
|
||||
}
|
||||
|
||||
export interface UmbTreeDataStore<T> extends UmbDataStore<T> {
|
||||
export interface UmbTreeStore<T> extends UmbDataStore<T> {
|
||||
getTreeRoot(): Observable<Array<T>>;
|
||||
getTreeItemChildren(key: string): Observable<Array<T>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbDataStoreBase
|
||||
* @implements {UmbDataStore<T>}
|
||||
* @template T
|
||||
* @description - Base class for Data Stores
|
||||
*/
|
||||
export abstract class UmbDataStoreBase<T extends UmbDataStoreIdentifiers> implements UmbDataStore<T> {
|
||||
public abstract readonly storeAlias: string;
|
||||
|
||||
protected _items = new UniqueBehaviorSubject(<Array<T>>[]);
|
||||
public readonly items = this._items.asObservable();
|
||||
|
||||
protected host: UmbControllerHostInterface;
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Delete items from the store.
|
||||
* @param {Array<string>} keys
|
||||
* @memberof UmbDataStoreBase
|
||||
*/
|
||||
public deleteItems(keys: Array<string>): 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<T>} items
|
||||
* @param {keyof T} [compareKey='key']
|
||||
* @memberof UmbDataStoreBase
|
||||
*/
|
||||
public updateItems(items: Array<T>, 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<T>}
|
||||
* @template T
|
||||
* @description - Base class for Data Stores
|
||||
*/
|
||||
export abstract class UmbNodeStoreBase<T extends UmbDataStoreIdentifiers> extends UmbDataStoreBase<T> {
|
||||
export interface UmbContentStore<T> extends UmbDataStore<T> {
|
||||
/**
|
||||
* @description - Request data by key. The data is added to the store and is returned as an Observable.
|
||||
* @param {string} key
|
||||
* @return {*} {(Observable<unknown>)}
|
||||
* @return {*} {(Observable<T>)}
|
||||
* @memberof UmbDataStoreBase
|
||||
*/
|
||||
abstract getByKey(key: string): Observable<unknown>;
|
||||
getByKey(key: string): Observable<T>;
|
||||
|
||||
/**
|
||||
* @description - Save data.
|
||||
@@ -90,5 +33,5 @@ export abstract class UmbNodeStoreBase<T extends UmbDataStoreIdentifiers> extend
|
||||
* @return {*} {(Promise<void>)}
|
||||
* @memberof UmbNodeStoreBase
|
||||
*/
|
||||
abstract save(data: T[]): Promise<void>;
|
||||
save(data: T[]): Promise<void>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user