diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/collection/workspace-view-collection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/collection/workspace-view-collection.element.ts
index 882dc1bdf9..255b7eb11b 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/collection/workspace-view-collection.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/collection/workspace-view-collection.element.ts
@@ -3,15 +3,16 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement } from 'lit/decorators.js';
import { ifDefined } from 'lit-html/directives/if-defined.js';
import { UmbWorkspaceContentContext } from '../../workspace-content.context';
+import { UmbMediaTreeStore } from '../../../../../../media/media/media.tree.store';
import {
UmbCollectionContext,
UMB_COLLECTION_CONTEXT_TOKEN,
-} from 'src/backoffice/shared/collection/collection.context';
-import { UmbMediaStore, UmbMediaStoreItemType } from 'src/backoffice/media/media/media.store';
+} from '../../../../../../shared/collection/collection.context';
import '../../../../../../shared/components/content-property/content-property.element';
import '../../../../../../shared/collection/dashboards/dashboard-collection.element';
import { UmbLitElement } from '@umbraco-cms/element';
+import { FolderTreeItem } from '@umbraco-cms/backend-api';
@customElement('umb-workspace-view-collection')
export class UmbWorkspaceViewCollectionElement extends UmbLitElement {
@@ -27,7 +28,7 @@ export class UmbWorkspaceViewCollectionElement extends UmbLitElement {
private _workspaceContext?: UmbWorkspaceContentContext;
- private _collectionContext?: UmbCollectionContext
;
+ private _collectionContext?: UmbCollectionContext;
constructor() {
super();
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 9e12012e43..3a494630a3 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
@@ -1,20 +1,16 @@
import { v4 as uuidv4 } from 'uuid';
-import { UniqueBehaviorSubject, UmbObserverController, createObservablePart } from '@umbraco-cms/observable-api';
-import {
- UmbNotificationDefaultData,
- UmbNotificationService,
- UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN,
-} from '@umbraco-cms/notification';
-import { UmbNodeStoreBase } from '@umbraco-cms/store';
+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 { EntityTreeItem } from '@umbraco-cms/backend-api';
+import { UniqueBehaviorSubject, UmbObserverController, createObservablePart } from '@umbraco-cms/observable-api';
+import { UmbContentStore } from '@umbraco-cms/store';
+import type { ContentTreeItem } from '@umbraco-cms/backend-api';
// TODO: Consider if its right to have this many class-inheritance of WorkspaceContext
// TODO: Could we extract this code into a 'Manager' of its own, which will be instantiated by the concrete Workspace Context. This will be more transparent and 'reuseable'
export abstract class UmbWorkspaceContentContext<
- ContentTypeType extends EntityTreeItem = EntityTreeItem,
- StoreType extends UmbNodeStoreBase = UmbNodeStoreBase
+ ContentTypeType extends ContentTreeItem = ContentTreeItem,
+ StoreType extends UmbContentStore = UmbContentStore
> {
protected _host: UmbControllerHostInterface;
@@ -106,7 +102,7 @@ export abstract class UmbWorkspaceContentContext<
// TODO: consider turning this into an abstract so each context implement this them selfs.
public save(): Promise {
if (!this._store) {
- // TODO: more beautiful error:
+ // TODO: add a more beautiful error:
console.error('Could not save cause workspace context has no store.');
return Promise.resolve();
}
@@ -122,7 +118,7 @@ export abstract class UmbWorkspaceContentContext<
});
}
- // TODO: how can we make sure to call this.
+ // TODO: how can we make sure to call this, we might need to turn this thing into a ContextProvider(extending) for it to call destroy?
public destroy(): void {
this._data.unsubscribe();
}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.detail.store.ts
new file mode 100644
index 0000000000..598a2f16d1
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.detail.store.ts
@@ -0,0 +1,100 @@
+import type { DictionaryDetails } from '@umbraco-cms/models';
+import { UmbContextToken } from '@umbraco-cms/context-api';
+import { createObservablePart, UniqueArrayBehaviorSubject } from '@umbraco-cms/observable-api';
+import { UmbStoreBase } from '@umbraco-cms/store';
+import { UmbControllerHostInterface } from '@umbraco-cms/controller';
+import { EntityTreeItem } from '@umbraco-cms/backend-api';
+
+
+export const UMB_DICTIONARY_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbDictionaryDetailStore');
+
+
+/**
+ * @export
+ * @class UmbDictionaryDetailStore
+ * @extends {UmbStoreBase}
+ * @description - Details Data Store for Data Types
+ */
+export class UmbDictionaryDetailStore extends UmbStoreBase {
+
+
+ // TODO: use the right type:
+ #data = new UniqueArrayBehaviorSubject([], (x) => x.key);
+
+
+ constructor(host: UmbControllerHostInterface) {
+ super(host, UMB_DICTIONARY_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 UmbDictionaryDetailStore
+ */
+ getByKey(key: string) {
+ // TODO: use backend cli when available.
+ fetch(`/umbraco/management/api/v1/document/dictionary/${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 Dictionary.
+ * @param {Array} Dictionaries
+ * @memberof UmbDictionaryDetailStore
+ * @return {*} {Promise}
+ */
+ save(data: DictionaryDetails[]) {
+ // 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/dictionary/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 UmbDictionaryDetailStore
+ * @return {*} {Promise}
+ */
+ async delete(keys: string[]) {
+ // TODO: use backend cli when available.
+ await fetch('/umbraco/backoffice/dictionary/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/translation/dictionary/dictionary.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.store.ts
deleted file mode 100644
index 133a0ed9e9..0000000000
--- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.store.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { map, Observable } from 'rxjs';
-import { UmbDataStoreBase } from '@umbraco-cms/store';
-import { DictionaryResource, EntityTreeItem } from '@umbraco-cms/backend-api';
-import { tryExecuteAndNotify } from '@umbraco-cms/resources';
-import { UmbContextToken } from '@umbraco-cms/context-api';
-
-export const STORE_ALIAS = 'UmbDictionaryStore';
-
-/**
- * @export
- * @class UmbDictionaryStore
- * @extends {UmbDataStoreBase}
- * @description - Data Store for Dictionary Items.
- */
-export class UmbDictionaryStore extends UmbDataStoreBase {
- public readonly storeAlias = STORE_ALIAS;
-
- /**
- * @description - Get the root of the tree.
- * @return {*} {Observable>}
- * @memberof UmbDictionaryStore
- */
- getTreeRoot(): Observable> {
- tryExecuteAndNotify(this.host, DictionaryResource.getTreeDictionaryRoot({})).then(({ data }) => {
- if (data) {
- this.updateItems(data.items);
- }
- });
-
- return this.items.pipe(map((items) => items.filter((item) => item.parentKey === null)));
- }
-
- /**
- * @description - Get the children of a tree item.
- * @param {string} key
- * @return {*} {Observable>}
- * @memberof UmbDataTypesStore
- */
- getTreeItemChildren(key: string): Observable> {
- tryExecuteAndNotify(
- this.host,
- DictionaryResource.getTreeDictionaryChildren({
- parentKey: key,
- })
- ).then(({ data }) => {
- if (data) {
- this.updateItems(data.items);
- }
- });
-
- return this.items.pipe(map((items) => items.filter((item) => item.parentKey === key)));
- }
-}
-
-export const UMB_DICTIONARY_STORE_CONTEXT_TOKEN = new UmbContextToken(STORE_ALIAS);
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.tree.store.ts
new file mode 100644
index 0000000000..f7f8687833
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/dictionary.tree.store.ts
@@ -0,0 +1,96 @@
+import { DictionaryResource, 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/store';
+import { UmbControllerHostInterface } from '@umbraco-cms/controller';
+
+
+export const UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbDictionaryTreeStore');
+
+
+/**
+ * @export
+ * @class UmbDictionaryTreeStore
+ * @extends {UmbStoreBase}
+ * @description - Tree Data Store for Data Types
+ */
+export class UmbDictionaryTreeStore extends UmbStoreBase {
+
+
+ #data = new UniqueArrayBehaviorSubject([], (x) => x.key);
+
+
+ constructor(host: UmbControllerHostInterface) {
+ super(host, UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN.toString());
+ }
+
+ // TODO: How can we avoid having this in both stores?
+ /**
+ * @description - Delete a Data Type.
+ * @param {string[]} keys
+ * @memberof UmbDictionarysStore
+ * @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, DictionaryResource.getTreeDictionaryRoot({})).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,
+ DictionaryResource.getTreeDictionaryChildren({
+ 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,
+ DictionaryResource.getTreeDictionaryItem({
+ 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/translation/dictionary/tree/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/tree/manifests.ts
index f399178b43..8ba7f7d41e 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/tree/manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/tree/manifests.ts
@@ -1,4 +1,4 @@
-import { STORE_ALIAS } from '../dictionary.store';
+import { UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN } from '../dictionary.tree.store';
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const treeAlias = 'Umb.Tree.Dictionary';
@@ -8,7 +8,7 @@ const tree: ManifestTree = {
alias: treeAlias,
name: 'Dictionary Tree',
meta: {
- storeAlias: STORE_ALIAS,
+ storeAlias: UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN.toString(),
},
};
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/user-group.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/user-group.store.ts
index edbb706351..6c2e68b807 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/user-group.store.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/user-group.store.ts
@@ -1,67 +1,67 @@
-import { map, Observable } from 'rxjs';
-import { UmbDataStoreBase } from '@umbraco-cms/store';
-import type { UserGroupDetails, UserGroupEntity } from '@umbraco-cms/models';
+import type { UserGroupDetails } from '@umbraco-cms/models';
import { UmbContextToken } from '@umbraco-cms/context-api';
+import { UmbControllerHostInterface } from '@umbraco-cms/controller';
+import { createObservablePart, UniqueArrayBehaviorSubject } from '@umbraco-cms/observable-api';
+import { UmbStoreBase } from '@umbraco-cms/store';
// TODO: get rid of this type addition & { ... }:
export type UmbUserGroupStoreItemType = UserGroupDetails & { users?: Array };
-export const STORE_ALIAS = 'UmbUserGroupStore';
+export const UMB_USER_GROUP_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbUserGroupStore');
/**
* @export
* @class UmbUserGroupStore
- * @extends {UmbDataStoreBase}
- * @description - Data Store for Users
+ * @extends {UmbStoreBase}
+ * @description - Data Store for User Groups
*/
-export class UmbUserGroupStore extends UmbDataStoreBase {
- public readonly storeAlias = STORE_ALIAS;
+export class UmbUserGroupStore extends UmbStoreBase {
- getAll(): Observable