From 81e8e15cba413d84f5d92635cd957547656a11de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 14:38:03 +0200 Subject: [PATCH] refactor step 1 --- .../src/backoffice/backoffice.element.ts | 2 + .../views/users/editor-view-users.element.ts | 2 +- .../grid}/editor-view-users-grid.element.ts | 46 +++++++--- .../table}/editor-view-users-table.element.ts | 31 +++++-- .../src/core/stores/user/user.store.ts | 92 +++++++++++++++++++ .../src/mocks/browser-handlers.ts | 2 + .../src/mocks/domains/users.handlers.ts | 22 +++++ 7 files changed, 173 insertions(+), 24 deletions(-) rename src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/{ => list-view-layouts/grid}/editor-view-users-grid.element.ts (71%) rename src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/{ => list-view-layouts/table}/editor-view-users-table.element.ts (91%) create mode 100644 src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts 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 aab13ad127..d29aaed274 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -25,6 +25,7 @@ import { UmbDocumentTypeStore } from '../core/stores/document-type.store'; import { UmbNodeStore } from '../core/stores/node.store'; import { UmbSectionStore } from '../core/stores/section.store'; import { UmbEntityStore } from '../core/stores/entity.store'; +import { UmbUserStore } from '../core/stores/user/user.store'; import { UmbPropertyEditorStore } from '../core/stores/property-editor/property-editor.store'; import { UmbIconStore } from '../core/stores/icon/icon.store'; import { UmbPropertyEditorConfigStore } from '../core/stores/property-editor-config/property-editor-config.store'; @@ -60,6 +61,7 @@ export class UmbBackofficeElement extends UmbContextConsumerMixin(UmbContextProv this.provideContext('umbNodeStore', new UmbNodeStore(this._umbEntityStore)); this.provideContext('umbDataTypeStore', new UmbDataTypeStore(this._umbEntityStore)); this.provideContext('umbDocumentTypeStore', new UmbDocumentTypeStore(this._umbEntityStore)); + this.provideContext('umbUserStore', new UmbUserStore(this._umbEntityStore)); this.provideContext('umbPropertyEditorStore', new UmbPropertyEditorStore()); this.provideContext('umbPropertyEditorConfigStore', new UmbPropertyEditorConfigStore()); this.provideContext('umbNotificationService', new UmbNotificationService()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts index 20e4ff026c..1dba2af6d6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts @@ -2,7 +2,7 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { UmbContextProviderMixin } from '../../../../../core/context'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; import { IRoute } from 'router-slot'; import { v4 as uuidv4 } from 'uuid'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts similarity index 71% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-grid.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index 3a79c58a76..d773c206b4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -5,6 +5,8 @@ import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; import { Subscription } from 'rxjs'; +import { UmbUserStore } from '../../../../../core/stores/user/user.store'; +import { ifDefined } from 'lit-html/directives/if-defined.js'; @customElement('umb-editor-view-users-grid') export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitElement) { @@ -34,24 +36,36 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl @state() private _selection: Array = []; - protected _usersContext?: UmbEditorViewUsersElement; - protected _usersSubscription?: Subscription; - protected _selectionSubscription?: Subscription; + private _userStore?: UmbUserStore; + private _usersContext?: UmbEditorViewUsersElement; + private _usersSubscription?: Subscription; + private _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); + this.consumeContext('umbUserStore', (userStore: UmbUserStore) => { + this._userStore = userStore; + this._observeUsers(); + }); + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { this._usersContext = usersContext; + this._observeSelection(); + }); + } - this._usersSubscription?.unsubscribe(); - this._selectionSubscription?.unsubscribe(); - this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { - this._users = users; - }); - this._selectionSubscription = this._usersContext?.selection.subscribe((selection: Array) => { - this._selection = selection; - }); + private _observeUsers() { + this._usersSubscription?.unsubscribe(); + this._usersSubscription = this._userStore?.getAll().subscribe((users) => { + this._users = users; + }); + } + + private _observeSelection() { + this._selectionSubscription?.unsubscribe(); + this._selectionSubscription = this._usersContext?.selection.subscribe((selection: Array) => { + this._selection = selection; }); } @@ -80,9 +94,9 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl } private renderUserCard(user: UserItem) { - if (!this._usersContext) return; + if (!this._userStore) return; - const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); + const statusLook = this._usersContext?.getTagLookAndColor(user.status ? user.status : ''); return html` this._selectRowHandler(user)} @unselected=${() => this._deselectRowHandler(user)}> ${user.status && user.status !== 'Active' - ? html` + ? html` ${user.status} ` : nothing} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts similarity index 91% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-table.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts index 572b3bd996..3a28ac02fe 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts @@ -5,6 +5,7 @@ import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import { UmbUserStore } from '../../../../../core/stores/user/user.store'; interface TableColumn { name: string; @@ -75,6 +76,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE @state() private _users: Array = []; + private _userStore?: UmbUserStore; private _usersContext?: UmbEditorViewUsersElement; private _usersSubscription?: Subscription; private _selectionSubscription?: Subscription; @@ -82,17 +84,14 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE connectedCallback(): void { super.connectedCallback(); + this.consumeContext('umbUserStore', (userStore: UmbUserStore) => { + this._userStore = userStore; + this._observeUsers(); + }); + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { this._usersContext = usersContext; - - this._usersSubscription?.unsubscribe(); - this._selectionSubscription?.unsubscribe(); - this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { - this._users = users; - }); - this._selectionSubscription = this._usersContext?.selection.subscribe((selection: Array) => { - this._selection = selection; - }); + this._observeSelection(); }); this._columns = [ @@ -142,6 +141,20 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE this._selectionSubscription?.unsubscribe(); } + private _observeUsers() { + this._usersSubscription?.unsubscribe(); + this._usersSubscription = this._userStore?.getAll().subscribe((users) => { + this._users = users; + }); + } + + private _observeSelection() { + this._selectionSubscription?.unsubscribe(); + this._selectionSubscription = this._usersContext?.selection.subscribe((selection: Array) => { + this._selection = selection; + }); + } + private _selectAllHandler(event: Event) { console.log('SELECT ALL NOT IMPLEMENTED'); } diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts new file mode 100644 index 0000000000..ae9b75e1c5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/stores/user/user.store.ts @@ -0,0 +1,92 @@ +import { map, Observable } from 'rxjs'; +import { UserItem } from '../../../backoffice/editors/users/views/users/editor-view-users.element'; +import { UmbEntityStore } from '../entity.store'; +import { UmbDataStoreBase } from '../store'; + +/** + * @export + * @class UmbUserStore + * @extends {UmbDataStoreBase} + * @description - Data Store for Users + */ +export class UmbUserStore extends UmbDataStoreBase { + private _entityStore: UmbEntityStore; + + constructor(entityStore: UmbEntityStore) { + super(); + this._entityStore = entityStore; + } + + getAll(): Observable> { + // TODO: use Fetcher API. + // TODO: only fetch if the data type is not in the store? + fetch(`/umbraco/backoffice/users`) + .then((res) => res.json()) + .then((data) => { + this.update(data.items); + }); + + return this.items; + } + + /** + * @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 UmbDataTypeStore + */ + getByKey(key: string): Observable { + // TODO: use Fetcher API. + // TODO: only fetch if the data type is not in the store? + fetch(`/umbraco/backoffice/users/${key}`) + .then((res) => res.json()) + .then((data) => { + console.log('getByKey', data); + this.update(data); + }); + + return this.items.pipe( + map((dataTypes: Array) => dataTypes.find((node: UserItem) => node.key === key) || null) + ); + } + + // public updateUser(user: UserItem) { + // const users = this._users.getValue(); + // const index = users.findIndex((u) => u.key === user.key); + // if (index === -1) return; + // users[index] = { ...users[index], ...user }; + // console.log('updateUser', user, users[index]); + // this._users.next(users); + // this.requestUpdate('users'); + // } + + // public inviteUser(name: string, email: string, userGroup: string, message: string): UserItem { + // const users = this._users.getValue(); + // const user = { + // id: this._users.getValue().length + 1, + // key: uuidv4(), + // name: name, + // email: email, + // status: 'invited', + // language: 'en', + // updateDate: new Date().toISOString(), + // createDate: new Date().toISOString(), + // failedLoginAttempts: 0, + // userGroup: userGroup, + // }; + // this._users.next([...users, user]); + // this.requestUpdate('users'); + + // //TODO: Send invite email with message + // return user; + // } + + // public deleteUser(key: string) { + // const users = this._users.getValue(); + // const index = users.findIndex((u) => u.key === key); + // if (index === -1) return; + // users.splice(index, 1); + // this._users.next(users); + // this.requestUpdate('users'); + // } +} diff --git a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts index 866364821d..f7124321ac 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts @@ -9,6 +9,7 @@ import * as serverHandlers from './domains/server.handlers'; import { handlers as upgradeHandlers } from './domains/upgrade.handlers'; import { handlers as userHandlers } from './domains/user.handlers'; import { handlers as propertyEditorHandlers } from './domains/property-editor.handlers'; +import { handlers as usersHandlers } from './domains/users.handlers'; const handlers = [ serverHandlers.serverVersionHandler, @@ -22,6 +23,7 @@ const handlers = [ ...propertyEditorHandlers, ...manifestsHandlers.default, ...publishedStatusHandlers, + ...usersHandlers, ]; switch (import.meta.env.VITE_UMBRACO_INSTALL_STATUS) { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts new file mode 100644 index 0000000000..ddcb14fb46 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts @@ -0,0 +1,22 @@ +import { rest } from 'msw'; +import { tempData } from '../../backoffice/editors/users/views/users/tempData'; + +// TODO: add schema +export const handlers = [ + rest.get('/umbraco/backoffice/users', (req, res, ctx) => { + const response = { + items: tempData, + }; + + return res(ctx.status(200), ctx.json(response)); + }), + + rest.get('/umbraco/backoffice/users/:key', (req, res, ctx) => { + const key = req.params.key as string; + if (!key) return; + + const user = tempData.find((x) => x.key === key); + + return res(ctx.status(200), ctx.json([user])); + }), +];