diff --git a/src/Umbraco.Web.UI.Client/libs/models/index.ts b/src/Umbraco.Web.UI.Client/libs/models/index.ts index 9e91bcb3df..3658a16304 100644 --- a/src/Umbraco.Web.UI.Client/libs/models/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/models/index.ts @@ -137,6 +137,10 @@ export interface MemberGroupDetails extends EntityTreeItem { key: string; // TODO: Remove this when the backend is fixed } +export interface MemberDetails extends EntityTreeItem { + key: string; // TODO: Remove this when the backend is fixed +} + // Dictionary export interface DictionaryDetails extends EntityTreeItem { key: string; // TODO: Remove this when the backend is fixed 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 7c1d8e3c72..522abf3596 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -27,6 +27,8 @@ import { UmbMemberTypeDetailStore } from './members/member-types/member-type.det import { UmbMemberTypeTreeStore } from './members/member-types/member-type.tree.store'; import { UmbMemberGroupDetailStore } from './members/member-groups/member-group.detail.store'; import { UmbMemberGroupTreeStore } from './members/member-groups/member-group.tree.store'; +import { UmbMemberDetailStore } from './members/members/member.detail.store'; +import { UmbMemberTreeStore } from './members/members/member.tree.store'; import { UmbDictionaryDetailStore } from './translation/dictionary/dictionary.detail.store'; import { UmbDictionaryTreeStore } from './translation/dictionary/dictionary.tree.store'; import { UmbDocumentBlueprintDetailStore } from './documents/document-blueprints/document-blueprint.detail.store'; @@ -96,6 +98,8 @@ export class UmbBackofficeElement extends UmbLitElement { new UmbUserGroupStore(this); new UmbMemberGroupDetailStore(this); new UmbMemberGroupTreeStore(this); + new UmbMemberDetailStore(this); + new UmbMemberTreeStore(this); new UmbDictionaryDetailStore(this); new UmbDictionaryTreeStore(this); new UmbDocumentBlueprintDetailStore(this); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.detail.store.ts index 9050bb1314..bbf4f61c2d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.detail.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.detail.store.ts @@ -1,7 +1,8 @@ import { Observable } from 'rxjs'; +import { umbMemberGroupData } from '../../../core/mocks/data/member-group.data'; import type { MemberGroupDetails } from '@umbraco-cms/models'; import { UmbContextToken } from '@umbraco-cms/context-api'; -import { ArrayState } from '@umbraco-cms/observable-api'; +import { ArrayState, createObservablePart } from '@umbraco-cms/observable-api'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/store'; @@ -33,28 +34,22 @@ export class UmbMemberGroupDetailStore extends UmbStoreBase implements UmbEntity * @return {*} {(Observable)} * @memberof UmbMemberGroupDetailStore */ - getByKey(key: string): Observable { + getByKey(key: string): Observable { // tryExecuteAndNotify(this.host, MemberGroupResource.getMemberGroupByKey({ key })).then(({ data }) => { // if (data) { // this.#data.appendOne(data); // } // }); - // return createObservablePart( - // this.#data, - // (groups) => groups.find((group) => group.key === key) as MemberGroupDetails - // ); + // temp until Resource is updated + const group = umbMemberGroupData.getByKey(key); + if (group) { + this.#data.appendOne(group); + } - // TODO: use backend cli when available. - fetch(`/umbraco/management/api/v1/member-group/${key}`) - .then((res) => res.json()) - .then((data) => { - this.#data.append(data); - console.log(data); - }); - - return this.#data.getObservablePart((memberGroups) => - memberGroups.find((memberGroup) => memberGroup.key === key) + return createObservablePart( + this.#data, + (groups) => groups.find((group) => group.key === key) as MemberGroupDetails ); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.tree.store.ts index faf1ec5320..87470e4dad 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.tree.store.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/member-group.tree.store.ts @@ -48,6 +48,7 @@ export class UmbMemberGroupTreeStore extends UmbStoreBase { 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); + console.log(this.#data); } }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/actions/action-member-group-delete.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/actions/action-member-group-delete.element.ts index 231fda58ce..9c4304f05b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/actions/action-member-group-delete.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/actions/action-member-group-delete.element.ts @@ -3,17 +3,14 @@ import { css, html } from 'lit'; import { customElement } from 'lit/decorators.js'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '../../../../../core/modal'; import UmbTreeItemActionElement from '../../../../shared/components/tree/action/tree-item-action.element'; -import { - UmbMemberGroupDetailStore, - UMB_MEMBER_GROUP_DETAIL_STORE_CONTEXT_TOKEN, -} from '../../member-group.detail.store'; +import { UmbMemberGroupTreeStore, UMB_MEMBER_GROUP_TREE_STORE_CONTEXT_TOKEN } from '../../member-group.tree.store'; @customElement('umb-tree-action-member-group-delete') export default class UmbTreeActionMemberGroupDeleteElement extends UmbTreeItemActionElement { static styles = [UUITextStyles, css``]; private _modalService?: UmbModalService; - private _memberGroupDetailStore?: UmbMemberGroupDetailStore; + private _memberGroupTreeStore?: UmbMemberGroupTreeStore; connectedCallback(): void { super.connectedCallback(); @@ -22,8 +19,8 @@ export default class UmbTreeActionMemberGroupDeleteElement extends UmbTreeItemAc this._modalService = modalService; }); - this.consumeContext(UMB_MEMBER_GROUP_DETAIL_STORE_CONTEXT_TOKEN, (memberGroupDetailStore) => { - this._memberGroupDetailStore = memberGroupDetailStore; + this.consumeContext(UMB_MEMBER_GROUP_TREE_STORE_CONTEXT_TOKEN, (memberGroupTreeStore) => { + this._memberGroupTreeStore = memberGroupTreeStore; }); } @@ -36,8 +33,8 @@ export default class UmbTreeActionMemberGroupDeleteElement extends UmbTreeItemAc }); modalHandler?.onClose().then(({ confirmed }: any) => { - if (confirmed && this._treeContextMenuService && this._memberGroupDetailStore && this._activeTreeItem) { - this._memberGroupDetailStore?.trash([this._activeTreeItem.key]); + if (confirmed && this._treeContextMenuService && this._memberGroupTreeStore && this._activeTreeItem) { + this._memberGroupTreeStore?.delete([this._activeTreeItem.key]); this._treeContextMenuService.close(); } }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/manifests.ts index ede9dff6de..d39cc39eab 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/tree/manifests.ts @@ -1,5 +1,5 @@ -import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models'; import { UMB_MEMBER_GROUP_TREE_STORE_CONTEXT_TOKEN } from '../member-group.tree.store'; +import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models'; const treeAlias = 'Umb.Tree.MemberGroups'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/views/info/workspace-view-member-group-info.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/views/info/workspace-view-member-group-info.element.ts index 0f81ac494d..cc2053fd03 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/views/info/workspace-view-member-group-info.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/views/info/workspace-view-member-group-info.element.ts @@ -43,7 +43,6 @@ export class UmbWorkspaceViewMemberGroupInfoElement extends UmbLitElement { // TODO: Figure out if this is the best way to consume the context or if it can be strongly typed with an UmbContextToken this.consumeContext('umbWorkspaceContext', (memberGroupContext) => { this._workspaceContext = memberGroupContext; - console.log(memberGroupContext); this._observeMemberGroup(); }); } @@ -52,7 +51,6 @@ export class UmbWorkspaceViewMemberGroupInfoElement extends UmbLitElement { if (!this._workspaceContext) return; this.observe(this._workspaceContext.data.pipe(distinctUntilChanged()), (memberGroup) => { - console.log(memberGroup); if (!memberGroup) return; // TODO: handle if model is not of the type wanted. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts new file mode 100644 index 0000000000..bb665251ad --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.detail.store.ts @@ -0,0 +1,59 @@ +import { Observable } from 'rxjs'; +import type { MemberDetails, MemberGroupDetails } from '@umbraco-cms/models'; +import { UmbContextToken } from '@umbraco-cms/context-api'; +import { ArrayState, createObservablePart } from '@umbraco-cms/observable-api'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; +import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/store'; +import { umbMemberData } from 'src/core/mocks/data/member.data'; + +export const UMB_MEMBER_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbMemberDetailStore'); + +/** + * @export + * @class UmbMemberDetailStore + * @extends {UmbStoreBase} + * @description - Detail Data Store for Members + */ +export class UmbMemberDetailStore extends UmbStoreBase implements UmbEntityDetailStore { + + #data = new ArrayState([], x => x.key); + public groups = this.#data.asObservable(); + + constructor(private host: UmbControllerHostInterface) { + super(host, UMB_MEMBER_DETAIL_STORE_CONTEXT_TOKEN.toString()); + } + + getScaffold(entityType: string, parentKey: string | null) { + return { + } as MemberDetails; + } + + /** + * @description - Request a Member by key. The Member is added to the store and is returned as an Observable. + * @param {string} key + * @return {*} {(Observable)} + * @memberof UmbMemberDetailStore + */ + getByKey(key: string): Observable { + // tryExecuteAndNotify(this.host, MemberResource.getMemberByKey({ key })).then(({ data }) => { + // if (data) {} + // this.#data.appendOne(data); + // } + // }); + + // temp until Resource is updated + const member = umbMemberData.getByKey(key); + if (member) { + this.#data.appendOne(member); + } + + return createObservablePart( + this.#data, + (members) => members.find((member) => member.key === key) as MemberDetails + ); + } + + async save(member: Array): Promise { + return null as any; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.tree.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.tree.store.ts new file mode 100644 index 0000000000..ee3c7a5e42 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/member.tree.store.ts @@ -0,0 +1,102 @@ +import { EntityTreeItem, MemberGroupResource } from '@umbraco-cms/backend-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/resources'; +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'; + +export const UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbMemberTreeStore'); + +/** + * @export + * @class UmbMemberTreeStore + * @extends {UmbStoreBase} + * @description - Tree Data Store for Members + */ +export class UmbMemberTreeStore extends UmbStoreBase { + // TODO: use the right type here: + #data = new ArrayState([], (x) => x.key); + + constructor(host: UmbControllerHostInterface) { + super(host, UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN.toString()); + } + + // TODO: How can we avoid having this in both stores? + /** + * @description - Delete a Member. + * @param {string[]} keys + * @memberof UmbMemberTreeStore + * @return {*} {Promise} + */ + async delete(keys: string[]) { + // TODO: use backend cli when available. + await fetch('/umbraco/backoffice/members/delete', { + method: 'POST', + body: JSON.stringify(keys), + headers: { + 'Content-Type': 'application/json', + }, + }); + + this.#data.remove(keys); + } + + async getTreeRoot() { + // TODO: use backend cli when available. + tryExecuteAndNotify( + this._host, + fetch('/umbraco/management/api/v1/tree/member/root') + .then((res) => res.json()) + .then((data) => { + this.#data.append(data.items); + debugger; + }) + ); + + console.log(this.#data); + + // tryExecuteAndNotify(this._host, MembersResource.getTreeMembersRoot({})).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: remove ignore when we know how to handle trashed items. + return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null)); + } + + getTreeItemChildren(key: string) { + // tryExecuteAndNotify( + // this._host, + // MembersResource.getTreeMembersChildren({ + // 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); + // } + // }); + + return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === key)); + } + + getTreeItems(keys: Array) { + // if (keys?.length > 0) { + // tryExecuteAndNotify( + // this._host, + // MembersResource.getTreeMembersItem({ + // 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 this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? ''))); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/manifests.ts index 83ec74ac8c..e1afd744ff 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/manifests.ts @@ -10,6 +10,7 @@ const sidebarMenuItem: ManifestSidebarMenuItem = { label: 'Members', icon: 'umb:folder', sections: ['Umb.Section.Members'], + entityType: 'member', }, }; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/members-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/members-sidebar-menu-item.element.ts index 3a9f7e7e87..8ab8e3b82e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/members-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/members-sidebar-menu-item.element.ts @@ -23,7 +23,8 @@ export class UmbMembersSidebarMenuItemElement extends UmbLitElement { label="Members" icon="umb:folder" @show-children=${this._onShowChildren} - @hide-children=${this._onHideChildren}> + @hide-children=${this._onHideChildren} + has-children> ${this._renderTree ? html`` : nothing} `; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/tree/actions/action-member-delete.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/tree/actions/action-member-delete.element.ts new file mode 100644 index 0000000000..e0e1a909c0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/tree/actions/action-member-delete.element.ts @@ -0,0 +1,54 @@ +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 UmbTreeItemActionElement from '../../../../shared/components/tree/action/tree-item-action.element'; +import { UmbMemberTreeStore, UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN } from '../../member.tree.store'; + +@customElement('umb-tree-action-member-delete') +export default class UmbTreeActionMemberDeleteElement extends UmbTreeItemActionElement { + static styles = [UUITextStyles, css``]; + + private _modalService?: UmbModalService; + private _memberTreeStore?: UmbMemberTreeStore; + + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext(UMB_MODAL_SERVICE_CONTEXT_TOKEN, (modalService) => { + this._modalService = modalService; + }); + + this.consumeContext(UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN, (memberTreeStore) => { + this._memberTreeStore = memberTreeStore; + }); + } + + private _handleLabelClick() { + const modalHandler = this._modalService?.confirm({ + headline: `Delete ${this._activeTreeItem?.name ?? 'item'}`, + content: 'Are you sure you want to delete this item?', + color: 'danger', + confirmLabel: 'Delete', + }); + + modalHandler?.onClose().then(({ confirmed }: any) => { + if (confirmed && this._treeContextMenuService && this._memberTreeStore && this._activeTreeItem) { + this._memberTreeStore?.delete([this._activeTreeItem.key]); + this._treeContextMenuService.close(); + } + }); + } + + render() { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-tree-action-member-delete': UmbTreeActionMemberDeleteElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/tree/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/tree/manifests.ts index c3f4d051af..d049dadb75 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/tree/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/tree/manifests.ts @@ -1,14 +1,29 @@ +import { UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN } from '../member.tree.store'; import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models'; const tree: ManifestTree = { type: 'tree', alias: 'Umb.Tree.Members', name: 'Members Tree', + weight: 10, meta: { - storeAlias: 'umbMemberTypesStore', + storeAlias: UMB_MEMBER_TREE_STORE_CONTEXT_TOKEN.toString(), }, }; -const treeItemActions: Array = []; +const treeItemActions: Array = [ + { + type: 'treeItemAction', + alias: 'Umb.TreeItemAction.Member.Delete', + name: 'Member Tree Item Action Delete', + loader: () => import('./actions/action-member-delete.element'), + weight: 100, + meta: { + entityType: 'member', + label: 'Delete', + icon: 'delete', + }, + }, +]; -export const manifests = [tree, ...treeItemActions]; +export const manifests = [tree, ...treeItemActions]; \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/workspace/member-workspace.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/workspace/member-workspace.stories.ts new file mode 100644 index 0000000000..4a9f3778ae --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/workspace/member-workspace.stories.ts @@ -0,0 +1,18 @@ +import './member-workspace.element'; + +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; + +import { data } from '../../../../core/mocks/data/member.data'; + +import type { UmbMemberWorkspaceElement } from './member-workspace.element'; + +export default { + title: 'Workspaces/Member', + component: 'umb-member-workspace', + id: 'umb-member-workspace', +} as Meta; + +export const AAAOverview: Story = () => + html` `; +AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts index ff8ad5b646..231eb8291c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts @@ -18,6 +18,7 @@ import { handlers as mediaHandlers } from './domains/media.handlers'; import { handlers as dictionaryHandlers } from './domains/dictionary.handlers'; import { handlers as mediaTypeHandlers } from './domains/media-type.handlers'; import { handlers as memberGroupHandlers } from './domains/member-group.handlers'; +import { handlers as memberHandlers } from './domains/member.handlers'; import { handlers as memberTypeHandlers } from './domains/member-type.handlers'; import { handlers as templateHandlers } from './domains/template.handlers'; import { handlers as languageHandlers } from './domains/language.handlers'; @@ -39,6 +40,7 @@ const handlers = [ ...userGroupsHandlers, ...mediaTypeHandlers, ...memberGroupHandlers, + ...memberHandlers, ...memberTypeHandlers, ...examineManagementHandlers, ...modelsBuilderHandlers, diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/member-group.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/member-group.data.ts index 19f363423d..005438157c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/data/member-group.data.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/member-group.data.ts @@ -1,11 +1,11 @@ -import type { MemberGroupDetails } from '@umbraco-cms/models'; -import { EntityTreeItem, PagedEntityTreeItem } from '@umbraco-cms/backend-api'; import { UmbEntityData } from './entity.data'; import { createEntityTreeItem } from './utils'; +import type { MemberGroupDetails } from '@umbraco-cms/models'; +import { EntityTreeItem, PagedEntityTreeItem } from '@umbraco-cms/backend-api'; export const data: Array = [ { - name: 'Member Group 1', + name: 'Member Group AAA', type: 'member-group', icon: 'umb:document', hasChildren: false, diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/data/member.data.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/data/member.data.ts new file mode 100644 index 0000000000..612475bc6e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/data/member.data.ts @@ -0,0 +1,47 @@ +import { UmbEntityData } from './entity.data'; +import { createEntityTreeItem } from './utils'; +import type { MemberDetails } from '@umbraco-cms/models'; +import { EntityTreeItem, PagedEntityTreeItem } from '@umbraco-cms/backend-api'; + +export const data: Array = [ + { + name: 'Member AAA', + type: 'member', + icon: 'umb:user', + hasChildren: false, + key: 'aaa08ccd-4179-464c-b634-6969149dd9f9', + isContainer: false, + parentKey: null, + }, +]; + +// Temp mocked database +// TODO: all properties are optional in the server schema. I don't think this is correct. +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +class UmbMemberData extends UmbEntityData { + constructor() { + super(data); + } + + getTreeRoot(): PagedEntityTreeItem { + const items = this.data.filter((item) => item.parentKey === null); + const treeItems = items.map((item) => createEntityTreeItem(item)); + const total = items.length; + return { items: treeItems, total }; + } + + getTreeItemChildren(key: string): PagedEntityTreeItem { + const items = this.data.filter((item) => item.parentKey === key); + const treeItems = items.map((item) => createEntityTreeItem(item)); + const total = items.length; + return { items: treeItems, total }; + } + + getTreeItem(keys: Array): Array { + const items = this.data.filter((item) => keys.includes(item.key ?? '')); + return items.map((item) => createEntityTreeItem(item)); + } +} + +export const umbMemberData = new UmbMemberData(); diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/member.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/member.handlers.ts new file mode 100644 index 0000000000..41555f9b2f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/member.handlers.ts @@ -0,0 +1,19 @@ +import { rest } from 'msw'; +import { umbMemberData } from '../data/member.data'; + +// TODO: add schema +export const handlers = [ + rest.get('/umbraco/management/api/v1/tree/member/root', (req, res, ctx) => { + const response = umbMemberData.getTreeRoot(); + return res(ctx.status(200), ctx.json(response)); + }), + + rest.get('/umbraco/management/api/v1/tree/member/item', (req, res, ctx) => { + const keys = req.url.searchParams.getAll('key'); + if (!keys) return; + + const items = umbMemberData.getTreeItem(keys); + + return res(ctx.status(200), ctx.json(items)); + }), +];