From f2244b6cf3365becb48cbdcf0356f62569d27564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 09:37:47 +0200 Subject: [PATCH 01/98] added User section and views --- .../editors/users/editor-users.element.ts | 51 ++++ .../editor-view-user-groups.element.ts | 24 ++ .../users/editor-view-users-list.element.ts | 244 ++++++++++++++++++ .../views/users/editor-view-users.element.ts | 95 +++++++ .../sections/users/users-section.element.ts | 19 ++ .../src/temp-internal-manifests.ts | 34 +++ 6 files changed, 467 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts new file mode 100644 index 0000000000..6029ada75d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts @@ -0,0 +1,51 @@ +import { UUIButtonState, UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { css, html, LitElement } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { distinctUntilChanged, Subscription } from 'rxjs'; +import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../core/context'; +import { UmbNotificationService } from '../../../core/services/notification'; +import { UmbDocumentTypeStore } from '../../../core/stores/document-type.store'; +import { DocumentTypeEntity } from '../../../mocks/data/document-type.data'; +import { UmbDocumentTypeContext } from './document-type.context'; + +import '../shared/editor-entity-layout/editor-entity-layout.element'; + +// Lazy load +// TODO: Make this dynamic, use load-extensions method to loop over extensions for this node. +import './views/user-groups/editor-view-user-groups.element'; +import { UmbNotificationDefaultData } from '../../../core/services/notification/layouts/default'; + +@customElement('umb-editor-users') +export class UmbEditorUsersElement extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) { + static styles = [ + UUITextStyles, + css` + :host { + display: block; + width: 100%; + height: 100%; + } + + #name { + width: 100%; + } + + #alias { + padding: 0 var(--uui-size-space-3); + } + `, + ]; + + render() { + return html` `; + } +} + +export default UmbEditorUsersElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-users': UmbEditorUsersElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts new file mode 100644 index 0000000000..1df1bf3ed9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts @@ -0,0 +1,24 @@ +import { css, html, LitElement } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import type { DocumentTypeEntity } from '../../../../../mocks/data/document-type.data'; +import { Subscription, distinctUntilChanged } from 'rxjs'; +import { UmbDocumentTypeContext } from '../../document-type.context'; + +@customElement('umb-editor-view-user-groups') +export class UmbEditorViewUserGroupsElement extends UmbContextConsumerMixin(LitElement) { + static styles = [UUITextStyles, css``]; + + render() { + return html`
USER GROUPS
`; + } +} + +export default UmbEditorViewUserGroupsElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-user-groups': UmbEditorViewUserGroupsElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts new file mode 100644 index 0000000000..bae3c8d727 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -0,0 +1,244 @@ +import { css, html, LitElement } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import { repeat } from 'lit/directives/repeat.js'; + +interface TableColumn { + name: string; + sort: Function; +} + +interface TableItem { + key: string; + name: string; + userGroup: string; + lastLogin: string; + status?: string; +} + +@customElement('umb-editor-view-users-list') +export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + uui-table-row uui-checkbox { + display: none; + } + uui-table-row:hover uui-icon, + uui-table-row[select-only] uui-icon { + display: none; + } + uui-table-row:hover uui-checkbox, + uui-table-row[select-only] uui-checkbox { + display: inline-block; + } + uui-table-head-cell:hover { + --uui-symbol-sort-hover: 1; + } + uui-table-head-cell button { + padding: 0; + background-color: transparent; + color: inherit; + border: none; + cursor: pointer; + font-weight: inherit; + font-size: inherit; + display: inline-flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + `, + ]; + + @state() + private _columns: Array = []; + + @state() + private _items: Array = []; + + @state() + private _selectionMode = false; + + @state() + private _selection: Array = []; + + @state() + private _sortingColumn: any = ''; + + @state() + private _sortingDesc = false; + + private _selectAllHandler(event: Event) { + const checkboxElement = event.target as HTMLInputElement; + this._selection = checkboxElement.checked ? this._items.map((item: TableItem) => item.key) : []; + this._selectionMode = this._selection.length > 0; + } + + private _selectHandler(event: Event, item: TableItem) { + const checkboxElement = event.target as HTMLInputElement; + this._selection = checkboxElement.checked + ? [...this._selection, item.key] + : this._selection.filter((selectionKey) => selectionKey !== item.key); + this._selectionMode = this._selection.length > 0; + } + private _selectRowHandler(item: TableItem) { + this._selection = [...this._selection, item.key]; + this._selectionMode = this._selection.length > 0; + } + private _unselectRowHandler(item: TableItem) { + this._selection = this._selection.filter((selectionKey) => selectionKey !== item.key); + this._selectionMode = this._selection.length > 0; + } + + private _sortingHandler(column: TableColumn) { + this._sortingDesc = this._sortingColumn === column.name ? !this._sortingDesc : false; + this._sortingColumn = column.name; + this._items = column.sort(this._items, this._sortingDesc); + } + + private _isSelected(key: string) { + return this._selection.includes(key); + } + + connectedCallback() { + super.connectedCallback(); + + this._columns = [ + { + name: 'Name', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => b.name.localeCompare(a.name)) + : [...items].sort((a, b) => a.name.localeCompare(b.name)); + }, + }, + { + name: 'User group', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => b.name.localeCompare(a.name)) + : [...items].sort((a, b) => a.name.localeCompare(b.name)); + }, + }, + { + name: 'Last login', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => +new Date(b.lastLogin) - +new Date(a.lastLogin)) + : [...items].sort((a, b) => +new Date(a.lastLogin) - +new Date(b.lastLogin)); + }, + }, + { + name: 'status', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => + b.status && a.status ? b.status.localeCompare(a.status) : (a.status ? 1 : 0) - (b.status ? 1 : 0) + ) + : [...items].sort((a, b) => + a.status && b.status ? a.status.localeCompare(b.status) : (b.status ? 1 : 0) - (a.status ? 1 : 0) + ); + }, + }, + ]; + + this._items = [ + { + key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', + name: 'Cecílie Bryon', + userGroup: 'Translators', + lastLogin: 'Fri, 23 April 2021', + status: 'Invited', + }, + { + key: '3179d0b2-eec2-4045-b86a-149e13b93e14', + name: 'Kathleen G. Smith', + userGroup: 'Editors', + lastLogin: 'Tue, 6 June 2021', // random date + status: 'Invited', + }, + { + key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', + name: 'Adrian Andresen', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0207', + name: 'Lorenza Trentino', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0202', + name: 'John Doe', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + ]; + } + + renderHeaderCellTemplate(column: TableColumn) { + return html` + + + + `; + } + + protected renderRowTemplate = (item: TableItem) => { + return html` this._selectRowHandler(item)} + @unselected=${() => this._unselectRowHandler(item)}> + +
+ +
+
+ + + + ${item.userGroup} + ${item.lastLogin} + ${item.status} +
`; + }; + + render() { + return html` +
Selected ${this._selection.length} of ${this._items.length}
+ + + + + + + ${this._columns.map((column) => this.renderHeaderCellTemplate(column))} + + ${repeat(this._items, (item) => item.key, this.renderRowTemplate)} + + `; + } +} + +export default UmbEditorViewUsersListElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-users-list': UmbEditorViewUsersListElement; + } +} 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 new file mode 100644 index 0000000000..f5f84d1611 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts @@ -0,0 +1,95 @@ +import { css, html, LitElement } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import type { DocumentTypeEntity } from '../../../../../mocks/data/document-type.data'; +import { Subscription, distinctUntilChanged } from 'rxjs'; +import './editor-view-users-list.element'; + +@customElement('umb-editor-view-users') +export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + #top-bar, + #user-list-top-bar { + display: flex; + justify-content: space-between; + } + + #user-list { + margin-top: var(--uui-size-layout-2); + font-size: 1rem; + } + + #user-grid { + display: none; //TODO Remove + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: var(--uui-size-space-4); + margin-top: var(--uui-size-space-4); + } + + uui-card-user { + width: 100%; + height: 180px; + } + + .user-login-time { + margin-top: auto; + } + `, + ]; + + render() { + return html`
+ +
+ + + + + + +
+
+ +
+
+ Users (23) +
+ Status: All + Groups: All + Order by: Name (A-Z) +
+
+
+ + Invited +
Editor
+ +
+ + +
Admin
+ +
+ + +
Translator
+ +
+
+ + +
`; + } +} + +export default UmbEditorViewUsersElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-users': UmbEditorViewUsersElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts new file mode 100644 index 0000000000..05b4916e11 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts @@ -0,0 +1,19 @@ +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +import '../../editors/shared/editor-entity-layout/editor-entity-layout.element'; + +@customElement('umb-section-users') +export class UmbSectionUsersElement extends LitElement { + render() { + return html` `; + } +} + +export default UmbSectionUsersElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-section-users': UmbSectionUsersElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index d24a1ab104..277ad11310 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -57,6 +57,16 @@ export const internalManifests: Array Promise import('./backoffice/sections/users/users-section.element'), + meta: { + pathname: 'users', + weight: 20, + }, + }, { type: 'dashboard', alias: 'Umb.Dashboard.Welcome', @@ -247,6 +257,30 @@ export const internalManifests: Array Promise import('./backoffice/editors/users/views/users/editor-view-users.element'), + meta: { + editors: ['Umb.Editor.Users'], + pathname: 'users', + weight: 1, + icon: 'document', + }, + }, + { + type: 'editorView', + alias: 'Umb.EditorView.Users.UserGroups', + name: 'User Groups', + loader: () => import('./backoffice/editors/users/views/user-groups/editor-view-user-groups.element'), + meta: { + editors: ['Umb.Editor.Users'], + pathname: 'user-groups', + weight: 0, + icon: 'document', + }, + }, { type: 'propertyAction', alias: 'Umb.PropertyAction.Copy', From 52e34398a3a10ef8808064399adfa602f6e4273f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 09:59:37 +0200 Subject: [PATCH 02/98] added grid and toggle between views --- .../users/editor-view-users-grid.element.ts | 71 ++++++++++++++ .../users/editor-view-users-list.element.ts | 52 ++-------- .../views/users/editor-view-users.element.ts | 98 ++++++++++++------- 3 files changed, 141 insertions(+), 80 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-grid.element.ts 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/editor-view-users-grid.element.ts new file mode 100644 index 0000000000..b781e8b40b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-grid.element.ts @@ -0,0 +1,71 @@ +import { css, html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import { repeat } from 'lit/directives/repeat.js'; + +interface TableColumn { + name: string; + sort: Function; +} + +interface TableItem { + key: string; + name: string; + userGroup: string; + lastLogin: string; + status?: string; +} + +@customElement('umb-editor-view-users-grid') +export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + #user-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: var(--uui-size-space-4); + margin-top: var(--uui-size-space-4); + } + + uui-card-user { + width: 100%; + height: 180px; + } + + .user-login-time { + margin-top: auto; + } + `, + ]; + + @property() + public users: Array = []; + + render() { + return html` +
+ ${repeat( + this.users, + (user) => user.key, + (user) => html` + + ${user.status ? html`${user.status}` : nothing} +
${user.userGroup}
+ +
+ ` + )} +
+ `; + } +} + +export default UmbEditorViewUsersGridElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-users-grid': UmbEditorViewUsersGridElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index bae3c8d727..fe99852fab 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -1,6 +1,6 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, state } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; @@ -52,11 +52,11 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl `, ]; - @state() - private _columns: Array = []; + @property() + public users: Array = []; @state() - private _items: Array = []; + private _columns: Array = []; @state() private _selectionMode = false; @@ -72,7 +72,7 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl private _selectAllHandler(event: Event) { const checkboxElement = event.target as HTMLInputElement; - this._selection = checkboxElement.checked ? this._items.map((item: TableItem) => item.key) : []; + this._selection = checkboxElement.checked ? this.users.map((item: TableItem) => item.key) : []; this._selectionMode = this._selection.length > 0; } @@ -95,7 +95,7 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl private _sortingHandler(column: TableColumn) { this._sortingDesc = this._sortingColumn === column.name ? !this._sortingDesc : false; this._sortingColumn = column.name; - this._items = column.sort(this._items, this._sortingDesc); + this.users = column.sort(this.users, this._sortingDesc); } private _isSelected(key: string) { @@ -143,41 +143,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl }, }, ]; - - this._items = [ - { - key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', - name: 'Cecílie Bryon', - userGroup: 'Translators', - lastLogin: 'Fri, 23 April 2021', - status: 'Invited', - }, - { - key: '3179d0b2-eec2-4045-b86a-149e13b93e14', - name: 'Kathleen G. Smith', - userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', // random date - status: 'Invited', - }, - { - key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', - name: 'Adrian Andresen', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0207', - name: 'Lorenza Trentino', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0202', - name: 'John Doe', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - ]; } renderHeaderCellTemplate(column: TableColumn) { @@ -217,7 +182,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl render() { return html` -
Selected ${this._selection.length} of ${this._items.length}
@@ -225,11 +189,11 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl + ?checked="${this._selection.length === this.users.length}"> ${this._columns.map((column) => this.renderHeaderCellTemplate(column))} - ${repeat(this._items, (item) => item.key, this.renderRowTemplate)} + ${repeat(this.users, (item) => item.key, this.renderRowTemplate)} `; } 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 f5f84d1611..1a2c942a7c 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 @@ -5,6 +5,9 @@ import { UmbContextConsumerMixin } from '../../../../../core/context'; import type { DocumentTypeEntity } from '../../../../../mocks/data/document-type.data'; import { Subscription, distinctUntilChanged } from 'rxjs'; import './editor-view-users-list.element'; +import './editor-view-users-grid.element'; + +export type UsersViewType = 'list' | 'grid'; @customElement('umb-editor-view-users') export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElement) { @@ -21,31 +24,71 @@ export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElemen margin-top: var(--uui-size-layout-2); font-size: 1rem; } - - #user-grid { - display: none; //TODO Remove - display: grid; - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); - gap: var(--uui-size-space-4); - margin-top: var(--uui-size-space-4); - } - - uui-card-user { - width: 100%; - height: 180px; - } - - .user-login-time { - margin-top: auto; - } `, ]; + @state() + private _viewType: UsersViewType = 'grid'; + + @state() + private _users = [ + { + key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', + name: 'Cecílie Bryon', + userGroup: 'Translators', + lastLogin: 'Fri, 23 April 2021', + status: 'Invited', + }, + { + key: '3179d0b2-eec2-4045-b86a-149e13b93e14', + name: 'Kathleen G. Smith', + userGroup: 'Editors', + lastLogin: 'Tue, 6 June 2021', // random date + status: 'Invited', + }, + { + key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', + name: 'Adrian Andresen', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0207', + name: 'Lorenza Trentino', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0202', + name: 'John Doe', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + ]; + + private _renderViewType() { + switch (this._viewType) { + case 'list': + return html``; + case 'grid': + return html``; + default: + return html``; + } + } + + private _toggleViewType() { + this._viewType = this._viewType === 'list' ? 'grid' : 'list'; + } + render() { return html`
- + @@ -63,25 +106,8 @@ export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElemen Order by: Name (A-Z)
-
- - Invited -
Editor
- -
- -
Admin
- -
- - -
Translator
- -
-
- - + ${this._renderViewType()} `; } } From 0832c35d46565a3ac844c9c38b3064f0d85235eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 10:31:40 +0200 Subject: [PATCH 03/98] added user context --- .../users/editor-view-users-grid.element.ts | 43 ++++--- .../users/editor-view-users-list.element.ts | 112 ++++++++++-------- .../views/users/editor-view-users.element.ts | 41 +++++-- 3 files changed, 117 insertions(+), 79 deletions(-) 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/editor-view-users-grid.element.ts index b781e8b40b..e0ae49691f 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/editor-view-users-grid.element.ts @@ -3,19 +3,8 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; - -interface TableColumn { - name: string; - sort: Function; -} - -interface TableItem { - key: string; - name: string; - userGroup: string; - lastLogin: string; - status?: string; -} +import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import { Subscription } from 'rxjs'; @customElement('umb-editor-view-users-grid') export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitElement) { @@ -40,14 +29,36 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl `, ]; - @property() - public users: Array = []; + @state() + private _users: Array = []; + + protected _usersSubscription?: Subscription; + protected _usersContext?: UmbEditorViewUsersElement; + + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this._usersContext = usersContext; + + this._usersSubscription?.unsubscribe(); + this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { + this._users = users; + }); + }); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this._usersSubscription?.unsubscribe(); + } render() { return html`
${repeat( - this.users, + this._users, (user) => user.key, (user) => html` diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index fe99852fab..dad56993ac 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -3,20 +3,14 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; +import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import { Subscription } from 'rxjs'; interface TableColumn { name: string; sort: Function; } -interface TableItem { - key: string; - name: string; - userGroup: string; - lastLogin: string; - status?: string; -} - @customElement('umb-editor-view-users-list') export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitElement) { static styles = [ @@ -52,9 +46,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl `, ]; - @property() - public users: Array = []; - @state() private _columns: Array = []; @@ -70,45 +61,28 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl @state() private _sortingDesc = false; - private _selectAllHandler(event: Event) { - const checkboxElement = event.target as HTMLInputElement; - this._selection = checkboxElement.checked ? this.users.map((item: TableItem) => item.key) : []; - this._selectionMode = this._selection.length > 0; - } + @state() + private _users: Array = []; - private _selectHandler(event: Event, item: TableItem) { - const checkboxElement = event.target as HTMLInputElement; - this._selection = checkboxElement.checked - ? [...this._selection, item.key] - : this._selection.filter((selectionKey) => selectionKey !== item.key); - this._selectionMode = this._selection.length > 0; - } - private _selectRowHandler(item: TableItem) { - this._selection = [...this._selection, item.key]; - this._selectionMode = this._selection.length > 0; - } - private _unselectRowHandler(item: TableItem) { - this._selection = this._selection.filter((selectionKey) => selectionKey !== item.key); - this._selectionMode = this._selection.length > 0; - } + protected _usersSubscription?: Subscription; + protected _usersContext?: UmbEditorViewUsersElement; - private _sortingHandler(column: TableColumn) { - this._sortingDesc = this._sortingColumn === column.name ? !this._sortingDesc : false; - this._sortingColumn = column.name; - this.users = column.sort(this.users, this._sortingDesc); - } - - private _isSelected(key: string) { - return this._selection.includes(key); - } - - connectedCallback() { + connectedCallback(): void { super.connectedCallback(); + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this._usersContext = usersContext; + + this._usersSubscription?.unsubscribe(); + this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { + this._users = users; + }); + }); + this._columns = [ { name: 'Name', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => b.name.localeCompare(a.name)) : [...items].sort((a, b) => a.name.localeCompare(b.name)); @@ -116,7 +90,7 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl }, { name: 'User group', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => b.name.localeCompare(a.name)) : [...items].sort((a, b) => a.name.localeCompare(b.name)); @@ -124,7 +98,7 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl }, { name: 'Last login', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => +new Date(b.lastLogin) - +new Date(a.lastLogin)) : [...items].sort((a, b) => +new Date(a.lastLogin) - +new Date(b.lastLogin)); @@ -132,7 +106,7 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl }, { name: 'status', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => b.status && a.status ? b.status.localeCompare(a.status) : (a.status ? 1 : 0) - (b.status ? 1 : 0) @@ -145,6 +119,44 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl ]; } + disconnectedCallback(): void { + super.disconnectedCallback(); + + this._usersSubscription?.unsubscribe(); + } + + private _selectAllHandler(event: Event) { + const checkboxElement = event.target as HTMLInputElement; + this._selection = checkboxElement.checked ? this._users.map((item: UserItem) => item.key) : []; + this._selectionMode = this._selection.length > 0; + } + + private _selectHandler(event: Event, item: UserItem) { + const checkboxElement = event.target as HTMLInputElement; + this._selection = checkboxElement.checked + ? [...this._selection, item.key] + : this._selection.filter((selectionKey) => selectionKey !== item.key); + this._selectionMode = this._selection.length > 0; + } + private _selectRowHandler(item: UserItem) { + this._selection = [...this._selection, item.key]; + this._selectionMode = this._selection.length > 0; + } + private _unselectRowHandler(item: UserItem) { + this._selection = this._selection.filter((selectionKey) => selectionKey !== item.key); + this._selectionMode = this._selection.length > 0; + } + + private _sortingHandler(column: TableColumn) { + this._sortingDesc = this._sortingColumn === column.name ? !this._sortingDesc : false; + this._sortingColumn = column.name; + this._users = column.sort(this._users, this._sortingDesc); + } + + private _isSelected(key: string) { + return this._selection.includes(key); + } + renderHeaderCellTemplate(column: TableColumn) { return html` @@ -157,8 +169,8 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl `; } - protected renderRowTemplate = (item: TableItem) => { - return html` { + return html` + ?checked="${this._selection.length === this._users.length}"> ${this._columns.map((column) => this.renderHeaderCellTemplate(column))} - ${repeat(this.users, (item) => item.key, this.renderRowTemplate)} + ${repeat(this._users, (item) => item.key, this.renderRowTemplate)} `; } 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 1a2c942a7c..63f21bb266 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 @@ -1,16 +1,23 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../../../core/context'; -import type { DocumentTypeEntity } from '../../../../../mocks/data/document-type.data'; -import { Subscription, distinctUntilChanged } from 'rxjs'; +import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../../../core/context'; import './editor-view-users-list.element'; import './editor-view-users-grid.element'; +import { BehaviorSubject, Observable } from 'rxjs'; export type UsersViewType = 'list' | 'grid'; +export interface UserItem { + key: string; + name: string; + userGroup: string; + lastLogin: string; + status?: string; +} + @customElement('umb-editor-view-users') -export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElement) { +export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElement) { static styles = [ UUITextStyles, css` @@ -27,11 +34,7 @@ export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElemen `, ]; - @state() - private _viewType: UsersViewType = 'grid'; - - @state() - private _users = [ + private tempData = [ { key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', name: 'Cecílie Bryon', @@ -43,7 +46,7 @@ export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElemen key: '3179d0b2-eec2-4045-b86a-149e13b93e14', name: 'Kathleen G. Smith', userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', // random date + lastLogin: 'Tue, 6 June 2021', status: 'Invited', }, { @@ -66,14 +69,26 @@ export class UmbEditorViewUsersElement extends UmbContextConsumerMixin(LitElemen }, ]; + @state() + private _viewType: UsersViewType = 'grid'; + + private _users: BehaviorSubject> = new BehaviorSubject(this.tempData); + public readonly users: Observable> = this._users.asObservable(); + + constructor() { + super(); + + this.provideContext('umbUsersContext', this); + } + private _renderViewType() { switch (this._viewType) { case 'list': - return html``; + return html``; case 'grid': - return html``; + return html``; default: - return html``; + return html``; } } From fe8adfd2ecf289c94594c4cdc0f31c27939410b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 10:49:57 +0200 Subject: [PATCH 04/98] added tag look and color lookup on context --- .../users/editor-view-users-list.element.ts | 28 ++++++++++++------- .../views/users/editor-view-users.element.ts | 17 ++++++++++- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index dad56993ac..0e3e642490 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -1,4 +1,4 @@ -import { css, html, LitElement } from 'lit'; +import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; @@ -169,26 +169,34 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl `; } - protected renderRowTemplate = (item: UserItem) => { + protected renderRowTemplate = (user: UserItem) => { + if (!this._usersContext) return; + + const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); + return html` this._selectRowHandler(item)} - @unselected=${() => this._unselectRowHandler(item)}> + ?selected=${this._isSelected(user.key)} + @selected=${() => this._selectRowHandler(user)} + @unselected=${() => this._unselectRowHandler(user)}>
- +
- ${item.userGroup} - ${item.lastLogin} - ${item.status} + ${user.userGroup} + ${user.lastLogin} + + ${user.status + ? html` ${user.status} ` + : nothing} +
`; }; 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 63f21bb266..abb5eba27d 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 @@ -5,6 +5,7 @@ import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../../.. import './editor-view-users-list.element'; import './editor-view-users-grid.element'; import { BehaviorSubject, Observable } from 'rxjs'; +import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; export type UsersViewType = 'list' | 'grid'; @@ -47,7 +48,7 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen name: 'Kathleen G. Smith', userGroup: 'Editors', lastLogin: 'Tue, 6 June 2021', - status: 'Invited', + status: 'Disabled', }, { key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', @@ -96,6 +97,20 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen this._viewType = this._viewType === 'list' ? 'grid' : 'list'; } + public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { + switch (status.toLowerCase()) { + case 'invited': + case 'inactive': + return { look: 'primary', color: 'warning' }; + case 'active': + return { look: 'primary', color: 'positive' }; + case 'disabled': + return { look: 'primary', color: 'danger' }; + default: + return { look: 'secondary', color: 'default' }; + } + } + render() { return html`
From f13621da836d8b951653a8fe18571ddb0012077a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 10:53:45 +0200 Subject: [PATCH 05/98] added tag lookup to grid --- .../users/editor-view-users-grid.element.ts | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) 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/editor-view-users-grid.element.ts index e0ae49691f..bc1728aa72 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/editor-view-users-grid.element.ts @@ -54,19 +54,31 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl this._usersSubscription?.unsubscribe(); } + private renderUserCard(user: UserItem) { + if (!this._usersContext) return; + + const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); + + return html` + + ${user.status + ? html` + ${user.status} + ` + : nothing} +
${user.userGroup}
+ +
+ `; + } + render() { return html`
${repeat( this._users, (user) => user.key, - (user) => html` - - ${user.status ? html`${user.status}` : nothing} -
${user.userGroup}
- -
- ` + (user) => this.renderUserCard(user) )}
`; From 62965ad3663b228d8f8a0253df122ddfef1bc49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 11:25:20 +0200 Subject: [PATCH 06/98] ts fix --- .../editors/users/views/users/editor-view-users-list.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index 0e3e642490..8eee501769 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -8,7 +8,7 @@ import { Subscription } from 'rxjs'; interface TableColumn { name: string; - sort: Function; + sort: (items: Array, desc: boolean) => Array; } @customElement('umb-editor-view-users-list') From 8ceef0f8ff20ee736b2f5db8d5ec0bc6cd6b3af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 11:30:00 +0200 Subject: [PATCH 07/98] styling --- .../users/views/users/editor-view-users-grid.element.ts | 1 - .../users/views/users/editor-view-users-list.element.ts | 3 +++ .../editors/users/views/users/editor-view-users.element.ts | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) 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/editor-view-users-grid.element.ts index bc1728aa72..4e1e0df15f 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/editor-view-users-grid.element.ts @@ -15,7 +15,6 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--uui-size-space-4); - margin-top: var(--uui-size-space-4); } uui-card-user { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index 8eee501769..e3a28d98b2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -16,6 +16,9 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl static styles = [ UUITextStyles, css` + uui-table { + box-shadow: var(--uui-shadow-depth-1, 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)); + } uui-table-row uui-checkbox { display: none; } 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 abb5eba27d..591a50a17d 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 @@ -28,6 +28,10 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen justify-content: space-between; } + #user-list-top-bar { + margin-bottom: var(--uui-size-space-4); + } + #user-list { margin-top: var(--uui-size-layout-2); font-size: 1rem; From cd7150d4f7c835a1fcb6d3e6879e562c8f4e00e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 14:25:11 +0200 Subject: [PATCH 08/98] added selection subscription --- .../users/editor-view-users-grid.element.ts | 23 +++++++++- .../users/editor-view-users-list.element.ts | 34 ++++++-------- .../views/users/editor-view-users.element.ts | 46 +++++++++++++------ 3 files changed, 68 insertions(+), 35 deletions(-) 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/editor-view-users-grid.element.ts index 4e1e0df15f..a4d3d8d18a 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/editor-view-users-grid.element.ts @@ -31,8 +31,12 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl @state() private _users: Array = []; - protected _usersSubscription?: Subscription; + @state() + private _selection: Array = []; + protected _usersContext?: UmbEditorViewUsersElement; + protected _usersSubscription?: Subscription; + protected _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); @@ -41,9 +45,13 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl 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; + }); }); } @@ -51,6 +59,11 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl super.disconnectedCallback(); this._usersSubscription?.unsubscribe(); + this._selectionSubscription?.unsubscribe(); + } + + private _isSelected(key: string) { + return this._selection.includes(key); } private renderUserCard(user: UserItem) { @@ -59,7 +72,13 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); return html` - + 0} + ?selected=${this._isSelected(user.key)} + @selected=${() => this._usersContext?.select(user.key)} + @unselected=${() => this._usersContext?.deselect(user.key)}> ${user.status ? html` ${user.status} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index e3a28d98b2..a4476ca19a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -67,8 +67,9 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl @state() private _users: Array = []; - protected _usersSubscription?: Subscription; protected _usersContext?: UmbEditorViewUsersElement; + protected _usersSubscription?: Subscription; + protected _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); @@ -77,9 +78,13 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl 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._columns = [ @@ -126,28 +131,19 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl super.disconnectedCallback(); this._usersSubscription?.unsubscribe(); + this._selectionSubscription?.unsubscribe(); } private _selectAllHandler(event: Event) { - const checkboxElement = event.target as HTMLInputElement; - this._selection = checkboxElement.checked ? this._users.map((item: UserItem) => item.key) : []; - this._selectionMode = this._selection.length > 0; + console.log('SELECT ALL NOT IMPLEMENTED'); } - private _selectHandler(event: Event, item: UserItem) { - const checkboxElement = event.target as HTMLInputElement; - this._selection = checkboxElement.checked - ? [...this._selection, item.key] - : this._selection.filter((selectionKey) => selectionKey !== item.key); - this._selectionMode = this._selection.length > 0; + private _selectRowHandler(user: UserItem) { + this._usersContext?.select(user.key); } - private _selectRowHandler(item: UserItem) { - this._selection = [...this._selection, item.key]; - this._selectionMode = this._selection.length > 0; - } - private _unselectRowHandler(item: UserItem) { - this._selection = this._selection.filter((selectionKey) => selectionKey !== item.key); - this._selectionMode = this._selection.length > 0; + + private _deselectRowHandler(user: UserItem) { + this._usersContext?.deselect(user.key); } private _sortingHandler(column: TableColumn) { @@ -181,8 +177,8 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl selectable ?select-only=${this._selectionMode} ?selected=${this._isSelected(user.key)} - @selected=${() => this._selectRowHandler(user)} - @unselected=${() => this._unselectRowHandler(user)}> + @selected=${() => this._usersContext?.select(user.key)} + @unselected=${() => this._usersContext?.deselect(user.key)}>
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 591a50a17d..60ced72460 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 @@ -80,12 +80,44 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen private _users: BehaviorSubject> = new BehaviorSubject(this.tempData); public readonly users: Observable> = this._users.asObservable(); + private _selection: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly selection: Observable> = this._selection.asObservable(); + constructor() { super(); this.provideContext('umbUsersContext', this); } + public setSelection(value: Array) { + if (!value) return; + this._selection.next(value); + } + + public select(key: string) { + const selection = this._selection.getValue(); + this._selection.next([...selection, key]); + } + + public deselect(key: string) { + const selection = this._selection.getValue(); + this._selection.next(selection.filter((k) => k !== key)); + } + + public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { + switch (status.toLowerCase()) { + case 'invited': + case 'inactive': + return { look: 'primary', color: 'warning' }; + case 'active': + return { look: 'primary', color: 'positive' }; + case 'disabled': + return { look: 'primary', color: 'danger' }; + default: + return { look: 'secondary', color: 'default' }; + } + } + private _renderViewType() { switch (this._viewType) { case 'list': @@ -101,20 +133,6 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen this._viewType = this._viewType === 'list' ? 'grid' : 'list'; } - public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { - switch (status.toLowerCase()) { - case 'invited': - case 'inactive': - return { look: 'primary', color: 'warning' }; - case 'active': - return { look: 'primary', color: 'positive' }; - case 'disabled': - return { look: 'primary', color: 'danger' }; - default: - return { look: 'secondary', color: 'default' }; - } - } - render() { return html`
From a1751f4c5868b651431c4c27a82d65669f6c2f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 15:02:37 +0200 Subject: [PATCH 09/98] added selection element --- .../editor-view-users-selection.element.ts | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts new file mode 100644 index 0000000000..8ae895f844 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts @@ -0,0 +1,86 @@ +import { css, html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import { repeat } from 'lit/directives/repeat.js'; +import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import { Subscription } from 'rxjs'; + +@customElement('umb-editor-view-users-selection') +export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + :host { + display: flex; + gap: var(--uui-size-3); + width: 100%; + padding: var(--uui-size-space-4); + background-color: var(--uui-color-selected); + color: var(--uui-color-selected-contrast); + align-items: center; + border-radius: var(--uui-size-space-2); + box-sizing: border-box; + } + `, + ]; + + @state() + private _users: Array = []; + + @state() + private _selection: Array = []; + + protected _usersContext?: UmbEditorViewUsersElement; + protected _usersSubscription?: Subscription; + protected _selectionSubscription?: Subscription; + + connectedCallback(): void { + super.connectedCallback(); + + 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; + }); + }); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this._usersSubscription?.unsubscribe(); + this._selectionSubscription?.unsubscribe(); + } + + private _handleClearSelection() { + this._usersContext?.setSelection([]); + } + + private _renderSelectionCount() { + return html`
${this._selection.length} of ${this._users.length} selected
`; + } + + render() { + return html` + ${this._renderSelectionCount()} + + + + `; + } +} + +export default UmbEditorViewUsersSelectionElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-users-selection': UmbEditorViewUsersSelectionElement; + } +} From 550f5265c739ff03bc4ae58e543cdd7d705b9cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 15:02:49 +0200 Subject: [PATCH 10/98] using selection element and more dummy data --- .../views/users/editor-view-users.element.ts | 136 +++++++++++++++++- 1 file changed, 129 insertions(+), 7 deletions(-) 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 60ced72460..5a73c3edaf 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 @@ -1,11 +1,12 @@ -import { css, html, LitElement } from 'lit'; +import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../../../core/context'; -import './editor-view-users-list.element'; -import './editor-view-users-grid.element'; import { BehaviorSubject, Observable } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; +import './editor-view-users-list.element'; +import './editor-view-users-grid.element'; +import './editor-view-users-selection.element'; export type UsersViewType = 'list' | 'grid'; @@ -36,6 +37,10 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen margin-top: var(--uui-size-layout-2); font-size: 1rem; } + + umb-editor-view-users-selection { + margin-bottom: var(--uui-size-layout-2); + } `, ]; @@ -72,6 +77,110 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen userGroup: 'Translators', lastLogin: 'Tue, 11 December 2021', }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0203', + name: 'Jane Doe', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0204', + name: 'John Smith', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0205', + name: 'Jane Smith', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0206', + name: 'Oliver Twist', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-2330-b66c336d0207', + name: 'Olivia Doe', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0208', + name: 'Hans Hansen', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'a9b18a00-58f2-sjh2-bf60-48d33ab156db', + name: 'Brian Adams', + userGroup: 'Translators', + lastLogin: 'Fri, 23 April 2021', + status: 'Invited', + }, + { + key: '3179d0b2-eec2-4432-b86a-149e13b93e14', + name: 'Smith John', + userGroup: 'Editors', + lastLogin: 'Tue, 6 June 2021', + status: 'Disabled', + }, + { + key: '1b1c9723-b845-4d9a-9ed2-b2f46c05fd72', + name: 'Reese Witherspoon', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-2f94-4e65-9330-b66c336d0207', + name: 'Denzel Washington', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e23-9330-b66c336d0202', + name: 'Leonardo DiCaprio', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-2394-4e65-9330-b66c336d0203', + name: 'Idris Elba', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b6u7336d0204', + name: 'Quentin Tarantino', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-2330-c66c336d0205', + name: 'Tom Hanks', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af82a-b994-4b65-9330-b66c336d0206', + name: 'Oprah Winfrey', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-2s30-b66b336d0207', + name: 'Pamela Anderson', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9930-b66c336d0l33t', + name: 'Keanu Reeves', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, ]; @state() @@ -92,16 +201,19 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen public setSelection(value: Array) { if (!value) return; this._selection.next(value); + this.requestUpdate('selection'); } public select(key: string) { const selection = this._selection.getValue(); this._selection.next([...selection, key]); + this.requestUpdate('selection'); } public deselect(key: string) { const selection = this._selection.getValue(); this._selection.next(selection.filter((k) => k !== key)); + this.requestUpdate('selection'); } public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { @@ -118,6 +230,10 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen } } + private _toggleViewType() { + this._viewType = this._viewType === 'list' ? 'grid' : 'list'; + } + private _renderViewType() { switch (this._viewType) { case 'list': @@ -129,12 +245,17 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen } } - private _toggleViewType() { - this._viewType = this._viewType === 'list' ? 'grid' : 'list'; + private _renderSelection() { + if (this._selection.getValue().length === 0) return nothing; + + return html``; } render() { - return html`
+ return html` + ${this._renderSelection()} + +
${this._renderViewType()} -
`; +
+ `; } } From 5f04b888c3f991aa5bed4c94847cd66708fd8845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 20 Sep 2022 15:38:21 +0200 Subject: [PATCH 11/98] Remove padding from editor-layout --- .../editors/shared/editor-layout/editor-layout.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.element.ts index 8d01d667a3..b4180bd213 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.element.ts @@ -30,7 +30,7 @@ export class UmbEditorLayout extends LitElement { } #main { - padding: var(--uui-size-6); + /* padding: 0 var(--uui-size-6); */ display: flex; flex: 1; flex-direction: column; From 2a47cf212ecc9b97be7ebeae10ba469bc597458c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 13:07:54 +0200 Subject: [PATCH 12/98] sticky header --- .../editor-view-users-selection.element.ts | 3 +- .../views/users/editor-view-users.element.ts | 59 +++++++++---------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts index 8ae895f844..5f93bae097 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts @@ -15,11 +15,10 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( display: flex; gap: var(--uui-size-3); width: 100%; - padding: var(--uui-size-space-4); + padding: var(--uui-size-space-4) var(--uui-size-space-6); background-color: var(--uui-color-selected); color: var(--uui-color-selected-contrast); align-items: center; - border-radius: var(--uui-size-space-2); box-sizing: border-box; } `, 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 5a73c3edaf..fd174f8d1e 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 @@ -23,23 +23,27 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen static styles = [ UUITextStyles, css` - #top-bar, + #sticky-top { + position: sticky; + top: 0px; + z-index: 1; + box-shadow: var(--uui-shadow-depth-2); + } + #user-list-top-bar { + padding: var(--uui-size-space-4) var(--uui-size-space-6); + background-color: var(--uui-color-surface-alt); display: flex; justify-content: space-between; + white-space: nowrap; + gap: 16px; + align-items: center; } - - #user-list-top-bar { - margin-bottom: var(--uui-size-space-4); - } - #user-list { - margin-top: var(--uui-size-layout-2); - font-size: 1rem; + padding: var(--uui-size-space-6); } - - umb-editor-view-users-selection { - margin-bottom: var(--uui-size-layout-2); + #input-search { + width: 100%; } `, ]; @@ -253,35 +257,28 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen render() { return html` - ${this._renderSelection()} - -
- -
- - - - - - -
-
- -
+
- Users (23) + +
Status: All Groups: All Order by: Name (A-Z) + + +
- ${this._renderViewType()} + ${this._renderSelection()}
+ + +
${this._renderViewType()}
`; } } From d89ef40f4be50efdd7f6ad7cf6ef1cd62c00ec45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 13:45:10 +0200 Subject: [PATCH 13/98] intersection observer --- .../views/users/editor-view-users.element.ts | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) 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 fd174f8d1e..0fdce86bb6 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 @@ -25,8 +25,13 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen css` #sticky-top { position: sticky; - top: 0px; + top: -1px; z-index: 1; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0), 0 1px 2px rgba(0, 0, 0, 0); + transition: 250ms box-shadow ease-in-out; + } + + #sticky-top.header-shadow { box-shadow: var(--uui-shadow-depth-2); } @@ -196,10 +201,32 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen private _selection: BehaviorSubject> = new BehaviorSubject(>[]); public readonly selection: Observable> = this._selection.asObservable(); + private _IntersectionObserverOptions = { + root: this, + rootMargin: '0px', + threshold: 1.0, + }; + constructor() { super(); this.provideContext('umbUsersContext', this); + this.setupHeaderIntersectionObserver(); + } + + public setupHeaderIntersectionObserver() { + requestAnimationFrame(() => { + const el = this.shadowRoot?.querySelector('#sticky-top'); + + if (el) { + const options = { threshold: [1] }; + const callback = (entries: IntersectionObserverEntry[]) => + entries[0].target.classList.toggle('header-shadow', entries[0].intersectionRatio < 1); + const observer = new IntersectionObserver(callback, options); + + observer.observe(el); + } + }); } public setSelection(value: Array) { From 3497d34ba27e014a83ee46d901ac065e4716c8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 14:53:25 +0200 Subject: [PATCH 14/98] added routing and user details --- .../users/editor-view-users-list.element.ts | 483 +++++++++++------- .../editor-view-users-selection.element.ts | 6 +- .../users/editor-view-users-table.element.ts | 227 ++++++++ .../editor-view-users-user-details.element.ts | 21 + .../views/users/editor-view-users.element.ts | 309 +---------- 5 files changed, 561 insertions(+), 485 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-table.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index a4476ca19a..ba96d2597b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -1,219 +1,326 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; -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 { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../../../core/context'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; +import './editor-view-users-table.element'; +import './editor-view-users-grid.element'; +import './editor-view-users-selection.element'; +import { IRoute } from 'router-slot'; -interface TableColumn { +export type UsersViewType = 'list' | 'grid'; + +export interface UserItem { + key: string; name: string; - sort: (items: Array, desc: boolean) => Array; + userGroup: string; + lastLogin: string; + status?: string; } @customElement('umb-editor-view-users-list') -export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitElement) { +export class UmbEditorViewUsersListElement extends UmbContextProviderMixin(LitElement) { static styles = [ UUITextStyles, css` - uui-table { - box-shadow: var(--uui-shadow-depth-1, 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)); + #sticky-top { + position: sticky; + top: -1px; + z-index: 1; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0), 0 1px 2px rgba(0, 0, 0, 0); + transition: 250ms box-shadow ease-in-out; } - uui-table-row uui-checkbox { - display: none; + + #sticky-top.header-shadow { + box-shadow: var(--uui-shadow-depth-2); } - uui-table-row:hover uui-icon, - uui-table-row[select-only] uui-icon { - display: none; - } - uui-table-row:hover uui-checkbox, - uui-table-row[select-only] uui-checkbox { - display: inline-block; - } - uui-table-head-cell:hover { - --uui-symbol-sort-hover: 1; - } - uui-table-head-cell button { - padding: 0; - background-color: transparent; - color: inherit; - border: none; - cursor: pointer; - font-weight: inherit; - font-size: inherit; - display: inline-flex; - align-items: center; + + #user-list-top-bar { + padding: var(--uui-size-space-4) var(--uui-size-space-6); + background-color: var(--uui-color-surface-alt); + display: flex; justify-content: space-between; + white-space: nowrap; + gap: 16px; + align-items: center; + } + #user-list { + padding: var(--uui-size-space-6); + padding-top: var(--uui-size-space-2); + } + #input-search { width: 100%; } `, ]; - @state() - private _columns: Array = []; + private tempData = [ + { + key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', + name: 'Cecílie Bryon', + userGroup: 'Translators', + lastLogin: 'Fri, 23 April 2021', + status: 'Invited', + }, + { + key: '3179d0b2-eec2-4045-b86a-149e13b93e14', + name: 'Kathleen G. Smith', + userGroup: 'Editors', + lastLogin: 'Tue, 6 June 2021', + status: 'Disabled', + }, + { + key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', + name: 'Adrian Andresen', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0207', + name: 'Lorenza Trentino', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0202', + name: 'John Doe', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0203', + name: 'Jane Doe', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0204', + name: 'John Smith', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0205', + name: 'Jane Smith', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0206', + name: 'Oliver Twist', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-2330-b66c336d0207', + name: 'Olivia Doe', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0208', + name: 'Hans Hansen', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'a9b18a00-58f2-sjh2-bf60-48d33ab156db', + name: 'Brian Adams', + userGroup: 'Translators', + lastLogin: 'Fri, 23 April 2021', + status: 'Invited', + }, + { + key: '3179d0b2-eec2-4432-b86a-149e13b93e14', + name: 'Smith John', + userGroup: 'Editors', + lastLogin: 'Tue, 6 June 2021', + status: 'Disabled', + }, + { + key: '1b1c9723-b845-4d9a-9ed2-b2f46c05fd72', + name: 'Reese Witherspoon', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-2f94-4e65-9330-b66c336d0207', + name: 'Denzel Washington', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e23-9330-b66c336d0202', + name: 'Leonardo DiCaprio', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-2394-4e65-9330-b66c336d0203', + name: 'Idris Elba', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b6u7336d0204', + name: 'Quentin Tarantino', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-2330-c66c336d0205', + name: 'Tom Hanks', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af82a-b994-4b65-9330-b66c336d0206', + name: 'Oprah Winfrey', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-2s30-b66b336d0207', + name: 'Pamela Anderson', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9930-b66c336d0l33t', + name: 'Keanu Reeves', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + ]; @state() - private _selectionMode = false; + private _viewType: UsersViewType = 'grid'; - @state() - private _selection: Array = []; + private _users: BehaviorSubject> = new BehaviorSubject(this.tempData); + public readonly users: Observable> = this._users.asObservable(); - @state() - private _sortingColumn: any = ''; + private _selection: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly selection: Observable> = this._selection.asObservable(); - @state() - private _sortingDesc = false; - - @state() - private _users: Array = []; - - protected _usersContext?: UmbEditorViewUsersElement; - protected _usersSubscription?: Subscription; - protected _selectionSubscription?: Subscription; - - connectedCallback(): void { - super.connectedCallback(); - - 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._columns = [ - { - name: 'Name', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => b.name.localeCompare(a.name)) - : [...items].sort((a, b) => a.name.localeCompare(b.name)); - }, - }, - { - name: 'User group', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => b.name.localeCompare(a.name)) - : [...items].sort((a, b) => a.name.localeCompare(b.name)); - }, - }, - { - name: 'Last login', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => +new Date(b.lastLogin) - +new Date(a.lastLogin)) - : [...items].sort((a, b) => +new Date(a.lastLogin) - +new Date(b.lastLogin)); - }, - }, - { - name: 'status', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => - b.status && a.status ? b.status.localeCompare(a.status) : (a.status ? 1 : 0) - (b.status ? 1 : 0) - ) - : [...items].sort((a, b) => - a.status && b.status ? a.status.localeCompare(b.status) : (b.status ? 1 : 0) - (a.status ? 1 : 0) - ); - }, - }, - ]; - } - - disconnectedCallback(): void { - super.disconnectedCallback(); - - this._usersSubscription?.unsubscribe(); - this._selectionSubscription?.unsubscribe(); - } - - private _selectAllHandler(event: Event) { - console.log('SELECT ALL NOT IMPLEMENTED'); - } - - private _selectRowHandler(user: UserItem) { - this._usersContext?.select(user.key); - } - - private _deselectRowHandler(user: UserItem) { - this._usersContext?.deselect(user.key); - } - - private _sortingHandler(column: TableColumn) { - this._sortingDesc = this._sortingColumn === column.name ? !this._sortingDesc : false; - this._sortingColumn = column.name; - this._users = column.sort(this._users, this._sortingDesc); - } - - private _isSelected(key: string) { - return this._selection.includes(key); - } - - renderHeaderCellTemplate(column: TableColumn) { - return html` - - - - `; - } - - protected renderRowTemplate = (user: UserItem) => { - if (!this._usersContext) return; - - const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); - - return html` this._usersContext?.select(user.key)} - @unselected=${() => this._usersContext?.deselect(user.key)}> - -
- -
-
- - - - ${user.userGroup} - ${user.lastLogin} - - ${user.status - ? html` ${user.status} ` - : nothing} - -
`; + private _IntersectionObserverOptions = { + root: this, + rootMargin: '0px', + threshold: 1.0, }; + constructor() { + super(); + + this.provideContext('umbUsersContext', this); + this.setupHeaderIntersectionObserver(); + } + + public setupHeaderIntersectionObserver() { + requestAnimationFrame(() => { + const el = this.shadowRoot?.querySelector('#sticky-top'); + + if (el) { + const options = { threshold: [1] }; + const callback = (entries: IntersectionObserverEntry[]) => + entries[0].target.classList.toggle('header-shadow', entries[0].intersectionRatio < 1); + const observer = new IntersectionObserver(callback, options); + + observer.observe(el); + } + }); + } + + public setSelection(value: Array) { + if (!value) return; + this._selection.next(value); + this.requestUpdate('selection'); + } + + public select(key: string) { + const selection = this._selection.getValue(); + this._selection.next([...selection, key]); + this.requestUpdate('selection'); + } + + public deselect(key: string) { + const selection = this._selection.getValue(); + this._selection.next(selection.filter((k) => k !== key)); + this.requestUpdate('selection'); + } + + public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { + switch (status.toLowerCase()) { + case 'invited': + case 'inactive': + return { look: 'primary', color: 'warning' }; + case 'active': + return { look: 'primary', color: 'positive' }; + case 'disabled': + return { look: 'primary', color: 'danger' }; + default: + return { look: 'secondary', color: 'default' }; + } + } + + private _toggleViewType() { + this._viewType = this._viewType === 'list' ? 'grid' : 'list'; + } + + private _renderViewType() { + switch (this._viewType) { + case 'list': + return html``; + case 'grid': + return html``; + default: + return html``; + } + } + + private _renderSelection() { + if (this._selection.getValue().length === 0) return nothing; + + return html``; + } + + @state() + private _routes: IRoute[] = [ + { + path: 'list', + component: () => import('./editor-view-users-table.element'), + }, + { + path: 'details/:key', + component: () => import('./editor-view-users-user-details.element'), + }, + ]; + render() { return html` - - - - - - - ${this._columns.map((column) => this.renderHeaderCellTemplate(column))} - - ${repeat(this._users, (item) => item.key, this.renderRowTemplate)} - +
+
+ + +
+ Status: All + Groups: All + Order by: Name (A-Z) + + + +
+
+ + ${this._renderSelection()} +
+ + + +
${this._renderViewType()}
`; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts index 5f93bae097..9fc07a1fc3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts @@ -3,8 +3,8 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; 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 UmbEditorViewUsersListElement, { UserItem } from './editor-view-users-list.element'; @customElement('umb-editor-view-users-selection') export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin(LitElement) { @@ -30,14 +30,14 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( @state() private _selection: Array = []; - protected _usersContext?: UmbEditorViewUsersElement; + protected _usersContext?: UmbEditorViewUsersListElement; protected _usersSubscription?: Subscription; protected _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersListElement) => { this._usersContext = usersContext; this._usersSubscription?.unsubscribe(); 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/editor-view-users-table.element.ts new file mode 100644 index 0000000000..f47c4a3dac --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-table.element.ts @@ -0,0 +1,227 @@ +import { css, html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import { repeat } from 'lit/directives/repeat.js'; +import { Subscription } from 'rxjs'; +import UmbEditorViewUsersListElement, { UserItem } from './editor-view-users-list.element'; + +interface TableColumn { + name: string; + sort: (items: Array, desc: boolean) => Array; +} + +@customElement('umb-editor-view-users-table') +export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + uui-table { + box-shadow: var(--uui-shadow-depth-1, 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)); + } + uui-table-row uui-checkbox { + display: none; + } + uui-table-row:hover uui-icon, + uui-table-row[select-only] uui-icon { + display: none; + } + uui-table-row:hover uui-checkbox, + uui-table-row[select-only] uui-checkbox { + display: inline-block; + } + uui-table-head-cell:hover { + --uui-symbol-sort-hover: 1; + } + uui-table-head-cell button { + padding: 0; + background-color: transparent; + color: inherit; + border: none; + cursor: pointer; + font-weight: inherit; + font-size: inherit; + display: inline-flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + `, + ]; + + @state() + private _columns: Array = []; + + @state() + private _selectionMode = false; + + @state() + private _selection: Array = []; + + @state() + private _sortingColumn: any = ''; + + @state() + private _sortingDesc = false; + + @state() + private _users: Array = []; + + protected _usersContext?: UmbEditorViewUsersListElement; + protected _usersSubscription?: Subscription; + protected _selectionSubscription?: Subscription; + + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersListElement) => { + 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._columns = [ + { + name: 'Name', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => b.name.localeCompare(a.name)) + : [...items].sort((a, b) => a.name.localeCompare(b.name)); + }, + }, + { + name: 'User group', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => b.name.localeCompare(a.name)) + : [...items].sort((a, b) => a.name.localeCompare(b.name)); + }, + }, + { + name: 'Last login', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => +new Date(b.lastLogin) - +new Date(a.lastLogin)) + : [...items].sort((a, b) => +new Date(a.lastLogin) - +new Date(b.lastLogin)); + }, + }, + { + name: 'status', + sort: (items: Array, desc: boolean) => { + return desc + ? [...items].sort((a, b) => + b.status && a.status ? b.status.localeCompare(a.status) : (a.status ? 1 : 0) - (b.status ? 1 : 0) + ) + : [...items].sort((a, b) => + a.status && b.status ? a.status.localeCompare(b.status) : (b.status ? 1 : 0) - (a.status ? 1 : 0) + ); + }, + }, + ]; + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this._usersSubscription?.unsubscribe(); + this._selectionSubscription?.unsubscribe(); + } + + private _selectAllHandler(event: Event) { + console.log('SELECT ALL NOT IMPLEMENTED'); + } + + private _selectRowHandler(user: UserItem) { + this._usersContext?.select(user.key); + } + + private _deselectRowHandler(user: UserItem) { + this._usersContext?.deselect(user.key); + } + + private _sortingHandler(column: TableColumn) { + this._sortingDesc = this._sortingColumn === column.name ? !this._sortingDesc : false; + this._sortingColumn = column.name; + this._users = column.sort(this._users, this._sortingDesc); + } + + private _isSelected(key: string) { + return this._selection.includes(key); + } + + renderHeaderCellTemplate(column: TableColumn) { + return html` + + + + `; + } + + protected renderRowTemplate = (user: UserItem) => { + if (!this._usersContext) return; + + const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); + + return html` this._usersContext?.select(user.key)} + @unselected=${() => this._usersContext?.deselect(user.key)}> + +
+ +
+
+ + + + ${user.userGroup} + ${user.lastLogin} + + ${user.status + ? html` ${user.status} ` + : nothing} + +
`; + }; + + render() { + return html` + + + + + + + ${this._columns.map((column) => this.renderHeaderCellTemplate(column))} + + ${repeat(this._users, (item) => item.key, this.renderRowTemplate)} + + `; + } +} + +export default UmbEditorViewUsersTableElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-users-table': UmbEditorViewUsersTableElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts new file mode 100644 index 0000000000..36179c6048 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -0,0 +1,21 @@ +import { css, html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; + +@customElement('umb-editor-view-users-user-details') +export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { + static styles = [UUITextStyles, css``]; + + render() { + return html`USER DETAILS `; + } +} + +export default UmbEditorViewUsersUserDetailsElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-users-user-details': UmbEditorViewUsersUserDetailsElement; + } +} 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 0fdce86bb6..7a889e5bdf 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 @@ -4,309 +4,30 @@ import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../../../core/context'; import { BehaviorSubject, Observable } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; -import './editor-view-users-list.element'; +import './editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; - -export type UsersViewType = 'list' | 'grid'; - -export interface UserItem { - key: string; - name: string; - userGroup: string; - lastLogin: string; - status?: string; -} +import './editor-view-users-user-details.element'; +import { IRoute } from 'router-slot'; @customElement('umb-editor-view-users') export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - #sticky-top { - position: sticky; - top: -1px; - z-index: 1; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0), 0 1px 2px rgba(0, 0, 0, 0); - transition: 250ms box-shadow ease-in-out; - } - - #sticky-top.header-shadow { - box-shadow: var(--uui-shadow-depth-2); - } - - #user-list-top-bar { - padding: var(--uui-size-space-4) var(--uui-size-space-6); - background-color: var(--uui-color-surface-alt); - display: flex; - justify-content: space-between; - white-space: nowrap; - gap: 16px; - align-items: center; - } - #user-list { - padding: var(--uui-size-space-6); - } - #input-search { - width: 100%; - } - `, - ]; - - private tempData = [ - { - key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', - name: 'Cecílie Bryon', - userGroup: 'Translators', - lastLogin: 'Fri, 23 April 2021', - status: 'Invited', - }, - { - key: '3179d0b2-eec2-4045-b86a-149e13b93e14', - name: 'Kathleen G. Smith', - userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', - status: 'Disabled', - }, - { - key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', - name: 'Adrian Andresen', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0207', - name: 'Lorenza Trentino', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0202', - name: 'John Doe', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0203', - name: 'Jane Doe', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0204', - name: 'John Smith', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0205', - name: 'Jane Smith', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0206', - name: 'Oliver Twist', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-b994-4e65-2330-b66c336d0207', - name: 'Olivia Doe', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0208', - name: 'Hans Hansen', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'a9b18a00-58f2-sjh2-bf60-48d33ab156db', - name: 'Brian Adams', - userGroup: 'Translators', - lastLogin: 'Fri, 23 April 2021', - status: 'Invited', - }, - { - key: '3179d0b2-eec2-4432-b86a-149e13b93e14', - name: 'Smith John', - userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', - status: 'Disabled', - }, - { - key: '1b1c9723-b845-4d9a-9ed2-b2f46c05fd72', - name: 'Reese Witherspoon', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-2f94-4e65-9330-b66c336d0207', - name: 'Denzel Washington', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e23-9330-b66c336d0202', - name: 'Leonardo DiCaprio', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-2394-4e65-9330-b66c336d0203', - name: 'Idris Elba', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b6u7336d0204', - name: 'Quentin Tarantino', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-b994-4e65-2330-c66c336d0205', - name: 'Tom Hanks', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af82a-b994-4b65-9330-b66c336d0206', - name: 'Oprah Winfrey', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-b994-4e65-2s30-b66b336d0207', - name: 'Pamela Anderson', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9930-b66c336d0l33t', - name: 'Keanu Reeves', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - ]; + static styles = [UUITextStyles, css``]; @state() - private _viewType: UsersViewType = 'grid'; - - private _users: BehaviorSubject> = new BehaviorSubject(this.tempData); - public readonly users: Observable> = this._users.asObservable(); - - private _selection: BehaviorSubject> = new BehaviorSubject(>[]); - public readonly selection: Observable> = this._selection.asObservable(); - - private _IntersectionObserverOptions = { - root: this, - rootMargin: '0px', - threshold: 1.0, - }; - - constructor() { - super(); - - this.provideContext('umbUsersContext', this); - this.setupHeaderIntersectionObserver(); - } - - public setupHeaderIntersectionObserver() { - requestAnimationFrame(() => { - const el = this.shadowRoot?.querySelector('#sticky-top'); - - if (el) { - const options = { threshold: [1] }; - const callback = (entries: IntersectionObserverEntry[]) => - entries[0].target.classList.toggle('header-shadow', entries[0].intersectionRatio < 1); - const observer = new IntersectionObserver(callback, options); - - observer.observe(el); - } - }); - } - - public setSelection(value: Array) { - if (!value) return; - this._selection.next(value); - this.requestUpdate('selection'); - } - - public select(key: string) { - const selection = this._selection.getValue(); - this._selection.next([...selection, key]); - this.requestUpdate('selection'); - } - - public deselect(key: string) { - const selection = this._selection.getValue(); - this._selection.next(selection.filter((k) => k !== key)); - this.requestUpdate('selection'); - } - - public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { - switch (status.toLowerCase()) { - case 'invited': - case 'inactive': - return { look: 'primary', color: 'warning' }; - case 'active': - return { look: 'primary', color: 'positive' }; - case 'disabled': - return { look: 'primary', color: 'danger' }; - default: - return { look: 'secondary', color: 'default' }; - } - } - - private _toggleViewType() { - this._viewType = this._viewType === 'list' ? 'grid' : 'list'; - } - - private _renderViewType() { - switch (this._viewType) { - case 'list': - return html``; - case 'grid': - return html``; - default: - return html``; - } - } - - private _renderSelection() { - if (this._selection.getValue().length === 0) return nothing; - - return html``; - } + private _routes: IRoute[] = [ + { + path: 'list', + component: () => import('./editor-view-users-list.element'), + }, + { + path: 'details/:key', + component: () => import('./editor-view-users-user-details.element'), + }, + ]; render() { - return html` -
-
- - -
- Status: All - Groups: All - Order by: Name (A-Z) - - - -
-
- - ${this._renderSelection()} -
- - -
${this._renderViewType()}
- `; + return html` `; } } From 8cd66dccb28ef420d2b37a89b46aa5fc768a1d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 15:05:40 +0200 Subject: [PATCH 15/98] moved router and context provider to top level --- .../users/editor-view-users-list.element.ts | 220 +++--------------- .../editor-view-users-selection.element.ts | 10 +- .../users/editor-view-users-table.element.ts | 14 +- .../views/users/editor-view-users.element.ts | 203 +++++++++++++++- 4 files changed, 236 insertions(+), 211 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index ba96d2597b..1287d5a0e8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -2,25 +2,18 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin, 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 './editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import { IRoute } from 'router-slot'; +import UmbEditorViewUsersElement from './editor-view-users.element'; export type UsersViewType = 'list' | 'grid'; -export interface UserItem { - key: string; - name: string; - userGroup: string; - lastLogin: string; - status?: string; -} - @customElement('umb-editor-view-users-list') -export class UmbEditorViewUsersListElement extends UmbContextProviderMixin(LitElement) { +export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitElement) { static styles = [ UUITextStyles, css` @@ -55,167 +48,40 @@ export class UmbEditorViewUsersListElement extends UmbContextProviderMixin(LitEl `, ]; - private tempData = [ - { - key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', - name: 'Cecílie Bryon', - userGroup: 'Translators', - lastLogin: 'Fri, 23 April 2021', - status: 'Invited', - }, - { - key: '3179d0b2-eec2-4045-b86a-149e13b93e14', - name: 'Kathleen G. Smith', - userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', - status: 'Disabled', - }, - { - key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', - name: 'Adrian Andresen', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0207', - name: 'Lorenza Trentino', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0202', - name: 'John Doe', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0203', - name: 'Jane Doe', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0204', - name: 'John Smith', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0205', - name: 'Jane Smith', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0206', - name: 'Oliver Twist', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-b994-4e65-2330-b66c336d0207', - name: 'Olivia Doe', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0208', - name: 'Hans Hansen', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'a9b18a00-58f2-sjh2-bf60-48d33ab156db', - name: 'Brian Adams', - userGroup: 'Translators', - lastLogin: 'Fri, 23 April 2021', - status: 'Invited', - }, - { - key: '3179d0b2-eec2-4432-b86a-149e13b93e14', - name: 'Smith John', - userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', - status: 'Disabled', - }, - { - key: '1b1c9723-b845-4d9a-9ed2-b2f46c05fd72', - name: 'Reese Witherspoon', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-2f94-4e65-9330-b66c336d0207', - name: 'Denzel Washington', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e23-9330-b66c336d0202', - name: 'Leonardo DiCaprio', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-2394-4e65-9330-b66c336d0203', - name: 'Idris Elba', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9330-b6u7336d0204', - name: 'Quentin Tarantino', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - { - key: 'b75af81a-b994-4e65-2330-c66c336d0205', - name: 'Tom Hanks', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af82a-b994-4b65-9330-b66c336d0206', - name: 'Oprah Winfrey', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - }, - { - key: 'b75af81a-b994-4e65-2s30-b66b336d0207', - name: 'Pamela Anderson', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - }, - { - key: 'b75af81a-b994-4e65-9930-b66c336d0l33t', - name: 'Keanu Reeves', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - }, - ]; - @state() private _viewType: UsersViewType = 'grid'; - private _users: BehaviorSubject> = new BehaviorSubject(this.tempData); - public readonly users: Observable> = this._users.asObservable(); + @state() + private _selection: Array = []; - private _selection: BehaviorSubject> = new BehaviorSubject(>[]); - public readonly selection: Observable> = this._selection.asObservable(); - - private _IntersectionObserverOptions = { - root: this, - rootMargin: '0px', - threshold: 1.0, - }; + private _usersContext?: UmbEditorViewUsersElement; + private _selectionSubscription?: Subscription; constructor() { super(); - this.provideContext('umbUsersContext', this); this.setupHeaderIntersectionObserver(); } + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this._usersContext = usersContext; + + this._selectionSubscription?.unsubscribe(); + this._selectionSubscription = this._usersContext?.selection.subscribe((selection: Array) => { + this._selection = selection; + }); + }); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this._selectionSubscription?.unsubscribe(); + } + public setupHeaderIntersectionObserver() { requestAnimationFrame(() => { const el = this.shadowRoot?.querySelector('#sticky-top'); @@ -231,38 +97,6 @@ export class UmbEditorViewUsersListElement extends UmbContextProviderMixin(LitEl }); } - public setSelection(value: Array) { - if (!value) return; - this._selection.next(value); - this.requestUpdate('selection'); - } - - public select(key: string) { - const selection = this._selection.getValue(); - this._selection.next([...selection, key]); - this.requestUpdate('selection'); - } - - public deselect(key: string) { - const selection = this._selection.getValue(); - this._selection.next(selection.filter((k) => k !== key)); - this.requestUpdate('selection'); - } - - public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { - switch (status.toLowerCase()) { - case 'invited': - case 'inactive': - return { look: 'primary', color: 'warning' }; - case 'active': - return { look: 'primary', color: 'positive' }; - case 'disabled': - return { look: 'primary', color: 'danger' }; - default: - return { look: 'secondary', color: 'default' }; - } - } - private _toggleViewType() { this._viewType = this._viewType === 'list' ? 'grid' : 'list'; } @@ -279,7 +113,7 @@ export class UmbEditorViewUsersListElement extends UmbContextProviderMixin(LitEl } private _renderSelection() { - if (this._selection.getValue().length === 0) return nothing; + if (this._selection.length === 0) return nothing; return html``; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts index 9fc07a1fc3..0b70e41c8a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts @@ -4,7 +4,7 @@ import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; -import UmbEditorViewUsersListElement, { UserItem } from './editor-view-users-list.element'; +import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; @customElement('umb-editor-view-users-selection') export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin(LitElement) { @@ -30,14 +30,14 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( @state() private _selection: Array = []; - protected _usersContext?: UmbEditorViewUsersListElement; - protected _usersSubscription?: Subscription; - protected _selectionSubscription?: Subscription; + private _usersContext?: UmbEditorViewUsersElement; + private _usersSubscription?: Subscription; + private _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersListElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { this._usersContext = usersContext; this._usersSubscription?.unsubscribe(); 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/editor-view-users-table.element.ts index f47c4a3dac..711798f375 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/editor-view-users-table.element.ts @@ -4,7 +4,7 @@ import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; -import UmbEditorViewUsersListElement, { UserItem } from './editor-view-users-list.element'; +import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; interface TableColumn { name: string; @@ -67,14 +67,14 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE @state() private _users: Array = []; - protected _usersContext?: UmbEditorViewUsersListElement; - protected _usersSubscription?: Subscription; - protected _selectionSubscription?: Subscription; + private _usersContext?: UmbEditorViewUsersElement; + private _usersSubscription?: Subscription; + private _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersListElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { this._usersContext = usersContext; this._usersSubscription?.unsubscribe(); @@ -177,8 +177,8 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE selectable ?select-only=${this._selectionMode} ?selected=${this._isSelected(user.key)} - @selected=${() => this._usersContext?.select(user.key)} - @unselected=${() => this._usersContext?.deselect(user.key)}> + @selected=${() => this._selectRowHandler(user)} + @unselected=${() => this._deselectRowHandler(user)}>
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 7a889e5bdf..96cdae7573 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 @@ -1,14 +1,22 @@ -import { css, html, LitElement, nothing } from 'lit'; +import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../../../core/context'; +import { customElement, state } from 'lit/decorators.js'; +import { UmbContextProviderMixin } from '../../../../../core/context'; import { BehaviorSubject, Observable } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; +import { IRoute } from 'router-slot'; import './editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-user-details.element'; -import { IRoute } from 'router-slot'; + +export interface UserItem { + key: string; + name: string; + userGroup: string; + lastLogin: string; + status?: string; +} @customElement('umb-editor-view-users') export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElement) { @@ -17,15 +25,198 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen @state() private _routes: IRoute[] = [ { - path: 'list', + path: '/', component: () => import('./editor-view-users-list.element'), }, { - path: 'details/:key', + path: '/:key', component: () => import('./editor-view-users-user-details.element'), }, ]; + private tempData = [ + { + key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', + name: 'Cecílie Bryon', + userGroup: 'Translators', + lastLogin: 'Fri, 23 April 2021', + status: 'Invited', + }, + { + key: '3179d0b2-eec2-4045-b86a-149e13b93e14', + name: 'Kathleen G. Smith', + userGroup: 'Editors', + lastLogin: 'Tue, 6 June 2021', + status: 'Disabled', + }, + { + key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', + name: 'Adrian Andresen', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0207', + name: 'Lorenza Trentino', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0202', + name: 'John Doe', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0203', + name: 'Jane Doe', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0204', + name: 'John Smith', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0205', + name: 'Jane Smith', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0206', + name: 'Oliver Twist', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-2330-b66c336d0207', + name: 'Olivia Doe', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b66c336d0208', + name: 'Hans Hansen', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'a9b18a00-58f2-sjh2-bf60-48d33ab156db', + name: 'Brian Adams', + userGroup: 'Translators', + lastLogin: 'Fri, 23 April 2021', + status: 'Invited', + }, + { + key: '3179d0b2-eec2-4432-b86a-149e13b93e14', + name: 'Smith John', + userGroup: 'Editors', + lastLogin: 'Tue, 6 June 2021', + status: 'Disabled', + }, + { + key: '1b1c9723-b845-4d9a-9ed2-b2f46c05fd72', + name: 'Reese Witherspoon', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-2f94-4e65-9330-b66c336d0207', + name: 'Denzel Washington', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e23-9330-b66c336d0202', + name: 'Leonardo DiCaprio', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-2394-4e65-9330-b66c336d0203', + name: 'Idris Elba', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9330-b6u7336d0204', + name: 'Quentin Tarantino', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + { + key: 'b75af81a-b994-4e65-2330-c66c336d0205', + name: 'Tom Hanks', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af82a-b994-4b65-9330-b66c336d0206', + name: 'Oprah Winfrey', + userGroup: 'Translators', + lastLogin: 'Tue, 11 December 2021', + }, + { + key: 'b75af81a-b994-4e65-2s30-b66b336d0207', + name: 'Pamela Anderson', + userGroup: 'Editors', + lastLogin: 'Fri, 13 April 2022', + }, + { + key: 'b75af81a-b994-4e65-9930-b66c336d0l33t', + name: 'Keanu Reeves', + userGroup: 'Administrators', + lastLogin: 'Mon, 15 November 2021', + }, + ]; + + private _users: BehaviorSubject> = new BehaviorSubject(this.tempData); + public readonly users: Observable> = this._users.asObservable(); + + private _selection: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly selection: Observable> = this._selection.asObservable(); + + constructor() { + super(); + + this.provideContext('umbUsersContext', this); + } + + public setSelection(value: Array) { + if (!value) return; + this._selection.next(value); + this.requestUpdate('selection'); + } + + public select(key: string) { + const selection = this._selection.getValue(); + this._selection.next([...selection, key]); + this.requestUpdate('selection'); + } + + public deselect(key: string) { + const selection = this._selection.getValue(); + this._selection.next(selection.filter((k) => k !== key)); + this.requestUpdate('selection'); + } + + public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { + switch (status.toLowerCase()) { + case 'invited': + case 'inactive': + return { look: 'primary', color: 'warning' }; + case 'active': + return { look: 'primary', color: 'positive' }; + case 'disabled': + return { look: 'primary', color: 'danger' }; + default: + return { look: 'secondary', color: 'default' }; + } + } + render() { return html` `; } From b13916d502e738147eb2a6ca5fab5123bd2dfecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 15:06:37 +0200 Subject: [PATCH 16/98] cleanup --- .../users/views/users/editor-view-users-list.element.ts | 7 +++---- .../views/users/editor-view-users-selection.element.ts | 5 ++--- .../users/views/users/editor-view-users-table.element.ts | 2 +- .../views/users/editor-view-users-user-details.element.ts | 4 ++-- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index 1287d5a0e8..837db5f441 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -1,9 +1,8 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../../../core/context'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; +import { customElement, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import { Subscription } from 'rxjs'; import './editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts index 0b70e41c8a..09b8164129 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts @@ -1,8 +1,7 @@ -import { css, html, LitElement, nothing } from 'lit'; +import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; +import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; 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/editor-view-users-table.element.ts index 711798f375..17c285826a 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/editor-view-users-table.element.ts @@ -1,6 +1,6 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; +import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 36179c6048..766bf11e5a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -1,6 +1,6 @@ -import { css, html, LitElement, nothing } from 'lit'; +import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; +import { customElement } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; @customElement('umb-editor-view-users-user-details') From f6654595e5b73557c492fa71fde917c3a23e9441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 15:25:02 +0200 Subject: [PATCH 17/98] get user from url and card open --- .../users/editor-view-users-grid.element.ts | 18 +++++++- .../editor-view-users-user-details.element.ts | 42 ++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) 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/editor-view-users-grid.element.ts index a4d3d8d18a..cc65027cce 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/editor-view-users-grid.element.ts @@ -66,6 +66,19 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl return this._selection.includes(key); } + //TODO How should we handle url stuff? + private _handleOpenCard(key: string) { + history.pushState(null, '', window.location.pathname + '/' + key); + } + + private _selectRowHandler(user: UserItem) { + this._usersContext?.select(user.key); + } + + private _deselectRowHandler(user: UserItem) { + this._usersContext?.deselect(user.key); + } + private renderUserCard(user: UserItem) { if (!this._usersContext) return; @@ -77,8 +90,9 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl selectable ?select-only=${this._selection.length > 0} ?selected=${this._isSelected(user.key)} - @selected=${() => this._usersContext?.select(user.key)} - @unselected=${() => this._usersContext?.deselect(user.key)}> + @open=${() => this._handleOpenCard(user.key)} + @selected=${() => this._selectRowHandler(user)} + @unselected=${() => this._deselectRowHandler(user)}> ${user.status ? html` ${user.status} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 766bf11e5a..3ad4c63aaf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -1,14 +1,52 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement } from 'lit/decorators.js'; +import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; +import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import { Subscription } from 'rxjs'; @customElement('umb-editor-view-users-user-details') export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { static styles = [UUITextStyles, css``]; + @state() + private _users: Array = []; + + @state() + private _user?: UserItem; + + protected _usersContext?: UmbEditorViewUsersElement; + protected _usersSubscription?: Subscription; + + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this._usersContext = usersContext; + + this._usersSubscription?.unsubscribe(); + this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { + this._users = users; + }); + }); + + // get user id from url path + const path = window.location.pathname; + const pathParts = path.split('/'); + const userKey = pathParts[pathParts.length - 1]; + + // get user from users array + this._user = this._users.find((user: UserItem) => user.key === userKey); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this._usersSubscription?.unsubscribe(); + } + render() { - return html`USER DETAILS `; + return html`${this._user?.name}`; } } From 7e563880e9540b86ee956b2d132491ba913f6bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 15:40:26 +0200 Subject: [PATCH 18/98] added user linking to table --- .../users/editor-view-users-grid.element.ts | 2 +- .../users/editor-view-users-list.element.ts | 9 ++++--- .../users/editor-view-users-table.element.ts | 26 ++++++++++++++++++- 3 files changed, 31 insertions(+), 6 deletions(-) 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/editor-view-users-grid.element.ts index cc65027cce..e449d9fee5 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/editor-view-users-grid.element.ts @@ -68,7 +68,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl //TODO How should we handle url stuff? private _handleOpenCard(key: string) { - history.pushState(null, '', window.location.pathname + '/' + key); + history.pushState(null, '', location.pathname + '/' + key); } private _selectRowHandler(user: UserItem) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index 837db5f441..92ab22ff16 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -134,12 +134,13 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl
- +
- Status: All - Groups: All - Order by: Name (A-Z) + Status: All + Groups: All + Order by: Name (A-Z) 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/editor-view-users-table.element.ts index 17c285826a..c09a5b660d 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/editor-view-users-table.element.ts @@ -46,6 +46,14 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE justify-content: space-between; width: 100%; } + .link-button { + font-weight: bold; + color: var(--uui-color-interactive); + } + .link-button:hover { + text-decoration: underline; + color: var(--uui-color-interactive-emphasis); + } `, ]; @@ -138,6 +146,12 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE console.log('SELECT ALL NOT IMPLEMENTED'); } + //TODO How should we handle url stuff? + private _handleOpenUser(event: Event, key: string) { + event.stopImmediatePropagation(); + history.pushState(null, '', location.pathname + '/' + key); + } + private _selectRowHandler(user: UserItem) { this._usersContext?.select(user.key); } @@ -186,7 +200,17 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
- ${user.name} +
${user.userGroup} From 2ba9a8cee210c473590ed94c61c192acd9214e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 21 Sep 2022 15:55:06 +0200 Subject: [PATCH 19/98] user details wip --- .../editor-view-users-user-details.element.ts | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 3ad4c63aaf..8bcfb49358 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -7,7 +7,38 @@ import { Subscription } from 'rxjs'; @customElement('umb-editor-view-users-user-details') export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { - static styles = [UUITextStyles, css``]; + static styles = [ + UUITextStyles, + css` + :host { + display: grid; + grid-template-columns: 1fr 350px; + gap: var(--uui-size-space-6); + padding: var(--uui-size-space-6); + } + + #left-column { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-4); + } + #right-column > uui-box > div { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-2); + } + uui-avatar { + width: 50%; + flex: 1 1 0%; + place-self: center; + } + hr { + border: none; + border-bottom: 1px solid var(--uui-color-divider); + width: 100%; + } + `, + ]; @state() private _users: Array = []; @@ -46,7 +77,26 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi } render() { - return html`${this._user?.name}`; + return html` +
+ +

Profile

+
+ +

Profile

+
+
+
+ +
+ + +
+ +
+
+
+ `; } } From 839631a53df1807cfbb6f32e80bbc588390d175a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Thu, 29 Sep 2022 14:40:17 +0200 Subject: [PATCH 20/98] merge --- .../users/editor-view-users-list.element.ts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index 92ab22ff16..b14b1c8d3a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -8,6 +8,10 @@ import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import { IRoute } from 'router-slot'; import UmbEditorViewUsersElement from './editor-view-users.element'; +<<<<<<< Updated upstream +======= +import { UUIPopoverElement } from '@umbraco-ui/uui'; +>>>>>>> Stashed changes export type UsersViewType = 'list' | 'grid'; @@ -44,6 +48,24 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl #input-search { width: 100%; } +<<<<<<< Updated upstream +======= + + uui-popover { + width: unset; + } + + .filter-dropdown { + display: flex; + gap: 8px; + flex-direction: column; + background-color: var(--uui-color-surface); + padding: var(--uui-size-space-4); + border-radius: var(--uui-size-border-radius); + box-shadow: var(--uui-shadow-depth-2); + width: fit-content; + } +>>>>>>> Stashed changes `, ]; @@ -129,6 +151,18 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl }, ]; +<<<<<<< Updated upstream +======= + private _handleTogglePopover(event: PointerEvent) { + const composedPath = event.composedPath(); + + const popover = composedPath.find((el) => el instanceof UUIPopoverElement) as UUIPopoverElement; + if (popover) { + popover.open = !popover.open; + } + } + +>>>>>>> Stashed changes render() { return html`
@@ -136,9 +170,45 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl
+<<<<<<< Updated upstream Status: All Groups: All Order by: Name (A-Z) +======= + + + Status: All + +
+ + + + +
+
+ + + Groups: All + +
+ + + + +
+
+ + + Order by: Name (A-Z) + +
+ + + + +
+
+>>>>>>> Stashed changes Date: Thu, 29 Sep 2022 14:43:28 +0200 Subject: [PATCH 21/98] merge fix --- .../users/editor-view-users-list.element.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index b14b1c8d3a..f55197e83c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -8,13 +8,9 @@ import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import { IRoute } from 'router-slot'; import UmbEditorViewUsersElement from './editor-view-users.element'; -<<<<<<< Updated upstream -======= import { UUIPopoverElement } from '@umbraco-ui/uui'; ->>>>>>> Stashed changes export type UsersViewType = 'list' | 'grid'; - @customElement('umb-editor-view-users-list') export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitElement) { static styles = [ @@ -48,8 +44,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl #input-search { width: 100%; } -<<<<<<< Updated upstream -======= uui-popover { width: unset; @@ -65,7 +59,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl box-shadow: var(--uui-shadow-depth-2); width: fit-content; } ->>>>>>> Stashed changes `, ]; @@ -151,8 +144,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl }, ]; -<<<<<<< Updated upstream -======= private _handleTogglePopover(event: PointerEvent) { const composedPath = event.composedPath(); @@ -162,7 +153,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl } } ->>>>>>> Stashed changes render() { return html`
@@ -170,11 +160,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl
-<<<<<<< Updated upstream - Status: All - Groups: All - Order by: Name (A-Z) -======= Status: All @@ -208,7 +193,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl
->>>>>>> Stashed changes Date: Thu, 29 Sep 2022 16:31:59 +0200 Subject: [PATCH 22/98] added email and language --- .../editor-view-users-user-details.element.ts | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 8bcfb49358..5d5f0031c2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -37,6 +37,12 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi border-bottom: 1px solid var(--uui-color-divider); width: 100%; } + uui-input { + width: 100%; + } + .faded-text { + color: var(--uui-color-text-alt); + } `, ]; @@ -49,6 +55,14 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi protected _usersContext?: UmbEditorViewUsersElement; protected _usersSubscription?: Subscription; + private _languages = [ + { name: 'English', value: 'en', selected: true }, + { name: 'Dutch', value: 'nl' }, + { name: 'French', value: 'fr' }, + { name: 'German', value: 'de' }, + { name: 'Spanish', value: 'es' }, + ]; + connectedCallback(): void { super.connectedCallback(); @@ -80,10 +94,22 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi return html`
-

Profile

+
Profile
+ + Email + + + + Language + +
-

Profile

+
Assign access
+
+ Groups +
Add groups to assign access and permissions
+
From c9d80ae81f0e4077a137b0dd12d3ac1424d89e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 09:49:05 +0200 Subject: [PATCH 23/98] added status toggle --- .../editor-view-users-user-details.element.ts | 34 ++++++++++++++-- .../views/users/editor-view-users.element.ts | 40 ++++++++++++++++--- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 5d5f0031c2..831d87512a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -1,4 +1,4 @@ -import { css, html, LitElement } from 'lit'; +import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; @@ -43,6 +43,9 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi .faded-text { color: var(--uui-color-text-alt); } + uui-tag { + width: fit-content; + } `, ]; @@ -52,6 +55,8 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi @state() private _user?: UserItem; + private _userKey = ''; + protected _usersContext?: UmbEditorViewUsersElement; protected _usersSubscription?: Subscription; @@ -72,16 +77,17 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi this._usersSubscription?.unsubscribe(); this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { this._users = users; + this._user = this._users.find((user: UserItem) => user.key === this._userKey); }); }); // get user id from url path const path = window.location.pathname; const pathParts = path.split('/'); - const userKey = pathParts[pathParts.length - 1]; + this._userKey = pathParts[pathParts.length - 1]; // get user from users array - this._user = this._users.find((user: UserItem) => user.key === userKey); + this._user = this._users.find((user: UserItem) => user.key === this._userKey); } disconnectedCallback(): void { @@ -90,7 +96,18 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi this._usersSubscription?.unsubscribe(); } + private _updateUserStatus() { + if (!this._user) return; + + const newStatus = this._user.status === 'Disabled' ? 'Active' : 'Disabled'; + + this._usersContext?.updateUser({ key: this._user.key, status: newStatus }); + } + render() { + if (!this._user || !this._usersContext) return html`User not found`; + + const status = this._usersContext.getTagLookAndColor(this._user.status); return html`
@@ -118,7 +135,18 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi
+ ${this._user?.status !== 'Invited' + ? html` + + ` + : nothing} + Status: + ${this._user.status}
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 96cdae7573..820ead2193 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 @@ -15,7 +15,7 @@ export interface UserItem { name: string; userGroup: string; lastLogin: string; - status?: string; + status: string; } @customElement('umb-editor-view-users') @@ -40,68 +40,77 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen name: 'Cecílie Bryon', userGroup: 'Translators', lastLogin: 'Fri, 23 April 2021', - status: 'Invited', + status: 'Active', }, { key: '3179d0b2-eec2-4045-b86a-149e13b93e14', name: 'Kathleen G. Smith', userGroup: 'Editors', lastLogin: 'Tue, 6 June 2021', - status: 'Disabled', + status: 'Active', }, { key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', name: 'Adrian Andresen', userGroup: 'Administrators', lastLogin: 'Mon, 15 November 2021', + status: 'Active', }, { key: 'b75af81a-b994-4e65-9330-b66c336d0207', name: 'Lorenza Trentino', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Disabled', }, { key: 'b75af81a-b994-4e65-9330-b66c336d0202', name: 'John Doe', userGroup: 'Translators', lastLogin: 'Tue, 11 December 2021', + status: 'Active', }, { key: 'b75af81a-b994-4e65-9330-b66c336d0203', name: 'Jane Doe', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Invited', }, { key: 'b75af81a-b994-4e65-9330-b66c336d0204', name: 'John Smith', userGroup: 'Administrators', lastLogin: 'Mon, 15 November 2021', + status: 'Active', }, { key: 'b75af81a-b994-4e65-9330-b66c336d0205', name: 'Jane Smith', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Active', }, { key: 'b75af81a-b994-4e65-9330-b66c336d0206', name: 'Oliver Twist', userGroup: 'Translators', lastLogin: 'Tue, 11 December 2021', + status: 'Active', }, { key: 'b75af81a-b994-4e65-2330-b66c336d0207', name: 'Olivia Doe', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Inactive', }, { key: 'b75af81a-b994-4e65-9330-b66c336d0208', name: 'Hans Hansen', userGroup: 'Administrators', lastLogin: 'Mon, 15 November 2021', + status: 'Active', }, { key: 'a9b18a00-58f2-sjh2-bf60-48d33ab156db', @@ -115,61 +124,70 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen name: 'Smith John', userGroup: 'Editors', lastLogin: 'Tue, 6 June 2021', - status: 'Disabled', + status: 'Active', }, { key: '1b1c9723-b845-4d9a-9ed2-b2f46c05fd72', name: 'Reese Witherspoon', userGroup: 'Administrators', lastLogin: 'Mon, 15 November 2021', + status: 'Disabled', }, { key: 'b75af81a-2f94-4e65-9330-b66c336d0207', name: 'Denzel Washington', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Active', }, { key: 'b75af81a-b994-4e23-9330-b66c336d0202', name: 'Leonardo DiCaprio', userGroup: 'Translators', lastLogin: 'Tue, 11 December 2021', + status: 'Active', }, { key: 'b75af81a-2394-4e65-9330-b66c336d0203', name: 'Idris Elba', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Active', }, { key: 'b75af81a-b994-4e65-9330-b6u7336d0204', name: 'Quentin Tarantino', userGroup: 'Administrators', lastLogin: 'Mon, 15 November 2021', + status: 'Active', }, { key: 'b75af81a-b994-4e65-2330-c66c336d0205', name: 'Tom Hanks', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Active', }, { key: 'b75af82a-b994-4b65-9330-b66c336d0206', name: 'Oprah Winfrey', userGroup: 'Translators', lastLogin: 'Tue, 11 December 2021', + status: 'Active', }, { key: 'b75af81a-b994-4e65-2s30-b66b336d0207', name: 'Pamela Anderson', userGroup: 'Editors', lastLogin: 'Fri, 13 April 2022', + status: 'Active', }, { key: 'b75af81a-b994-4e65-9930-b66c336d0l33t', name: 'Keanu Reeves', userGroup: 'Administrators', lastLogin: 'Mon, 15 November 2021', + status: 'Active', }, ]; @@ -203,8 +221,18 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen this.requestUpdate('selection'); } - public getTagLookAndColor(status: string): { color: InterfaceColor; look: InterfaceLook } { - switch (status.toLowerCase()) { + 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 getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { + switch ((status || '').toLowerCase()) { case 'invited': case 'inactive': return { look: 'primary', color: 'warning' }; From 5f9e365c6e2ed4e5b185d52ab30b01c5c9ba9feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 10:04:11 +0200 Subject: [PATCH 24/98] added user info --- .../editor-view-users-user-details.element.ts | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 831d87512a..cab1a389a7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -46,6 +46,14 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi uui-tag { width: fit-content; } + #user-info { + display: flex; + gap: var(--uui-size-space-6); + } + #user-info > div { + display: flex; + flex-direction: column; + } `, ]; @@ -100,8 +108,10 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi if (!this._user) return; const newStatus = this._user.status === 'Disabled' ? 'Active' : 'Disabled'; + const newUser = this._user; + newUser.status = newStatus; - this._usersContext?.updateUser({ key: this._user.key, status: newStatus }); + this._usersContext?.updateUser(newUser); } render() { @@ -131,7 +141,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi
-
+

@@ -145,8 +155,45 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi ` : nothing} - Status: - ${this._user.status} +
+ Status: + ${this._user.status} +
+ ${this._user?.status === 'Invited' + ? html` + + + ` + : nothing} +
+ Last login: + ${this._user.lastLogin} +
+
+ Failed login attempts + NOT IMPLEMENTED +
+
+ Last lockout date: + NOT IMPLEMENTED +
+
+ Password last changed: + NOT IMPLEMENTED +
+
+ User created: + NOT IMPLEMENTED +
+
+ User last updated: + NOT IMPLEMENTED +
+
+ Id: + ${this._user.key} + NOT IMPLEMENTED +
From 21bd345b8f5bc9e2c0335c5d9624625623696cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 10:08:09 +0200 Subject: [PATCH 25/98] added user deletion --- .../users/editor-view-users-user-details.element.ts | 9 ++++++++- .../users/views/users/editor-view-users.element.ts | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index cab1a389a7..3c4bd5e63c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -114,6 +114,13 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi this._usersContext?.updateUser(newUser); } + private _deleteUser() { + if (!this._user) return; + + this._usersContext?.deleteUser(this._user.key); + history.back(); + } + render() { if (!this._user || !this._usersContext) return html`User not found`; @@ -154,7 +161,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi label="${this._user.status === 'Disabled' ? 'Enable' : 'Disable'}"> ` : nothing} - +
Status: ${this._user.status} 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 820ead2193..6cdd4d1804 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 @@ -231,6 +231,15 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen this.requestUpdate('users'); } + 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'); + } + public getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { switch ((status || '').toLowerCase()) { case 'invited': From 5059002e4a0dbcbfac1052bc2dc6f38197d12a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 10:28:26 +0200 Subject: [PATCH 26/98] added access and split render into two methods --- .../editor-view-users-user-details.element.ts | 198 +++++++++++------- 1 file changed, 118 insertions(+), 80 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 3c4bd5e63c..2fef9a5005 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -42,6 +42,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi } .faded-text { color: var(--uui-color-text-alt); + font-size: 0.8rem; } uui-tag { width: fit-content; @@ -54,6 +55,17 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi display: flex; flex-direction: column; } + .access-content { + margin-top: var(--uui-size-space-1); + margin-bottom: var(--uui-size-space-4); + display: flex; + align-items: center; + line-height: 1; + gap: var(--uui-size-space-3); + } + .access-content > span { + align-self: end; + } `, ]; @@ -118,92 +130,118 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi if (!this._user) return; this._usersContext?.deleteUser(this._user.key); - history.back(); + history.back(); //TODO Should redirect to users section + } + + private renderLeftColumn() { + if (!this._user) return nothing; + + return html` +
Profile
+ + Email + + + + Language + + +
+ +
Assign access
+
+ Groups +
Add groups to assign access and permissions
+
+
+ +
Access
+
+ Based on the assigned groups and start nodes, the user has access to the following nodes +
+ + Content +
+ + Content Root +
+ + Media +
+ + Media Root +
+
`; + } + + private renderRightColumn() { + if (!this._user || !this._usersContext) return nothing; + + const status = this._usersContext.getTagLookAndColor(this._user.status); + return html` +
+ + +
+ ${this._user?.status !== 'Invited' + ? html` + + ` + : nothing} + +
+ Status: + ${this._user.status} +
+ ${this._user?.status === 'Invited' + ? html` + + + ` + : nothing} +
+ Last login: + ${this._user.lastLogin} +
+
+ Failed login attempts + NOT IMPLEMENTED +
+
+ Last lockout date: + NOT IMPLEMENTED +
+
+ Password last changed: + NOT IMPLEMENTED +
+
+ User created: + NOT IMPLEMENTED +
+
+ User last updated: + NOT IMPLEMENTED +
+
+ Id: + ${this._user.key} + NOT IMPLEMENTED +
+
+
`; } render() { if (!this._user || !this._usersContext) return html`User not found`; - const status = this._usersContext.getTagLookAndColor(this._user.status); return html` -
- -
Profile
- - Email - - - - Language - - -
- -
Assign access
-
- Groups -
Add groups to assign access and permissions
-
-
-
-
- -
- - -
- ${this._user?.status !== 'Invited' - ? html` - - ` - : nothing} - -
- Status: - ${this._user.status} -
- ${this._user?.status === 'Invited' - ? html` - - - ` - : nothing} -
- Last login: - ${this._user.lastLogin} -
-
- Failed login attempts - NOT IMPLEMENTED -
-
- Last lockout date: - NOT IMPLEMENTED -
-
- Password last changed: - NOT IMPLEMENTED -
-
- User created: - NOT IMPLEMENTED -
-
- User last updated: - NOT IMPLEMENTED -
-
- Id: - ${this._user.key} - NOT IMPLEMENTED -
-
-
-
+
${this.renderLeftColumn()}
+
${this.renderRightColumn()}
`; } } From da48578882e247886c692652e01ac240c1424fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 11:16:22 +0200 Subject: [PATCH 27/98] updated mock data and implemented user info --- .../users/editor-view-users-grid.element.ts | 9 +- .../editor-view-users-user-details.element.ts | 57 +- .../views/users/editor-view-users.element.ts | 173 +-- .../editors/users/views/users/tempData.ts | 1368 +++++++++++++++++ 4 files changed, 1424 insertions(+), 183 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts 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/editor-view-users-grid.element.ts index e449d9fee5..5846edb92b 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/editor-view-users-grid.element.ts @@ -98,8 +98,13 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl ${user.status} ` : nothing} -
${user.userGroup}
- +
USER GROUPS NOT IMPLEMENTED
+ ${user.lastLoginDate + ? html`` + : html``} `; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 2fef9a5005..fc021e2dd0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -4,6 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; import { Subscription } from 'rxjs'; +import { tempData } from './tempData'; @customElement('umb-editor-view-users-user-details') export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { @@ -80,24 +81,30 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi protected _usersContext?: UmbEditorViewUsersElement; protected _usersSubscription?: Subscription; - private _languages = [ - { name: 'English', value: 'en', selected: true }, - { name: 'Dutch', value: 'nl' }, - { name: 'French', value: 'fr' }, - { name: 'German', value: 'de' }, - { name: 'Spanish', value: 'es' }, - ]; + private _languages = tempData //TODO Get languages from API instead of fakeData + .reduce((acc, curr) => { + if (!acc.includes(curr.language)) { + acc.push(curr.language); + } + return acc; + }, [] as Array) + .map((language) => { + return { + name: language, + value: language, + selected: false, + }; + }); connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { this._usersContext = usersContext; this._usersSubscription?.unsubscribe(); this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { this._users = users; - this._user = this._users.find((user: UserItem) => user.key === this._userKey); + this._initUser(); }); }); @@ -106,8 +113,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi const pathParts = path.split('/'); this._userKey = pathParts[pathParts.length - 1]; - // get user from users array - this._user = this._users.find((user: UserItem) => user.key === this._userKey); + this._initUser(); } disconnectedCallback(): void { @@ -116,6 +122,15 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi this._usersSubscription?.unsubscribe(); } + private _initUser() { + this._user = this._users.find((user: UserItem) => user.key === this._userKey); + + const index = this._languages.findIndex((language) => language.value === this._user?.language); + if (index !== -1) { + this._languages[index].selected = true; + } + } + private _updateUserStatus() { if (!this._user) return; @@ -138,11 +153,11 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi return html`
Profile
- + Email - + - + Language @@ -205,32 +220,32 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi : nothing}
Last login: - ${this._user.lastLogin} + ${this._user.lastLoginDate || `${this._user.name} has not logged in yet`}
Failed login attempts - NOT IMPLEMENTED + ${this._user.failedLoginAttempts}
Last lockout date: - NOT IMPLEMENTED + ${this._user.lastLockoutDate || `${this._user.name} has not been locked out`}
Password last changed: - NOT IMPLEMENTED + ${this._user.lastLoginDate || `${this._user.name} has not changed password`}
User created: - NOT IMPLEMENTED + ${this._user.createDate}
User last updated: - NOT IMPLEMENTED + ${this._user.updateDate}
Id: + ${this._user.id} ${this._user.key} - NOT IMPLEMENTED
`; 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 6cdd4d1804..33854a0c06 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 @@ -10,12 +10,22 @@ import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-user-details.element'; +import { tempData } from './tempData'; + export interface UserItem { + id: number; key: string; name: string; - userGroup: string; - lastLogin: string; + email: string; status: string; + language: string; + lastLoginDate?: string; + lastLockoutDate?: string; + lastPasswordChangeDate?: string; + updateDate: string; + createDate: string; + failedLoginAttempts: number; + userGroup?: string; //TODO Implement this } @customElement('umb-editor-view-users') @@ -34,164 +44,7 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen }, ]; - private tempData = [ - { - key: 'a9b18a00-58f2-420e-bf60-48d33ab156db', - name: 'Cecílie Bryon', - userGroup: 'Translators', - lastLogin: 'Fri, 23 April 2021', - status: 'Active', - }, - { - key: '3179d0b2-eec2-4045-b86a-149e13b93e14', - name: 'Kathleen G. Smith', - userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', - status: 'Active', - }, - { - key: '1b1c9733-b845-4d9a-9ed2-b2f46c05fd72', - name: 'Adrian Andresen', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0207', - name: 'Lorenza Trentino', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Disabled', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0202', - name: 'John Doe', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0203', - name: 'Jane Doe', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Invited', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0204', - name: 'John Smith', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0205', - name: 'Jane Smith', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0206', - name: 'Oliver Twist', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-2330-b66c336d0207', - name: 'Olivia Doe', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Inactive', - }, - { - key: 'b75af81a-b994-4e65-9330-b66c336d0208', - name: 'Hans Hansen', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - status: 'Active', - }, - { - key: 'a9b18a00-58f2-sjh2-bf60-48d33ab156db', - name: 'Brian Adams', - userGroup: 'Translators', - lastLogin: 'Fri, 23 April 2021', - status: 'Invited', - }, - { - key: '3179d0b2-eec2-4432-b86a-149e13b93e14', - name: 'Smith John', - userGroup: 'Editors', - lastLogin: 'Tue, 6 June 2021', - status: 'Active', - }, - { - key: '1b1c9723-b845-4d9a-9ed2-b2f46c05fd72', - name: 'Reese Witherspoon', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - status: 'Disabled', - }, - { - key: 'b75af81a-2f94-4e65-9330-b66c336d0207', - name: 'Denzel Washington', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e23-9330-b66c336d0202', - name: 'Leonardo DiCaprio', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - status: 'Active', - }, - { - key: 'b75af81a-2394-4e65-9330-b66c336d0203', - name: 'Idris Elba', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-9330-b6u7336d0204', - name: 'Quentin Tarantino', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-2330-c66c336d0205', - name: 'Tom Hanks', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Active', - }, - { - key: 'b75af82a-b994-4b65-9330-b66c336d0206', - name: 'Oprah Winfrey', - userGroup: 'Translators', - lastLogin: 'Tue, 11 December 2021', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-2s30-b66b336d0207', - name: 'Pamela Anderson', - userGroup: 'Editors', - lastLogin: 'Fri, 13 April 2022', - status: 'Active', - }, - { - key: 'b75af81a-b994-4e65-9930-b66c336d0l33t', - name: 'Keanu Reeves', - userGroup: 'Administrators', - lastLogin: 'Mon, 15 November 2021', - status: 'Active', - }, - ]; - - private _users: BehaviorSubject> = new BehaviorSubject(this.tempData); + private _users: BehaviorSubject> = new BehaviorSubject(tempData); public readonly users: Observable> = this._users.asObservable(); private _selection: BehaviorSubject> = new BehaviorSubject(>[]); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts new file mode 100644 index 0000000000..f799aa5ad0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts @@ -0,0 +1,1368 @@ +import { UserItem } from './editor-view-users.element'; + +export const tempData: Array = [ + { + id: 1, + key: '50f184d4-71f3-4a43-b8be-7a36340fbd0d', + name: 'Nat Linnane', + email: 'nlinnane0@fda.gov', + language: 'Greek', + status: 'Inactive', + lastLoginDate: '9/11/2022', + lastLockoutDate: '5/31/2022', + lastPasswordChangeDate: '1/10/2022', + updateDate: '8/27/2022', + createDate: '9/19/2022', + failedLoginAttempts: 52, + }, + { + id: 2, + key: '7c9c5510-a7b6-43fd-a2d1-51de0009eabf', + name: 'Tyrus Hows', + email: 'thows1@hatena.ne.jp', + language: 'Gagauz', + status: 'Inactive', + lastLoginDate: '9/1/2022', + lastLockoutDate: '2/9/2022', + lastPasswordChangeDate: '8/22/2022', + updateDate: '12/2/2021', + createDate: '9/17/2022', + failedLoginAttempts: 717, + }, + { + id: 3, + key: 'fa3cca42-3b65-4fce-9e9b-5b09ca44f536', + name: 'Nisse Grattan', + email: 'ngrattan2@alexa.com', + language: 'Tok Pisin', + status: 'Active', + lastLoginDate: '3/22/2022', + lastLockoutDate: '12/2/2021', + lastPasswordChangeDate: '5/28/2022', + updateDate: '9/4/2022', + createDate: '8/7/2022', + failedLoginAttempts: 873, + }, + { + id: 4, + key: '381383ef-8d81-455c-bcbc-5e95a5cdc897', + name: 'Thain Rainville', + email: 'trainville3@merriam-webster.com', + language: 'Tajik', + status: 'Active', + lastLoginDate: '2/28/2022', + lastLockoutDate: '1/6/2022', + lastPasswordChangeDate: '7/1/2022', + updateDate: '9/14/2022', + createDate: '2/20/2022', + failedLoginAttempts: 786, + }, + { + id: 5, + key: 'e3dcaf95-7d55-42e6-a023-ce179523bf48', + name: 'Perren Balsdon', + email: 'pbalsdon4@ezinearticles.com', + language: 'Somali', + status: 'Active', + lastLoginDate: '5/6/2022', + lastLockoutDate: '11/12/2021', + lastPasswordChangeDate: '11/10/2021', + updateDate: '5/8/2022', + createDate: '1/12/2022', + failedLoginAttempts: 884, + }, + { + id: 6, + key: '05d0356e-051f-4d00-8b56-24667deab75d', + name: 'Athene Bilborough', + email: 'abilborough5@princeton.edu', + language: 'Tetum', + status: 'Active', + lastLoginDate: '3/11/2022', + lastLockoutDate: '7/7/2022', + lastPasswordChangeDate: '3/8/2022', + updateDate: '12/31/2021', + createDate: '10/2/2022', + failedLoginAttempts: 527, + }, + { + id: 7, + key: 'ac906ed0-d8e0-4ca5-8f03-d817ce31fb7e', + name: 'Carline Sharp', + email: 'csharp6@com.com', + language: 'Portuguese', + status: 'Inactive', + lastLoginDate: '3/6/2022', + lastLockoutDate: '5/20/2022', + lastPasswordChangeDate: '10/9/2021', + updateDate: '1/19/2022', + createDate: '7/3/2022', + failedLoginAttempts: 324, + }, + { + id: 8, + key: '6e34346d-639e-4538-a2cc-9a8a6ba40545', + name: 'Tansy Hanna', + email: 'thanna7@google.pl', + language: 'Papiamento', + status: 'Active', + lastLoginDate: '9/10/2022', + lastLockoutDate: '10/28/2021', + lastPasswordChangeDate: '2/26/2022', + updateDate: '3/12/2022', + createDate: '3/6/2022', + failedLoginAttempts: 937, + }, + { + id: 9, + key: '978c1d59-0814-404d-a4c4-b5abceb4b1b6', + name: 'Heidie Mohan', + email: 'hmohan8@google.co.jp', + language: 'Montenegrin', + status: 'Active', + lastLoginDate: '6/16/2022', + lastLockoutDate: '3/2/2022', + lastPasswordChangeDate: '4/14/2022', + updateDate: '1/30/2022', + createDate: '12/13/2021', + failedLoginAttempts: 804, + }, + { + id: 10, + key: '98d36a68-9b74-435f-8790-d177726f6fed', + name: 'Alden Blaschke', + email: 'ablaschke9@marketwatch.com', + language: 'Mongolian', + status: 'Inactive', + lastLoginDate: '6/27/2022', + lastLockoutDate: '4/16/2022', + lastPasswordChangeDate: '12/31/2021', + updateDate: '4/9/2022', + createDate: '6/18/2022', + failedLoginAttempts: 458, + }, + { + id: 11, + key: 'bf6b7fbe-d3e7-4ca8-9b6d-7daca03c2411', + name: 'Hollis Rouf', + email: 'hroufa@irs.gov', + language: 'Papiamento', + status: 'Inactive', + updateDate: '9/11/2022', + createDate: '6/18/2022', + failedLoginAttempts: 532, + }, + { + id: 12, + key: 'cf1d90af-5b77-4e00-98be-145214443c24', + name: 'Neils Janiak', + email: 'njaniakb@indiatimes.com', + language: 'Aymara', + status: 'Inactive', + updateDate: '11/7/2021', + createDate: '12/30/2021', + failedLoginAttempts: 800, + }, + { + id: 13, + key: '11e6ddc8-33e3-461b-8147-155eac339978', + name: 'Zarah Slaughter', + email: 'zslaughterc@storify.com', + language: 'Afrikaans', + status: 'Invited', + lastLoginDate: '1/1/2022', + lastLockoutDate: '5/4/2022', + lastPasswordChangeDate: '3/6/2022', + updateDate: '11/10/2021', + createDate: '8/1/2022', + failedLoginAttempts: 182, + }, + { + id: 14, + key: 'fb651643-3f2b-4b8e-ab96-a4f3fa15303a', + name: 'Elly Corbishley', + email: 'ecorbishleyd@hexun.com', + language: 'Kyrgyz', + status: 'Invited', + lastLoginDate: '6/3/2022', + lastLockoutDate: '4/4/2022', + lastPasswordChangeDate: '12/21/2021', + updateDate: '7/19/2022', + createDate: '5/12/2022', + failedLoginAttempts: 426, + }, + { + id: 15, + key: '1e329702-50d3-4176-b5db-9315ac6ac2a3', + name: 'Alisander Leupold', + email: 'aleupolde@webnode.com', + language: 'Nepali', + status: 'Inactive', + lastLoginDate: '1/4/2022', + lastLockoutDate: '9/15/2022', + lastPasswordChangeDate: '5/24/2022', + updateDate: '9/20/2022', + createDate: '3/15/2022', + failedLoginAttempts: 327, + }, + { + id: 16, + key: '1fead0fa-8d19-4153-abb0-980c18973d21', + name: 'Gennie Casaccia', + email: 'gcasacciaf@vkontakte.ru', + language: 'Catalan', + status: 'Active', + lastLoginDate: '4/11/2022', + lastLockoutDate: '3/17/2022', + lastPasswordChangeDate: '4/30/2022', + updateDate: '10/15/2021', + createDate: '2/14/2022', + failedLoginAttempts: 469, + }, + { + id: 17, + key: 'd273cd7c-cbd4-4535-83d1-921b9c1255b3', + name: 'Vaughan Longstreet', + email: 'vlongstreetg@jugem.jp', + language: 'Khmer', + status: 'Active', + lastLoginDate: '3/16/2022', + lastLockoutDate: '11/4/2021', + lastPasswordChangeDate: '3/23/2022', + updateDate: '7/18/2022', + createDate: '8/24/2022', + failedLoginAttempts: 737, + }, + { + id: 18, + key: 'e2f0b261-8900-41a3-b80c-6a54e55da4a7', + name: 'Vanda Scamadin', + email: 'vscamadinh@list-manage.com', + language: 'Telugu', + status: 'Inactive', + updateDate: '7/16/2022', + createDate: '1/5/2022', + failedLoginAttempts: 721, + }, + { + id: 19, + key: '54ff0b22-f419-47c0-a6a0-85a2ba43a300', + name: 'Reagen Nore', + email: 'rnorei@ning.com', + language: 'Kyrgyz', + status: 'Disabled', + lastLoginDate: '7/10/2022', + lastLockoutDate: '4/29/2022', + lastPasswordChangeDate: '10/26/2021', + updateDate: '12/17/2021', + createDate: '12/7/2021', + failedLoginAttempts: 351, + }, + { + id: 20, + key: '2b8dfa33-3dea-407e-8bcc-038f903ec37c', + name: 'Crosby Breens', + email: 'cbreensj@google.com.br', + language: 'Māori', + status: 'Disabled', + lastLoginDate: '8/7/2022', + lastLockoutDate: '5/23/2022', + lastPasswordChangeDate: '1/26/2022', + updateDate: '11/12/2021', + createDate: '5/24/2022', + failedLoginAttempts: 182, + }, + { + id: 21, + key: 'd0244fdc-4b68-4a71-a11b-7c047503ba38', + name: 'Felipe Finicj', + email: 'ffinicjk@economist.com', + language: 'Latvian', + status: 'Active', + lastLoginDate: '11/5/2021', + lastLockoutDate: '7/12/2022', + lastPasswordChangeDate: '4/12/2022', + updateDate: '12/16/2021', + createDate: '11/27/2021', + failedLoginAttempts: 212, + }, + { + id: 22, + key: '0934aae0-d565-4087-87ea-171c23ed012c', + name: 'Ash Shepstone', + email: 'ashepstonel@arizona.edu', + language: 'French', + status: 'Invited', + lastLoginDate: '1/18/2022', + lastLockoutDate: '10/17/2021', + lastPasswordChangeDate: '11/24/2021', + updateDate: '4/14/2022', + createDate: '6/5/2022', + failedLoginAttempts: 825, + }, + { + id: 23, + key: '1e244947-6fb6-4c34-8e22-87d14e1002b4', + name: 'Franni Plester', + email: 'fplesterm@nytimes.com', + language: 'Hungarian', + status: 'Active', + lastLoginDate: '7/27/2022', + lastLockoutDate: '8/17/2022', + lastPasswordChangeDate: '3/2/2022', + updateDate: '2/26/2022', + createDate: '7/18/2022', + failedLoginAttempts: 10, + }, + { + id: 24, + key: 'e6539e00-e4e7-4b09-a8ba-2bb5026b1842', + name: "Pearla O'Cooney", + email: 'pocooneyn@hugedomains.com', + language: 'Persian', + status: 'Disabled', + lastLoginDate: '3/29/2022', + lastLockoutDate: '3/18/2022', + lastPasswordChangeDate: '11/25/2021', + updateDate: '4/27/2022', + createDate: '11/10/2021', + failedLoginAttempts: 774, + }, + { + id: 25, + key: '2fa83b80-d938-472f-b4f0-a480c342bfdc', + name: 'Brittaney Linsay', + email: 'blinsayo@godaddy.com', + language: 'Amharic', + status: 'Disabled', + lastLoginDate: '9/21/2022', + lastLockoutDate: '1/28/2022', + lastPasswordChangeDate: '6/15/2022', + updateDate: '9/5/2022', + createDate: '9/6/2022', + failedLoginAttempts: 538, + }, + { + id: 26, + key: '2f40ba2c-36f4-45f9-94ff-2ee01be3a83f', + name: 'Terry McCorkell', + email: 'tmccorkellp@noaa.gov', + language: 'Dhivehi', + status: 'Active', + lastLoginDate: '7/23/2022', + lastLockoutDate: '7/24/2022', + lastPasswordChangeDate: '10/11/2021', + updateDate: '12/9/2021', + createDate: '12/10/2021', + failedLoginAttempts: 766, + }, + { + id: 27, + key: 'ff5c07f1-9628-4f1a-b416-46e9669ff261', + name: 'Amalea Barbour', + email: 'abarbourq@businesswire.com', + language: 'Catalan', + status: 'Invited', + lastLoginDate: '11/29/2021', + lastLockoutDate: '1/17/2022', + lastPasswordChangeDate: '2/2/2022', + updateDate: '5/18/2022', + createDate: '12/31/2021', + failedLoginAttempts: 903, + }, + { + id: 28, + key: '188a2fed-c3f1-4e2f-8e96-1a930f2dbeaa', + name: 'Bethena Grewe', + email: 'bgrewer@naver.com', + language: 'Haitian Creole', + status: 'Active', + lastLoginDate: '11/12/2021', + lastLockoutDate: '6/4/2022', + lastPasswordChangeDate: '8/25/2022', + updateDate: '2/23/2022', + createDate: '7/10/2022', + failedLoginAttempts: 348, + }, + { + id: 29, + key: '7651d063-7a6a-4ccf-a14f-a4123e4e0154', + name: 'Yorgos Ferroni', + email: 'yferronis@unblog.fr', + language: 'Afrikaans', + status: 'Inactive', + lastLoginDate: '7/13/2022', + lastLockoutDate: '3/16/2022', + lastPasswordChangeDate: '2/2/2022', + updateDate: '12/19/2021', + createDate: '5/2/2022', + failedLoginAttempts: 774, + }, + { + id: 30, + key: 'd8798556-96e1-4a4b-bc61-29baad622d1d', + name: 'Ivar Wisbey', + email: 'iwisbeyt@blogspot.com', + language: 'Lao', + status: 'Invited', + lastLoginDate: '6/15/2022', + lastLockoutDate: '3/4/2022', + lastPasswordChangeDate: '2/1/2022', + updateDate: '5/22/2022', + createDate: '5/6/2022', + failedLoginAttempts: 912, + }, + { + id: 31, + key: 'd0633a4e-7532-4a36-be2e-5befe8a46f66', + name: 'Casie Greatland', + email: 'cgreatlandu@google.cn', + language: 'Māori', + status: 'Disabled', + lastLoginDate: '12/19/2021', + lastLockoutDate: '10/15/2021', + lastPasswordChangeDate: '3/4/2022', + updateDate: '4/5/2022', + createDate: '6/6/2022', + failedLoginAttempts: 261, + }, + { + id: 32, + key: 'af784e2b-02bf-4d75-b199-0fa92bd1a12c', + name: 'Bat Dake', + email: 'bdakev@mapy.cz', + language: 'Armenian', + status: 'Invited', + lastLoginDate: '9/17/2022', + lastLockoutDate: '12/17/2021', + lastPasswordChangeDate: '3/10/2022', + updateDate: '7/13/2022', + createDate: '9/18/2022', + failedLoginAttempts: 589, + }, + { + id: 33, + key: '0a25512d-a7d2-429b-9e92-ebc3cae5ca19', + name: 'Chlo Skirven', + email: 'cskirvenw@histats.com', + language: 'Irish Gaelic', + status: 'Invited', + lastLoginDate: '6/22/2022', + lastLockoutDate: '6/7/2022', + lastPasswordChangeDate: '10/27/2021', + updateDate: '8/26/2022', + createDate: '10/31/2021', + failedLoginAttempts: 323, + }, + { + id: 34, + key: 'aadb0afb-b42e-4b84-9889-91f177b4f03f', + name: 'Delmer Porch', + email: 'dporchx@newyorker.com', + language: 'Punjabi', + status: 'Disabled', + lastLoginDate: '1/22/2022', + lastLockoutDate: '12/10/2021', + lastPasswordChangeDate: '5/24/2022', + updateDate: '8/28/2022', + createDate: '4/26/2022', + failedLoginAttempts: 300, + }, + { + id: 35, + key: 'd8f5122b-06c7-4253-9358-0ffb673fd6fa', + name: 'Gussi Lednor', + email: 'glednory@google.de', + language: 'Romanian', + status: 'Invited', + lastLoginDate: '6/1/2022', + lastLockoutDate: '11/17/2021', + lastPasswordChangeDate: '12/25/2021', + updateDate: '2/3/2022', + createDate: '6/9/2022', + failedLoginAttempts: 39, + }, + { + id: 36, + key: 'f81d21b6-c2bd-455c-9614-80c6f0ca7aba', + name: 'Tish Kubacki', + email: 'tkubackiz@gmpg.org', + language: 'Bosnian', + status: 'Disabled', + lastLoginDate: '11/29/2021', + lastLockoutDate: '11/28/2021', + lastPasswordChangeDate: '12/1/2021', + updateDate: '5/25/2022', + createDate: '8/6/2022', + failedLoginAttempts: 826, + }, + { + id: 37, + key: 'e5d98b85-6d9b-40b4-8237-cf98db0a6331', + name: 'Madelene Le Noury', + email: 'mle10@google.com.au', + language: 'Punjabi', + status: 'Invited', + lastLoginDate: '6/8/2022', + lastLockoutDate: '11/1/2021', + lastPasswordChangeDate: '8/19/2022', + updateDate: '8/29/2022', + createDate: '8/2/2022', + failedLoginAttempts: 619, + }, + { + id: 38, + key: 'bb96eeb6-2f4c-4eda-a277-91077b0219b0', + name: 'Alberta Headech', + email: 'aheadech11@diigo.com', + language: 'Kazakh', + status: 'Active', + lastLoginDate: '8/12/2022', + lastLockoutDate: '8/8/2022', + lastPasswordChangeDate: '10/29/2021', + updateDate: '2/4/2022', + createDate: '10/18/2021', + failedLoginAttempts: 191, + }, + { + id: 39, + key: '56a2d315-0cc5-4b0d-9ae3-8a7b7326e531', + name: 'Kenon Maybey', + email: 'kmaybey12@cdbaby.com', + language: 'Telugu', + status: 'Active', + lastLoginDate: '6/11/2022', + lastLockoutDate: '3/4/2022', + lastPasswordChangeDate: '5/5/2022', + updateDate: '10/21/2021', + createDate: '9/1/2022', + failedLoginAttempts: 45, + }, + { + id: 40, + key: 'dddae890-939e-48fd-89da-90631be9401f', + name: 'Brig Totterdill', + email: 'btotterdill13@telegraph.co.uk', + language: 'Tajik', + status: 'Disabled', + lastLoginDate: '8/11/2022', + lastLockoutDate: '3/31/2022', + lastPasswordChangeDate: '4/30/2022', + updateDate: '3/9/2022', + createDate: '3/23/2022', + failedLoginAttempts: 936, + }, + { + id: 41, + key: '96359df7-74a3-4eff-a729-40eac9a85fcc', + name: 'Kore Faragher', + email: 'kfaragher14@elpais.com', + language: 'Georgian', + status: 'Disabled', + lastLoginDate: '5/9/2022', + lastLockoutDate: '4/19/2022', + lastPasswordChangeDate: '7/26/2022', + updateDate: '10/17/2021', + createDate: '4/14/2022', + failedLoginAttempts: 843, + }, + { + id: 42, + key: 'af74ab26-81f2-4c51-8867-24acc7021c3c', + name: 'Benedicto Oda', + email: 'boda15@zimbio.com', + language: 'Hungarian', + status: 'Active', + lastLoginDate: '7/6/2022', + lastLockoutDate: '12/27/2021', + lastPasswordChangeDate: '9/15/2022', + updateDate: '1/13/2022', + createDate: '4/1/2022', + failedLoginAttempts: 262, + }, + { + id: 43, + key: '81648dc6-93d5-468d-8fac-fcdd0fb854cd', + name: 'Celinka Gyorffy', + email: 'cgyorffy16@godaddy.com', + language: 'Punjabi', + status: 'Inactive', + lastLoginDate: '7/15/2022', + lastLockoutDate: '5/24/2022', + lastPasswordChangeDate: '2/26/2022', + updateDate: '3/27/2022', + createDate: '8/3/2022', + failedLoginAttempts: 606, + }, + { + id: 44, + key: '1c8fd6b4-ccd4-4bc3-9cde-bb705e2618aa', + name: 'Arri Goretti', + email: 'agoretti17@pcworld.com', + language: 'Armenian', + status: 'Invited', + updateDate: '1/24/2022', + createDate: '7/11/2022', + failedLoginAttempts: 234, + }, + { + id: 45, + key: 'dd26e22b-bcab-449f-8a35-ae63be90e8c6', + name: 'Giffie Strattan', + email: 'gstrattan18@cisco.com', + language: 'Maltese', + status: 'Disabled', + lastLoginDate: '5/15/2022', + lastLockoutDate: '10/21/2021', + lastPasswordChangeDate: '2/2/2022', + updateDate: '4/12/2022', + createDate: '7/7/2022', + failedLoginAttempts: 62, + }, + { + id: 46, + key: '08b5e626-20e6-486d-a289-baa5b49ee360', + name: 'Aeriel Webling', + email: 'awebling19@usgs.gov', + language: 'Dutch', + status: 'Disabled', + lastLoginDate: '7/20/2022', + lastLockoutDate: '11/17/2021', + lastPasswordChangeDate: '8/22/2022', + updateDate: '8/31/2022', + createDate: '7/8/2022', + failedLoginAttempts: 34, + }, + { + id: 47, + key: '064981b2-f8e4-4a25-a16e-1fe3441ae0a0', + name: 'Roderic Heckle', + email: 'rheckle1a@pbs.org', + language: 'Dari', + status: 'Inactive', + updateDate: '7/31/2022', + createDate: '2/19/2022', + failedLoginAttempts: 279, + }, + { + id: 48, + key: '0c221634-03be-4e69-9399-350c1da61641', + name: 'Gonzalo Magister', + email: 'gmagister1b@jigsy.com', + language: 'Hungarian', + status: 'Disabled', + lastLoginDate: '8/21/2022', + lastLockoutDate: '6/23/2022', + lastPasswordChangeDate: '2/11/2022', + updateDate: '6/23/2022', + createDate: '8/1/2022', + failedLoginAttempts: 227, + }, + { + id: 49, + key: 'e26f1576-483e-4132-a25a-1eaddf63f40d', + name: 'Nickolai Landsborough', + email: 'nlandsborough1c@ask.com', + language: 'Guaraní', + status: 'Inactive', + lastLoginDate: '11/25/2021', + lastLockoutDate: '7/24/2022', + lastPasswordChangeDate: '4/20/2022', + updateDate: '8/17/2022', + createDate: '10/31/2021', + failedLoginAttempts: 85, + }, + { + id: 50, + key: '7032b5ea-467a-43aa-9a23-33f195cfa0a0', + name: 'Linn Early', + email: 'learly1d@msn.com', + language: 'Swedish', + status: 'Active', + lastLoginDate: '10/18/2021', + lastLockoutDate: '6/14/2022', + lastPasswordChangeDate: '4/10/2022', + updateDate: '10/26/2021', + createDate: '7/30/2022', + failedLoginAttempts: 198, + }, + { + id: 51, + key: '57bb4927-a7a7-4dc9-af48-f418f1c0fbc6', + name: 'Julianna Jakab', + email: 'jjakab1e@cbsnews.com', + language: 'Malay', + status: 'Active', + lastLoginDate: '3/22/2022', + lastLockoutDate: '6/2/2022', + lastPasswordChangeDate: '9/7/2022', + updateDate: '3/14/2022', + createDate: '10/19/2021', + failedLoginAttempts: 387, + }, + { + id: 52, + key: 'd5bb1d61-1201-43b8-b3df-2bd9b4bf1269', + name: 'Erick Hovell', + email: 'ehovell1f@ucoz.com', + language: 'New Zealand Sign Language', + status: 'Disabled', + updateDate: '11/30/2021', + createDate: '3/4/2022', + failedLoginAttempts: 150, + }, + { + id: 53, + key: '3e711421-bdc3-411e-909c-ba7230396266', + name: 'Bondon Berends', + email: 'bberends1g@si.edu', + language: 'Zulu', + status: 'Invited', + updateDate: '1/12/2022', + createDate: '4/22/2022', + failedLoginAttempts: 455, + }, + { + id: 54, + key: '2c0806e0-a7dc-46bd-a4c1-85a7d0799c56', + name: 'Rubie Palluschek', + email: 'rpalluschek1h@multiply.com', + language: 'Icelandic', + status: 'Disabled', + lastLoginDate: '7/18/2022', + lastLockoutDate: '1/14/2022', + lastPasswordChangeDate: '8/13/2022', + updateDate: '1/17/2022', + createDate: '4/9/2022', + failedLoginAttempts: 427, + }, + { + id: 55, + key: '5fc52879-4684-44b1-9c39-63fc47d85587', + name: 'Kass Gaisford', + email: 'kgaisford1i@tiny.cc', + language: 'Hiri Motu', + status: 'Invited', + lastLoginDate: '12/22/2021', + lastLockoutDate: '9/10/2022', + lastPasswordChangeDate: '6/6/2022', + updateDate: '1/2/2022', + createDate: '7/1/2022', + failedLoginAttempts: 951, + }, + { + id: 56, + key: '0daeefb8-8f39-4d63-be8e-eef0239b418c', + name: 'Eba Fewings', + email: 'efewings1j@hexun.com', + language: 'Quechua', + status: 'Invited', + lastLoginDate: '11/30/2021', + lastLockoutDate: '4/17/2022', + lastPasswordChangeDate: '7/8/2022', + updateDate: '3/7/2022', + createDate: '6/19/2022', + failedLoginAttempts: 371, + }, + { + id: 57, + key: 'f34d019d-af85-4579-b510-b0e5a27c05ab', + name: 'Rand Espadate', + email: 'respadate1k@skyrock.com', + language: 'Persian', + status: 'Disabled', + lastLoginDate: '8/22/2022', + lastLockoutDate: '6/14/2022', + lastPasswordChangeDate: '9/5/2022', + updateDate: '2/11/2022', + createDate: '2/21/2022', + failedLoginAttempts: 5, + }, + { + id: 58, + key: 'acab2dd7-baae-40ef-b272-96ec50e633f7', + name: 'Bobina Macconachy', + email: 'bmacconachy1l@wikipedia.org', + language: 'Gujarati', + status: 'Active', + lastLoginDate: '5/25/2022', + lastLockoutDate: '6/28/2022', + lastPasswordChangeDate: '6/26/2022', + updateDate: '8/11/2022', + createDate: '3/12/2022', + failedLoginAttempts: 243, + }, + { + id: 59, + key: '8e3c0364-0c2a-451e-a65d-7c46cfba2436', + name: 'Walther Pattie', + email: 'wpattie1m@example.com', + language: 'Zulu', + status: 'Invited', + updateDate: '3/8/2022', + createDate: '10/8/2021', + failedLoginAttempts: 381, + }, + { + id: 60, + key: '0548a79d-a767-450c-9823-e170284347e9', + name: 'Elton Jedrychowski', + email: 'ejedrychowski1n@cam.ac.uk', + language: 'Greek', + status: 'Invited', + lastLoginDate: '5/16/2022', + lastLockoutDate: '7/18/2022', + lastPasswordChangeDate: '11/28/2021', + updateDate: '7/27/2022', + createDate: '9/30/2022', + failedLoginAttempts: 27, + }, + { + id: 61, + key: 'd97f31cd-939d-4686-b282-e6613c930ce9', + name: 'Melamie Chifney', + email: 'mchifney1o@umich.edu', + language: 'Albanian', + status: 'Active', + lastLoginDate: '3/16/2022', + lastLockoutDate: '12/22/2021', + lastPasswordChangeDate: '1/8/2022', + updateDate: '10/22/2021', + createDate: '12/9/2021', + failedLoginAttempts: 807, + }, + { + id: 62, + key: '160614dd-5749-4a74-878e-ac82e8cfe21b', + name: 'Auroora Theuff', + email: 'atheuff1p@over-blog.com', + language: 'Kurdish', + status: 'Inactive', + lastLoginDate: '11/28/2021', + lastLockoutDate: '11/17/2021', + lastPasswordChangeDate: '11/20/2021', + updateDate: '4/9/2022', + createDate: '6/29/2022', + failedLoginAttempts: 334, + }, + { + id: 63, + key: '3a1a9869-d103-40fb-98ac-4cce9e16ac17', + name: 'Law Cours', + email: 'lcours1q@google.co.uk', + language: 'Arabic', + status: 'Invited', + lastLoginDate: '3/27/2022', + lastLockoutDate: '12/2/2021', + lastPasswordChangeDate: '3/14/2022', + updateDate: '7/14/2022', + createDate: '2/4/2022', + failedLoginAttempts: 129, + }, + { + id: 64, + key: '174fd2e2-ac91-4eae-a366-2fe7e4322d88', + name: 'Clarke Rosenhaus', + email: 'crosenhaus1r@globo.com', + language: 'Afrikaans', + status: 'Active', + lastLoginDate: '6/23/2022', + lastLockoutDate: '7/4/2022', + lastPasswordChangeDate: '12/5/2021', + updateDate: '4/18/2022', + createDate: '8/16/2022', + failedLoginAttempts: 450, + }, + { + id: 65, + key: '762844a8-b64e-473a-ba50-f2cb446c8e93', + name: 'Nevins Gabler', + email: 'ngabler1s@psu.edu', + language: 'Korean', + status: 'Invited', + updateDate: '12/2/2021', + createDate: '12/14/2021', + failedLoginAttempts: 189, + }, + { + id: 66, + key: '46f28ab6-06ca-4d9f-93e4-742218ed5dca', + name: 'Bondon Corrin', + email: 'bcorrin1t@ustream.tv', + language: 'Hiri Motu', + status: 'Active', + lastLoginDate: '1/14/2022', + lastLockoutDate: '6/14/2022', + lastPasswordChangeDate: '11/28/2021', + updateDate: '9/10/2022', + createDate: '5/12/2022', + failedLoginAttempts: 359, + }, + { + id: 67, + key: 'b55ca6f9-2fd3-4e0d-a222-6df52db14007', + name: 'Juli Birtwistle', + email: 'jbirtwistle1u@histats.com', + language: 'Haitian Creole', + status: 'Active', + lastLoginDate: '11/25/2021', + lastLockoutDate: '3/20/2022', + lastPasswordChangeDate: '12/20/2021', + updateDate: '6/16/2022', + createDate: '11/29/2021', + failedLoginAttempts: 956, + }, + { + id: 68, + key: 'a5c7ea42-3257-48fe-9497-f684e6cdebaa', + name: 'Tomasine Hirsthouse', + email: 'thirsthouse1v@ehow.com', + language: 'Bosnian', + status: 'Disabled', + lastLoginDate: '9/19/2022', + lastLockoutDate: '4/21/2022', + lastPasswordChangeDate: '2/7/2022', + updateDate: '2/12/2022', + createDate: '1/3/2022', + failedLoginAttempts: 533, + }, + { + id: 69, + key: '4f9da285-8b73-4f74-9e54-50d04f1441a0', + name: 'Candide Flecknell', + email: 'cflecknell1w@guardian.co.uk', + language: 'Estonian', + status: 'Disabled', + lastLoginDate: '3/25/2022', + lastLockoutDate: '10/26/2021', + lastPasswordChangeDate: '12/3/2021', + updateDate: '12/31/2021', + createDate: '1/31/2022', + failedLoginAttempts: 621, + }, + { + id: 70, + key: '4054205f-6d9d-4bea-b1b2-29168dead18d', + name: 'Skelly Hockey', + email: 'shockey1x@usa.gov', + language: 'Burmese', + status: 'Active', + updateDate: '8/30/2022', + createDate: '1/16/2022', + failedLoginAttempts: 211, + }, + { + id: 71, + key: '1574526d-614b-41f4-abb4-4066fac8815c', + name: 'Nicholas Woan', + email: 'nwoan1y@istockphoto.com', + language: 'Māori', + status: 'Invited', + lastLoginDate: '4/16/2022', + lastLockoutDate: '4/17/2022', + lastPasswordChangeDate: '7/14/2022', + updateDate: '12/30/2021', + createDate: '1/19/2022', + failedLoginAttempts: 78, + }, + { + id: 72, + key: '745e0d21-44a6-4df1-81a0-d796ff7e6801', + name: 'Asa Kase', + email: 'akase1z@scribd.com', + language: 'Irish Gaelic', + status: 'Invited', + updateDate: '7/16/2022', + createDate: '10/23/2021', + failedLoginAttempts: 790, + }, + { + id: 73, + key: 'e0fc930c-6ed5-4064-a039-9e2c3b0dc644', + name: 'Emmerich Sisey', + email: 'esisey20@baidu.com', + language: 'Tetum', + status: 'Active', + lastLoginDate: '5/22/2022', + lastLockoutDate: '6/26/2022', + lastPasswordChangeDate: '5/22/2022', + updateDate: '5/8/2022', + createDate: '9/20/2022', + failedLoginAttempts: 10, + }, + { + id: 74, + key: '0f36289e-abce-4fa9-a524-49664389c2ef', + name: 'Trish Cerith', + email: 'tcerith21@tuttocitta.it', + language: 'Spanish', + status: 'Invited', + lastLoginDate: '1/11/2022', + lastLockoutDate: '9/1/2022', + lastPasswordChangeDate: '1/29/2022', + updateDate: '10/16/2021', + createDate: '1/13/2022', + failedLoginAttempts: 417, + }, + { + id: 75, + key: 'c7a02de0-2eb6-461d-8036-e163b12ef2b5', + name: 'Netty Rudge', + email: 'nrudge22@xinhuanet.com', + language: 'Fijian', + status: 'Active', + lastLoginDate: '4/21/2022', + lastLockoutDate: '7/21/2022', + lastPasswordChangeDate: '11/6/2021', + updateDate: '11/12/2021', + createDate: '4/4/2022', + failedLoginAttempts: 214, + }, + { + id: 76, + key: 'dfa94377-3eb7-4318-804c-892f125cdb65', + name: 'Joane Kuhne', + email: 'jkuhne23@opera.com', + language: 'Danish', + status: 'Active', + lastLoginDate: '1/10/2022', + lastLockoutDate: '9/18/2022', + lastPasswordChangeDate: '9/6/2022', + updateDate: '2/9/2022', + createDate: '4/14/2022', + failedLoginAttempts: 735, + }, + { + id: 77, + key: '34114a3c-b6a9-41e4-ad65-377abb1f2fbd', + name: 'Sheilah Nattrass', + email: 'snattrass24@sbwire.com', + language: 'Korean', + status: 'Invited', + lastLoginDate: '5/7/2022', + lastLockoutDate: '10/20/2021', + lastPasswordChangeDate: '11/13/2021', + updateDate: '12/6/2021', + createDate: '6/25/2022', + failedLoginAttempts: 480, + }, + { + id: 78, + key: 'c9a62d42-9b32-441b-b758-283526c749b1', + name: "Luella O'Geaney", + email: 'logeaney25@foxnews.com', + language: 'Arabic', + status: 'Disabled', + lastLoginDate: '10/21/2021', + lastLockoutDate: '8/12/2022', + lastPasswordChangeDate: '7/20/2022', + updateDate: '5/11/2022', + createDate: '5/19/2022', + failedLoginAttempts: 828, + }, + { + id: 79, + key: '4c54110a-5768-4979-adf0-c8e52a2ae6a6', + name: 'Cyrille Curm', + email: 'ccurm26@forbes.com', + language: 'Icelandic', + status: 'Active', + lastLoginDate: '12/17/2021', + lastLockoutDate: '8/9/2022', + lastPasswordChangeDate: '10/14/2021', + updateDate: '5/19/2022', + createDate: '5/5/2022', + failedLoginAttempts: 840, + }, + { + id: 80, + key: '86bdee19-c4a6-412c-9c38-173232993952', + name: 'Leonard Vitall', + email: 'lvitall27@clickbank.net', + language: 'Haitian Creole', + status: 'Inactive', + lastLoginDate: '8/12/2022', + lastLockoutDate: '2/26/2022', + lastPasswordChangeDate: '10/2/2022', + updateDate: '12/31/2021', + createDate: '1/13/2022', + failedLoginAttempts: 588, + }, + { + id: 81, + key: '0961184f-5b1a-4e21-b598-c2e4fda4b498', + name: 'Nickie Bronger', + email: 'nbronger28@xrea.com', + language: 'West Frisian', + status: 'Active', + lastLoginDate: '8/5/2022', + lastLockoutDate: '1/21/2022', + lastPasswordChangeDate: '4/8/2022', + updateDate: '5/11/2022', + createDate: '10/12/2021', + failedLoginAttempts: 639, + }, + { + id: 82, + key: '7cc8803f-9c20-44aa-9399-d4ec5e52e008', + name: 'Annie Butterworth', + email: 'abutterworth29@marketwatch.com', + language: 'Bulgarian', + status: 'Active', + lastLoginDate: '10/30/2021', + lastLockoutDate: '10/5/2021', + lastPasswordChangeDate: '5/3/2022', + updateDate: '4/4/2022', + createDate: '1/25/2022', + failedLoginAttempts: 912, + }, + { + id: 83, + key: '61ec70a3-6a8d-42fe-88f3-c866328c4a9c', + name: 'Dasi Ughi', + email: 'dughi2a@vimeo.com', + language: 'Yiddish', + status: 'Disabled', + lastLoginDate: '10/14/2021', + lastLockoutDate: '1/11/2022', + lastPasswordChangeDate: '8/1/2022', + updateDate: '10/31/2021', + createDate: '7/2/2022', + failedLoginAttempts: 494, + }, + { + id: 84, + key: '21bbdd96-ea8d-463c-8d10-fd6d016bf4e0', + name: 'Lawrence Cansfield', + email: 'lcansfield2b@istockphoto.com', + language: 'Estonian', + status: 'Disabled', + lastLoginDate: '3/24/2022', + lastLockoutDate: '10/11/2021', + lastPasswordChangeDate: '5/20/2022', + updateDate: '12/1/2021', + createDate: '10/26/2021', + failedLoginAttempts: 258, + }, + { + id: 85, + key: 'f897a981-0452-4c06-b875-dab80109051b', + name: 'Gal Lyster', + email: 'glyster2c@google.cn', + language: 'Indonesian', + status: 'Disabled', + lastLoginDate: '8/29/2022', + lastLockoutDate: '9/25/2022', + lastPasswordChangeDate: '10/16/2021', + updateDate: '4/16/2022', + createDate: '3/17/2022', + failedLoginAttempts: 103, + }, + { + id: 86, + key: '1f8d4217-3037-444e-b91a-0e18f20b3919', + name: 'Caron Crolly', + email: 'ccrolly2d@jalbum.net', + language: 'Italian', + status: 'Disabled', + lastLoginDate: '7/12/2022', + lastLockoutDate: '3/20/2022', + lastPasswordChangeDate: '1/4/2022', + updateDate: '11/26/2021', + createDate: '6/5/2022', + failedLoginAttempts: 211, + }, + { + id: 87, + key: 'f4449cde-ef12-4068-9f13-6104d281e494', + name: 'Juliana Clorley', + email: 'jclorley2e@mail.ru', + language: 'Luxembourgish', + status: 'Active', + lastLoginDate: '10/17/2021', + lastLockoutDate: '8/4/2022', + lastPasswordChangeDate: '12/23/2021', + updateDate: '2/23/2022', + createDate: '8/22/2022', + failedLoginAttempts: 208, + }, + { + id: 88, + key: 'ac75e813-22bc-4d42-8f98-a4ba6f19bdf8', + name: 'Kylynn Falvey', + email: 'kfalvey2f@com.com', + language: 'Zulu', + status: 'Inactive', + lastLoginDate: '3/4/2022', + lastLockoutDate: '6/4/2022', + lastPasswordChangeDate: '6/9/2022', + updateDate: '2/14/2022', + createDate: '1/30/2022', + failedLoginAttempts: 75, + }, + { + id: 89, + key: 'ba9caf4c-aeee-48e8-a7d7-3ff2239c0186', + name: 'Marty Shurrock', + email: 'mshurrock2g@hhs.gov', + language: 'Danish', + status: 'Inactive', + lastLoginDate: '10/2/2022', + lastLockoutDate: '9/16/2022', + lastPasswordChangeDate: '12/3/2021', + updateDate: '5/26/2022', + createDate: '4/30/2022', + failedLoginAttempts: 40, + }, + { + id: 90, + key: '924e087c-b0b5-4c59-a8b8-a71ad112c4b0', + name: 'Goldia Crates', + email: 'gcrates2h@privacy.gov.au', + language: 'Pashto', + status: 'Inactive', + lastLoginDate: '9/27/2022', + lastLockoutDate: '2/7/2022', + lastPasswordChangeDate: '12/9/2021', + updateDate: '5/5/2022', + createDate: '9/25/2022', + failedLoginAttempts: 710, + }, + { + id: 91, + key: '909154d4-5c84-461d-b256-552f358a0d68', + name: 'Ted Stratley', + email: 'tstratley2i@tinypic.com', + language: 'Mongolian', + status: 'Inactive', + lastLoginDate: '4/19/2022', + lastLockoutDate: '9/24/2022', + lastPasswordChangeDate: '10/24/2021', + updateDate: '7/29/2022', + createDate: '2/7/2022', + failedLoginAttempts: 730, + }, + { + id: 92, + key: '284e7d5a-1b10-4814-a5fd-da17180c1753', + name: 'Rubia Collecott', + email: 'rcollecott2j@oaic.gov.au', + language: 'Somali', + status: 'Inactive', + updateDate: '1/27/2022', + createDate: '3/7/2022', + failedLoginAttempts: 250, + }, + { + id: 93, + key: '91205c6e-3be9-47fc-b5f3-01c89306dcd5', + name: 'Nilson Britland', + email: 'nbritland2k@facebook.com', + language: 'Ndebele', + status: 'Disabled', + lastLoginDate: '8/25/2022', + lastLockoutDate: '12/31/2021', + lastPasswordChangeDate: '8/15/2022', + updateDate: '8/14/2022', + createDate: '11/17/2021', + failedLoginAttempts: 360, + }, + { + id: 94, + key: 'da108699-76d9-4691-9dbd-c11a16cf3514', + name: 'Johannes Slucock', + email: 'jslucock2l@buzzfeed.com', + language: 'Malagasy', + status: 'Inactive', + lastLoginDate: '1/5/2022', + lastLockoutDate: '10/11/2021', + lastPasswordChangeDate: '2/17/2022', + updateDate: '6/13/2022', + createDate: '7/19/2022', + failedLoginAttempts: 397, + }, + { + id: 95, + key: '7469307b-a87b-49b9-8dab-100d7d7e31d0', + name: 'Rodrick Twelftree', + email: 'rtwelftree2m@nbcnews.com', + language: 'Luxembourgish', + status: 'Active', + lastLoginDate: '5/23/2022', + lastLockoutDate: '6/21/2022', + lastPasswordChangeDate: '8/27/2022', + updateDate: '10/20/2021', + createDate: '10/24/2021', + failedLoginAttempts: 104, + }, + { + id: 96, + key: 'cc7c8bbb-580f-445e-8af5-c3bf14b4a560', + name: 'Liesa Arnoll', + email: 'larnoll2n@webnode.com', + language: 'Hebrew', + status: 'Active', + lastLoginDate: '9/13/2022', + lastLockoutDate: '7/14/2022', + lastPasswordChangeDate: '2/28/2022', + updateDate: '6/20/2022', + createDate: '11/5/2021', + failedLoginAttempts: 78, + }, + { + id: 97, + key: '1c75ef97-b3f2-4194-b109-fd5c82efe9de', + name: 'Cindra Simkiss', + email: 'csimkiss2o@google.es', + language: 'Gagauz', + status: 'Disabled', + lastLoginDate: '4/18/2022', + lastLockoutDate: '9/2/2022', + lastPasswordChangeDate: '5/5/2022', + updateDate: '4/30/2022', + createDate: '9/25/2022', + failedLoginAttempts: 887, + }, + { + id: 98, + key: 'a010a09d-2e23-4403-806c-16fcfe70fcd4', + name: 'Belle Conrard', + email: 'bconrard2p@mozilla.org', + language: 'Hindi', + status: 'Invited', + lastLoginDate: '7/18/2022', + lastLockoutDate: '6/25/2022', + lastPasswordChangeDate: '2/21/2022', + updateDate: '7/18/2022', + createDate: '4/12/2022', + failedLoginAttempts: 477, + }, + { + id: 99, + key: '8c9bfaac-098f-43a4-91ee-a9eaf5dfe5ea', + name: 'Tremain Minor', + email: 'tminor2q@storify.com', + language: 'Chinese', + status: 'Invited', + lastLoginDate: '7/31/2022', + lastLockoutDate: '5/11/2022', + lastPasswordChangeDate: '11/10/2021', + updateDate: '8/9/2022', + createDate: '7/24/2022', + failedLoginAttempts: 160, + }, + { + id: 100, + key: 'ecb0ced9-c1c1-486d-a317-5f2b320859bd', + name: 'Isador Tibbles', + email: 'itibbles2r@cafepress.com', + language: 'Assamese', + status: 'Active', + lastLoginDate: '4/7/2022', + lastLockoutDate: '2/4/2022', + lastPasswordChangeDate: '11/14/2021', + updateDate: '4/14/2022', + createDate: '11/16/2021', + failedLoginAttempts: 932, + }, +]; From bc24ffcfdf7347d51c45a1438aa346fa84e6a252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 11:18:55 +0200 Subject: [PATCH 28/98] fixed lastLogin in users-table --- .../users/views/users/editor-view-users-table.element.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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/editor-view-users-table.element.ts index c09a5b660d..c8d7b0e931 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/editor-view-users-table.element.ts @@ -116,8 +116,8 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE name: 'Last login', sort: (items: Array, desc: boolean) => { return desc - ? [...items].sort((a, b) => +new Date(b.lastLogin) - +new Date(a.lastLogin)) - : [...items].sort((a, b) => +new Date(a.lastLogin) - +new Date(b.lastLogin)); + ? [...items].sort((a, b) => +new Date(b.lastLoginDate || 0) - +new Date(a.lastLoginDate || 0)) + : [...items].sort((a, b) => +new Date(a.lastLoginDate || 0) - +new Date(b.lastLoginDate || 0)); }, }, { @@ -214,7 +214,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE
${user.userGroup} - ${user.lastLogin} + ${user.lastLoginDate} ${user.status ? html` ${user.status} ` From 54acab17986b9a07f00871ddd82b1f4061798f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 11:22:15 +0200 Subject: [PATCH 29/98] added email --- .../users/views/users/editor-view-users-user-details.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index fc021e2dd0..b795a53c79 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -155,7 +155,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi
Profile
Email - + Language From 2ace9a9d92662b8d1b95229f22411a24287ff91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 11:24:07 +0200 Subject: [PATCH 30/98] Hide tag when active --- .../editors/users/views/users/editor-view-users-grid.element.ts | 2 +- .../users/views/users/editor-view-users-table.element.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/editor-view-users-grid.element.ts index 5846edb92b..7023fd33f8 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/editor-view-users-grid.element.ts @@ -93,7 +93,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl @open=${() => this._handleOpenCard(user.key)} @selected=${() => this._selectRowHandler(user)} @unselected=${() => this._deselectRowHandler(user)}> - ${user.status + ${user.status && user.status !== 'Active' ? html` ${user.status} ` 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/editor-view-users-table.element.ts index c8d7b0e931..66dfd3b8d3 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/editor-view-users-table.element.ts @@ -216,7 +216,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE ${user.userGroup} ${user.lastLoginDate} - ${user.status + ${user.status && user.status !== 'Active' ? html` ${user.status} ` : nothing} From 49d449ec5f05828ea8b72e3026f9fc8486d99b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 11:38:38 +0200 Subject: [PATCH 31/98] added content pickers --- .../editor-view-users-user-details.element.ts | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index b795a53c79..37ced17ba3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -5,6 +5,7 @@ import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; import { Subscription } from 'rxjs'; import { tempData } from './tempData'; +import '../../../../property-editors/content-picker/property-editor-content-picker.element'; @customElement('umb-editor-view-users-user-details') export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { @@ -56,6 +57,11 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi display: flex; flex-direction: column; } + #assign-access { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-4); + } .access-content { margin-top: var(--uui-size-space-1); margin-bottom: var(--uui-size-space-4); @@ -163,10 +169,22 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi -
Assign access
-
- Groups -
Add groups to assign access and permissions
+
+
Assign access
+
+ Groups +
Add groups to assign access and permissions
+
+
+ Content start nodes +
Limit the content tree to specific start nodes
+ +
+
+ Media start nodes +
Limit the media library to specific start nodes
+ +
From 21def0e01bc5d4615e2c0a8ab32d05bb7185433b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 12:22:40 +0200 Subject: [PATCH 32/98] fix avatar size --- .../views/users/editor-view-users-user-details.element.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 37ced17ba3..a6dcb88992 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -30,8 +30,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi gap: var(--uui-size-space-2); } uui-avatar { - width: 50%; - flex: 1 1 0%; + font-size: var(--uui-size-16); place-self: center; } hr { From 2eb97eb93fbd1b38710b91be81f012d79b97e246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 14:28:14 +0200 Subject: [PATCH 33/98] added 100% height to layout router slot --- .../editor-entity-layout/editor-entity-layout.element.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts index 550627ead6..9dd3c6f90a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts @@ -46,6 +46,10 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { margin-left: auto; } + router-slot { + height: 100%; + } + uui-input { width: 100%; } From ee93f9541c0fd013e296e612b08051c2d27d37c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 3 Oct 2022 15:15:57 +0200 Subject: [PATCH 34/98] added invite form --- .../users/editor-view-users-invite.element.ts | 160 ++++++++++++++++++ .../users/editor-view-users-list.element.ts | 19 ++- .../views/users/editor-view-users.element.ts | 27 ++- 3 files changed, 198 insertions(+), 8 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts new file mode 100644 index 0000000000..0ac7cef2e4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts @@ -0,0 +1,160 @@ +import { css, html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, query, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import { Subscription } from 'rxjs'; +import './editor-view-users-table.element'; +import './editor-view-users-grid.element'; +import './editor-view-users-selection.element'; +import { IRoute } from 'router-slot'; +import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import { UUIPopoverElement } from '@umbraco-ui/uui'; + +export type UsersViewType = 'list' | 'grid'; +@customElement('umb-editor-view-users-invite') +export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + :host { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + } + uui-box { + max-width: 500px; + } + uui-form-layout-item { + display: flex; + flex-direction: column; + } + uui-input { + width: 100%; + } + #post-invite-buttons { + display: flex; + } + form { + display: flex; + flex-direction: column; + box-sizing: border-box; + } + uui-form-layout-item { + margin-bottom: 0; + } + uui-textarea { + --uui-textarea-min-height: 100px; + } + uui + `, + ]; + + @state() + private _showPostInvite = false; + + private _usersContext?: UmbEditorViewUsersElement; + + private _invitedUser?: UserItem; + + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this._usersContext = usersContext; + }); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + } + + private _handleSubmit(e: Event) { + e.preventDefault(); + + const form = e.target as HTMLFormElement; + if (!form) return; + + const isValid = form.checkValidity(); + if (!isValid) return; + + const formData = new FormData(form); + + const name = formData.get('name') as string; + const email = formData.get('email') as string; + const userGroup = formData.get('userGroup') as string; + const message = formData.get('message') as string; + + this._invitedUser = this._usersContext?.inviteUser(name, email, userGroup, message); + this._showPostInvite = true; + } + + private _resetForm() { + this._showPostInvite = false; + this._invitedUser = undefined; + } + + private _goToProfile() { + //TODO: navigate to user profile + } + + private _renderForm() { + return html`

Invite user

+

+ Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on + how to log in to Umbraco. Invites last for 72 hours. +

+ +
+ + Name + + + + Email + + + + User group + Add groups to assign access and permissions + ADD USER GROUP PICKER HERE + + + Message + + + +
+
`; + } + + private _renderPostInvite() { + if (!this._invitedUser) return nothing; + + return html`
+

${this._invitedUser.name} has been invited

+

An invitation has been sent to the new user with details about how to log in to Umbraco.

+
+ + +
+
`; + } + + render() { + return html`${this._showPostInvite ? this._renderPostInvite() : this._renderForm()}`; + } +} + +export default UmbEditorViewUsersInviteElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-users-invite': UmbEditorViewUsersInviteElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts index f55197e83c..e427595fea 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts @@ -6,6 +6,7 @@ import { Subscription } from 'rxjs'; import './editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; +import './editor-view-users-invite.element'; import { IRoute } from 'router-slot'; import UmbEditorViewUsersElement from './editor-view-users.element'; import { UUIPopoverElement } from '@umbraco-ui/uui'; @@ -59,6 +60,10 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl box-shadow: var(--uui-shadow-depth-2); width: fit-content; } + a { + color: inherit; + text-decoration: none; + } `, ]; @@ -135,12 +140,12 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl @state() private _routes: IRoute[] = [ { - path: 'list', - component: () => import('./editor-view-users-table.element'), + path: '/grid', + component: () => import('./editor-view-users-grid.element'), }, { - path: 'details/:key', - component: () => import('./editor-view-users-user-details.element'), + path: '/list', + component: () => import('./editor-view-users-table.element'), }, ]; @@ -157,7 +162,9 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl return html`
- + + +
@@ -208,7 +215,7 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl -
${this._renderViewType()}
+ `; } } 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 33854a0c06..67b635f282 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 @@ -5,10 +5,12 @@ import { UmbContextProviderMixin } from '../../../../../core/context'; import { BehaviorSubject, Observable } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; import { IRoute } from 'router-slot'; +import { v4 as uuidv4 } from 'uuid'; import './editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-user-details.element'; +import './editor-view-users-invite.element'; import { tempData } from './tempData'; @@ -39,8 +41,8 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen component: () => import('./editor-view-users-list.element'), }, { - path: '/:key', - component: () => import('./editor-view-users-user-details.element'), + path: '/invite', + component: () => import('./editor-view-users-invite.element'), }, ]; @@ -84,6 +86,27 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen 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); From 3675a4516163e08e66955d4cb8cb29a10120a0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 12:02:42 +0200 Subject: [PATCH 35/98] renamed list to overview, and wip routing --- .../users/editor-view-users-grid.element.ts | 2 +- ... => editor-view-users-overview.element.ts} | 37 ++++++++----------- .../users/editor-view-users-table.element.ts | 2 +- .../views/users/editor-view-users.element.ts | 14 +++++-- 4 files changed, 28 insertions(+), 27 deletions(-) rename src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/{editor-view-users-list.element.ts => editor-view-users-overview.element.ts} (87%) 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/editor-view-users-grid.element.ts index 7023fd33f8..3a79c58a76 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/editor-view-users-grid.element.ts @@ -68,7 +68,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl //TODO How should we handle url stuff? private _handleOpenCard(key: string) { - history.pushState(null, '', location.pathname + '/' + key); + history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO Change to a tag with href and make dynamic } private _selectRowHandler(user: UserItem) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts similarity index 87% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts index e427595fea..a15ef41b1b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts @@ -10,10 +10,11 @@ import './editor-view-users-invite.element'; import { IRoute } from 'router-slot'; import UmbEditorViewUsersElement from './editor-view-users.element'; import { UUIPopoverElement } from '@umbraco-ui/uui'; +import { isPathActive } from 'router-slot'; export type UsersViewType = 'list' | 'grid'; -@customElement('umb-editor-view-users-list') -export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitElement) { +@customElement('umb-editor-view-users-overview') +export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(LitElement) { static styles = [ UUITextStyles, css` @@ -67,9 +68,6 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl `, ]; - @state() - private _viewType: UsersViewType = 'grid'; - @state() private _selection: Array = []; @@ -117,18 +115,11 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl } private _toggleViewType() { - this._viewType = this._viewType === 'list' ? 'grid' : 'list'; - } + const isList = window.location.pathname.split('/').pop() === 'list'; - private _renderViewType() { - switch (this._viewType) { - case 'list': - return html``; - case 'grid': - return html``; - default: - return html``; - } + isList + ? history.pushState(null, '', '/section/users/view/users/overview/grid') + : history.pushState(null, '', '/section/users/view/users/overview/list'); } private _renderSelection() { @@ -140,13 +131,17 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl @state() private _routes: IRoute[] = [ { - path: '/grid', + path: 'grid', component: () => import('./editor-view-users-grid.element'), }, { - path: '/list', + path: 'list', component: () => import('./editor-view-users-table.element'), }, + { + path: '**', + redirectTo: '/section/users/view/users/overview/grid', //TODO: this should be dynamic + }, ]; private _handleTogglePopover(event: PointerEvent) { @@ -214,16 +209,14 @@ export class UmbEditorViewUsersListElement extends UmbContextConsumerMixin(LitEl
- - `; } } -export default UmbEditorViewUsersListElement; +export default UmbEditorViewUsersOverviewElement; declare global { interface HTMLElementTagNameMap { - 'umb-editor-view-users-list': UmbEditorViewUsersListElement; + 'umb-editor-view-users-overview': UmbEditorViewUsersOverviewElement; } } 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/editor-view-users-table.element.ts index 66dfd3b8d3..572b3bd996 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/editor-view-users-table.element.ts @@ -149,7 +149,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE //TODO How should we handle url stuff? private _handleOpenUser(event: Event, key: string) { event.stopImmediatePropagation(); - history.pushState(null, '', location.pathname + '/' + key); + history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO: make a tag with href } private _selectRowHandler(user: UserItem) { 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 67b635f282..20e4ff026c 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 @@ -37,13 +37,21 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen @state() private _routes: IRoute[] = [ { - path: '/', - component: () => import('./editor-view-users-list.element'), + path: 'overview', + component: () => import('./editor-view-users-overview.element'), }, { - path: '/invite', + path: 'invite', component: () => import('./editor-view-users-invite.element'), }, + { + path: 'details/:key', + component: () => import('./editor-view-users-user-details.element'), + }, + { + path: '**', + redirectTo: '/section/users/view/users/overview', //TODO: this should be dynamic + }, ]; private _users: BehaviorSubject> = new BehaviorSubject(tempData); From 31f559a5ca7a6d52923a56f26c4bd351393aebcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 12:03:46 +0200 Subject: [PATCH 36/98] cleanup --- .../src/backoffice/editors/users/editor-users.element.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts index 6029ada75d..0f3f8549c7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts @@ -1,20 +1,13 @@ -import { UUIButtonState, UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement } from 'lit'; -import { customElement, property, state } from 'lit/decorators.js'; -import { distinctUntilChanged, Subscription } from 'rxjs'; +import { customElement } from 'lit/decorators.js'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../core/context'; -import { UmbNotificationService } from '../../../core/services/notification'; -import { UmbDocumentTypeStore } from '../../../core/stores/document-type.store'; -import { DocumentTypeEntity } from '../../../mocks/data/document-type.data'; -import { UmbDocumentTypeContext } from './document-type.context'; import '../shared/editor-entity-layout/editor-entity-layout.element'; // Lazy load // TODO: Make this dynamic, use load-extensions method to loop over extensions for this node. import './views/user-groups/editor-view-user-groups.element'; -import { UmbNotificationDefaultData } from '../../../core/services/notification/layouts/default'; @customElement('umb-editor-users') export class UmbEditorUsersElement extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) { From 23ec98874cb6e309d193704f606a59a9cf77670e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 13:38:28 +0200 Subject: [PATCH 37/98] added editor action extension, schemas and api --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 119 +++++++++++------- .../schemas/generated-schema.ts | 47 ++++--- .../editor-action-extension.element.ts | 46 +++++++ .../editor-entity-layout.element.ts | 30 ++++- .../editor-action-users-save.element.ts | 24 ++++ .../src/core/extension/extension.registry.ts | 2 + .../src/core/models/index.ts | 2 + .../src/temp-internal-manifests.ts | 18 +++ .../temp-schema-generator/manifests.ts | 19 ++- 9 files changed, 240 insertions(+), 67 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index 3c4e98e020..8819b25df0 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -486,6 +486,78 @@ components: - meta - alias - name + MetaEditorAction: + type: object + properties: + editors: + type: array + items: + type: string + required: + - editors + IManifestEditorAction: + type: object + properties: + type: + type: string + enum: + - editorAction + meta: + $ref: '#/components/schemas/MetaEditorAction' + js: + type: string + elementName: + type: string + alias: + type: string + name: + type: string + required: + - type + - meta + - alias + - name + MetaEditorView: + type: object + properties: + editors: + type: array + items: + type: string + pathname: + type: string + weight: + type: number + format: float + icon: + type: string + required: + - editors + - pathname + - weight + - icon + IManifestEditorView: + type: object + properties: + type: + type: string + enum: + - editorView + meta: + $ref: '#/components/schemas/MetaEditorView' + js: + type: string + elementName: + type: string + alias: + type: string + name: + type: string + required: + - type + - meta + - alias + - name MetaTreeItemAction: type: object properties: @@ -624,47 +696,6 @@ components: - meta - alias - name - MetaEditorView: - type: object - properties: - editors: - type: array - items: - type: string - pathname: - type: string - weight: - type: number - format: float - icon: - type: string - required: - - editors - - pathname - - weight - - icon - IManifestEditorView: - type: object - properties: - type: - type: string - enum: - - editorView - meta: - $ref: '#/components/schemas/MetaEditorView' - js: - type: string - elementName: - type: string - alias: - type: string - name: - type: string - required: - - type - - meta - - alias - - name MetaPropertyAction: type: object properties: @@ -765,10 +796,11 @@ components: - $ref: '#/components/schemas/IManifestSection' - $ref: '#/components/schemas/IManifestTree' - $ref: '#/components/schemas/IManifestEditor' + - $ref: '#/components/schemas/IManifestEditorAction' + - $ref: '#/components/schemas/IManifestEditorView' - $ref: '#/components/schemas/IManifestTreeItemAction' - $ref: '#/components/schemas/IManifestPropertyEditorUI' - $ref: '#/components/schemas/IManifestDashboard' - - $ref: '#/components/schemas/IManifestEditorView' - $ref: '#/components/schemas/IManifestPropertyAction' - $ref: '#/components/schemas/IManifestPackageView' - $ref: '#/components/schemas/IManifestEntrypoint' @@ -779,10 +811,11 @@ components: section: '#/components/schemas/IManifestSection' tree: '#/components/schemas/IManifestTree' editor: '#/components/schemas/IManifestEditor' + editorAction: '#/components/schemas/IManifestEditorAction' + editorView: '#/components/schemas/IManifestEditorView' treeItemAction: '#/components/schemas/IManifestTreeItemAction' propertyEditorUI: '#/components/schemas/IManifestPropertyEditorUI' dashboard: '#/components/schemas/IManifestDashboard' - editorView: '#/components/schemas/IManifestEditorView' propertyAction: '#/components/schemas/IManifestPropertyAction' packageView: '#/components/schemas/IManifestPackageView' entrypoint: '#/components/schemas/IManifestEntrypoint' diff --git a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts index fdc1e66117..c134812f22 100644 --- a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts +++ b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts @@ -151,6 +151,34 @@ export interface components { alias: string; name: string; }; + MetaEditorAction: { + editors: string[]; + }; + IManifestEditorAction: { + /** @enum {string} */ + type: "editorAction"; + meta: components["schemas"]["MetaEditorAction"]; + js?: string; + elementName?: string; + alias: string; + name: string; + }; + MetaEditorView: { + editors: string[]; + pathname: string; + /** Format: float */ + weight: number; + icon: string; + }; + IManifestEditorView: { + /** @enum {string} */ + type: "editorView"; + meta: components["schemas"]["MetaEditorView"]; + js?: string; + elementName?: string; + alias: string; + name: string; + }; MetaTreeItemAction: { trees: string[]; label: string; @@ -206,22 +234,6 @@ export interface components { alias: string; name: string; }; - MetaEditorView: { - editors: string[]; - pathname: string; - /** Format: float */ - weight: number; - icon: string; - }; - IManifestEditorView: { - /** @enum {string} */ - type: "editorView"; - meta: components["schemas"]["MetaEditorView"]; - js?: string; - elementName?: string; - alias: string; - name: string; - }; MetaPropertyAction: { propertyEditors: string[]; }; @@ -264,10 +276,11 @@ export interface components { | components["schemas"]["IManifestSection"] | components["schemas"]["IManifestTree"] | components["schemas"]["IManifestEditor"] + | components["schemas"]["IManifestEditorAction"] + | components["schemas"]["IManifestEditorView"] | components["schemas"]["IManifestTreeItemAction"] | components["schemas"]["IManifestPropertyEditorUI"] | components["schemas"]["IManifestDashboard"] - | components["schemas"]["IManifestEditorView"] | components["schemas"]["IManifestPropertyAction"] | components["schemas"]["IManifestPackageView"] | components["schemas"]["IManifestEntrypoint"] diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts new file mode 100644 index 0000000000..de0542a5b4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-action-extension/editor-action-extension.element.ts @@ -0,0 +1,46 @@ +import { UUITextStyles } from '@umbraco-ui/uui'; +import { CSSResultGroup, html, LitElement } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { createExtensionElement } from '../../../../core/extension'; +import type { ManifestEditorAction } from '../../../../core/models'; + +@customElement('umb-editor-action-extension') +export class UmbEditorActionExtensionElement extends LitElement { + static styles: CSSResultGroup = [UUITextStyles]; + + private _editorAction?: ManifestEditorAction; + @property({ type: Object }) + public get editorAction(): ManifestEditorAction | undefined { + return this._editorAction; + } + public set editorAction(value: ManifestEditorAction | undefined) { + this._editorAction = value; + this._createElement(); + } + + @state() + private _element?: any; + + private async _createElement() { + if (!this.editorAction) return; + + try { + this._element = await createExtensionElement(this.editorAction); + if (!this._element) return; + + this._element.editorAction = this.editorAction; + } catch (error) { + // TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.) + } + } + + render() { + return html`${this._element}`; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-action-extension': UmbEditorActionExtensionElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts index 9dd3c6f90a..c424638fa2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts @@ -1,4 +1,5 @@ import '../editor-layout/editor-layout.element'; +import '../editor-action-extension/editor-action-extension.element'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement, nothing } from 'lit'; @@ -8,7 +9,7 @@ import { map, Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../core/context'; import { createExtensionElement, UmbExtensionRegistry } from '../../../../core/extension'; -import type { ManifestEditorView } from '../../../../core/models'; +import type { ManifestEditorAction, ManifestEditorView } from '../../../../core/models'; @customElement('umb-editor-entity-layout') export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { @@ -71,6 +72,9 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { @state() private _editorViews: Array = []; + @state() + private _editorActions: Array = []; + @state() private _currentView = ''; @@ -79,6 +83,7 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { private _extensionRegistry?: UmbExtensionRegistry; private _editorViewsSubscription?: Subscription; + private _editorActionsSubscription?: Subscription; private _routerFolder = ''; constructor() { @@ -86,7 +91,8 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => { this._extensionRegistry = extensionRegistry; - this._useEditorViews(); + this._observeEditorViews(); + this._observeEditorActions(); }); } @@ -96,7 +102,7 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { this._routerFolder = window.location.pathname.split('/view')[0]; } - private _useEditorViews() { + private _observeEditorViews() { this._editorViewsSubscription?.unsubscribe(); this._editorViewsSubscription = this._extensionRegistry @@ -114,6 +120,17 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { }); } + private _observeEditorActions() { + this._editorActionsSubscription?.unsubscribe(); + + this._editorActionsSubscription = this._extensionRegistry + ?.extensionsOfType('editorAction') + .pipe(map((extensions) => extensions.filter((extension) => extension.meta.editors.includes(this.alias)))) + .subscribe((editorActions) => { + this._editorActions = editorActions; + }); + } + private async _createRoutes() { if (this._editorViews.length > 0) { this._routes = []; @@ -184,7 +201,12 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { `; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts new file mode 100644 index 0000000000..a536251d32 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts @@ -0,0 +1,24 @@ +import { css, html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, state } from 'lit/decorators.js'; + +@customElement('umb-editor-action-users-save') +export class UmbEditorActionUsersSaveElement extends LitElement { + static styles = [UUITextStyles, css``]; + + private _handleSave() { + console.log('save'); + } + + render() { + return html``; + } +} + +export default UmbEditorActionUsersSaveElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-action-users-save': UmbEditorActionUsersSaveElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts index 4b8f2c9599..6b0c2c4b28 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts @@ -17,6 +17,7 @@ import type { ManifestTree, ManifestTreeItemAction, ManifestEditor, + ManifestEditorAction, ManifestCustom, ManifestPackageView, } from '../models'; @@ -65,6 +66,7 @@ export class UmbExtensionRegistry { extensionsOfType(type: 'treeItemAction'): Observable>; extensionsOfType(type: 'dashboard'): Observable>; extensionsOfType(type: 'editorView'): Observable>; + extensionsOfType(type: 'editorAction'): Observable>; extensionsOfType(type: 'propertyEditorUI'): Observable>; extensionsOfType(type: 'propertyAction'): Observable>; extensionsOfType(type: 'packageView'): Observable>; diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index 80f628566e..937ba5b4db 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -22,6 +22,7 @@ export type ManifestSection = components['schemas']['IManifestSection']; export type ManifestTree = components['schemas']['IManifestTree']; export type ManifestTreeItemAction = components['schemas']['IManifestTreeItemAction']; export type ManifestEditor = components['schemas']['IManifestEditor']; +export type ManifestEditorAction = components['schemas']['IManifestEditorAction']; export type ManifestPropertyEditorUI = components['schemas']['IManifestPropertyEditorUI']; export type ManifestDashboard = components['schemas']['IManifestDashboard']; export type ManifestEditorView = components['schemas']['IManifestEditorView']; @@ -40,6 +41,7 @@ export type ManifestElementType = | ManifestPropertyEditorUI | ManifestDashboard | ManifestEditorView + | ManifestEditorAction | ManifestPackageView; // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index 277ad11310..af460b0f6b 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -269,6 +269,24 @@ export const internalManifests: Array Promise import('./backoffice/editors/users/views/users/actions/editor-action-users-save.element'), + meta: { + editors: ['Umb.Editor.Users'], + }, + }, + { + type: 'editorAction', + alias: 'Umb.EditorAction.Users.Delete', + name: 'EditorActionUserDelete', + loader: () => import('./backoffice/editors/users/views/users/actions/editor-action-users-save.element'), + meta: { + editors: ['Umb.Editor.DataType'], + }, + }, { type: 'editorView', alias: 'Umb.EditorView.Users.UserGroups', diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts index 01e470e6f6..a32cf4710d 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -33,10 +33,11 @@ export type Manifest = | IManifestSection | IManifestTree | IManifestEditor + | IManifestEditorAction + | IManifestEditorView | IManifestTreeItemAction | IManifestPropertyEditorUI | IManifestDashboard - | IManifestEditorView | IManifestPropertyAction | IManifestPackageView | IManifestEntrypoint @@ -46,13 +47,15 @@ export type ManifestStandardTypes = | 'section' | 'tree' | 'editor' + | 'editorView' + | 'editorAction' | 'treeItemAction' | 'propertyEditorUI' | 'dashboard' - | 'editorView' | 'propertyAction' | 'packageView' - | 'entrypoint'; + | 'entrypoint' + ; export interface ManifestsResponse { manifests: Manifest[]; @@ -156,6 +159,16 @@ export interface IManifestSection extends IManifestElement { meta: MetaSection; } +export interface IManifestEditorAction extends IManifestElement { + type: 'editorAction'; + meta: MetaEditorAction; +} + +export interface MetaEditorAction { + editors: Array; +} + + export interface IManifestTree extends IManifestElement { type: 'tree'; meta: MetaTree; 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 38/98] 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])); + }), +]; From 4a1c7d73504cb394171b45e8c5fdab864cf67425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 14:41:13 +0200 Subject: [PATCH 39/98] fix imports --- .../users/views/users/editor-view-users-invite.element.ts | 2 +- .../users/views/users/editor-view-users-overview.element.ts | 4 ++-- .../editors/users/views/users/editor-view-users.element.ts | 4 ++-- .../grid/editor-view-users-grid.element.ts | 6 +++--- .../table/editor-view-users-table.element.ts | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts index 0ac7cef2e4..6e6143e71f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts @@ -3,7 +3,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, query, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { Subscription } from 'rxjs'; -import './editor-view-users-table.element'; +import './list-view-layouts/table/editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import { IRoute } from 'router-slot'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts index a15ef41b1b..fcabed8f9f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts @@ -3,7 +3,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { Subscription } from 'rxjs'; -import './editor-view-users-table.element'; +import './list-view-layouts/table/editor-view-users-table.element'; import './editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; @@ -136,7 +136,7 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L }, { path: 'list', - component: () => import('./editor-view-users-table.element'), + component: () => import('./list-view-layouts/table/editor-view-users-table.element'), }, { path: '**', 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 1dba2af6d6..db52459e4c 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 @@ -6,8 +6,8 @@ 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'; -import './editor-view-users-table.element'; -import './editor-view-users-grid.element'; +import './list-view-layouts/table/editor-view-users-table.element'; +import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-user-details.element'; import './editor-view-users-invite.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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 index d773c206b4..e1e4bc06f3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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 @@ -1,12 +1,12 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; -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'; +import { UmbContextConsumerMixin } from '../../../../../../../core/context'; +import UmbEditorViewUsersElement, { UserItem } from '../../editor-view-users.element'; +import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; @customElement('umb-editor-view-users-grid') export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/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 index 3a28ac02fe..0e1dfad0d7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/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 @@ -1,11 +1,11 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../../../core/context'; +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'; +import UmbEditorViewUsersElement, { UserItem } from '../../editor-view-users.element'; +import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; interface TableColumn { name: string; From bdc4daa2a26ec06c7b6060f979674bc36b989877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 15:15:45 +0200 Subject: [PATCH 40/98] WIP MSW setup --- .../users/editor-view-users-invite.element.ts | 10 +- .../editor-view-users-overview.element.ts | 4 +- .../editor-view-users-user-details.element.ts | 16 +- .../views/users/editor-view-users.element.ts | 93 +- .../grid/editor-view-users-grid.element.ts | 11 +- .../table/editor-view-users-table.element.ts | 21 +- .../editors/users/views/users/tempData.ts | 1368 +------------ .../src/core/models/index.ts | 19 + .../src/core/stores/user/user.store.ts | 12 +- .../src/mocks/data/entity.data.ts | 4 +- .../src/mocks/data/users.data.ts | 1778 +++++++++++++++++ .../src/mocks/domains/users.handlers.ts | 6 +- 12 files changed, 1868 insertions(+), 1474 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts index 6e6143e71f..fe22ea0932 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts @@ -1,14 +1,8 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, query, state } from 'lit/decorators.js'; +import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import { Subscription } from 'rxjs'; -import './list-view-layouts/table/editor-view-users-table.element'; -import './editor-view-users-grid.element'; -import './editor-view-users-selection.element'; -import { IRoute } from 'router-slot'; -import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; -import { UUIPopoverElement } from '@umbraco-ui/uui'; +import UmbEditorViewUsersElement from './editor-view-users.element'; export type UsersViewType = 'list' | 'grid'; @customElement('umb-editor-view-users-invite') diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts index fcabed8f9f..c6dd3ac427 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts @@ -4,7 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { Subscription } from 'rxjs'; import './list-view-layouts/table/editor-view-users-table.element'; -import './editor-view-users-grid.element'; +import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; import { IRoute } from 'router-slot'; @@ -132,7 +132,7 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L private _routes: IRoute[] = [ { path: 'grid', - component: () => import('./editor-view-users-grid.element'), + component: () => import('./list-view-layouts/grid/editor-view-users-grid.element'), }, { path: 'list', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index a6dcb88992..6670d2bed8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -4,7 +4,6 @@ import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; import { Subscription } from 'rxjs'; -import { tempData } from './tempData'; import '../../../../property-editors/content-picker/property-editor-content-picker.element'; @customElement('umb-editor-view-users-user-details') @@ -86,20 +85,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi protected _usersContext?: UmbEditorViewUsersElement; protected _usersSubscription?: Subscription; - private _languages = tempData //TODO Get languages from API instead of fakeData - .reduce((acc, curr) => { - if (!acc.includes(curr.language)) { - acc.push(curr.language); - } - return acc; - }, [] as Array) - .map((language) => { - return { - name: language, - value: language, - selected: false, - }; - }); + private _languages = []; //TODO Add languages connectedCallback(): void { super.connectedCallback(); 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 db52459e4c..6d2d399bd1 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 @@ -12,23 +12,7 @@ import './editor-view-users-selection.element'; import './editor-view-users-user-details.element'; import './editor-view-users-invite.element'; -import { tempData } from './tempData'; - -export interface UserItem { - id: number; - key: string; - name: string; - email: string; - status: string; - language: string; - lastLoginDate?: string; - lastLockoutDate?: string; - lastPasswordChangeDate?: string; - updateDate: string; - createDate: string; - failedLoginAttempts: number; - userGroup?: string; //TODO Implement this -} +import type { UserDetails, UserEntity } from '../../../../../core/models'; @customElement('umb-editor-view-users') export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElement) { @@ -54,9 +38,6 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen }, ]; - private _users: BehaviorSubject> = new BehaviorSubject(tempData); - public readonly users: Observable> = this._users.asObservable(); - private _selection: BehaviorSubject> = new BehaviorSubject(>[]); public readonly selection: Observable> = this._selection.asObservable(); @@ -84,45 +65,45 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen this.requestUpdate('selection'); } - 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 updateUser(user: UserEntity) { + // 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'); + // public inviteUser(name: string, email: string, userGroup: string, message: string): UserEntity { + // 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; - } + // //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'); - } + // 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'); + // } public getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { switch ((status || '').toLowerCase()) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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 index e1e4bc06f3..7e1c30a4d4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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,8 +5,9 @@ import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; import { ifDefined } from 'lit-html/directives/if-defined.js'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; -import UmbEditorViewUsersElement, { UserItem } from '../../editor-view-users.element'; +import UmbEditorViewUsersElement from '../../editor-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; +import type { UserEntity } from '../../../../../../../core/models'; @customElement('umb-editor-view-users-grid') export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitElement) { @@ -31,7 +32,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl ]; @state() - private _users: Array = []; + private _users: Array = []; @state() private _selection: Array = []; @@ -85,15 +86,15 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO Change to a tag with href and make dynamic } - private _selectRowHandler(user: UserItem) { + private _selectRowHandler(user: UserEntity) { this._usersContext?.select(user.key); } - private _deselectRowHandler(user: UserItem) { + private _deselectRowHandler(user: UserEntity) { this._usersContext?.deselect(user.key); } - private renderUserCard(user: UserItem) { + private renderUserCard(user: UserEntity) { if (!this._userStore) return; const statusLook = this._usersContext?.getTagLookAndColor(user.status ? user.status : ''); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/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 index 0e1dfad0d7..f95d5ed34c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/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 @@ -4,12 +4,13 @@ import { customElement, state } from 'lit/decorators.js'; 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 UmbEditorViewUsersElement from '../../editor-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; +import type { UserEntity } from '../../../../../../../core/models'; interface TableColumn { name: string; - sort: (items: Array, desc: boolean) => Array; + sort: (items: Array, desc: boolean) => Array; } @customElement('umb-editor-view-users-table') @@ -74,7 +75,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE private _sortingDesc = false; @state() - private _users: Array = []; + private _users: Array = []; private _userStore?: UmbUserStore; private _usersContext?: UmbEditorViewUsersElement; @@ -97,7 +98,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE this._columns = [ { name: 'Name', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => b.name.localeCompare(a.name)) : [...items].sort((a, b) => a.name.localeCompare(b.name)); @@ -105,7 +106,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE }, { name: 'User group', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => b.name.localeCompare(a.name)) : [...items].sort((a, b) => a.name.localeCompare(b.name)); @@ -113,7 +114,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE }, { name: 'Last login', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => +new Date(b.lastLoginDate || 0) - +new Date(a.lastLoginDate || 0)) : [...items].sort((a, b) => +new Date(a.lastLoginDate || 0) - +new Date(b.lastLoginDate || 0)); @@ -121,7 +122,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE }, { name: 'status', - sort: (items: Array, desc: boolean) => { + sort: (items: Array, desc: boolean) => { return desc ? [...items].sort((a, b) => b.status && a.status ? b.status.localeCompare(a.status) : (a.status ? 1 : 0) - (b.status ? 1 : 0) @@ -165,11 +166,11 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO: make a tag with href } - private _selectRowHandler(user: UserItem) { + private _selectRowHandler(user: UserEntity) { this._usersContext?.select(user.key); } - private _deselectRowHandler(user: UserItem) { + private _deselectRowHandler(user: UserEntity) { this._usersContext?.deselect(user.key); } @@ -195,7 +196,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE `; } - protected renderRowTemplate = (user: UserItem) => { + protected renderRowTemplate = (user: UserEntity) => { if (!this._usersContext) return; const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts index f799aa5ad0..139597f9cb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts @@ -1,1368 +1,2 @@ -import { UserItem } from './editor-view-users.element'; -export const tempData: Array = [ - { - id: 1, - key: '50f184d4-71f3-4a43-b8be-7a36340fbd0d', - name: 'Nat Linnane', - email: 'nlinnane0@fda.gov', - language: 'Greek', - status: 'Inactive', - lastLoginDate: '9/11/2022', - lastLockoutDate: '5/31/2022', - lastPasswordChangeDate: '1/10/2022', - updateDate: '8/27/2022', - createDate: '9/19/2022', - failedLoginAttempts: 52, - }, - { - id: 2, - key: '7c9c5510-a7b6-43fd-a2d1-51de0009eabf', - name: 'Tyrus Hows', - email: 'thows1@hatena.ne.jp', - language: 'Gagauz', - status: 'Inactive', - lastLoginDate: '9/1/2022', - lastLockoutDate: '2/9/2022', - lastPasswordChangeDate: '8/22/2022', - updateDate: '12/2/2021', - createDate: '9/17/2022', - failedLoginAttempts: 717, - }, - { - id: 3, - key: 'fa3cca42-3b65-4fce-9e9b-5b09ca44f536', - name: 'Nisse Grattan', - email: 'ngrattan2@alexa.com', - language: 'Tok Pisin', - status: 'Active', - lastLoginDate: '3/22/2022', - lastLockoutDate: '12/2/2021', - lastPasswordChangeDate: '5/28/2022', - updateDate: '9/4/2022', - createDate: '8/7/2022', - failedLoginAttempts: 873, - }, - { - id: 4, - key: '381383ef-8d81-455c-bcbc-5e95a5cdc897', - name: 'Thain Rainville', - email: 'trainville3@merriam-webster.com', - language: 'Tajik', - status: 'Active', - lastLoginDate: '2/28/2022', - lastLockoutDate: '1/6/2022', - lastPasswordChangeDate: '7/1/2022', - updateDate: '9/14/2022', - createDate: '2/20/2022', - failedLoginAttempts: 786, - }, - { - id: 5, - key: 'e3dcaf95-7d55-42e6-a023-ce179523bf48', - name: 'Perren Balsdon', - email: 'pbalsdon4@ezinearticles.com', - language: 'Somali', - status: 'Active', - lastLoginDate: '5/6/2022', - lastLockoutDate: '11/12/2021', - lastPasswordChangeDate: '11/10/2021', - updateDate: '5/8/2022', - createDate: '1/12/2022', - failedLoginAttempts: 884, - }, - { - id: 6, - key: '05d0356e-051f-4d00-8b56-24667deab75d', - name: 'Athene Bilborough', - email: 'abilborough5@princeton.edu', - language: 'Tetum', - status: 'Active', - lastLoginDate: '3/11/2022', - lastLockoutDate: '7/7/2022', - lastPasswordChangeDate: '3/8/2022', - updateDate: '12/31/2021', - createDate: '10/2/2022', - failedLoginAttempts: 527, - }, - { - id: 7, - key: 'ac906ed0-d8e0-4ca5-8f03-d817ce31fb7e', - name: 'Carline Sharp', - email: 'csharp6@com.com', - language: 'Portuguese', - status: 'Inactive', - lastLoginDate: '3/6/2022', - lastLockoutDate: '5/20/2022', - lastPasswordChangeDate: '10/9/2021', - updateDate: '1/19/2022', - createDate: '7/3/2022', - failedLoginAttempts: 324, - }, - { - id: 8, - key: '6e34346d-639e-4538-a2cc-9a8a6ba40545', - name: 'Tansy Hanna', - email: 'thanna7@google.pl', - language: 'Papiamento', - status: 'Active', - lastLoginDate: '9/10/2022', - lastLockoutDate: '10/28/2021', - lastPasswordChangeDate: '2/26/2022', - updateDate: '3/12/2022', - createDate: '3/6/2022', - failedLoginAttempts: 937, - }, - { - id: 9, - key: '978c1d59-0814-404d-a4c4-b5abceb4b1b6', - name: 'Heidie Mohan', - email: 'hmohan8@google.co.jp', - language: 'Montenegrin', - status: 'Active', - lastLoginDate: '6/16/2022', - lastLockoutDate: '3/2/2022', - lastPasswordChangeDate: '4/14/2022', - updateDate: '1/30/2022', - createDate: '12/13/2021', - failedLoginAttempts: 804, - }, - { - id: 10, - key: '98d36a68-9b74-435f-8790-d177726f6fed', - name: 'Alden Blaschke', - email: 'ablaschke9@marketwatch.com', - language: 'Mongolian', - status: 'Inactive', - lastLoginDate: '6/27/2022', - lastLockoutDate: '4/16/2022', - lastPasswordChangeDate: '12/31/2021', - updateDate: '4/9/2022', - createDate: '6/18/2022', - failedLoginAttempts: 458, - }, - { - id: 11, - key: 'bf6b7fbe-d3e7-4ca8-9b6d-7daca03c2411', - name: 'Hollis Rouf', - email: 'hroufa@irs.gov', - language: 'Papiamento', - status: 'Inactive', - updateDate: '9/11/2022', - createDate: '6/18/2022', - failedLoginAttempts: 532, - }, - { - id: 12, - key: 'cf1d90af-5b77-4e00-98be-145214443c24', - name: 'Neils Janiak', - email: 'njaniakb@indiatimes.com', - language: 'Aymara', - status: 'Inactive', - updateDate: '11/7/2021', - createDate: '12/30/2021', - failedLoginAttempts: 800, - }, - { - id: 13, - key: '11e6ddc8-33e3-461b-8147-155eac339978', - name: 'Zarah Slaughter', - email: 'zslaughterc@storify.com', - language: 'Afrikaans', - status: 'Invited', - lastLoginDate: '1/1/2022', - lastLockoutDate: '5/4/2022', - lastPasswordChangeDate: '3/6/2022', - updateDate: '11/10/2021', - createDate: '8/1/2022', - failedLoginAttempts: 182, - }, - { - id: 14, - key: 'fb651643-3f2b-4b8e-ab96-a4f3fa15303a', - name: 'Elly Corbishley', - email: 'ecorbishleyd@hexun.com', - language: 'Kyrgyz', - status: 'Invited', - lastLoginDate: '6/3/2022', - lastLockoutDate: '4/4/2022', - lastPasswordChangeDate: '12/21/2021', - updateDate: '7/19/2022', - createDate: '5/12/2022', - failedLoginAttempts: 426, - }, - { - id: 15, - key: '1e329702-50d3-4176-b5db-9315ac6ac2a3', - name: 'Alisander Leupold', - email: 'aleupolde@webnode.com', - language: 'Nepali', - status: 'Inactive', - lastLoginDate: '1/4/2022', - lastLockoutDate: '9/15/2022', - lastPasswordChangeDate: '5/24/2022', - updateDate: '9/20/2022', - createDate: '3/15/2022', - failedLoginAttempts: 327, - }, - { - id: 16, - key: '1fead0fa-8d19-4153-abb0-980c18973d21', - name: 'Gennie Casaccia', - email: 'gcasacciaf@vkontakte.ru', - language: 'Catalan', - status: 'Active', - lastLoginDate: '4/11/2022', - lastLockoutDate: '3/17/2022', - lastPasswordChangeDate: '4/30/2022', - updateDate: '10/15/2021', - createDate: '2/14/2022', - failedLoginAttempts: 469, - }, - { - id: 17, - key: 'd273cd7c-cbd4-4535-83d1-921b9c1255b3', - name: 'Vaughan Longstreet', - email: 'vlongstreetg@jugem.jp', - language: 'Khmer', - status: 'Active', - lastLoginDate: '3/16/2022', - lastLockoutDate: '11/4/2021', - lastPasswordChangeDate: '3/23/2022', - updateDate: '7/18/2022', - createDate: '8/24/2022', - failedLoginAttempts: 737, - }, - { - id: 18, - key: 'e2f0b261-8900-41a3-b80c-6a54e55da4a7', - name: 'Vanda Scamadin', - email: 'vscamadinh@list-manage.com', - language: 'Telugu', - status: 'Inactive', - updateDate: '7/16/2022', - createDate: '1/5/2022', - failedLoginAttempts: 721, - }, - { - id: 19, - key: '54ff0b22-f419-47c0-a6a0-85a2ba43a300', - name: 'Reagen Nore', - email: 'rnorei@ning.com', - language: 'Kyrgyz', - status: 'Disabled', - lastLoginDate: '7/10/2022', - lastLockoutDate: '4/29/2022', - lastPasswordChangeDate: '10/26/2021', - updateDate: '12/17/2021', - createDate: '12/7/2021', - failedLoginAttempts: 351, - }, - { - id: 20, - key: '2b8dfa33-3dea-407e-8bcc-038f903ec37c', - name: 'Crosby Breens', - email: 'cbreensj@google.com.br', - language: 'Māori', - status: 'Disabled', - lastLoginDate: '8/7/2022', - lastLockoutDate: '5/23/2022', - lastPasswordChangeDate: '1/26/2022', - updateDate: '11/12/2021', - createDate: '5/24/2022', - failedLoginAttempts: 182, - }, - { - id: 21, - key: 'd0244fdc-4b68-4a71-a11b-7c047503ba38', - name: 'Felipe Finicj', - email: 'ffinicjk@economist.com', - language: 'Latvian', - status: 'Active', - lastLoginDate: '11/5/2021', - lastLockoutDate: '7/12/2022', - lastPasswordChangeDate: '4/12/2022', - updateDate: '12/16/2021', - createDate: '11/27/2021', - failedLoginAttempts: 212, - }, - { - id: 22, - key: '0934aae0-d565-4087-87ea-171c23ed012c', - name: 'Ash Shepstone', - email: 'ashepstonel@arizona.edu', - language: 'French', - status: 'Invited', - lastLoginDate: '1/18/2022', - lastLockoutDate: '10/17/2021', - lastPasswordChangeDate: '11/24/2021', - updateDate: '4/14/2022', - createDate: '6/5/2022', - failedLoginAttempts: 825, - }, - { - id: 23, - key: '1e244947-6fb6-4c34-8e22-87d14e1002b4', - name: 'Franni Plester', - email: 'fplesterm@nytimes.com', - language: 'Hungarian', - status: 'Active', - lastLoginDate: '7/27/2022', - lastLockoutDate: '8/17/2022', - lastPasswordChangeDate: '3/2/2022', - updateDate: '2/26/2022', - createDate: '7/18/2022', - failedLoginAttempts: 10, - }, - { - id: 24, - key: 'e6539e00-e4e7-4b09-a8ba-2bb5026b1842', - name: "Pearla O'Cooney", - email: 'pocooneyn@hugedomains.com', - language: 'Persian', - status: 'Disabled', - lastLoginDate: '3/29/2022', - lastLockoutDate: '3/18/2022', - lastPasswordChangeDate: '11/25/2021', - updateDate: '4/27/2022', - createDate: '11/10/2021', - failedLoginAttempts: 774, - }, - { - id: 25, - key: '2fa83b80-d938-472f-b4f0-a480c342bfdc', - name: 'Brittaney Linsay', - email: 'blinsayo@godaddy.com', - language: 'Amharic', - status: 'Disabled', - lastLoginDate: '9/21/2022', - lastLockoutDate: '1/28/2022', - lastPasswordChangeDate: '6/15/2022', - updateDate: '9/5/2022', - createDate: '9/6/2022', - failedLoginAttempts: 538, - }, - { - id: 26, - key: '2f40ba2c-36f4-45f9-94ff-2ee01be3a83f', - name: 'Terry McCorkell', - email: 'tmccorkellp@noaa.gov', - language: 'Dhivehi', - status: 'Active', - lastLoginDate: '7/23/2022', - lastLockoutDate: '7/24/2022', - lastPasswordChangeDate: '10/11/2021', - updateDate: '12/9/2021', - createDate: '12/10/2021', - failedLoginAttempts: 766, - }, - { - id: 27, - key: 'ff5c07f1-9628-4f1a-b416-46e9669ff261', - name: 'Amalea Barbour', - email: 'abarbourq@businesswire.com', - language: 'Catalan', - status: 'Invited', - lastLoginDate: '11/29/2021', - lastLockoutDate: '1/17/2022', - lastPasswordChangeDate: '2/2/2022', - updateDate: '5/18/2022', - createDate: '12/31/2021', - failedLoginAttempts: 903, - }, - { - id: 28, - key: '188a2fed-c3f1-4e2f-8e96-1a930f2dbeaa', - name: 'Bethena Grewe', - email: 'bgrewer@naver.com', - language: 'Haitian Creole', - status: 'Active', - lastLoginDate: '11/12/2021', - lastLockoutDate: '6/4/2022', - lastPasswordChangeDate: '8/25/2022', - updateDate: '2/23/2022', - createDate: '7/10/2022', - failedLoginAttempts: 348, - }, - { - id: 29, - key: '7651d063-7a6a-4ccf-a14f-a4123e4e0154', - name: 'Yorgos Ferroni', - email: 'yferronis@unblog.fr', - language: 'Afrikaans', - status: 'Inactive', - lastLoginDate: '7/13/2022', - lastLockoutDate: '3/16/2022', - lastPasswordChangeDate: '2/2/2022', - updateDate: '12/19/2021', - createDate: '5/2/2022', - failedLoginAttempts: 774, - }, - { - id: 30, - key: 'd8798556-96e1-4a4b-bc61-29baad622d1d', - name: 'Ivar Wisbey', - email: 'iwisbeyt@blogspot.com', - language: 'Lao', - status: 'Invited', - lastLoginDate: '6/15/2022', - lastLockoutDate: '3/4/2022', - lastPasswordChangeDate: '2/1/2022', - updateDate: '5/22/2022', - createDate: '5/6/2022', - failedLoginAttempts: 912, - }, - { - id: 31, - key: 'd0633a4e-7532-4a36-be2e-5befe8a46f66', - name: 'Casie Greatland', - email: 'cgreatlandu@google.cn', - language: 'Māori', - status: 'Disabled', - lastLoginDate: '12/19/2021', - lastLockoutDate: '10/15/2021', - lastPasswordChangeDate: '3/4/2022', - updateDate: '4/5/2022', - createDate: '6/6/2022', - failedLoginAttempts: 261, - }, - { - id: 32, - key: 'af784e2b-02bf-4d75-b199-0fa92bd1a12c', - name: 'Bat Dake', - email: 'bdakev@mapy.cz', - language: 'Armenian', - status: 'Invited', - lastLoginDate: '9/17/2022', - lastLockoutDate: '12/17/2021', - lastPasswordChangeDate: '3/10/2022', - updateDate: '7/13/2022', - createDate: '9/18/2022', - failedLoginAttempts: 589, - }, - { - id: 33, - key: '0a25512d-a7d2-429b-9e92-ebc3cae5ca19', - name: 'Chlo Skirven', - email: 'cskirvenw@histats.com', - language: 'Irish Gaelic', - status: 'Invited', - lastLoginDate: '6/22/2022', - lastLockoutDate: '6/7/2022', - lastPasswordChangeDate: '10/27/2021', - updateDate: '8/26/2022', - createDate: '10/31/2021', - failedLoginAttempts: 323, - }, - { - id: 34, - key: 'aadb0afb-b42e-4b84-9889-91f177b4f03f', - name: 'Delmer Porch', - email: 'dporchx@newyorker.com', - language: 'Punjabi', - status: 'Disabled', - lastLoginDate: '1/22/2022', - lastLockoutDate: '12/10/2021', - lastPasswordChangeDate: '5/24/2022', - updateDate: '8/28/2022', - createDate: '4/26/2022', - failedLoginAttempts: 300, - }, - { - id: 35, - key: 'd8f5122b-06c7-4253-9358-0ffb673fd6fa', - name: 'Gussi Lednor', - email: 'glednory@google.de', - language: 'Romanian', - status: 'Invited', - lastLoginDate: '6/1/2022', - lastLockoutDate: '11/17/2021', - lastPasswordChangeDate: '12/25/2021', - updateDate: '2/3/2022', - createDate: '6/9/2022', - failedLoginAttempts: 39, - }, - { - id: 36, - key: 'f81d21b6-c2bd-455c-9614-80c6f0ca7aba', - name: 'Tish Kubacki', - email: 'tkubackiz@gmpg.org', - language: 'Bosnian', - status: 'Disabled', - lastLoginDate: '11/29/2021', - lastLockoutDate: '11/28/2021', - lastPasswordChangeDate: '12/1/2021', - updateDate: '5/25/2022', - createDate: '8/6/2022', - failedLoginAttempts: 826, - }, - { - id: 37, - key: 'e5d98b85-6d9b-40b4-8237-cf98db0a6331', - name: 'Madelene Le Noury', - email: 'mle10@google.com.au', - language: 'Punjabi', - status: 'Invited', - lastLoginDate: '6/8/2022', - lastLockoutDate: '11/1/2021', - lastPasswordChangeDate: '8/19/2022', - updateDate: '8/29/2022', - createDate: '8/2/2022', - failedLoginAttempts: 619, - }, - { - id: 38, - key: 'bb96eeb6-2f4c-4eda-a277-91077b0219b0', - name: 'Alberta Headech', - email: 'aheadech11@diigo.com', - language: 'Kazakh', - status: 'Active', - lastLoginDate: '8/12/2022', - lastLockoutDate: '8/8/2022', - lastPasswordChangeDate: '10/29/2021', - updateDate: '2/4/2022', - createDate: '10/18/2021', - failedLoginAttempts: 191, - }, - { - id: 39, - key: '56a2d315-0cc5-4b0d-9ae3-8a7b7326e531', - name: 'Kenon Maybey', - email: 'kmaybey12@cdbaby.com', - language: 'Telugu', - status: 'Active', - lastLoginDate: '6/11/2022', - lastLockoutDate: '3/4/2022', - lastPasswordChangeDate: '5/5/2022', - updateDate: '10/21/2021', - createDate: '9/1/2022', - failedLoginAttempts: 45, - }, - { - id: 40, - key: 'dddae890-939e-48fd-89da-90631be9401f', - name: 'Brig Totterdill', - email: 'btotterdill13@telegraph.co.uk', - language: 'Tajik', - status: 'Disabled', - lastLoginDate: '8/11/2022', - lastLockoutDate: '3/31/2022', - lastPasswordChangeDate: '4/30/2022', - updateDate: '3/9/2022', - createDate: '3/23/2022', - failedLoginAttempts: 936, - }, - { - id: 41, - key: '96359df7-74a3-4eff-a729-40eac9a85fcc', - name: 'Kore Faragher', - email: 'kfaragher14@elpais.com', - language: 'Georgian', - status: 'Disabled', - lastLoginDate: '5/9/2022', - lastLockoutDate: '4/19/2022', - lastPasswordChangeDate: '7/26/2022', - updateDate: '10/17/2021', - createDate: '4/14/2022', - failedLoginAttempts: 843, - }, - { - id: 42, - key: 'af74ab26-81f2-4c51-8867-24acc7021c3c', - name: 'Benedicto Oda', - email: 'boda15@zimbio.com', - language: 'Hungarian', - status: 'Active', - lastLoginDate: '7/6/2022', - lastLockoutDate: '12/27/2021', - lastPasswordChangeDate: '9/15/2022', - updateDate: '1/13/2022', - createDate: '4/1/2022', - failedLoginAttempts: 262, - }, - { - id: 43, - key: '81648dc6-93d5-468d-8fac-fcdd0fb854cd', - name: 'Celinka Gyorffy', - email: 'cgyorffy16@godaddy.com', - language: 'Punjabi', - status: 'Inactive', - lastLoginDate: '7/15/2022', - lastLockoutDate: '5/24/2022', - lastPasswordChangeDate: '2/26/2022', - updateDate: '3/27/2022', - createDate: '8/3/2022', - failedLoginAttempts: 606, - }, - { - id: 44, - key: '1c8fd6b4-ccd4-4bc3-9cde-bb705e2618aa', - name: 'Arri Goretti', - email: 'agoretti17@pcworld.com', - language: 'Armenian', - status: 'Invited', - updateDate: '1/24/2022', - createDate: '7/11/2022', - failedLoginAttempts: 234, - }, - { - id: 45, - key: 'dd26e22b-bcab-449f-8a35-ae63be90e8c6', - name: 'Giffie Strattan', - email: 'gstrattan18@cisco.com', - language: 'Maltese', - status: 'Disabled', - lastLoginDate: '5/15/2022', - lastLockoutDate: '10/21/2021', - lastPasswordChangeDate: '2/2/2022', - updateDate: '4/12/2022', - createDate: '7/7/2022', - failedLoginAttempts: 62, - }, - { - id: 46, - key: '08b5e626-20e6-486d-a289-baa5b49ee360', - name: 'Aeriel Webling', - email: 'awebling19@usgs.gov', - language: 'Dutch', - status: 'Disabled', - lastLoginDate: '7/20/2022', - lastLockoutDate: '11/17/2021', - lastPasswordChangeDate: '8/22/2022', - updateDate: '8/31/2022', - createDate: '7/8/2022', - failedLoginAttempts: 34, - }, - { - id: 47, - key: '064981b2-f8e4-4a25-a16e-1fe3441ae0a0', - name: 'Roderic Heckle', - email: 'rheckle1a@pbs.org', - language: 'Dari', - status: 'Inactive', - updateDate: '7/31/2022', - createDate: '2/19/2022', - failedLoginAttempts: 279, - }, - { - id: 48, - key: '0c221634-03be-4e69-9399-350c1da61641', - name: 'Gonzalo Magister', - email: 'gmagister1b@jigsy.com', - language: 'Hungarian', - status: 'Disabled', - lastLoginDate: '8/21/2022', - lastLockoutDate: '6/23/2022', - lastPasswordChangeDate: '2/11/2022', - updateDate: '6/23/2022', - createDate: '8/1/2022', - failedLoginAttempts: 227, - }, - { - id: 49, - key: 'e26f1576-483e-4132-a25a-1eaddf63f40d', - name: 'Nickolai Landsborough', - email: 'nlandsborough1c@ask.com', - language: 'Guaraní', - status: 'Inactive', - lastLoginDate: '11/25/2021', - lastLockoutDate: '7/24/2022', - lastPasswordChangeDate: '4/20/2022', - updateDate: '8/17/2022', - createDate: '10/31/2021', - failedLoginAttempts: 85, - }, - { - id: 50, - key: '7032b5ea-467a-43aa-9a23-33f195cfa0a0', - name: 'Linn Early', - email: 'learly1d@msn.com', - language: 'Swedish', - status: 'Active', - lastLoginDate: '10/18/2021', - lastLockoutDate: '6/14/2022', - lastPasswordChangeDate: '4/10/2022', - updateDate: '10/26/2021', - createDate: '7/30/2022', - failedLoginAttempts: 198, - }, - { - id: 51, - key: '57bb4927-a7a7-4dc9-af48-f418f1c0fbc6', - name: 'Julianna Jakab', - email: 'jjakab1e@cbsnews.com', - language: 'Malay', - status: 'Active', - lastLoginDate: '3/22/2022', - lastLockoutDate: '6/2/2022', - lastPasswordChangeDate: '9/7/2022', - updateDate: '3/14/2022', - createDate: '10/19/2021', - failedLoginAttempts: 387, - }, - { - id: 52, - key: 'd5bb1d61-1201-43b8-b3df-2bd9b4bf1269', - name: 'Erick Hovell', - email: 'ehovell1f@ucoz.com', - language: 'New Zealand Sign Language', - status: 'Disabled', - updateDate: '11/30/2021', - createDate: '3/4/2022', - failedLoginAttempts: 150, - }, - { - id: 53, - key: '3e711421-bdc3-411e-909c-ba7230396266', - name: 'Bondon Berends', - email: 'bberends1g@si.edu', - language: 'Zulu', - status: 'Invited', - updateDate: '1/12/2022', - createDate: '4/22/2022', - failedLoginAttempts: 455, - }, - { - id: 54, - key: '2c0806e0-a7dc-46bd-a4c1-85a7d0799c56', - name: 'Rubie Palluschek', - email: 'rpalluschek1h@multiply.com', - language: 'Icelandic', - status: 'Disabled', - lastLoginDate: '7/18/2022', - lastLockoutDate: '1/14/2022', - lastPasswordChangeDate: '8/13/2022', - updateDate: '1/17/2022', - createDate: '4/9/2022', - failedLoginAttempts: 427, - }, - { - id: 55, - key: '5fc52879-4684-44b1-9c39-63fc47d85587', - name: 'Kass Gaisford', - email: 'kgaisford1i@tiny.cc', - language: 'Hiri Motu', - status: 'Invited', - lastLoginDate: '12/22/2021', - lastLockoutDate: '9/10/2022', - lastPasswordChangeDate: '6/6/2022', - updateDate: '1/2/2022', - createDate: '7/1/2022', - failedLoginAttempts: 951, - }, - { - id: 56, - key: '0daeefb8-8f39-4d63-be8e-eef0239b418c', - name: 'Eba Fewings', - email: 'efewings1j@hexun.com', - language: 'Quechua', - status: 'Invited', - lastLoginDate: '11/30/2021', - lastLockoutDate: '4/17/2022', - lastPasswordChangeDate: '7/8/2022', - updateDate: '3/7/2022', - createDate: '6/19/2022', - failedLoginAttempts: 371, - }, - { - id: 57, - key: 'f34d019d-af85-4579-b510-b0e5a27c05ab', - name: 'Rand Espadate', - email: 'respadate1k@skyrock.com', - language: 'Persian', - status: 'Disabled', - lastLoginDate: '8/22/2022', - lastLockoutDate: '6/14/2022', - lastPasswordChangeDate: '9/5/2022', - updateDate: '2/11/2022', - createDate: '2/21/2022', - failedLoginAttempts: 5, - }, - { - id: 58, - key: 'acab2dd7-baae-40ef-b272-96ec50e633f7', - name: 'Bobina Macconachy', - email: 'bmacconachy1l@wikipedia.org', - language: 'Gujarati', - status: 'Active', - lastLoginDate: '5/25/2022', - lastLockoutDate: '6/28/2022', - lastPasswordChangeDate: '6/26/2022', - updateDate: '8/11/2022', - createDate: '3/12/2022', - failedLoginAttempts: 243, - }, - { - id: 59, - key: '8e3c0364-0c2a-451e-a65d-7c46cfba2436', - name: 'Walther Pattie', - email: 'wpattie1m@example.com', - language: 'Zulu', - status: 'Invited', - updateDate: '3/8/2022', - createDate: '10/8/2021', - failedLoginAttempts: 381, - }, - { - id: 60, - key: '0548a79d-a767-450c-9823-e170284347e9', - name: 'Elton Jedrychowski', - email: 'ejedrychowski1n@cam.ac.uk', - language: 'Greek', - status: 'Invited', - lastLoginDate: '5/16/2022', - lastLockoutDate: '7/18/2022', - lastPasswordChangeDate: '11/28/2021', - updateDate: '7/27/2022', - createDate: '9/30/2022', - failedLoginAttempts: 27, - }, - { - id: 61, - key: 'd97f31cd-939d-4686-b282-e6613c930ce9', - name: 'Melamie Chifney', - email: 'mchifney1o@umich.edu', - language: 'Albanian', - status: 'Active', - lastLoginDate: '3/16/2022', - lastLockoutDate: '12/22/2021', - lastPasswordChangeDate: '1/8/2022', - updateDate: '10/22/2021', - createDate: '12/9/2021', - failedLoginAttempts: 807, - }, - { - id: 62, - key: '160614dd-5749-4a74-878e-ac82e8cfe21b', - name: 'Auroora Theuff', - email: 'atheuff1p@over-blog.com', - language: 'Kurdish', - status: 'Inactive', - lastLoginDate: '11/28/2021', - lastLockoutDate: '11/17/2021', - lastPasswordChangeDate: '11/20/2021', - updateDate: '4/9/2022', - createDate: '6/29/2022', - failedLoginAttempts: 334, - }, - { - id: 63, - key: '3a1a9869-d103-40fb-98ac-4cce9e16ac17', - name: 'Law Cours', - email: 'lcours1q@google.co.uk', - language: 'Arabic', - status: 'Invited', - lastLoginDate: '3/27/2022', - lastLockoutDate: '12/2/2021', - lastPasswordChangeDate: '3/14/2022', - updateDate: '7/14/2022', - createDate: '2/4/2022', - failedLoginAttempts: 129, - }, - { - id: 64, - key: '174fd2e2-ac91-4eae-a366-2fe7e4322d88', - name: 'Clarke Rosenhaus', - email: 'crosenhaus1r@globo.com', - language: 'Afrikaans', - status: 'Active', - lastLoginDate: '6/23/2022', - lastLockoutDate: '7/4/2022', - lastPasswordChangeDate: '12/5/2021', - updateDate: '4/18/2022', - createDate: '8/16/2022', - failedLoginAttempts: 450, - }, - { - id: 65, - key: '762844a8-b64e-473a-ba50-f2cb446c8e93', - name: 'Nevins Gabler', - email: 'ngabler1s@psu.edu', - language: 'Korean', - status: 'Invited', - updateDate: '12/2/2021', - createDate: '12/14/2021', - failedLoginAttempts: 189, - }, - { - id: 66, - key: '46f28ab6-06ca-4d9f-93e4-742218ed5dca', - name: 'Bondon Corrin', - email: 'bcorrin1t@ustream.tv', - language: 'Hiri Motu', - status: 'Active', - lastLoginDate: '1/14/2022', - lastLockoutDate: '6/14/2022', - lastPasswordChangeDate: '11/28/2021', - updateDate: '9/10/2022', - createDate: '5/12/2022', - failedLoginAttempts: 359, - }, - { - id: 67, - key: 'b55ca6f9-2fd3-4e0d-a222-6df52db14007', - name: 'Juli Birtwistle', - email: 'jbirtwistle1u@histats.com', - language: 'Haitian Creole', - status: 'Active', - lastLoginDate: '11/25/2021', - lastLockoutDate: '3/20/2022', - lastPasswordChangeDate: '12/20/2021', - updateDate: '6/16/2022', - createDate: '11/29/2021', - failedLoginAttempts: 956, - }, - { - id: 68, - key: 'a5c7ea42-3257-48fe-9497-f684e6cdebaa', - name: 'Tomasine Hirsthouse', - email: 'thirsthouse1v@ehow.com', - language: 'Bosnian', - status: 'Disabled', - lastLoginDate: '9/19/2022', - lastLockoutDate: '4/21/2022', - lastPasswordChangeDate: '2/7/2022', - updateDate: '2/12/2022', - createDate: '1/3/2022', - failedLoginAttempts: 533, - }, - { - id: 69, - key: '4f9da285-8b73-4f74-9e54-50d04f1441a0', - name: 'Candide Flecknell', - email: 'cflecknell1w@guardian.co.uk', - language: 'Estonian', - status: 'Disabled', - lastLoginDate: '3/25/2022', - lastLockoutDate: '10/26/2021', - lastPasswordChangeDate: '12/3/2021', - updateDate: '12/31/2021', - createDate: '1/31/2022', - failedLoginAttempts: 621, - }, - { - id: 70, - key: '4054205f-6d9d-4bea-b1b2-29168dead18d', - name: 'Skelly Hockey', - email: 'shockey1x@usa.gov', - language: 'Burmese', - status: 'Active', - updateDate: '8/30/2022', - createDate: '1/16/2022', - failedLoginAttempts: 211, - }, - { - id: 71, - key: '1574526d-614b-41f4-abb4-4066fac8815c', - name: 'Nicholas Woan', - email: 'nwoan1y@istockphoto.com', - language: 'Māori', - status: 'Invited', - lastLoginDate: '4/16/2022', - lastLockoutDate: '4/17/2022', - lastPasswordChangeDate: '7/14/2022', - updateDate: '12/30/2021', - createDate: '1/19/2022', - failedLoginAttempts: 78, - }, - { - id: 72, - key: '745e0d21-44a6-4df1-81a0-d796ff7e6801', - name: 'Asa Kase', - email: 'akase1z@scribd.com', - language: 'Irish Gaelic', - status: 'Invited', - updateDate: '7/16/2022', - createDate: '10/23/2021', - failedLoginAttempts: 790, - }, - { - id: 73, - key: 'e0fc930c-6ed5-4064-a039-9e2c3b0dc644', - name: 'Emmerich Sisey', - email: 'esisey20@baidu.com', - language: 'Tetum', - status: 'Active', - lastLoginDate: '5/22/2022', - lastLockoutDate: '6/26/2022', - lastPasswordChangeDate: '5/22/2022', - updateDate: '5/8/2022', - createDate: '9/20/2022', - failedLoginAttempts: 10, - }, - { - id: 74, - key: '0f36289e-abce-4fa9-a524-49664389c2ef', - name: 'Trish Cerith', - email: 'tcerith21@tuttocitta.it', - language: 'Spanish', - status: 'Invited', - lastLoginDate: '1/11/2022', - lastLockoutDate: '9/1/2022', - lastPasswordChangeDate: '1/29/2022', - updateDate: '10/16/2021', - createDate: '1/13/2022', - failedLoginAttempts: 417, - }, - { - id: 75, - key: 'c7a02de0-2eb6-461d-8036-e163b12ef2b5', - name: 'Netty Rudge', - email: 'nrudge22@xinhuanet.com', - language: 'Fijian', - status: 'Active', - lastLoginDate: '4/21/2022', - lastLockoutDate: '7/21/2022', - lastPasswordChangeDate: '11/6/2021', - updateDate: '11/12/2021', - createDate: '4/4/2022', - failedLoginAttempts: 214, - }, - { - id: 76, - key: 'dfa94377-3eb7-4318-804c-892f125cdb65', - name: 'Joane Kuhne', - email: 'jkuhne23@opera.com', - language: 'Danish', - status: 'Active', - lastLoginDate: '1/10/2022', - lastLockoutDate: '9/18/2022', - lastPasswordChangeDate: '9/6/2022', - updateDate: '2/9/2022', - createDate: '4/14/2022', - failedLoginAttempts: 735, - }, - { - id: 77, - key: '34114a3c-b6a9-41e4-ad65-377abb1f2fbd', - name: 'Sheilah Nattrass', - email: 'snattrass24@sbwire.com', - language: 'Korean', - status: 'Invited', - lastLoginDate: '5/7/2022', - lastLockoutDate: '10/20/2021', - lastPasswordChangeDate: '11/13/2021', - updateDate: '12/6/2021', - createDate: '6/25/2022', - failedLoginAttempts: 480, - }, - { - id: 78, - key: 'c9a62d42-9b32-441b-b758-283526c749b1', - name: "Luella O'Geaney", - email: 'logeaney25@foxnews.com', - language: 'Arabic', - status: 'Disabled', - lastLoginDate: '10/21/2021', - lastLockoutDate: '8/12/2022', - lastPasswordChangeDate: '7/20/2022', - updateDate: '5/11/2022', - createDate: '5/19/2022', - failedLoginAttempts: 828, - }, - { - id: 79, - key: '4c54110a-5768-4979-adf0-c8e52a2ae6a6', - name: 'Cyrille Curm', - email: 'ccurm26@forbes.com', - language: 'Icelandic', - status: 'Active', - lastLoginDate: '12/17/2021', - lastLockoutDate: '8/9/2022', - lastPasswordChangeDate: '10/14/2021', - updateDate: '5/19/2022', - createDate: '5/5/2022', - failedLoginAttempts: 840, - }, - { - id: 80, - key: '86bdee19-c4a6-412c-9c38-173232993952', - name: 'Leonard Vitall', - email: 'lvitall27@clickbank.net', - language: 'Haitian Creole', - status: 'Inactive', - lastLoginDate: '8/12/2022', - lastLockoutDate: '2/26/2022', - lastPasswordChangeDate: '10/2/2022', - updateDate: '12/31/2021', - createDate: '1/13/2022', - failedLoginAttempts: 588, - }, - { - id: 81, - key: '0961184f-5b1a-4e21-b598-c2e4fda4b498', - name: 'Nickie Bronger', - email: 'nbronger28@xrea.com', - language: 'West Frisian', - status: 'Active', - lastLoginDate: '8/5/2022', - lastLockoutDate: '1/21/2022', - lastPasswordChangeDate: '4/8/2022', - updateDate: '5/11/2022', - createDate: '10/12/2021', - failedLoginAttempts: 639, - }, - { - id: 82, - key: '7cc8803f-9c20-44aa-9399-d4ec5e52e008', - name: 'Annie Butterworth', - email: 'abutterworth29@marketwatch.com', - language: 'Bulgarian', - status: 'Active', - lastLoginDate: '10/30/2021', - lastLockoutDate: '10/5/2021', - lastPasswordChangeDate: '5/3/2022', - updateDate: '4/4/2022', - createDate: '1/25/2022', - failedLoginAttempts: 912, - }, - { - id: 83, - key: '61ec70a3-6a8d-42fe-88f3-c866328c4a9c', - name: 'Dasi Ughi', - email: 'dughi2a@vimeo.com', - language: 'Yiddish', - status: 'Disabled', - lastLoginDate: '10/14/2021', - lastLockoutDate: '1/11/2022', - lastPasswordChangeDate: '8/1/2022', - updateDate: '10/31/2021', - createDate: '7/2/2022', - failedLoginAttempts: 494, - }, - { - id: 84, - key: '21bbdd96-ea8d-463c-8d10-fd6d016bf4e0', - name: 'Lawrence Cansfield', - email: 'lcansfield2b@istockphoto.com', - language: 'Estonian', - status: 'Disabled', - lastLoginDate: '3/24/2022', - lastLockoutDate: '10/11/2021', - lastPasswordChangeDate: '5/20/2022', - updateDate: '12/1/2021', - createDate: '10/26/2021', - failedLoginAttempts: 258, - }, - { - id: 85, - key: 'f897a981-0452-4c06-b875-dab80109051b', - name: 'Gal Lyster', - email: 'glyster2c@google.cn', - language: 'Indonesian', - status: 'Disabled', - lastLoginDate: '8/29/2022', - lastLockoutDate: '9/25/2022', - lastPasswordChangeDate: '10/16/2021', - updateDate: '4/16/2022', - createDate: '3/17/2022', - failedLoginAttempts: 103, - }, - { - id: 86, - key: '1f8d4217-3037-444e-b91a-0e18f20b3919', - name: 'Caron Crolly', - email: 'ccrolly2d@jalbum.net', - language: 'Italian', - status: 'Disabled', - lastLoginDate: '7/12/2022', - lastLockoutDate: '3/20/2022', - lastPasswordChangeDate: '1/4/2022', - updateDate: '11/26/2021', - createDate: '6/5/2022', - failedLoginAttempts: 211, - }, - { - id: 87, - key: 'f4449cde-ef12-4068-9f13-6104d281e494', - name: 'Juliana Clorley', - email: 'jclorley2e@mail.ru', - language: 'Luxembourgish', - status: 'Active', - lastLoginDate: '10/17/2021', - lastLockoutDate: '8/4/2022', - lastPasswordChangeDate: '12/23/2021', - updateDate: '2/23/2022', - createDate: '8/22/2022', - failedLoginAttempts: 208, - }, - { - id: 88, - key: 'ac75e813-22bc-4d42-8f98-a4ba6f19bdf8', - name: 'Kylynn Falvey', - email: 'kfalvey2f@com.com', - language: 'Zulu', - status: 'Inactive', - lastLoginDate: '3/4/2022', - lastLockoutDate: '6/4/2022', - lastPasswordChangeDate: '6/9/2022', - updateDate: '2/14/2022', - createDate: '1/30/2022', - failedLoginAttempts: 75, - }, - { - id: 89, - key: 'ba9caf4c-aeee-48e8-a7d7-3ff2239c0186', - name: 'Marty Shurrock', - email: 'mshurrock2g@hhs.gov', - language: 'Danish', - status: 'Inactive', - lastLoginDate: '10/2/2022', - lastLockoutDate: '9/16/2022', - lastPasswordChangeDate: '12/3/2021', - updateDate: '5/26/2022', - createDate: '4/30/2022', - failedLoginAttempts: 40, - }, - { - id: 90, - key: '924e087c-b0b5-4c59-a8b8-a71ad112c4b0', - name: 'Goldia Crates', - email: 'gcrates2h@privacy.gov.au', - language: 'Pashto', - status: 'Inactive', - lastLoginDate: '9/27/2022', - lastLockoutDate: '2/7/2022', - lastPasswordChangeDate: '12/9/2021', - updateDate: '5/5/2022', - createDate: '9/25/2022', - failedLoginAttempts: 710, - }, - { - id: 91, - key: '909154d4-5c84-461d-b256-552f358a0d68', - name: 'Ted Stratley', - email: 'tstratley2i@tinypic.com', - language: 'Mongolian', - status: 'Inactive', - lastLoginDate: '4/19/2022', - lastLockoutDate: '9/24/2022', - lastPasswordChangeDate: '10/24/2021', - updateDate: '7/29/2022', - createDate: '2/7/2022', - failedLoginAttempts: 730, - }, - { - id: 92, - key: '284e7d5a-1b10-4814-a5fd-da17180c1753', - name: 'Rubia Collecott', - email: 'rcollecott2j@oaic.gov.au', - language: 'Somali', - status: 'Inactive', - updateDate: '1/27/2022', - createDate: '3/7/2022', - failedLoginAttempts: 250, - }, - { - id: 93, - key: '91205c6e-3be9-47fc-b5f3-01c89306dcd5', - name: 'Nilson Britland', - email: 'nbritland2k@facebook.com', - language: 'Ndebele', - status: 'Disabled', - lastLoginDate: '8/25/2022', - lastLockoutDate: '12/31/2021', - lastPasswordChangeDate: '8/15/2022', - updateDate: '8/14/2022', - createDate: '11/17/2021', - failedLoginAttempts: 360, - }, - { - id: 94, - key: 'da108699-76d9-4691-9dbd-c11a16cf3514', - name: 'Johannes Slucock', - email: 'jslucock2l@buzzfeed.com', - language: 'Malagasy', - status: 'Inactive', - lastLoginDate: '1/5/2022', - lastLockoutDate: '10/11/2021', - lastPasswordChangeDate: '2/17/2022', - updateDate: '6/13/2022', - createDate: '7/19/2022', - failedLoginAttempts: 397, - }, - { - id: 95, - key: '7469307b-a87b-49b9-8dab-100d7d7e31d0', - name: 'Rodrick Twelftree', - email: 'rtwelftree2m@nbcnews.com', - language: 'Luxembourgish', - status: 'Active', - lastLoginDate: '5/23/2022', - lastLockoutDate: '6/21/2022', - lastPasswordChangeDate: '8/27/2022', - updateDate: '10/20/2021', - createDate: '10/24/2021', - failedLoginAttempts: 104, - }, - { - id: 96, - key: 'cc7c8bbb-580f-445e-8af5-c3bf14b4a560', - name: 'Liesa Arnoll', - email: 'larnoll2n@webnode.com', - language: 'Hebrew', - status: 'Active', - lastLoginDate: '9/13/2022', - lastLockoutDate: '7/14/2022', - lastPasswordChangeDate: '2/28/2022', - updateDate: '6/20/2022', - createDate: '11/5/2021', - failedLoginAttempts: 78, - }, - { - id: 97, - key: '1c75ef97-b3f2-4194-b109-fd5c82efe9de', - name: 'Cindra Simkiss', - email: 'csimkiss2o@google.es', - language: 'Gagauz', - status: 'Disabled', - lastLoginDate: '4/18/2022', - lastLockoutDate: '9/2/2022', - lastPasswordChangeDate: '5/5/2022', - updateDate: '4/30/2022', - createDate: '9/25/2022', - failedLoginAttempts: 887, - }, - { - id: 98, - key: 'a010a09d-2e23-4403-806c-16fcfe70fcd4', - name: 'Belle Conrard', - email: 'bconrard2p@mozilla.org', - language: 'Hindi', - status: 'Invited', - lastLoginDate: '7/18/2022', - lastLockoutDate: '6/25/2022', - lastPasswordChangeDate: '2/21/2022', - updateDate: '7/18/2022', - createDate: '4/12/2022', - failedLoginAttempts: 477, - }, - { - id: 99, - key: '8c9bfaac-098f-43a4-91ee-a9eaf5dfe5ea', - name: 'Tremain Minor', - email: 'tminor2q@storify.com', - language: 'Chinese', - status: 'Invited', - lastLoginDate: '7/31/2022', - lastLockoutDate: '5/11/2022', - lastPasswordChangeDate: '11/10/2021', - updateDate: '8/9/2022', - createDate: '7/24/2022', - failedLoginAttempts: 160, - }, - { - id: 100, - key: 'ecb0ced9-c1c1-486d-a317-5f2b320859bd', - name: 'Isador Tibbles', - email: 'itibbles2r@cafepress.com', - language: 'Assamese', - status: 'Active', - lastLoginDate: '4/7/2022', - lastLockoutDate: '2/4/2022', - lastPasswordChangeDate: '11/14/2021', - updateDate: '4/14/2022', - createDate: '11/16/2021', - failedLoginAttempts: 932, - }, -]; + diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index eb350ccc3c..571f81ce4b 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -1,4 +1,5 @@ import type { components } from '../../../schemas/generated-schema'; +import { Entity } from '../../mocks/data/entities'; export type PostInstallRequest = components['schemas']['InstallSetupRequest']; export type StatusResponse = components['schemas']['StatusResponse']; @@ -55,3 +56,21 @@ export type ManifestElementType = // eslint-disable-next-line @typescript-eslint/no-explicit-any export type HTMLElementConstructor = new (...args: any[]) => T; + +// Users +export interface UserEntity extends Entity { + type: 'user'; +} + +export interface UserDetails extends UserEntity { + email: string; + status: string; + language: string; + lastLoginDate?: string; + lastLockoutDate?: string; + lastPasswordChangeDate?: string; + updateDate: string; + createDate: string; + failedLoginAttempts: number; + userGroup?: string; //TODO Implement this +} 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 index ae9b75e1c5..013bd33c01 100644 --- 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 @@ -1,15 +1,15 @@ import { map, Observable } from 'rxjs'; -import { UserItem } from '../../../backoffice/editors/users/views/users/editor-view-users.element'; +import type { UserEntity } from '../../models'; import { UmbEntityStore } from '../entity.store'; import { UmbDataStoreBase } from '../store'; /** * @export * @class UmbUserStore - * @extends {UmbDataStoreBase} + * @extends {UmbDataStoreBase} * @description - Data Store for Users */ -export class UmbUserStore extends UmbDataStoreBase { +export class UmbUserStore extends UmbDataStoreBase { private _entityStore: UmbEntityStore; constructor(entityStore: UmbEntityStore) { @@ -17,7 +17,7 @@ export class UmbUserStore extends UmbDataStoreBase { this._entityStore = entityStore; } - getAll(): Observable> { + getAll(): Observable> { // TODO: use Fetcher API. // TODO: only fetch if the data type is not in the store? fetch(`/umbraco/backoffice/users`) @@ -35,7 +35,7 @@ export class UmbUserStore extends UmbDataStoreBase { * @return {*} {(Observable)} * @memberof UmbDataTypeStore */ - getByKey(key: string): Observable { + 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}`) @@ -46,7 +46,7 @@ export class UmbUserStore extends UmbDataStoreBase { }); return this.items.pipe( - map((dataTypes: Array) => dataTypes.find((node: UserItem) => node.key === key) || null) + map((dataTypes: Array) => dataTypes.find((node: UserEntity) => node.key === key) || null) ); } diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts index 3393cf8f98..f51b05c6eb 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts @@ -7,9 +7,9 @@ export class UmbEntityData extends UmbData { super(data); } - getItems(type = '', parentKey = '') { + getItems(type: string, parentKey = '') { if (!type) return []; - return entities.filter((item) => item.type === type && item.parentKey === parentKey); + return this.data.filter((item) => item.type === type && item.parentKey === parentKey); } getByKey(key: string) { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts new file mode 100644 index 0000000000..4a3ded1cca --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts @@ -0,0 +1,1778 @@ +import type { UserDetails } from '../../core/models'; +import { UmbEntityData } from './entity.data'; + +export const data: Array = [ + { + key: '50f184d4-71f3-4a43-b8be-7a36340fbd0d', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Nat Linnane', + email: 'nlinnane0@fda.gov', + language: 'Greek', + status: 'Inactive', + lastLoginDate: '9/11/2022', + lastLockoutDate: '5/31/2022', + lastPasswordChangeDate: '1/10/2022', + updateDate: '8/27/2022', + createDate: '9/19/2022', + failedLoginAttempts: 52, + }, + { + key: '7c9c5510-a7b6-43fd-a2d1-51de0009eabf', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Tyrus Hows', + email: 'thows1@hatena.ne.jp', + language: 'Gagauz', + status: 'Inactive', + lastLoginDate: '9/1/2022', + lastLockoutDate: '2/9/2022', + lastPasswordChangeDate: '8/22/2022', + updateDate: '12/2/2021', + createDate: '9/17/2022', + failedLoginAttempts: 717, + }, + { + key: 'fa3cca42-3b65-4fce-9e9b-5b09ca44f536', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Nisse Grattan', + email: 'ngrattan2@alexa.com', + language: 'Tok Pisin', + status: 'Active', + lastLoginDate: '3/22/2022', + lastLockoutDate: '12/2/2021', + lastPasswordChangeDate: '5/28/2022', + updateDate: '9/4/2022', + createDate: '8/7/2022', + failedLoginAttempts: 873, + }, + { + key: '381383ef-8d81-455c-bcbc-5e95a5cdc897', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Thain Rainville', + email: 'trainville3@merriam-webster.com', + language: 'Tajik', + status: 'Active', + lastLoginDate: '2/28/2022', + lastLockoutDate: '1/6/2022', + lastPasswordChangeDate: '7/1/2022', + updateDate: '9/14/2022', + createDate: '2/20/2022', + failedLoginAttempts: 786, + }, + { + key: 'e3dcaf95-7d55-42e6-a023-ce179523bf48', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Perren Balsdon', + email: 'pbalsdon4@ezinearticles.com', + language: 'Somali', + status: 'Active', + lastLoginDate: '5/6/2022', + lastLockoutDate: '11/12/2021', + lastPasswordChangeDate: '11/10/2021', + updateDate: '5/8/2022', + createDate: '1/12/2022', + failedLoginAttempts: 884, + }, + { + key: '05d0356e-051f-4d00-8b56-24667deab75d', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Athene Bilborough', + email: 'abilborough5@princeton.edu', + language: 'Tetum', + status: 'Active', + lastLoginDate: '3/11/2022', + lastLockoutDate: '7/7/2022', + lastPasswordChangeDate: '3/8/2022', + updateDate: '12/31/2021', + createDate: '10/2/2022', + failedLoginAttempts: 527, + }, + { + key: 'ac906ed0-d8e0-4ca5-8f03-d817ce31fb7e', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Carline Sharp', + email: 'csharp6@com.com', + language: 'Portuguese', + status: 'Inactive', + lastLoginDate: '3/6/2022', + lastLockoutDate: '5/20/2022', + lastPasswordChangeDate: '10/9/2021', + updateDate: '1/19/2022', + createDate: '7/3/2022', + failedLoginAttempts: 324, + }, + { + key: '6e34346d-639e-4538-a2cc-9a8a6ba40545', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Tansy Hanna', + email: 'thanna7@google.pl', + language: 'Papiamento', + status: 'Active', + lastLoginDate: '9/10/2022', + lastLockoutDate: '10/28/2021', + lastPasswordChangeDate: '2/26/2022', + updateDate: '3/12/2022', + createDate: '3/6/2022', + failedLoginAttempts: 937, + }, + { + key: '978c1d59-0814-404d-a4c4-b5abceb4b1b6', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + name: 'Tyrus Howsa', + icon: 'umb:user', + email: 'hmohan8@google.co.jp', + language: 'Montenegrin', + status: 'Active', + lastLoginDate: '6/16/2022', + lastLockoutDate: '3/2/2022', + lastPasswordChangeDate: '4/14/2022', + updateDate: '1/30/2022', + createDate: '12/13/2021', + failedLoginAttempts: 804, + }, + { + key: '98d36a68-9b74-435f-8790-d177726f6fed', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Alden Blaschke', + email: 'ablaschke9@marketwatch.com', + language: 'Mongolian', + status: 'Inactive', + lastLoginDate: '6/27/2022', + lastLockoutDate: '4/16/2022', + lastPasswordChangeDate: '12/31/2021', + updateDate: '4/9/2022', + createDate: '6/18/2022', + failedLoginAttempts: 458, + }, + { + key: 'bf6b7fbe-d3e7-4ca8-9b6d-7daca03c2411', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Hollis Rouf', + email: 'hroufa@irs.gov', + language: 'Papiamento', + status: 'Inactive', + updateDate: '9/11/2022', + createDate: '6/18/2022', + failedLoginAttempts: 532, + }, + { + key: 'cf1d90af-5b77-4e00-98be-145214443c24', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Neils Janiak', + email: 'njaniakb@indiatimes.com', + language: 'Aymara', + status: 'Inactive', + updateDate: '11/7/2021', + createDate: '12/30/2021', + failedLoginAttempts: 800, + }, + { + key: '11e6ddc8-33e3-461b-8147-155eac339978', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Zarah Slaughter', + email: 'zslaughterc@storify.com', + language: 'Afrikaans', + status: 'Invited', + lastLoginDate: '1/1/2022', + lastLockoutDate: '5/4/2022', + lastPasswordChangeDate: '3/6/2022', + updateDate: '11/10/2021', + createDate: '8/1/2022', + failedLoginAttempts: 182, + }, + { + key: 'fb651643-3f2b-4b8e-ab96-a4f3fa15303a', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Elly Corbishley', + email: 'ecorbishleyd@hexun.com', + language: 'Kyrgyz', + status: 'Invited', + lastLoginDate: '6/3/2022', + lastLockoutDate: '4/4/2022', + lastPasswordChangeDate: '12/21/2021', + updateDate: '7/19/2022', + createDate: '5/12/2022', + failedLoginAttempts: 426, + }, + { + key: '1e329702-50d3-4176-b5db-9315ac6ac2a3', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Alisander Leupold', + email: 'aleupolde@webnode.com', + language: 'Nepali', + status: 'Inactive', + lastLoginDate: '1/4/2022', + lastLockoutDate: '9/15/2022', + lastPasswordChangeDate: '5/24/2022', + updateDate: '9/20/2022', + createDate: '3/15/2022', + failedLoginAttempts: 327, + }, + { + key: '1fead0fa-8d19-4153-abb0-980c18973d21', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Gennie Casaccia', + email: 'gcasacciaf@vkontakte.ru', + language: 'Catalan', + status: 'Active', + lastLoginDate: '4/11/2022', + lastLockoutDate: '3/17/2022', + lastPasswordChangeDate: '4/30/2022', + updateDate: '10/15/2021', + createDate: '2/14/2022', + failedLoginAttempts: 469, + }, + { + key: 'd273cd7c-cbd4-4535-83d1-921b9c1255b3', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Vaughan Longstreet', + email: 'vlongstreetg@jugem.jp', + language: 'Khmer', + status: 'Active', + lastLoginDate: '3/16/2022', + lastLockoutDate: '11/4/2021', + lastPasswordChangeDate: '3/23/2022', + updateDate: '7/18/2022', + createDate: '8/24/2022', + failedLoginAttempts: 737, + }, + { + key: 'e2f0b261-8900-41a3-b80c-6a54e55da4a7', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Vanda Scamadin', + email: 'vscamadinh@list-manage.com', + language: 'Telugu', + status: 'Inactive', + updateDate: '7/16/2022', + createDate: '1/5/2022', + failedLoginAttempts: 721, + }, + { + key: '54ff0b22-f419-47c0-a6a0-85a2ba43a300', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Reagen Nore', + email: 'rnorei@ning.com', + language: 'Kyrgyz', + status: 'Disabled', + lastLoginDate: '7/10/2022', + lastLockoutDate: '4/29/2022', + lastPasswordChangeDate: '10/26/2021', + updateDate: '12/17/2021', + createDate: '12/7/2021', + failedLoginAttempts: 351, + }, + { + key: '2b8dfa33-3dea-407e-8bcc-038f903ec37c', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Crosby Breens', + email: 'cbreensj@google.com.br', + language: 'Māori', + status: 'Disabled', + lastLoginDate: '8/7/2022', + lastLockoutDate: '5/23/2022', + lastPasswordChangeDate: '1/26/2022', + updateDate: '11/12/2021', + createDate: '5/24/2022', + failedLoginAttempts: 182, + }, + { + key: 'd0244fdc-4b68-4a71-a11b-7c047503ba38', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Felipe Finicj', + email: 'ffinicjk@economist.com', + language: 'Latvian', + status: 'Active', + lastLoginDate: '11/5/2021', + lastLockoutDate: '7/12/2022', + lastPasswordChangeDate: '4/12/2022', + updateDate: '12/16/2021', + createDate: '11/27/2021', + failedLoginAttempts: 212, + }, + { + key: '0934aae0-d565-4087-87ea-171c23ed012c', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Ash Shepstone', + email: 'ashepstonel@arizona.edu', + language: 'French', + status: 'Invited', + lastLoginDate: '1/18/2022', + lastLockoutDate: '10/17/2021', + lastPasswordChangeDate: '11/24/2021', + updateDate: '4/14/2022', + createDate: '6/5/2022', + failedLoginAttempts: 825, + }, + { + key: '1e244947-6fb6-4c34-8e22-87d14e1002b4', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Franni Plester', + email: 'fplesterm@nytimes.com', + language: 'Hungarian', + status: 'Active', + lastLoginDate: '7/27/2022', + lastLockoutDate: '8/17/2022', + lastPasswordChangeDate: '3/2/2022', + updateDate: '2/26/2022', + createDate: '7/18/2022', + failedLoginAttempts: 10, + }, + { + key: 'e6539e00-e4e7-4b09-a8ba-2bb5026b1842', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: "Pearla O'Cooney", + email: 'pocooneyn@hugedomains.com', + language: 'Persian', + status: 'Disabled', + lastLoginDate: '3/29/2022', + lastLockoutDate: '3/18/2022', + lastPasswordChangeDate: '11/25/2021', + updateDate: '4/27/2022', + createDate: '11/10/2021', + failedLoginAttempts: 774, + }, + { + key: '2fa83b80-d938-472f-b4f0-a480c342bfdc', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Brittaney Linsay', + email: 'blinsayo@godaddy.com', + language: 'Amharic', + status: 'Disabled', + lastLoginDate: '9/21/2022', + lastLockoutDate: '1/28/2022', + lastPasswordChangeDate: '6/15/2022', + updateDate: '9/5/2022', + createDate: '9/6/2022', + failedLoginAttempts: 538, + }, + { + key: '2f40ba2c-36f4-45f9-94ff-2ee01be3a83f', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Terry McCorkell', + email: 'tmccorkellp@noaa.gov', + language: 'Dhivehi', + status: 'Active', + lastLoginDate: '7/23/2022', + lastLockoutDate: '7/24/2022', + lastPasswordChangeDate: '10/11/2021', + updateDate: '12/9/2021', + createDate: '12/10/2021', + failedLoginAttempts: 766, + }, + { + key: 'ff5c07f1-9628-4f1a-b416-46e9669ff261', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Amalea Barbour', + email: 'abarbourq@businesswire.com', + language: 'Catalan', + status: 'Invited', + lastLoginDate: '11/29/2021', + lastLockoutDate: '1/17/2022', + lastPasswordChangeDate: '2/2/2022', + updateDate: '5/18/2022', + createDate: '12/31/2021', + failedLoginAttempts: 903, + }, + { + key: '188a2fed-c3f1-4e2f-8e96-1a930f2dbeaa', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Bethena Grewe', + email: 'bgrewer@naver.com', + language: 'Haitian Creole', + status: 'Active', + lastLoginDate: '11/12/2021', + lastLockoutDate: '6/4/2022', + lastPasswordChangeDate: '8/25/2022', + updateDate: '2/23/2022', + createDate: '7/10/2022', + failedLoginAttempts: 348, + }, + { + key: '7651d063-7a6a-4ccf-a14f-a4123e4e0154', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Yorgos Ferroni', + email: 'yferronis@unblog.fr', + language: 'Afrikaans', + status: 'Inactive', + lastLoginDate: '7/13/2022', + lastLockoutDate: '3/16/2022', + lastPasswordChangeDate: '2/2/2022', + updateDate: '12/19/2021', + createDate: '5/2/2022', + failedLoginAttempts: 774, + }, + { + key: 'd8798556-96e1-4a4b-bc61-29baad622d1d', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Ivar Wisbey', + email: 'iwisbeyt@blogspot.com', + language: 'Lao', + status: 'Invited', + lastLoginDate: '6/15/2022', + lastLockoutDate: '3/4/2022', + lastPasswordChangeDate: '2/1/2022', + updateDate: '5/22/2022', + createDate: '5/6/2022', + failedLoginAttempts: 912, + }, + { + key: 'd0633a4e-7532-4a36-be2e-5befe8a46f66', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Casie Greatland', + email: 'cgreatlandu@google.cn', + language: 'Māori', + status: 'Disabled', + lastLoginDate: '12/19/2021', + lastLockoutDate: '10/15/2021', + lastPasswordChangeDate: '3/4/2022', + updateDate: '4/5/2022', + createDate: '6/6/2022', + failedLoginAttempts: 261, + }, + { + key: 'af784e2b-02bf-4d75-b199-0fa92bd1a12c', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Bat Dake', + email: 'bdakev@mapy.cz', + language: 'Armenian', + status: 'Invited', + lastLoginDate: '9/17/2022', + lastLockoutDate: '12/17/2021', + lastPasswordChangeDate: '3/10/2022', + updateDate: '7/13/2022', + createDate: '9/18/2022', + failedLoginAttempts: 589, + }, + { + key: '0a25512d-a7d2-429b-9e92-ebc3cae5ca19', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Chlo Skirven', + email: 'cskirvenw@histats.com', + language: 'Irish Gaelic', + status: 'Invited', + lastLoginDate: '6/22/2022', + lastLockoutDate: '6/7/2022', + lastPasswordChangeDate: '10/27/2021', + updateDate: '8/26/2022', + createDate: '10/31/2021', + failedLoginAttempts: 323, + }, + { + key: 'aadb0afb-b42e-4b84-9889-91f177b4f03f', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Delmer Porch', + email: 'dporchx@newyorker.com', + language: 'Punjabi', + status: 'Disabled', + lastLoginDate: '1/22/2022', + lastLockoutDate: '12/10/2021', + lastPasswordChangeDate: '5/24/2022', + updateDate: '8/28/2022', + createDate: '4/26/2022', + failedLoginAttempts: 300, + }, + { + key: 'd8f5122b-06c7-4253-9358-0ffb673fd6fa', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Gussi Lednor', + email: 'glednory@google.de', + language: 'Romanian', + status: 'Invited', + lastLoginDate: '6/1/2022', + lastLockoutDate: '11/17/2021', + lastPasswordChangeDate: '12/25/2021', + updateDate: '2/3/2022', + createDate: '6/9/2022', + failedLoginAttempts: 39, + }, + { + key: 'f81d21b6-c2bd-455c-9614-80c6f0ca7aba', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Tish Kubacki', + email: 'tkubackiz@gmpg.org', + language: 'Bosnian', + status: 'Disabled', + lastLoginDate: '11/29/2021', + lastLockoutDate: '11/28/2021', + lastPasswordChangeDate: '12/1/2021', + updateDate: '5/25/2022', + createDate: '8/6/2022', + failedLoginAttempts: 826, + }, + { + key: 'e5d98b85-6d9b-40b4-8237-cf98db0a6331', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Madelene Le Noury', + email: 'mle10@google.com.au', + language: 'Punjabi', + status: 'Invited', + lastLoginDate: '6/8/2022', + lastLockoutDate: '11/1/2021', + lastPasswordChangeDate: '8/19/2022', + updateDate: '8/29/2022', + createDate: '8/2/2022', + failedLoginAttempts: 619, + }, + { + key: 'bb96eeb6-2f4c-4eda-a277-91077b0219b0', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Alberta Headech', + email: 'aheadech11@diigo.com', + language: 'Kazakh', + status: 'Active', + lastLoginDate: '8/12/2022', + lastLockoutDate: '8/8/2022', + lastPasswordChangeDate: '10/29/2021', + updateDate: '2/4/2022', + createDate: '10/18/2021', + failedLoginAttempts: 191, + }, + { + key: '56a2d315-0cc5-4b0d-9ae3-8a7b7326e531', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Kenon Maybey', + email: 'kmaybey12@cdbaby.com', + language: 'Telugu', + status: 'Active', + lastLoginDate: '6/11/2022', + lastLockoutDate: '3/4/2022', + lastPasswordChangeDate: '5/5/2022', + updateDate: '10/21/2021', + createDate: '9/1/2022', + failedLoginAttempts: 45, + }, + { + key: 'dddae890-939e-48fd-89da-90631be9401f', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Brig Totterdill', + email: 'btotterdill13@telegraph.co.uk', + language: 'Tajik', + status: 'Disabled', + lastLoginDate: '8/11/2022', + lastLockoutDate: '3/31/2022', + lastPasswordChangeDate: '4/30/2022', + updateDate: '3/9/2022', + createDate: '3/23/2022', + failedLoginAttempts: 936, + }, + { + key: '96359df7-74a3-4eff-a729-40eac9a85fcc', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Kore Faragher', + email: 'kfaragher14@elpais.com', + language: 'Georgian', + status: 'Disabled', + lastLoginDate: '5/9/2022', + lastLockoutDate: '4/19/2022', + lastPasswordChangeDate: '7/26/2022', + updateDate: '10/17/2021', + createDate: '4/14/2022', + failedLoginAttempts: 843, + }, + { + key: 'af74ab26-81f2-4c51-8867-24acc7021c3c', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Benedicto Oda', + email: 'boda15@zimbio.com', + language: 'Hungarian', + status: 'Active', + lastLoginDate: '7/6/2022', + lastLockoutDate: '12/27/2021', + lastPasswordChangeDate: '9/15/2022', + updateDate: '1/13/2022', + createDate: '4/1/2022', + failedLoginAttempts: 262, + }, + { + key: '81648dc6-93d5-468d-8fac-fcdd0fb854cd', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Celinka Gyorffy', + email: 'cgyorffy16@godaddy.com', + language: 'Punjabi', + status: 'Inactive', + lastLoginDate: '7/15/2022', + lastLockoutDate: '5/24/2022', + lastPasswordChangeDate: '2/26/2022', + updateDate: '3/27/2022', + createDate: '8/3/2022', + failedLoginAttempts: 606, + }, + { + key: '1c8fd6b4-ccd4-4bc3-9cde-bb705e2618aa', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Arri Goretti', + email: 'agoretti17@pcworld.com', + language: 'Armenian', + status: 'Invited', + updateDate: '1/24/2022', + createDate: '7/11/2022', + failedLoginAttempts: 234, + }, + { + key: 'dd26e22b-bcab-449f-8a35-ae63be90e8c6', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Giffie Strattan', + email: 'gstrattan18@cisco.com', + language: 'Maltese', + status: 'Disabled', + lastLoginDate: '5/15/2022', + lastLockoutDate: '10/21/2021', + lastPasswordChangeDate: '2/2/2022', + updateDate: '4/12/2022', + createDate: '7/7/2022', + failedLoginAttempts: 62, + }, + { + key: '08b5e626-20e6-486d-a289-baa5b49ee360', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Aeriel Webling', + email: 'awebling19@usgs.gov', + language: 'Dutch', + status: 'Disabled', + lastLoginDate: '7/20/2022', + lastLockoutDate: '11/17/2021', + lastPasswordChangeDate: '8/22/2022', + updateDate: '8/31/2022', + createDate: '7/8/2022', + failedLoginAttempts: 34, + }, + { + key: '064981b2-f8e4-4a25-a16e-1fe3441ae0a0', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Roderic Heckle', + email: 'rheckle1a@pbs.org', + language: 'Dari', + status: 'Inactive', + updateDate: '7/31/2022', + createDate: '2/19/2022', + failedLoginAttempts: 279, + }, + { + key: '0c221634-03be-4e69-9399-350c1da61641', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Gonzalo Magister', + email: 'gmagister1b@jigsy.com', + language: 'Hungarian', + status: 'Disabled', + lastLoginDate: '8/21/2022', + lastLockoutDate: '6/23/2022', + lastPasswordChangeDate: '2/11/2022', + updateDate: '6/23/2022', + createDate: '8/1/2022', + failedLoginAttempts: 227, + }, + { + key: 'e26f1576-483e-4132-a25a-1eaddf63f40d', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Nickolai Landsborough', + email: 'nlandsborough1c@ask.com', + language: 'Guaraní', + status: 'Inactive', + lastLoginDate: '11/25/2021', + lastLockoutDate: '7/24/2022', + lastPasswordChangeDate: '4/20/2022', + updateDate: '8/17/2022', + createDate: '10/31/2021', + failedLoginAttempts: 85, + }, + { + key: '7032b5ea-467a-43aa-9a23-33f195cfa0a0', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Linn Early', + email: 'learly1d@msn.com', + language: 'Swedish', + status: 'Active', + lastLoginDate: '10/18/2021', + lastLockoutDate: '6/14/2022', + lastPasswordChangeDate: '4/10/2022', + updateDate: '10/26/2021', + createDate: '7/30/2022', + failedLoginAttempts: 198, + }, + { + key: '57bb4927-a7a7-4dc9-af48-f418f1c0fbc6', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Julianna Jakab', + email: 'jjakab1e@cbsnews.com', + language: 'Malay', + status: 'Active', + lastLoginDate: '3/22/2022', + lastLockoutDate: '6/2/2022', + lastPasswordChangeDate: '9/7/2022', + updateDate: '3/14/2022', + createDate: '10/19/2021', + failedLoginAttempts: 387, + }, + { + key: 'd5bb1d61-1201-43b8-b3df-2bd9b4bf1269', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Erick Hovell', + email: 'ehovell1f@ucoz.com', + language: 'New Zealand Sign Language', + status: 'Disabled', + updateDate: '11/30/2021', + createDate: '3/4/2022', + failedLoginAttempts: 150, + }, + { + key: '3e711421-bdc3-411e-909c-ba7230396266', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Bondon Berends', + email: 'bberends1g@si.edu', + language: 'Zulu', + status: 'Invited', + updateDate: '1/12/2022', + createDate: '4/22/2022', + failedLoginAttempts: 455, + }, + { + key: '2c0806e0-a7dc-46bd-a4c1-85a7d0799c56', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Rubie Palluschek', + email: 'rpalluschek1h@multiply.com', + language: 'Icelandic', + status: 'Disabled', + lastLoginDate: '7/18/2022', + lastLockoutDate: '1/14/2022', + lastPasswordChangeDate: '8/13/2022', + updateDate: '1/17/2022', + createDate: '4/9/2022', + failedLoginAttempts: 427, + }, + { + key: '5fc52879-4684-44b1-9c39-63fc47d85587', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Kass Gaisford', + email: 'kgaisford1i@tiny.cc', + language: 'Hiri Motu', + status: 'Invited', + lastLoginDate: '12/22/2021', + lastLockoutDate: '9/10/2022', + lastPasswordChangeDate: '6/6/2022', + updateDate: '1/2/2022', + createDate: '7/1/2022', + failedLoginAttempts: 951, + }, + { + key: '0daeefb8-8f39-4d63-be8e-eef0239b418c', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Eba Fewings', + email: 'efewings1j@hexun.com', + language: 'Quechua', + status: 'Invited', + lastLoginDate: '11/30/2021', + lastLockoutDate: '4/17/2022', + lastPasswordChangeDate: '7/8/2022', + updateDate: '3/7/2022', + createDate: '6/19/2022', + failedLoginAttempts: 371, + }, + { + key: 'f34d019d-af85-4579-b510-b0e5a27c05ab', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Rand Espadate', + email: 'respadate1k@skyrock.com', + language: 'Persian', + status: 'Disabled', + lastLoginDate: '8/22/2022', + lastLockoutDate: '6/14/2022', + lastPasswordChangeDate: '9/5/2022', + updateDate: '2/11/2022', + createDate: '2/21/2022', + failedLoginAttempts: 5, + }, + { + key: 'acab2dd7-baae-40ef-b272-96ec50e633f7', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Bobina Macconachy', + email: 'bmacconachy1l@wikipedia.org', + language: 'Gujarati', + status: 'Active', + lastLoginDate: '5/25/2022', + lastLockoutDate: '6/28/2022', + lastPasswordChangeDate: '6/26/2022', + updateDate: '8/11/2022', + createDate: '3/12/2022', + failedLoginAttempts: 243, + }, + { + key: '8e3c0364-0c2a-451e-a65d-7c46cfba2436', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Walther Pattie', + email: 'wpattie1m@example.com', + language: 'Zulu', + status: 'Invited', + updateDate: '3/8/2022', + createDate: '10/8/2021', + failedLoginAttempts: 381, + }, + { + key: '0548a79d-a767-450c-9823-e170284347e9', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Elton Jedrychowski', + email: 'ejedrychowski1n@cam.ac.uk', + language: 'Greek', + status: 'Invited', + lastLoginDate: '5/16/2022', + lastLockoutDate: '7/18/2022', + lastPasswordChangeDate: '11/28/2021', + updateDate: '7/27/2022', + createDate: '9/30/2022', + failedLoginAttempts: 27, + }, + { + key: 'd97f31cd-939d-4686-b282-e6613c930ce9', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Melamie Chifney', + email: 'mchifney1o@umich.edu', + language: 'Albanian', + status: 'Active', + lastLoginDate: '3/16/2022', + lastLockoutDate: '12/22/2021', + lastPasswordChangeDate: '1/8/2022', + updateDate: '10/22/2021', + createDate: '12/9/2021', + failedLoginAttempts: 807, + }, + { + key: '160614dd-5749-4a74-878e-ac82e8cfe21b', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Auroora Theuff', + email: 'atheuff1p@over-blog.com', + language: 'Kurdish', + status: 'Inactive', + lastLoginDate: '11/28/2021', + lastLockoutDate: '11/17/2021', + lastPasswordChangeDate: '11/20/2021', + updateDate: '4/9/2022', + createDate: '6/29/2022', + failedLoginAttempts: 334, + }, + { + key: '3a1a9869-d103-40fb-98ac-4cce9e16ac17', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Law Cours', + email: 'lcours1q@google.co.uk', + language: 'Arabic', + status: 'Invited', + lastLoginDate: '3/27/2022', + lastLockoutDate: '12/2/2021', + lastPasswordChangeDate: '3/14/2022', + updateDate: '7/14/2022', + createDate: '2/4/2022', + failedLoginAttempts: 129, + }, + { + key: '174fd2e2-ac91-4eae-a366-2fe7e4322d88', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Clarke Rosenhaus', + email: 'crosenhaus1r@globo.com', + language: 'Afrikaans', + status: 'Active', + lastLoginDate: '6/23/2022', + lastLockoutDate: '7/4/2022', + lastPasswordChangeDate: '12/5/2021', + updateDate: '4/18/2022', + createDate: '8/16/2022', + failedLoginAttempts: 450, + }, + { + key: '762844a8-b64e-473a-ba50-f2cb446c8e93', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Nevins Gabler', + email: 'ngabler1s@psu.edu', + language: 'Korean', + status: 'Invited', + updateDate: '12/2/2021', + createDate: '12/14/2021', + failedLoginAttempts: 189, + }, + { + key: '46f28ab6-06ca-4d9f-93e4-742218ed5dca', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Bondon Corrin', + email: 'bcorrin1t@ustream.tv', + language: 'Hiri Motu', + status: 'Active', + lastLoginDate: '1/14/2022', + lastLockoutDate: '6/14/2022', + lastPasswordChangeDate: '11/28/2021', + updateDate: '9/10/2022', + createDate: '5/12/2022', + failedLoginAttempts: 359, + }, + { + key: 'b55ca6f9-2fd3-4e0d-a222-6df52db14007', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Juli Birtwistle', + email: 'jbirtwistle1u@histats.com', + language: 'Haitian Creole', + status: 'Active', + lastLoginDate: '11/25/2021', + lastLockoutDate: '3/20/2022', + lastPasswordChangeDate: '12/20/2021', + updateDate: '6/16/2022', + createDate: '11/29/2021', + failedLoginAttempts: 956, + }, + { + key: 'a5c7ea42-3257-48fe-9497-f684e6cdebaa', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Tomasine Hirsthouse', + email: 'thirsthouse1v@ehow.com', + language: 'Bosnian', + status: 'Disabled', + lastLoginDate: '9/19/2022', + lastLockoutDate: '4/21/2022', + lastPasswordChangeDate: '2/7/2022', + updateDate: '2/12/2022', + createDate: '1/3/2022', + failedLoginAttempts: 533, + }, + { + key: '4f9da285-8b73-4f74-9e54-50d04f1441a0', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + email: 'cflecknell1w@guardian.co.uk', + name: 'Barnie Flecknell', + language: 'Estonian', + status: 'Disabled', + lastLoginDate: '3/25/2022', + lastLockoutDate: '10/26/2021', + lastPasswordChangeDate: '12/3/2021', + updateDate: '12/31/2021', + createDate: '1/31/2022', + failedLoginAttempts: 621, + }, + { + key: '4054205f-6d9d-4bea-b1b2-29168dead18d', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Skelly Hockey', + email: 'shockey1x@usa.gov', + language: 'Burmese', + status: 'Active', + updateDate: '8/30/2022', + createDate: '1/16/2022', + failedLoginAttempts: 211, + }, + { + key: '1574526d-614b-41f4-abb4-4066fac8815c', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Nicholas Woan', + email: 'nwoan1y@istockphoto.com', + language: 'Māori', + status: 'Invited', + lastLoginDate: '4/16/2022', + lastLockoutDate: '4/17/2022', + lastPasswordChangeDate: '7/14/2022', + updateDate: '12/30/2021', + createDate: '1/19/2022', + failedLoginAttempts: 78, + }, + { + key: '745e0d21-44a6-4df1-81a0-d796ff7e6801', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Asa Kase', + email: 'akase1z@scribd.com', + language: 'Irish Gaelic', + status: 'Invited', + updateDate: '7/16/2022', + createDate: '10/23/2021', + failedLoginAttempts: 790, + }, + { + key: 'e0fc930c-6ed5-4064-a039-9e2c3b0dc644', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Emmerich Sisey', + email: 'emm@sis.com', + language: 'Tetum', + status: 'Active', + lastLoginDate: '5/22/2022', + lastLockoutDate: '6/26/2022', + lastPasswordChangeDate: '5/22/2022', + updateDate: '5/8/2022', + createDate: '9/20/2022', + failedLoginAttempts: 10, + }, + { + key: '0f36289e-abce-4fa9-a524-49664389c2ef', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Trish Cerith', + email: 'tcerith21@tuttocitta.it', + language: 'Spanish', + status: 'Invited', + lastLoginDate: '1/11/2022', + lastLockoutDate: '9/1/2022', + lastPasswordChangeDate: '1/29/2022', + updateDate: '10/16/2021', + createDate: '1/13/2022', + failedLoginAttempts: 417, + }, + { + key: 'c7a02de0-2eb6-461d-8036-e163b12ef2b5', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Netty Rudge', + email: 'nrudge22@xinhuanet.com', + language: 'Fijian', + status: 'Active', + lastLoginDate: '4/21/2022', + lastLockoutDate: '7/21/2022', + lastPasswordChangeDate: '11/6/2021', + updateDate: '11/12/2021', + createDate: '4/4/2022', + failedLoginAttempts: 214, + }, + { + key: 'dfa94377-3eb7-4318-804c-892f125cdb65', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Joane Kuhne', + email: 'jkuhne23@opera.com', + language: 'Danish', + status: 'Active', + lastLoginDate: '1/10/2022', + lastLockoutDate: '9/18/2022', + lastPasswordChangeDate: '9/6/2022', + updateDate: '2/9/2022', + createDate: '4/14/2022', + failedLoginAttempts: 735, + }, + { + key: '34114a3c-b6a9-41e4-ad65-377abb1f2fbd', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Sheilah Nattrass', + email: 'snattrass24@sbwire.com', + language: 'Korean', + status: 'Invited', + lastLoginDate: '5/7/2022', + lastLockoutDate: '10/20/2021', + lastPasswordChangeDate: '11/13/2021', + updateDate: '12/6/2021', + createDate: '6/25/2022', + failedLoginAttempts: 480, + }, + { + key: 'c9a62d42-9b32-441b-b758-283526c749b1', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: "Luella O'Geaney", + email: 'logeaney25@foxnews.com', + language: 'Arabic', + status: 'Disabled', + lastLoginDate: '10/21/2021', + lastLockoutDate: '8/12/2022', + lastPasswordChangeDate: '7/20/2022', + updateDate: '5/11/2022', + createDate: '5/19/2022', + failedLoginAttempts: 828, + }, + { + key: '4c54110a-5768-4979-adf0-c8e52a2ae6a6', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Cyrille Curm', + email: 'ccurm26@forbes.com', + language: 'Icelandic', + status: 'Active', + lastLoginDate: '12/17/2021', + lastLockoutDate: '8/9/2022', + lastPasswordChangeDate: '10/14/2021', + updateDate: '5/19/2022', + createDate: '5/5/2022', + failedLoginAttempts: 840, + }, + { + key: '86bdee19-c4a6-412c-9c38-173232993952', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Leonard Vitall', + email: 'lvitall27@clickbank.net', + language: 'Haitian Creole', + status: 'Inactive', + lastLoginDate: '8/12/2022', + lastLockoutDate: '2/26/2022', + lastPasswordChangeDate: '10/2/2022', + updateDate: '12/31/2021', + createDate: '1/13/2022', + failedLoginAttempts: 588, + }, + { + key: '0961184f-5b1a-4e21-b598-c2e4fda4b498', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Nickie Bronger', + email: 'nbronger28@xrea.com', + language: 'West Frisian', + status: 'Active', + lastLoginDate: '8/5/2022', + lastLockoutDate: '1/21/2022', + lastPasswordChangeDate: '4/8/2022', + updateDate: '5/11/2022', + createDate: '10/12/2021', + failedLoginAttempts: 639, + }, + { + key: '7cc8803f-9c20-44aa-9399-d4ec5e52e008', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Annie Butterworth', + email: 'abutterworth29@marketwatch.com', + language: 'Bulgarian', + status: 'Active', + lastLoginDate: '10/30/2021', + lastLockoutDate: '10/5/2021', + lastPasswordChangeDate: '5/3/2022', + updateDate: '4/4/2022', + createDate: '1/25/2022', + failedLoginAttempts: 912, + }, + { + key: '61ec70a3-6a8d-42fe-88f3-c866328c4a9c', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Dasi Ughi', + email: 'dughi2a@vimeo.com', + status: 'Disabled', + lastLoginDate: '10/14/2021', + lastLockoutDate: '1/11/2022', + lastPasswordChangeDate: '8/1/2022', + updateDate: '10/31/2021', + createDate: '7/2/2022', + failedLoginAttempts: 494, + language: 'Danish', + }, + { + key: '21bbdd96-ea8d-463c-8d10-fd6d016bf4e0', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Lawrence Cansfield', + email: 'lcansfield2b@istockphoto.com', + language: 'Estonian', + status: 'Disabled', + lastLoginDate: '3/24/2022', + lastLockoutDate: '10/11/2021', + lastPasswordChangeDate: '5/20/2022', + updateDate: '12/1/2021', + createDate: '10/26/2021', + failedLoginAttempts: 258, + }, + { + key: 'f897a981-0452-4c06-b875-dab80109051b', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Gal Lyster', + email: 'glyster2c@google.cn', + language: 'Indonesian', + status: 'Disabled', + lastLoginDate: '8/29/2022', + lastLockoutDate: '9/25/2022', + lastPasswordChangeDate: '10/16/2021', + updateDate: '4/16/2022', + createDate: '3/17/2022', + failedLoginAttempts: 103, + }, + { + key: '1f8d4217-3037-444e-b91a-0e18f20b3919', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Caron Crolly', + email: 'ccrolly2d@jalbum.net', + language: 'Italian', + status: 'Disabled', + lastLoginDate: '7/12/2022', + lastLockoutDate: '3/20/2022', + lastPasswordChangeDate: '1/4/2022', + updateDate: '11/26/2021', + createDate: '6/5/2022', + failedLoginAttempts: 211, + }, + { + key: 'f4449cde-ef12-4068-9f13-6104d281e494', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Juliana Clorley', + email: 'jclorley2e@mail.ru', + language: 'Luxembourgish', + status: 'Active', + lastLoginDate: '10/17/2021', + lastLockoutDate: '8/4/2022', + lastPasswordChangeDate: '12/23/2021', + updateDate: '2/23/2022', + createDate: '8/22/2022', + failedLoginAttempts: 208, + }, + { + key: 'ac75e813-22bc-4d42-8f98-a4ba6f19bdf8', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Kylynn Falvey', + email: 'kfalvey2f@com.com', + language: 'Zulu', + status: 'Inactive', + lastLoginDate: '3/4/2022', + lastLockoutDate: '6/4/2022', + lastPasswordChangeDate: '6/9/2022', + updateDate: '2/14/2022', + createDate: '1/30/2022', + failedLoginAttempts: 75, + }, + { + key: 'ba9caf4c-aeee-48e8-a7d7-3ff2239c0186', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Marty Shurrock', + email: 'mshurrock2g@hhs.gov', + language: 'Danish', + status: 'Inactive', + lastLoginDate: '10/2/2022', + lastLockoutDate: '9/16/2022', + lastPasswordChangeDate: '12/3/2021', + updateDate: '5/26/2022', + createDate: '4/30/2022', + failedLoginAttempts: 40, + }, + { + key: '924e087c-b0b5-4c59-a8b8-a71ad112c4b0', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Goldia Crates', + email: 'gcrates2h@privacy.gov.au', + language: 'Pashto', + status: 'Inactive', + lastLoginDate: '9/27/2022', + lastLockoutDate: '2/7/2022', + lastPasswordChangeDate: '12/9/2021', + updateDate: '5/5/2022', + createDate: '9/25/2022', + failedLoginAttempts: 710, + }, + { + key: '909154d4-5c84-461d-b256-552f358a0d68', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Ted Stratley', + email: 'tstratley2i@tinypic.com', + language: 'Mongolian', + status: 'Inactive', + lastLoginDate: '4/19/2022', + lastLockoutDate: '9/24/2022', + lastPasswordChangeDate: '10/24/2021', + updateDate: '7/29/2022', + createDate: '2/7/2022', + failedLoginAttempts: 730, + }, + { + key: '284e7d5a-1b10-4814-a5fd-da17180c1753', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Rubia Collecott', + email: 'rcollecott2j@oaic.gov.au', + language: 'Somali', + status: 'Inactive', + updateDate: '1/27/2022', + createDate: '3/7/2022', + failedLoginAttempts: 250, + }, + { + key: '91205c6e-3be9-47fc-b5f3-01c89306dcd5', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Nilson Britland', + email: 'nbritland2k@facebook.com', + language: 'Ndebele', + status: 'Disabled', + lastLoginDate: '8/25/2022', + lastLockoutDate: '12/31/2021', + lastPasswordChangeDate: '8/15/2022', + updateDate: '8/14/2022', + createDate: '11/17/2021', + failedLoginAttempts: 360, + }, + { + key: 'da108699-76d9-4691-9dbd-c11a16cf3514', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Johannes Slucock', + email: 'jslucock2l@buzzfeed.com', + language: 'Malagasy', + status: 'Inactive', + lastLoginDate: '1/5/2022', + lastLockoutDate: '10/11/2021', + lastPasswordChangeDate: '2/17/2022', + updateDate: '6/13/2022', + createDate: '7/19/2022', + failedLoginAttempts: 397, + }, + { + key: '7469307b-a87b-49b9-8dab-100d7d7e31d0', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Rodrick Twelftree', + email: 'rtwelftree2m@nbcnews.com', + language: 'Luxembourgish', + status: 'Active', + lastLoginDate: '5/23/2022', + lastLockoutDate: '6/21/2022', + lastPasswordChangeDate: '8/27/2022', + updateDate: '10/20/2021', + createDate: '10/24/2021', + failedLoginAttempts: 104, + }, + { + key: 'cc7c8bbb-580f-445e-8af5-c3bf14b4a560', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Liesa Arnoll', + email: 'larnoll2n@webnode.com', + language: 'Hebrew', + status: 'Active', + lastLoginDate: '9/13/2022', + lastLockoutDate: '7/14/2022', + lastPasswordChangeDate: '2/28/2022', + updateDate: '6/20/2022', + createDate: '11/5/2021', + failedLoginAttempts: 78, + }, + { + key: '1c75ef97-b3f2-4194-b109-fd5c82efe9de', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Cindra Simkiss', + email: 'csimkiss2o@google.es', + language: 'Gagauz', + status: 'Disabled', + lastLoginDate: '4/18/2022', + lastLockoutDate: '9/2/2022', + lastPasswordChangeDate: '5/5/2022', + updateDate: '4/30/2022', + createDate: '9/25/2022', + failedLoginAttempts: 887, + }, + { + key: 'a010a09d-2e23-4403-806c-16fcfe70fcd4', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Belle Conrard', + email: 'bconrard2p@mozilla.org', + language: 'Hindi', + status: 'Invited', + lastLoginDate: '7/18/2022', + lastLockoutDate: '6/25/2022', + lastPasswordChangeDate: '2/21/2022', + updateDate: '7/18/2022', + createDate: '4/12/2022', + failedLoginAttempts: 477, + }, + { + key: '8c9bfaac-098f-43a4-91ee-a9eaf5dfe5ea', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Tremain Minor', + email: 'tminor2q@storify.com', + language: 'Chinese', + status: 'Invited', + lastLoginDate: '7/31/2022', + lastLockoutDate: '5/11/2022', + lastPasswordChangeDate: '11/10/2021', + updateDate: '8/9/2022', + createDate: '7/24/2022', + failedLoginAttempts: 160, + }, + { + key: 'ecb0ced9-c1c1-486d-a317-5f2b320859bd', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + icon: 'umb:user', + name: 'Isador Tibbles', + email: 'itibbles2r@cafepress.com', + language: 'Assamese', + status: 'Active', + lastLoginDate: '4/7/2022', + lastLockoutDate: '2/4/2022', + lastPasswordChangeDate: '11/14/2021', + updateDate: '4/14/2022', + createDate: '11/16/2021', + failedLoginAttempts: 932, + }, +]; + +// Temp mocked database +class UmbUsersData extends UmbEntityData { + constructor() { + super(data); + } +} + +export const umbUsersData = new UmbUsersData(); 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 index ddcb14fb46..9421437e4d 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts @@ -1,11 +1,11 @@ import { rest } from 'msw'; -import { tempData } from '../../backoffice/editors/users/views/users/tempData'; +import { umbUsersData } from '../data/users.data'; // TODO: add schema export const handlers = [ rest.get('/umbraco/backoffice/users', (req, res, ctx) => { const response = { - items: tempData, + items: umbUsersData.getItems('user'), }; return res(ctx.status(200), ctx.json(response)); @@ -15,7 +15,7 @@ export const handlers = [ const key = req.params.key as string; if (!key) return; - const user = tempData.find((x) => x.key === key); + const user = umbUsersData.getByKey(key); return res(ctx.status(200), ctx.json([user])); }), From 568b32a303e01c7045ac2dc7a42d0b01840ebcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Tue, 4 Oct 2022 15:53:37 +0200 Subject: [PATCH 41/98] user store --- .../editor-action-users-save.element.ts | 17 ++++++- .../editor-view-users-user-details.element.ts | 51 +++++++------------ .../views/users/editor-view-users.element.ts | 8 ++- .../src/core/stores/user/user.store.ts | 37 +++++++++++--- .../src/mocks/domains/users.handlers.ts | 12 ++++- 5 files changed, 81 insertions(+), 44 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts index a536251d32..544a3e30ea 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts @@ -1,12 +1,27 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; +import { UmbContextConsumerMixin } from '../../../../../../core/context'; +import { UmbUserStore } from '../../../../../../core/stores/user/user.store'; +import { Subscription } from 'rxjs'; +import type { UserEntity } from '../../../../../../core/models'; @customElement('umb-editor-action-users-save') -export class UmbEditorActionUsersSaveElement extends LitElement { +export class UmbEditorActionUsersSaveElement extends UmbContextConsumerMixin(LitElement) { static styles = [UUITextStyles, css``]; + private _userStore?: UmbUserStore; + + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext('umbUserStore', (userStore: UmbUserStore) => { + this._userStore = userStore; + }); + } + private _handleSave() { + // this._userStore.save() console.log('save'); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 6670d2bed8..71f9abbe9b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -1,10 +1,12 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, state } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import UmbEditorViewUsersElement from './editor-view-users.element'; import { Subscription } from 'rxjs'; import '../../../../property-editors/content-picker/property-editor-content-picker.element'; +import { UmbUserStore } from '../../../../../core/stores/user/user.store'; +import { UserDetails } from '../../../../../core/models'; @customElement('umb-editor-view-users-user-details') export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { @@ -75,36 +77,28 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi ]; @state() - private _users: Array = []; + private _user?: UserDetails | null; - @state() - private _user?: UserItem; + @property() + public key = ''; - private _userKey = ''; - - protected _usersContext?: UmbEditorViewUsersElement; + protected _userStore?: UmbUserStore; protected _usersSubscription?: Subscription; private _languages = []; //TODO Add languages connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { - this._usersContext = usersContext; + this.consumeContext('umbUserStore', (usersContext: UmbUserStore) => { + this._userStore = usersContext; this._usersSubscription?.unsubscribe(); - this._usersSubscription = this._usersContext?.users.subscribe((users: Array) => { - this._users = users; - this._initUser(); + this._usersSubscription = this._userStore?.getByKey(this.key).subscribe((user) => { + this._user = user; }); }); - // get user id from url path - const path = window.location.pathname; - const pathParts = path.split('/'); - this._userKey = pathParts[pathParts.length - 1]; - - this._initUser(); + console.log(this.key); } disconnectedCallback(): void { @@ -113,15 +107,6 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi this._usersSubscription?.unsubscribe(); } - private _initUser() { - this._user = this._users.find((user: UserItem) => user.key === this._userKey); - - const index = this._languages.findIndex((language) => language.value === this._user?.language); - if (index !== -1) { - this._languages[index].selected = true; - } - } - private _updateUserStatus() { if (!this._user) return; @@ -129,13 +114,13 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi const newUser = this._user; newUser.status = newStatus; - this._usersContext?.updateUser(newUser); + // this._userStore?.updateUser(newUser); } private _deleteUser() { if (!this._user) return; - this._usersContext?.deleteUser(this._user.key); + // this._userStore?.deleteUser(this._user.key); history.back(); //TODO Should redirect to users section } @@ -193,9 +178,9 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi } private renderRightColumn() { - if (!this._user || !this._usersContext) return nothing; + if (!this._user || !this._userStore) return nothing; - const status = this._usersContext.getTagLookAndColor(this._user.status); + // const status = this._userStore.getTagLookAndColor(this._user.status); return html`
@@ -255,7 +240,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi } render() { - if (!this._user || !this._usersContext) return html`User not found`; + if (!this._user) return html`User not found`; return html`
${this.renderLeftColumn()}
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 6d2d399bd1..197e5f8b5c 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 @@ -4,15 +4,15 @@ import { customElement, state } from 'lit/decorators.js'; import { UmbContextProviderMixin } from '../../../../../core/context'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; -import { IRoute } from 'router-slot'; +import { IRoute, IRoutingInfo } from 'router-slot'; import { v4 as uuidv4 } from 'uuid'; import './list-view-layouts/table/editor-view-users-table.element'; import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; -import './editor-view-users-user-details.element'; import './editor-view-users-invite.element'; import type { UserDetails, UserEntity } from '../../../../../core/models'; +import type { UmbEditorViewUsersUserDetailsElement } from './editor-view-users-user-details.element'; @customElement('umb-editor-view-users') export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElement) { @@ -31,6 +31,10 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen { path: 'details/:key', component: () => import('./editor-view-users-user-details.element'), + setup: (component: unknown, info: IRoutingInfo) => { + const element = component as UmbEditorViewUsersUserDetailsElement; + element.key = info.match.params.key; + }, }, { path: '**', 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 index 013bd33c01..7bf91e49dc 100644 --- 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 @@ -1,5 +1,5 @@ import { map, Observable } from 'rxjs'; -import type { UserEntity } from '../../models'; +import type { UserDetails, UserEntity } from '../../models'; import { UmbEntityStore } from '../entity.store'; import { UmbDataStoreBase } from '../store'; @@ -9,7 +9,7 @@ import { UmbDataStoreBase } from '../store'; * @extends {UmbDataStoreBase} * @description - Data Store for Users */ -export class UmbUserStore extends UmbDataStoreBase { +export class UmbUserStore extends UmbDataStoreBase { private _entityStore: UmbEntityStore; constructor(entityStore: UmbEntityStore) { @@ -17,7 +17,7 @@ export class UmbUserStore extends UmbDataStoreBase { this._entityStore = entityStore; } - getAll(): Observable> { + getAll(): Observable> { // TODO: use Fetcher API. // TODO: only fetch if the data type is not in the store? fetch(`/umbraco/backoffice/users`) @@ -35,21 +35,44 @@ export class UmbUserStore extends UmbDataStoreBase { * @return {*} {(Observable)} * @memberof UmbDataTypeStore */ - getByKey(key: string): Observable { + 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); + this.update([data]); }); return this.items.pipe( - map((dataTypes: Array) => dataTypes.find((node: UserEntity) => node.key === key) || null) + map((items: Array) => items.find((node: UserDetails) => node.key === key) || null) ); } + /** + * @description - Save a Data Type. + * @param {Array} dataTypes + * @memberof UmbDataTypeStore + * @return {*} {Promise} + */ + async save(users: Array): Promise { + // TODO: use Fetcher API. + try { + const res = await fetch('/umbraco/backoffice/users/save', { + method: 'POST', + body: JSON.stringify(users), + headers: { + 'Content-Type': 'application/json', + }, + }); + const json = await res.json(); + this.update(json); + this._entityStore.update(json); + } catch (error) { + console.error('Save Data Type error', error); + } + } + // public updateUser(user: UserItem) { // const users = this._users.getValue(); // const index = users.findIndex((u) => u.key === user.key); 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 index 9421437e4d..9e57d81e8b 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts @@ -1,4 +1,5 @@ import { rest } from 'msw'; +import type { UserDetails } from '../../core/models'; import { umbUsersData } from '../data/users.data'; // TODO: add schema @@ -17,6 +18,15 @@ export const handlers = [ const user = umbUsersData.getByKey(key); - return res(ctx.status(200), ctx.json([user])); + return res(ctx.status(200), ctx.json(user)); + }), + + rest.post('/umbraco/backoffice/users/save', async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + const saved = umbUsersData.save(data); + + return res(ctx.status(200), ctx.json(saved)); }), ]; From 86afcdce1527c634e178c79de04ee06a154f12b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 5 Oct 2022 11:49:37 +0200 Subject: [PATCH 42/98] user CRUD wip --- .../editor-view-users-user-details.element.ts | 22 ++-- .../views/users/editor-view-users.element.ts | 40 ------- .../grid/editor-view-users-grid.element.ts | 2 +- .../table/editor-view-users-table.element.ts | 2 +- .../src/core/stores/store.ts | 2 +- .../src/core/stores/user/user.store.ts | 72 +++++++++++-- .../src/mocks/data/entity.data.ts | 6 ++ .../src/mocks/data/users.data.ts | 100 +++++++++++------- .../src/mocks/domains/users.handlers.ts | 30 ++++++ 9 files changed, 173 insertions(+), 103 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 71f9abbe9b..50c74d1ab5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -97,8 +97,6 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi this._user = user; }); }); - - console.log(this.key); } disconnectedCallback(): void { @@ -108,20 +106,17 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi } private _updateUserStatus() { - if (!this._user) return; + if (!this._user || !this._userStore) return; - const newStatus = this._user.status === 'Disabled' ? 'Active' : 'Disabled'; - const newUser = this._user; - newUser.status = newStatus; - - // this._userStore?.updateUser(newUser); + const isDisabled = this._user.status === 'Disabled'; + isDisabled ? this._userStore.enableUsers([this._user.key]) : this._userStore.disableUsers([this._user.key]); } private _deleteUser() { - if (!this._user) return; + if (!this._user || !this._userStore) return; - // this._userStore?.deleteUser(this._user.key); - history.back(); //TODO Should redirect to users section + this._userStore.deleteUsers([this._user.key]); + // history.back(); //TODO Should redirect to users section } private renderLeftColumn() { @@ -180,6 +175,8 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi private renderRightColumn() { if (!this._user || !this._userStore) return nothing; + console.log('user', this._user); + // const status = this._userStore.getTagLookAndColor(this._user.status); return html`
@@ -231,8 +228,7 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi ${this._user.updateDate}
- Id: - ${this._user.id} + Key: ${this._user.key}
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 197e5f8b5c..a098a0dce3 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 @@ -69,46 +69,6 @@ export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElemen this.requestUpdate('selection'); } - // public updateUser(user: UserEntity) { - // 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): UserEntity { - // 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'); - // } - public getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { switch ((status || '').toLowerCase()) { case 'invited': diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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 index 7e1c30a4d4..9243972edc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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 @@ -108,7 +108,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl @open=${() => this._handleOpenCard(user.key)} @selected=${() => this._selectRowHandler(user)} @unselected=${() => this._deselectRowHandler(user)}> - ${user.status && user.status !== 'Active' + ${user.status && user.status !== 'Enabled' ? html` ${user.userGroup} ${user.lastLoginDate} - ${user.status && user.status !== 'Active' + ${user.status && user.status !== 'Enabled' ? html` ${user.status} ` : nothing} 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 eecf943a10..7d31d0994f 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts @@ -18,7 +18,7 @@ export interface UmbDataStore { * @description - Base class for Data Stores */ export class UmbDataStoreBase implements UmbDataStore { - private _items: BehaviorSubject> = new BehaviorSubject(>[]); + protected _items: BehaviorSubject> = new BehaviorSubject(>[]); public readonly items: Observable> = this._items.asObservable(); /** 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 index 7bf91e49dc..f8fda7a4ed 100644 --- 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 @@ -49,12 +49,72 @@ export class UmbUserStore extends UmbDataStoreBase { ); } - /** - * @description - Save a Data Type. - * @param {Array} dataTypes - * @memberof UmbDataTypeStore - * @return {*} {Promise} - */ + async enableUsers(userKeys: Array): Promise { + // TODO: use Fetcher API. + try { + const res = await fetch('/umbraco/backoffice/users/enable', { + method: 'POST', + body: JSON.stringify(userKeys), + headers: { + 'Content-Type': 'application/json', + }, + }); + const enabledKeys = await res.json(); + const storedUsers = this._items.getValue().filter((user) => enabledKeys.includes(user.key)); + + storedUsers.forEach((user) => { + user.status = 'Enabled'; + }); + + this.update(storedUsers); + this._entityStore.update(storedUsers); + } catch (error) { + console.error('Enable Users failed', error); + } + } + + async disableUsers(userKeys: Array): Promise { + // TODO: use Fetcher API. + try { + const res = await fetch('/umbraco/backoffice/users/disable', { + method: 'POST', + body: JSON.stringify(userKeys), + headers: { + 'Content-Type': 'application/json', + }, + }); + const disabledKeys = await res.json(); + const storedUsers = this._items.getValue().filter((user) => disabledKeys.includes(user.key)); + + storedUsers.forEach((user) => { + user.status = 'Disabled'; + }); + + this.update(storedUsers); + this._entityStore.update(storedUsers); + } catch (error) { + console.error('Disable Users failed', error); + } + } + + async deleteUsers(userKeys: Array): Promise { + // TODO: use Fetcher API. + try { + const res = await fetch('/umbraco/backoffice/users/delete', { + method: 'POST', + body: JSON.stringify(userKeys), + headers: { + 'Content-Type': 'application/json', + }, + }); + const json = await res.json(); + this.update(json); + this._entityStore.update(json); + } catch (error) { + console.error('Delete Users failed', error); + } + } + async save(users: Array): Promise { // TODO: use Fetcher API. try { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts index f51b05c6eb..517832d7de 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts @@ -47,6 +47,12 @@ export class UmbEntityData extends UmbData { return trashedItems; } + delete(keys: Array) { + const deletedKeys = this.data.filter((item) => keys.includes(item.key)).map((item) => item.key); + this.data = this.data.filter((item) => keys.indexOf(item.key) === -1); + return deletedKeys; + } + protected updateData(updateItem: T) { const itemIndex = this.data.findIndex((item) => item.key === updateItem.key); const item = this.data[itemIndex]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts index 4a3ded1cca..76a6956bd4 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts @@ -1,6 +1,31 @@ import type { UserDetails } from '../../core/models'; import { UmbEntityData } from './entity.data'; +// Temp mocked database +class UmbUsersData extends UmbEntityData { + constructor(data: UserDetails[]) { + super(data); + } + + enable(keys: string[]) { + const users = this.data.filter((user) => keys.includes(user.key)); + users.forEach((user) => { + user.status = 'Enabled'; + this.updateData(user); + }); + return users.map((user) => user.key); + } + + disable(keys: string[]) { + const users = this.data.filter((user) => keys.includes(user.key)); + users.forEach((user) => { + user.status = 'Disabled'; + this.updateData(user); + }); + return users.map((user) => user.key); + } +} + export const data: Array = [ { key: '50f184d4-71f3-4a43-b8be-7a36340fbd0d', @@ -48,7 +73,7 @@ export const data: Array = [ name: 'Nisse Grattan', email: 'ngrattan2@alexa.com', language: 'Tok Pisin', - status: 'Active', + status: 'Enabled', lastLoginDate: '3/22/2022', lastLockoutDate: '12/2/2021', lastPasswordChangeDate: '5/28/2022', @@ -66,7 +91,7 @@ export const data: Array = [ name: 'Thain Rainville', email: 'trainville3@merriam-webster.com', language: 'Tajik', - status: 'Active', + status: 'Enabled', lastLoginDate: '2/28/2022', lastLockoutDate: '1/6/2022', lastPasswordChangeDate: '7/1/2022', @@ -84,7 +109,7 @@ export const data: Array = [ name: 'Perren Balsdon', email: 'pbalsdon4@ezinearticles.com', language: 'Somali', - status: 'Active', + status: 'Enabled', lastLoginDate: '5/6/2022', lastLockoutDate: '11/12/2021', lastPasswordChangeDate: '11/10/2021', @@ -102,7 +127,7 @@ export const data: Array = [ name: 'Athene Bilborough', email: 'abilborough5@princeton.edu', language: 'Tetum', - status: 'Active', + status: 'Enabled', lastLoginDate: '3/11/2022', lastLockoutDate: '7/7/2022', lastPasswordChangeDate: '3/8/2022', @@ -138,7 +163,7 @@ export const data: Array = [ name: 'Tansy Hanna', email: 'thanna7@google.pl', language: 'Papiamento', - status: 'Active', + status: 'Enabled', lastLoginDate: '9/10/2022', lastLockoutDate: '10/28/2021', lastPasswordChangeDate: '2/26/2022', @@ -156,7 +181,7 @@ export const data: Array = [ icon: 'umb:user', email: 'hmohan8@google.co.jp', language: 'Montenegrin', - status: 'Active', + status: 'Enabled', lastLoginDate: '6/16/2022', lastLockoutDate: '3/2/2022', lastPasswordChangeDate: '4/14/2022', @@ -276,7 +301,7 @@ export const data: Array = [ name: 'Gennie Casaccia', email: 'gcasacciaf@vkontakte.ru', language: 'Catalan', - status: 'Active', + status: 'Enabled', lastLoginDate: '4/11/2022', lastLockoutDate: '3/17/2022', lastPasswordChangeDate: '4/30/2022', @@ -294,7 +319,7 @@ export const data: Array = [ name: 'Vaughan Longstreet', email: 'vlongstreetg@jugem.jp', language: 'Khmer', - status: 'Active', + status: 'Enabled', lastLoginDate: '3/16/2022', lastLockoutDate: '11/4/2021', lastPasswordChangeDate: '3/23/2022', @@ -363,7 +388,7 @@ export const data: Array = [ name: 'Felipe Finicj', email: 'ffinicjk@economist.com', language: 'Latvian', - status: 'Active', + status: 'Enabled', lastLoginDate: '11/5/2021', lastLockoutDate: '7/12/2022', lastPasswordChangeDate: '4/12/2022', @@ -399,7 +424,7 @@ export const data: Array = [ name: 'Franni Plester', email: 'fplesterm@nytimes.com', language: 'Hungarian', - status: 'Active', + status: 'Enabled', lastLoginDate: '7/27/2022', lastLockoutDate: '8/17/2022', lastPasswordChangeDate: '3/2/2022', @@ -453,7 +478,7 @@ export const data: Array = [ name: 'Terry McCorkell', email: 'tmccorkellp@noaa.gov', language: 'Dhivehi', - status: 'Active', + status: 'Enabled', lastLoginDate: '7/23/2022', lastLockoutDate: '7/24/2022', lastPasswordChangeDate: '10/11/2021', @@ -489,7 +514,7 @@ export const data: Array = [ name: 'Bethena Grewe', email: 'bgrewer@naver.com', language: 'Haitian Creole', - status: 'Active', + status: 'Enabled', lastLoginDate: '11/12/2021', lastLockoutDate: '6/4/2022', lastPasswordChangeDate: '8/25/2022', @@ -669,7 +694,7 @@ export const data: Array = [ name: 'Alberta Headech', email: 'aheadech11@diigo.com', language: 'Kazakh', - status: 'Active', + status: 'Enabled', lastLoginDate: '8/12/2022', lastLockoutDate: '8/8/2022', lastPasswordChangeDate: '10/29/2021', @@ -687,7 +712,7 @@ export const data: Array = [ name: 'Kenon Maybey', email: 'kmaybey12@cdbaby.com', language: 'Telugu', - status: 'Active', + status: 'Enabled', lastLoginDate: '6/11/2022', lastLockoutDate: '3/4/2022', lastPasswordChangeDate: '5/5/2022', @@ -741,7 +766,7 @@ export const data: Array = [ name: 'Benedicto Oda', email: 'boda15@zimbio.com', language: 'Hungarian', - status: 'Active', + status: 'Enabled', lastLoginDate: '7/6/2022', lastLockoutDate: '12/27/2021', lastPasswordChangeDate: '9/15/2022', @@ -879,7 +904,7 @@ export const data: Array = [ name: 'Linn Early', email: 'learly1d@msn.com', language: 'Swedish', - status: 'Active', + status: 'Enabled', lastLoginDate: '10/18/2021', lastLockoutDate: '6/14/2022', lastPasswordChangeDate: '4/10/2022', @@ -897,7 +922,7 @@ export const data: Array = [ name: 'Julianna Jakab', email: 'jjakab1e@cbsnews.com', language: 'Malay', - status: 'Active', + status: 'Enabled', lastLoginDate: '3/22/2022', lastLockoutDate: '6/2/2022', lastPasswordChangeDate: '9/7/2022', @@ -1017,7 +1042,7 @@ export const data: Array = [ name: 'Bobina Macconachy', email: 'bmacconachy1l@wikipedia.org', language: 'Gujarati', - status: 'Active', + status: 'Enabled', lastLoginDate: '5/25/2022', lastLockoutDate: '6/28/2022', lastPasswordChangeDate: '6/26/2022', @@ -1068,7 +1093,7 @@ export const data: Array = [ name: 'Melamie Chifney', email: 'mchifney1o@umich.edu', language: 'Albanian', - status: 'Active', + status: 'Enabled', lastLoginDate: '3/16/2022', lastLockoutDate: '12/22/2021', lastPasswordChangeDate: '1/8/2022', @@ -1122,7 +1147,7 @@ export const data: Array = [ name: 'Clarke Rosenhaus', email: 'crosenhaus1r@globo.com', language: 'Afrikaans', - status: 'Active', + status: 'Enabled', lastLoginDate: '6/23/2022', lastLockoutDate: '7/4/2022', lastPasswordChangeDate: '12/5/2021', @@ -1155,7 +1180,7 @@ export const data: Array = [ name: 'Bondon Corrin', email: 'bcorrin1t@ustream.tv', language: 'Hiri Motu', - status: 'Active', + status: 'Enabled', lastLoginDate: '1/14/2022', lastLockoutDate: '6/14/2022', lastPasswordChangeDate: '11/28/2021', @@ -1173,7 +1198,7 @@ export const data: Array = [ name: 'Juli Birtwistle', email: 'jbirtwistle1u@histats.com', language: 'Haitian Creole', - status: 'Active', + status: 'Enabled', lastLoginDate: '11/25/2021', lastLockoutDate: '3/20/2022', lastPasswordChangeDate: '12/20/2021', @@ -1227,7 +1252,7 @@ export const data: Array = [ name: 'Skelly Hockey', email: 'shockey1x@usa.gov', language: 'Burmese', - status: 'Active', + status: 'Enabled', updateDate: '8/30/2022', createDate: '1/16/2022', failedLoginAttempts: 211, @@ -1275,7 +1300,7 @@ export const data: Array = [ name: 'Emmerich Sisey', email: 'emm@sis.com', language: 'Tetum', - status: 'Active', + status: 'Enabled', lastLoginDate: '5/22/2022', lastLockoutDate: '6/26/2022', lastPasswordChangeDate: '5/22/2022', @@ -1311,7 +1336,7 @@ export const data: Array = [ name: 'Netty Rudge', email: 'nrudge22@xinhuanet.com', language: 'Fijian', - status: 'Active', + status: 'Enabled', lastLoginDate: '4/21/2022', lastLockoutDate: '7/21/2022', lastPasswordChangeDate: '11/6/2021', @@ -1329,7 +1354,7 @@ export const data: Array = [ name: 'Joane Kuhne', email: 'jkuhne23@opera.com', language: 'Danish', - status: 'Active', + status: 'Enabled', lastLoginDate: '1/10/2022', lastLockoutDate: '9/18/2022', lastPasswordChangeDate: '9/6/2022', @@ -1383,7 +1408,7 @@ export const data: Array = [ name: 'Cyrille Curm', email: 'ccurm26@forbes.com', language: 'Icelandic', - status: 'Active', + status: 'Enabled', lastLoginDate: '12/17/2021', lastLockoutDate: '8/9/2022', lastPasswordChangeDate: '10/14/2021', @@ -1419,7 +1444,7 @@ export const data: Array = [ name: 'Nickie Bronger', email: 'nbronger28@xrea.com', language: 'West Frisian', - status: 'Active', + status: 'Enabled', lastLoginDate: '8/5/2022', lastLockoutDate: '1/21/2022', lastPasswordChangeDate: '4/8/2022', @@ -1437,7 +1462,7 @@ export const data: Array = [ name: 'Annie Butterworth', email: 'abutterworth29@marketwatch.com', language: 'Bulgarian', - status: 'Active', + status: 'Enabled', lastLoginDate: '10/30/2021', lastLockoutDate: '10/5/2021', lastPasswordChangeDate: '5/3/2022', @@ -1527,7 +1552,7 @@ export const data: Array = [ name: 'Juliana Clorley', email: 'jclorley2e@mail.ru', language: 'Luxembourgish', - status: 'Active', + status: 'Enabled', lastLoginDate: '10/17/2021', lastLockoutDate: '8/4/2022', lastPasswordChangeDate: '12/23/2021', @@ -1668,7 +1693,7 @@ export const data: Array = [ name: 'Rodrick Twelftree', email: 'rtwelftree2m@nbcnews.com', language: 'Luxembourgish', - status: 'Active', + status: 'Enabled', lastLoginDate: '5/23/2022', lastLockoutDate: '6/21/2022', lastPasswordChangeDate: '8/27/2022', @@ -1686,7 +1711,7 @@ export const data: Array = [ name: 'Liesa Arnoll', email: 'larnoll2n@webnode.com', language: 'Hebrew', - status: 'Active', + status: 'Enabled', lastLoginDate: '9/13/2022', lastLockoutDate: '7/14/2022', lastPasswordChangeDate: '2/28/2022', @@ -1758,7 +1783,7 @@ export const data: Array = [ name: 'Isador Tibbles', email: 'itibbles2r@cafepress.com', language: 'Assamese', - status: 'Active', + status: 'Enabled', lastLoginDate: '4/7/2022', lastLockoutDate: '2/4/2022', lastPasswordChangeDate: '11/14/2021', @@ -1768,11 +1793,4 @@ export const data: Array = [ }, ]; -// Temp mocked database -class UmbUsersData extends UmbEntityData { - constructor() { - super(data); - } -} - -export const umbUsersData = new UmbUsersData(); +export const umbUsersData = new UmbUsersData(data); 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 index 9e57d81e8b..80f488f39e 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts @@ -23,10 +23,40 @@ export const handlers = [ rest.post('/umbraco/backoffice/users/save', async (req, res, ctx) => { const data = await req.json(); + console.log('HEJSA'); if (!data) return; const saved = umbUsersData.save(data); + console.log('saved', saved); + return res(ctx.status(200), ctx.json(saved)); }), + + rest.post>('/umbraco/backoffice/users/enable', async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + const enabledKeys = umbUsersData.enable(data); + + return res(ctx.status(200), ctx.json(enabledKeys)); + }), + + rest.post>('/umbraco/backoffice/users/disable', async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + const disabledKeys = umbUsersData.disable(data); + + return res(ctx.status(200), ctx.json(disabledKeys)); + }), + + rest.post>('/umbraco/backoffice/users/delete', async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + const deletedKeys = umbUsersData.delete(data); + + return res(ctx.status(200), ctx.json(deletedKeys)); + }), ]; From fd64ef526e826b1a1685d1903481a0617b80b27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 5 Oct 2022 12:00:40 +0200 Subject: [PATCH 43/98] delete now works --- .../views/users/editor-view-users-user-details.element.ts | 3 ++- src/Umbraco.Web.UI.Client/src/core/stores/store.ts | 7 +++++++ .../src/core/stores/user/user.store.ts | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 50c74d1ab5..35725a7589 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -116,7 +116,8 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi if (!this._user || !this._userStore) return; this._userStore.deleteUsers([this._user.key]); - // history.back(); //TODO Should redirect to users section + + history.pushState(null, '', '/section/users/view/users/overview'); } private renderLeftColumn() { 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 7d31d0994f..8da1cdd170 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/store.ts @@ -21,6 +21,13 @@ export class UmbDataStoreBase implements UmbD protected _items: BehaviorSubject> = new BehaviorSubject(>[]); public readonly items: Observable> = this._items.asObservable(); + public delete(deletedKeys: Array): void { + const remainingItems = this._items + .getValue() + .filter((item) => item.key && deletedKeys.includes(item.key) === false); + this._items.next(remainingItems); + } + /** * @description - Update the store with new items. Existing items are updated, new items are added. Existing items are matched by the compareKey. * @param {Array} updatedItems 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 index f8fda7a4ed..6cbe539c93 100644 --- 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 @@ -107,9 +107,9 @@ export class UmbUserStore extends UmbDataStoreBase { 'Content-Type': 'application/json', }, }); - const json = await res.json(); - this.update(json); - this._entityStore.update(json); + const deletedKeys = await res.json(); + this.delete(deletedKeys); + this._entityStore.delete(deletedKeys); } catch (error) { console.error('Delete Users failed', error); } From 3f5db3175b655810f7899bdf4fc564f256b4cc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 5 Oct 2022 12:10:37 +0200 Subject: [PATCH 44/98] removed height from router slot in editor entity layout --- .../editor-entity-layout/editor-entity-layout.element.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts index 6ffa2b346b..d3cdfb25ab 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity-layout/editor-entity-layout.element.ts @@ -59,10 +59,6 @@ export class UmbEditorEntityLayout extends UmbContextConsumerMixin(LitElement) { margin-left: auto; } - router-slot { - height: 100%; - } - uui-input { width: 100%; } From ee4f4f532b1765823c7b62df0f76cd89b2628d37 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 13:25:38 +0200 Subject: [PATCH 45/98] only render sidebar if there are trees --- .../backoffice/sections/shared/section.element.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 97295c277e..0e477d3ecc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -1,5 +1,5 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { css, html, LitElement } from 'lit'; +import { css, html, LitElement, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { Subscription, map, switchMap, EMPTY, of } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../core/context'; @@ -123,9 +123,13 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { render() { return html` - - - + ${this._trees && this._trees.length > 0 + ? html` + + + + ` + : nothing} From be753176686d0d17d429c756cae81c55990f2f10 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 13:26:11 +0200 Subject: [PATCH 46/98] rename method --- .../src/backoffice/sections/shared/section.element.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 0e477d3ecc..9ee58ab70c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -45,21 +45,21 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { // TODO: wait for more contexts this.consumeContext('umbExtensionRegistry', (extensionsRegistry: UmbExtensionRegistry) => { this._extensionRegistry = extensionsRegistry; - this._useTrees(); + this._observeTrees(); }); this.consumeContext('umbSectionContext', (sectionContext: UmbSectionContext) => { this._sectionContext = sectionContext; - this._useTrees(); + this._observeTrees(); }); this.consumeContext('umbEntityStore', (entityStore: UmbEntityStore) => { this._entityStore = entityStore; - this._useTrees(); + this._observeTrees(); }); } - private _useTrees() { + private _observeTrees() { if (!this._sectionContext || !this._extensionRegistry || !this._entityStore) return; this._treesSubscription?.unsubscribe(); From 62c059877108d3f6a4b79a2307629eb950264b77 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:23:32 +0200 Subject: [PATCH 47/98] introduce section views extensions --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 46 +++++++ .../schemas/generated-schema.ts | 18 +++ .../user-groups/editor-user-groups.element.ts | 17 +++ .../sections/shared/section.element.ts | 118 +++++++++++++++++- .../sections/users/users-section.element.ts | 4 +- .../section-view-user-groups.element.ts | 17 +++ .../views/users/section-view-users.element.ts | 17 +++ .../src/core/extension/extension.registry.ts | 2 + .../src/core/models/index.ts | 2 + .../src/temp-internal-manifests.ts | 26 ++++ .../temp-schema-generator/manifests.ts | 19 ++- 11 files changed, 274 insertions(+), 12 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index 4f97d5a6ae..60a8dd4d33 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -514,6 +514,50 @@ components: - meta - alias - name + MetaSectionView: + type: object + properties: + sections: + type: array + items: + type: string + label: + type: string + pathname: + type: string + weight: + type: number + format: float + icon: + type: string + required: + - sections + - label + - pathname + - weight + - icon + IManifestSectionView: + type: object + properties: + type: + type: string + enum: + - sectionView + meta: + $ref: '#/components/schemas/MetaSectionView' + js: + type: string + elementName: + type: string + alias: + type: string + name: + type: string + required: + - type + - meta + - alias + - name MetaTree: type: object properties: @@ -929,6 +973,7 @@ components: Manifest: oneOf: - $ref: '#/components/schemas/IManifestSection' + - $ref: '#/components/schemas/IManifestSectionView' - $ref: '#/components/schemas/IManifestTree' - $ref: '#/components/schemas/IManifestEditor' - $ref: '#/components/schemas/IManifestEditorAction' @@ -944,6 +989,7 @@ components: propertyName: type mapping: section: '#/components/schemas/IManifestSection' + sectionView: '#/components/schemas/IManifestSectionView' tree: '#/components/schemas/IManifestTree' editor: '#/components/schemas/IManifestEditor' editorAction: '#/components/schemas/IManifestEditorAction' diff --git a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts index d094caa2fc..107092c9ff 100644 --- a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts +++ b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts @@ -141,6 +141,23 @@ export interface components { alias: string; name: string; }; + MetaSectionView: { + sections: string[]; + label: string; + pathname: string; + /** Format: float */ + weight: number; + icon: string; + }; + IManifestSectionView: { + /** @enum {string} */ + type: "sectionView"; + meta: components["schemas"]["MetaSectionView"]; + js?: string; + elementName?: string; + alias: string; + name: string; + }; MetaTree: { /** Format: float */ weight: number; @@ -309,6 +326,7 @@ export interface components { }; Manifest: | components["schemas"]["IManifestSection"] + | components["schemas"]["IManifestSectionView"] | components["schemas"]["IManifestTree"] | components["schemas"]["IManifestEditor"] | components["schemas"]["IManifestEditorAction"] diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts new file mode 100644 index 0000000000..15ae67aa6d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts @@ -0,0 +1,17 @@ +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +@customElement('umb-editor-user-groups') +export class UmbEditorUserGroupsElement extends LitElement { + render() { + return html`
User Groups
`; + } +} + +export default UmbEditorUserGroupsElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-user-groups': UmbEditorUserGroupsElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 9ee58ab70c..c4503699b7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -3,13 +3,14 @@ import { css, html, LitElement, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { Subscription, map, switchMap, EMPTY, of } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../core/context'; -import { UmbExtensionRegistry } from '../../../core/extension'; +import { createExtensionElement, UmbExtensionRegistry } from '../../../core/extension'; import { UmbSectionContext } from '../section.context'; -import type { ManifestTree, ManifestEditor } from '../../../core/models'; +import type { ManifestTree, ManifestEditor, ManifestSectionView } from '../../../core/models'; import '../shared/section-trees.element.ts'; import { UmbEditorEntityElement } from '../../editors/shared/editor-entity/editor-entity.element'; import { UmbEntityStore } from '../../../core/stores/entity.store'; +import { IRoutingInfo } from 'router-slot'; @customElement('umb-section') export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { @@ -20,6 +21,19 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { flex: 1 1 auto; height: 100%; } + + #header { + display: flex; + gap: 16px; + align-items: center; + min-height: 60px; + } + + uui-tab-group { + --uui-tab-divider: var(--uui-color-border); + border-left: 1px solid var(--uui-color-border); + border-right: 1px solid var(--uui-color-border); + } `, ]; @@ -28,7 +42,16 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { private _routes: Array = []; @state() - private _trees?: Array; + private _trees: Array = []; + + @state() + private _views: Array = []; + + @state() + private _currentViewPath = ''; + + @state() + private _routerFolder = ''; private _editors?: Array; private _editorsSubscription?: Subscription; @@ -38,6 +61,7 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { private _sectionContext?: UmbSectionContext; private _extensionRegistry?: UmbExtensionRegistry; private _treesSubscription?: Subscription; + private _viewsSubscription?: Subscription; constructor() { super(); @@ -46,19 +70,28 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { this.consumeContext('umbExtensionRegistry', (extensionsRegistry: UmbExtensionRegistry) => { this._extensionRegistry = extensionsRegistry; this._observeTrees(); + this._observeViews(); }); this.consumeContext('umbSectionContext', (sectionContext: UmbSectionContext) => { this._sectionContext = sectionContext; this._observeTrees(); + this._observeViews(); }); this.consumeContext('umbEntityStore', (entityStore: UmbEntityStore) => { this._entityStore = entityStore; this._observeTrees(); + this._observeViews(); }); } + connectedCallback(): void { + super.connectedCallback(); + /* TODO: find a way to construct absolute urls */ + this._routerFolder = window.location.pathname.split('/view')[0]; + } + private _observeTrees() { if (!this._sectionContext || !this._extensionRegistry || !this._entityStore) return; @@ -84,11 +117,12 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { ) .subscribe((trees) => { this._trees = trees; - this._createRoutes(); + if (this._trees.length === 0) return; + this._createTreeRoutes(); }); } - private _createRoutes() { + private _createTreeRoutes() { const treeRoutes = this._trees?.map(() => { return { @@ -114,16 +148,65 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { ]; } + private _observeViews() { + if (!this._sectionContext || !this._extensionRegistry || !this._entityStore) return; + + this._viewsSubscription?.unsubscribe(); + + this._viewsSubscription = this._sectionContext?.data + .pipe( + switchMap((section) => { + if (!section) return EMPTY; + + return ( + this._extensionRegistry + ?.extensionsOfType('sectionView') + .pipe( + map((views) => + views + .filter((view) => view.meta.sections.includes(section.alias)) + .sort((a, b) => b.meta.weight - a.meta.weight) + ) + ) ?? of([]) + ); + }) + ) + .subscribe((views) => { + this._views = views; + if (this._views.length === 0) return; + this._createViewRoutes(); + }); + } + + private _createViewRoutes() { + this._routes = + this._views?.map((view) => { + return { + path: 'view/' + view.meta.pathname, + component: () => createExtensionElement(view), + setup: (component: UmbEditorEntityElement, info: IRoutingInfo) => { + this._currentViewPath = info.match.route.path; + }, + }; + }) ?? []; + + this._routes.push({ + path: '**', + redirectTo: 'view/' + this._views?.[0]?.meta.pathname, + }); + } + disconnectedCallback(): void { super.disconnectedCallback(); this._treesSubscription?.unsubscribe(); this._editorsSubscription?.unsubscribe(); + this._viewsSubscription?.unsubscribe(); } render() { return html` - ${this._trees && this._trees.length > 0 + ${this._trees.length > 0 ? html` @@ -131,11 +214,34 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { ` : nothing} + ${this._views.length > 0 ? html` ` : nothing} `; } + + private _renderViews() { + return html` + ${this._views?.length > 0 + ? html` + + ${this._views.map( + (view: ManifestSectionView) => html` + + + ${view.meta.label || view.name} + + ` + )} + + ` + : nothing} + `; + } } declare global { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts index 05b4916e11..b106dbc5c5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts @@ -1,12 +1,10 @@ import { html, LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; -import '../../editors/shared/editor-entity-layout/editor-entity-layout.element'; - @customElement('umb-section-users') export class UmbSectionUsersElement extends LitElement { render() { - return html` `; + return html` `; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts new file mode 100644 index 0000000000..af30f3053c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts @@ -0,0 +1,17 @@ +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +@customElement('umb-section-view-user-groups') +export class UmbSectionViewUserGroupsElement extends LitElement { + render() { + return html`
CONTENT FOR USER GROUPS SECTION VIEW
`; + } +} + +export default UmbSectionViewUserGroupsElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-section-view-user-groups': UmbSectionViewUserGroupsElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts new file mode 100644 index 0000000000..b15a6fd391 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -0,0 +1,17 @@ +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +@customElement('umb-section-view-users') +export class UmbSectionViewUsersElement extends LitElement { + render() { + return html` USERS VIEW SECTION`; + } +} + +export default UmbSectionViewUsersElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-section-view-users': UmbSectionViewUsersElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts index 73f11d88a3..0d2956f597 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts @@ -7,6 +7,7 @@ import type { ManifestPropertyAction, ManifestPropertyEditorUI, ManifestSection, + ManifestSectionView, ManifestTree, ManifestTreeItemAction, ManifestEditor, @@ -59,6 +60,7 @@ export class UmbExtensionRegistry { // Typings concept, need to put all core types to get a good array return type for the provided type... extensionsOfType(type: 'section'): Observable>; + extensionsOfType(type: 'sectionView'): Observable>; extensionsOfType(type: 'tree'): Observable>; extensionsOfType(type: 'editor'): Observable>; extensionsOfType(type: 'treeItemAction'): Observable>; diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index 571f81ce4b..0ef956568e 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -20,6 +20,7 @@ export type TelemetryModel = components['schemas']['TelemetryModel']; export type ServerStatus = components['schemas']['ServerStatus']; export type ManifestTypes = components['schemas']['Manifest']; export type ManifestSection = components['schemas']['IManifestSection']; +export type ManifestSectionView = components['schemas']['IManifestSectionView']; export type ManifestTree = components['schemas']['IManifestTree']; export type ManifestTreeItemAction = components['schemas']['IManifestTreeItemAction']; export type ManifestEditor = components['schemas']['IManifestEditor']; @@ -44,6 +45,7 @@ export type PropertyEditorConfigDefaultData = components['schemas']['PropertyEdi export type ManifestElementType = | ManifestSection + | ManifestSectionView | ManifestTree | ManifestTreeItemAction | ManifestEditor diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index 0f862fb53b..e9677b8c12 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -622,4 +622,30 @@ export const internalManifests: Array Promise import('./backoffice/sections/users/views/users/section-view-users.element'), + meta: { + sections: ['Umb.Section.Users'], + label: 'Users', + pathname: 'users', + weight: 200, + icon: 'umb:user', + }, + }, + { + type: 'sectionView', + alias: 'Umb.SectionView.UserGroups', + name: 'User Groups Section View', + loader: () => import('./backoffice/sections/users/views/user-groups/section-view-user-groups.element'), + meta: { + sections: ['Umb.Section.Users'], + label: 'User Groups', + pathname: 'user-groups', + weight: 100, + icon: 'umb:users', + }, + }, ]; diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts index dacb8f2473..ac441b5ade 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -32,6 +32,7 @@ export class ManifestsPackagesInstalled { export type Manifest = | IManifestSection + | IManifestSectionView | IManifestTree | IManifestEditor | IManifestEditorAction @@ -46,6 +47,7 @@ export type Manifest = export type ManifestStandardTypes = | 'section' + | 'sectionView' | 'tree' | 'editor' | 'editorView' @@ -55,8 +57,7 @@ export type ManifestStandardTypes = | 'dashboard' | 'propertyAction' | 'packageView' - | 'entrypoint' - ; + | 'entrypoint'; export interface ManifestsResponse { manifests: Manifest[]; @@ -88,6 +89,14 @@ export interface MetaSection { weight: number; } +export interface MetaSectionView { + sections: Array; + label: string; + pathname: string; + weight: number; + icon: string; +} + export interface MetaTree { weight: number; sections: Array; @@ -151,6 +160,11 @@ export interface IManifestSection extends IManifestElement { meta: MetaSection; } +export interface IManifestSectionView extends IManifestElement { + type: 'sectionView'; + meta: MetaSectionView; +} + export interface IManifestEditorAction extends IManifestElement { type: 'editorAction'; meta: MetaEditorAction; @@ -160,7 +174,6 @@ export interface MetaEditorAction { editors: Array; } - export interface IManifestTree extends IManifestElement { type: 'tree'; meta: MetaTree; From a95dc5e13d422e55d6a1c9031838ae272c8912d0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:30:10 +0200 Subject: [PATCH 48/98] move users section view --- .../users/editor-view-users-invite.element.ts | 6 +- .../editor-view-users-overview.element.ts | 6 +- .../editor-view-users-selection.element.ts | 8 +- .../editor-view-users-user-details.element.ts | 2 +- .../views/users/editor-view-users.element.ts | 97 ------------------- .../grid/editor-view-users-grid.element.ts | 6 +- .../table/editor-view-users-table.element.ts | 6 +- .../views/users/section-view-users.element.ts | 88 ++++++++++++++++- .../src/temp-internal-manifests.ts | 2 +- 9 files changed, 103 insertions(+), 118 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts index fe22ea0932..8b781d3f0a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts @@ -2,7 +2,7 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import UmbEditorViewUsersElement from './editor-view-users.element'; +import UmbSectionViewUsersElement from '../../../../sections/users/views/users/section-view-users.element'; export type UsersViewType = 'list' | 'grid'; @customElement('umb-editor-view-users-invite') @@ -48,14 +48,14 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Lit @state() private _showPostInvite = false; - private _usersContext?: UmbEditorViewUsersElement; + private _usersContext?: UmbSectionViewUsersElement; private _invitedUser?: UserItem; connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbSectionViewUsersElement) => { this._usersContext = usersContext; }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts index c6dd3ac427..08701cff71 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts @@ -8,7 +8,7 @@ import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; import { IRoute } from 'router-slot'; -import UmbEditorViewUsersElement from './editor-view-users.element'; +import UmbSectionViewUsersElement from '../../../../sections/users/views/users/section-view-users.element'; import { UUIPopoverElement } from '@umbraco-ui/uui'; import { isPathActive } from 'router-slot'; @@ -71,7 +71,7 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L @state() private _selection: Array = []; - private _usersContext?: UmbEditorViewUsersElement; + private _usersContext?: UmbSectionViewUsersElement; private _selectionSubscription?: Subscription; constructor() { @@ -83,7 +83,7 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbSectionViewUsersElement) => { this._usersContext = usersContext; this._selectionSubscription?.unsubscribe(); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts index 09b8164129..f375aa7744 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts @@ -3,7 +3,9 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { Subscription } from 'rxjs'; -import UmbEditorViewUsersElement, { UserItem } from './editor-view-users.element'; +import UmbSectionViewUsersElement, { + UserItem, +} from '../../../../sections/users/views/users/section-view-users.element'; @customElement('umb-editor-view-users-selection') export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin(LitElement) { @@ -29,14 +31,14 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( @state() private _selection: Array = []; - private _usersContext?: UmbEditorViewUsersElement; + private _usersContext?: UmbSectionViewUsersElement; private _usersSubscription?: Subscription; private _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbSectionViewUsersElement) => { this._usersContext = usersContext; this._usersSubscription?.unsubscribe(); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index 35725a7589..df0775c21d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -2,7 +2,7 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import UmbEditorViewUsersElement from './editor-view-users.element'; +import UmbSectionViewUsersElement from '../../../../sections/users/views/users/section-view-users.element'; import { Subscription } from 'rxjs'; import '../../../../property-editors/content-picker/property-editor-content-picker.element'; import { UmbUserStore } from '../../../../../core/stores/user/user.store'; 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 deleted file mode 100644 index a098a0dce3..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users.element.ts +++ /dev/null @@ -1,97 +0,0 @@ -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, Subscription } from 'rxjs'; -import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; -import { IRoute, IRoutingInfo } from 'router-slot'; -import { v4 as uuidv4 } from 'uuid'; -import './list-view-layouts/table/editor-view-users-table.element'; -import './list-view-layouts/grid/editor-view-users-grid.element'; -import './editor-view-users-selection.element'; -import './editor-view-users-invite.element'; - -import type { UserDetails, UserEntity } from '../../../../../core/models'; -import type { UmbEditorViewUsersUserDetailsElement } from './editor-view-users-user-details.element'; - -@customElement('umb-editor-view-users') -export class UmbEditorViewUsersElement extends UmbContextProviderMixin(LitElement) { - static styles = [UUITextStyles, css``]; - - @state() - private _routes: IRoute[] = [ - { - path: 'overview', - component: () => import('./editor-view-users-overview.element'), - }, - { - path: 'invite', - component: () => import('./editor-view-users-invite.element'), - }, - { - path: 'details/:key', - component: () => import('./editor-view-users-user-details.element'), - setup: (component: unknown, info: IRoutingInfo) => { - const element = component as UmbEditorViewUsersUserDetailsElement; - element.key = info.match.params.key; - }, - }, - { - path: '**', - redirectTo: '/section/users/view/users/overview', //TODO: this should be dynamic - }, - ]; - - private _selection: BehaviorSubject> = new BehaviorSubject(>[]); - public readonly selection: Observable> = this._selection.asObservable(); - - constructor() { - super(); - - this.provideContext('umbUsersContext', this); - } - - public setSelection(value: Array) { - if (!value) return; - this._selection.next(value); - this.requestUpdate('selection'); - } - - public select(key: string) { - const selection = this._selection.getValue(); - this._selection.next([...selection, key]); - this.requestUpdate('selection'); - } - - public deselect(key: string) { - const selection = this._selection.getValue(); - this._selection.next(selection.filter((k) => k !== key)); - this.requestUpdate('selection'); - } - - public getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { - switch ((status || '').toLowerCase()) { - case 'invited': - case 'inactive': - return { look: 'primary', color: 'warning' }; - case 'active': - return { look: 'primary', color: 'positive' }; - case 'disabled': - return { look: 'primary', color: 'danger' }; - default: - return { look: 'secondary', color: 'default' }; - } - } - - render() { - return html` `; - } -} - -export default UmbEditorViewUsersElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-editor-view-users': UmbEditorViewUsersElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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 index 9243972edc..26c5eab443 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/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,7 +5,7 @@ import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; import { ifDefined } from 'lit-html/directives/if-defined.js'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; -import UmbEditorViewUsersElement from '../../editor-view-users.element'; +import UmbSectionViewUsersElement from '../../../../../../sections/users/views/users/section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../../../../core/models'; @@ -38,7 +38,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl private _selection: Array = []; private _userStore?: UmbUserStore; - private _usersContext?: UmbEditorViewUsersElement; + private _usersContext?: UmbSectionViewUsersElement; private _usersSubscription?: Subscription; private _selectionSubscription?: Subscription; @@ -50,7 +50,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl this._observeUsers(); }); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbSectionViewUsersElement) => { this._usersContext = usersContext; this._observeSelection(); }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/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 index 0138d023d4..362f4b7e08 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/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 @@ -4,7 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; -import UmbEditorViewUsersElement from '../../editor-view-users.element'; +import UmbSectionViewUsersElement from '../../../../../../sections/users/views/users/section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../../../../core/models'; @@ -78,7 +78,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE private _users: Array = []; private _userStore?: UmbUserStore; - private _usersContext?: UmbEditorViewUsersElement; + private _usersContext?: UmbSectionViewUsersElement; private _usersSubscription?: Subscription; private _selectionSubscription?: Subscription; @@ -90,7 +90,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE this._observeUsers(); }); - this.consumeContext('umbUsersContext', (usersContext: UmbEditorViewUsersElement) => { + this.consumeContext('umbUsersContext', (usersContext: UmbSectionViewUsersElement) => { this._usersContext = usersContext; this._observeSelection(); }); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index b15a6fd391..cf60b7aa12 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -1,10 +1,90 @@ -import { html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; +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, Subscription } from 'rxjs'; +import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; +import { IRoute, IRoutingInfo } from 'router-slot'; +import { v4 as uuidv4 } from 'uuid'; +import '../../../../editors/users/views/users/list-view-layouts/table/editor-view-users-table.element'; +import '../../../../editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element'; +import '../../../../editors/users/views/users/editor-view-users-selection.element'; +import '../../../../editors/users/views/users/editor-view-users-invite.element'; + +import type { UserDetails, UserEntity } from '../../../../../core/models'; +import type { UmbEditorViewUsersUserDetailsElement } from '../../../../editors/users/views/users/editor-view-users-user-details.element'; @customElement('umb-section-view-users') -export class UmbSectionViewUsersElement extends LitElement { +export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitElement) { + static styles = [UUITextStyles, css``]; + + @state() + private _routes: IRoute[] = [ + { + path: 'overview', + component: () => import('../../../../editors/users/views/users/editor-view-users-overview.element'), + }, + { + path: 'invite', + component: () => import('../../../../editors/users/views/users/editor-view-users-invite.element'), + }, + { + path: 'details/:key', + component: () => import('../../../../editors/users/views/users/editor-view-users-user-details.element'), + setup: (component: unknown, info: IRoutingInfo) => { + const element = component as UmbEditorViewUsersUserDetailsElement; + element.key = info.match.params.key; + }, + }, + { + path: '**', + redirectTo: '/section/users/view/users/overview', //TODO: this should be dynamic + }, + ]; + + private _selection: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly selection: Observable> = this._selection.asObservable(); + + constructor() { + super(); + + this.provideContext('umbUsersContext', this); + } + + public setSelection(value: Array) { + if (!value) return; + this._selection.next(value); + this.requestUpdate('selection'); + } + + public select(key: string) { + const selection = this._selection.getValue(); + this._selection.next([...selection, key]); + this.requestUpdate('selection'); + } + + public deselect(key: string) { + const selection = this._selection.getValue(); + this._selection.next(selection.filter((k) => k !== key)); + this.requestUpdate('selection'); + } + + public getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { + switch ((status || '').toLowerCase()) { + case 'invited': + case 'inactive': + return { look: 'primary', color: 'warning' }; + case 'active': + return { look: 'primary', color: 'positive' }; + case 'disabled': + return { look: 'primary', color: 'danger' }; + default: + return { look: 'secondary', color: 'default' }; + } + } + render() { - return html` USERS VIEW SECTION`; + return html` `; } } diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index e9677b8c12..215dd2407d 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -346,7 +346,7 @@ export const internalManifests: Array Promise import('./backoffice/editors/users/views/users/editor-view-users.element'), + loader: () => import('./backoffice/sections/users/views/users/section-view-users.element'), meta: { editors: ['Umb.Editor.Users'], pathname: 'users', From ccfe5e37cfb0ed281c68a20e509b1d757be965d4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:30:53 +0200 Subject: [PATCH 49/98] move old user groups view --- .../editor-view-user-groups.element.ts | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts deleted file mode 100644 index 1df1bf3ed9..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/user-groups/editor-view-user-groups.element.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { css, html, LitElement } from 'lit'; -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../../../core/context'; -import type { DocumentTypeEntity } from '../../../../../mocks/data/document-type.data'; -import { Subscription, distinctUntilChanged } from 'rxjs'; -import { UmbDocumentTypeContext } from '../../document-type.context'; - -@customElement('umb-editor-view-user-groups') -export class UmbEditorViewUserGroupsElement extends UmbContextConsumerMixin(LitElement) { - static styles = [UUITextStyles, css``]; - - render() { - return html`
USER GROUPS
`; - } -} - -export default UmbEditorViewUserGroupsElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-editor-view-user-groups': UmbEditorViewUserGroupsElement; - } -} From 0d0d54dd4d985801ef5d6933854f82f48cceebd3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:31:52 +0200 Subject: [PATCH 50/98] remove from manifest --- .../src/temp-internal-manifests.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index 215dd2407d..b68838d3e4 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -372,18 +372,6 @@ export const internalManifests: Array Promise import('./backoffice/editors/users/views/user-groups/editor-view-user-groups.element'), - meta: { - editors: ['Umb.Editor.Users'], - pathname: 'user-groups', - weight: 0, - icon: 'document', - }, - }, { type: 'propertyAction', alias: 'Umb.PropertyAction.Copy', From 543443dded6d3b476bb2c5e1265d4602b4b148a5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:35:38 +0200 Subject: [PATCH 51/98] move files for users section view --- .../backoffice/editors/users/views/users/tempData.ts | 2 -- .../views/users/editor-view-users-invite.element.ts | 2 +- .../users/editor-view-users-overview.element.ts | 2 +- .../users/editor-view-users-selection.element.ts | 4 +--- .../grid/editor-view-users-grid.element.ts | 2 +- .../table/editor-view-users-table.element.ts | 2 +- .../users/views/users/section-view-users.element.ts | 12 ++++++------ 7 files changed, 11 insertions(+), 15 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts rename src/Umbraco.Web.UI.Client/src/backoffice/{editors => sections}/users/views/users/editor-view-users-invite.element.ts (97%) rename src/Umbraco.Web.UI.Client/src/backoffice/{editors => sections}/users/views/users/editor-view-users-overview.element.ts (98%) rename src/Umbraco.Web.UI.Client/src/backoffice/{editors => sections}/users/views/users/editor-view-users-selection.element.ts (95%) rename src/Umbraco.Web.UI.Client/src/backoffice/{editors => sections}/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts (97%) rename src/Umbraco.Web.UI.Client/src/backoffice/{editors => sections}/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts (98%) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts deleted file mode 100644 index 139597f9cb..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/tempData.ts +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts similarity index 97% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts index 8b781d3f0a..e51758ed27 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts @@ -2,7 +2,7 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import UmbSectionViewUsersElement from '../../../../sections/users/views/users/section-view-users.element'; +import UmbSectionViewUsersElement from './section-view-users.element'; export type UsersViewType = 'list' | 'grid'; @customElement('umb-editor-view-users-invite') diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts similarity index 98% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts index 08701cff71..e27a9229ea 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts @@ -8,7 +8,7 @@ import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; import { IRoute } from 'router-slot'; -import UmbSectionViewUsersElement from '../../../../sections/users/views/users/section-view-users.element'; +import UmbSectionViewUsersElement from './section-view-users.element'; import { UUIPopoverElement } from '@umbraco-ui/uui'; import { isPathActive } from 'router-slot'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts similarity index 95% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts index f375aa7744..a81e3e5f04 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts @@ -3,9 +3,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import { Subscription } from 'rxjs'; -import UmbSectionViewUsersElement, { - UserItem, -} from '../../../../sections/users/views/users/section-view-users.element'; +import UmbSectionViewUsersElement, { UserItem } from './section-view-users.element'; @customElement('umb-editor-view-users-selection') export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts similarity index 97% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index 26c5eab443..3f532c60cd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -5,7 +5,7 @@ import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; import { ifDefined } from 'lit-html/directives/if-defined.js'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; -import UmbSectionViewUsersElement from '../../../../../../sections/users/views/users/section-view-users.element'; +import UmbSectionViewUsersElement from '../../section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../../../../core/models'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts similarity index 98% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts index 362f4b7e08..f8088bdf48 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts @@ -4,7 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; -import UmbSectionViewUsersElement from '../../../../../../sections/users/views/users/section-view-users.element'; +import UmbSectionViewUsersElement from '../../section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../../../../core/models'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index cf60b7aa12..dd55c19657 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -6,10 +6,10 @@ import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; import { IRoute, IRoutingInfo } from 'router-slot'; import { v4 as uuidv4 } from 'uuid'; -import '../../../../editors/users/views/users/list-view-layouts/table/editor-view-users-table.element'; -import '../../../../editors/users/views/users/list-view-layouts/grid/editor-view-users-grid.element'; -import '../../../../editors/users/views/users/editor-view-users-selection.element'; -import '../../../../editors/users/views/users/editor-view-users-invite.element'; +import './list-view-layouts/table/editor-view-users-table.element'; +import './list-view-layouts/grid/editor-view-users-grid.element'; +import './editor-view-users-selection.element'; +import './editor-view-users-invite.element'; import type { UserDetails, UserEntity } from '../../../../../core/models'; import type { UmbEditorViewUsersUserDetailsElement } from '../../../../editors/users/views/users/editor-view-users-user-details.element'; @@ -22,11 +22,11 @@ export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitEleme private _routes: IRoute[] = [ { path: 'overview', - component: () => import('../../../../editors/users/views/users/editor-view-users-overview.element'), + component: () => import('./editor-view-users-overview.element'), }, { path: 'invite', - component: () => import('../../../../editors/users/views/users/editor-view-users-invite.element'), + component: () => import('./editor-view-users-invite.element'), }, { path: 'details/:key', From 266e91ea267458eaa7ab97126cac46d8abb3d170 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:37:12 +0200 Subject: [PATCH 52/98] fix import order --- .../users/actions/editor-action-users-save.element.ts | 2 +- .../views/users/editor-view-users-user-details.element.ts | 4 ++-- .../src/backoffice/sections/shared/section.element.ts | 2 +- .../views/users/editor-view-users-overview.element.ts | 7 +++---- .../views/users/editor-view-users-selection.element.ts | 2 +- .../table/editor-view-users-table.element.ts | 2 +- .../users/views/users/section-view-users.element.ts | 2 +- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts index 544a3e30ea..36fd45fb49 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts @@ -1,9 +1,9 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; +import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../../../core/context'; import { UmbUserStore } from '../../../../../../core/stores/user/user.store'; -import { Subscription } from 'rxjs'; import type { UserEntity } from '../../../../../../core/models'; @customElement('umb-editor-action-users-save') diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts index df0775c21d..2c6ea9c82c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts @@ -1,12 +1,12 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; +import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbSectionViewUsersElement from '../../../../sections/users/views/users/section-view-users.element'; -import { Subscription } from 'rxjs'; import '../../../../property-editors/content-picker/property-editor-content-picker.element'; import { UmbUserStore } from '../../../../../core/stores/user/user.store'; -import { UserDetails } from '../../../../../core/models'; +import type { UserDetails } from '../../../../../core/models'; @customElement('umb-editor-view-users-user-details') export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index c4503699b7..353cc2fad4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -2,6 +2,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { Subscription, map, switchMap, EMPTY, of } from 'rxjs'; +import { IRoutingInfo } from 'router-slot'; import { UmbContextConsumerMixin } from '../../../core/context'; import { createExtensionElement, UmbExtensionRegistry } from '../../../core/extension'; import { UmbSectionContext } from '../section.context'; @@ -10,7 +11,6 @@ import type { ManifestTree, ManifestEditor, ManifestSectionView } from '../../.. import '../shared/section-trees.element.ts'; import { UmbEditorEntityElement } from '../../editors/shared/editor-entity/editor-entity.element'; import { UmbEntityStore } from '../../../core/stores/entity.store'; -import { IRoutingInfo } from 'router-slot'; @customElement('umb-section') export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts index e27a9229ea..0ca11fb943 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts @@ -1,16 +1,15 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../../../core/context'; import { Subscription } from 'rxjs'; import './list-view-layouts/table/editor-view-users-table.element'; import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; -import { IRoute } from 'router-slot'; -import UmbSectionViewUsersElement from './section-view-users.element'; +import { IRoute , isPathActive } from 'router-slot'; import { UUIPopoverElement } from '@umbraco-ui/uui'; -import { isPathActive } from 'router-slot'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import UmbSectionViewUsersElement from './section-view-users.element'; export type UsersViewType = 'list' | 'grid'; @customElement('umb-editor-view-users-overview') diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts index a81e3e5f04..94dd75b282 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts @@ -1,8 +1,8 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../../../core/context'; import { Subscription } from 'rxjs'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbSectionViewUsersElement, { UserItem } from './section-view-users.element'; @customElement('umb-editor-view-users-selection') diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts index f8088bdf48..9700a32a98 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts @@ -1,9 +1,9 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../../../../../core/context'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; +import { UmbContextConsumerMixin } from '../../../../../../../core/context'; import UmbSectionViewUsersElement from '../../section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../../../../core/models'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index dd55c19657..eab6228273 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -1,11 +1,11 @@ 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, Subscription } from 'rxjs'; import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; import { IRoute, IRoutingInfo } from 'router-slot'; import { v4 as uuidv4 } from 'uuid'; +import { UmbContextProviderMixin } from '../../../../../core/context'; import './list-view-layouts/table/editor-view-users-table.element'; import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; From 135183b03309b70eb3dbf6bc3a0a4f8aa4f5e2b6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:46:34 +0200 Subject: [PATCH 53/98] refactor user editor --- .../user-group/editor-user-group.element.ts | 17 +++++++ .../user-groups/editor-user-groups.element.ts | 17 ------- .../editor-action-user-save.element.ts} | 14 +++--- .../editor-user.element.ts} | 18 ++++---- .../editors/users/editor-users.element.ts | 44 ------------------- .../editor-view-users-overview.element.ts | 2 +- .../views/users/section-view-users.element.ts | 6 +-- .../src/temp-internal-manifests.ts | 28 ++++-------- 8 files changed, 45 insertions(+), 101 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts rename src/Umbraco.Web.UI.Client/src/backoffice/editors/{users/views/users/actions/editor-action-users-save.element.ts => user/actions/editor-action-user-save.element.ts} (60%) rename src/Umbraco.Web.UI.Client/src/backoffice/editors/{users/views/users/editor-view-users-user-details.element.ts => user/editor-user.element.ts} (90%) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts new file mode 100644 index 0000000000..a731b87c06 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts @@ -0,0 +1,17 @@ +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +@customElement('umb-editor-user-group') +export class UmbEditorUserGroupElement extends LitElement { + render() { + return html`
User Group
`; + } +} + +export default UmbEditorUserGroupElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-user-group': UmbEditorUserGroupElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts deleted file mode 100644 index 15ae67aa6d..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-groups/editor-user-groups.element.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; - -@customElement('umb-editor-user-groups') -export class UmbEditorUserGroupsElement extends LitElement { - render() { - return html`
User Groups
`; - } -} - -export default UmbEditorUserGroupsElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-editor-user-groups': UmbEditorUserGroupsElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts similarity index 60% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts index 36fd45fb49..f15417ceec 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/actions/editor-action-users-save.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts @@ -2,12 +2,12 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../../../../core/context'; -import { UmbUserStore } from '../../../../../../core/stores/user/user.store'; -import type { UserEntity } from '../../../../../../core/models'; +import { UmbContextConsumerMixin } from '../../../../core/context'; +import { UmbUserStore } from '../../../../core/stores/user/user.store'; +import type { UserEntity } from '../../../../core/models'; -@customElement('umb-editor-action-users-save') -export class UmbEditorActionUsersSaveElement extends UmbContextConsumerMixin(LitElement) { +@customElement('umb-editor-action-user-save') +export class UmbEditorActionUserSaveElement extends UmbContextConsumerMixin(LitElement) { static styles = [UUITextStyles, css``]; private _userStore?: UmbUserStore; @@ -30,10 +30,10 @@ export class UmbEditorActionUsersSaveElement extends UmbContextConsumerMixin(Lit } } -export default UmbEditorActionUsersSaveElement; +export default UmbEditorActionUserSaveElement; declare global { interface HTMLElementTagNameMap { - 'umb-editor-action-users-save': UmbEditorActionUsersSaveElement; + 'umb-editor-action-user-save': UmbEditorActionUserSaveElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts similarity index 90% rename from src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index 2c6ea9c82c..8630c3f092 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/views/users/editor-view-users-user-details.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -2,14 +2,14 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../../../core/context'; -import UmbSectionViewUsersElement from '../../../../sections/users/views/users/section-view-users.element'; -import '../../../../property-editors/content-picker/property-editor-content-picker.element'; -import { UmbUserStore } from '../../../../../core/stores/user/user.store'; -import type { UserDetails } from '../../../../../core/models'; +import { UmbContextConsumerMixin } from '../../../core/context'; +import UmbSectionViewUsersElement from '../../sections/users/views/users/section-view-users.element'; +import '../../property-editors/content-picker/property-editor-content-picker.element'; +import { UmbUserStore } from '../../../core/stores/user/user.store'; +import type { UserDetails } from '../../../core/models'; -@customElement('umb-editor-view-users-user-details') -export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixin(LitElement) { +@customElement('umb-editor-user') +export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { static styles = [ UUITextStyles, css` @@ -246,10 +246,10 @@ export class UmbEditorViewUsersUserDetailsElement extends UmbContextConsumerMixi } } -export default UmbEditorViewUsersUserDetailsElement; +export default UmbEditorUserElement; declare global { interface HTMLElementTagNameMap { - 'umb-editor-view-users-user-details': UmbEditorViewUsersUserDetailsElement; + 'umb-editor-view-users-user-details': UmbEditorUserElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts deleted file mode 100644 index 0f3f8549c7..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/users/editor-users.element.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../core/context'; - -import '../shared/editor-entity-layout/editor-entity-layout.element'; - -// Lazy load -// TODO: Make this dynamic, use load-extensions method to loop over extensions for this node. -import './views/user-groups/editor-view-user-groups.element'; - -@customElement('umb-editor-users') -export class UmbEditorUsersElement extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - width: 100%; - height: 100%; - } - - #name { - width: 100%; - } - - #alias { - padding: 0 var(--uui-size-space-3); - } - `, - ]; - - render() { - return html` `; - } -} - -export default UmbEditorUsersElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-editor-users': UmbEditorUsersElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts index 0ca11fb943..fd6c2a6ae0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts @@ -6,7 +6,7 @@ import './list-view-layouts/table/editor-view-users-table.element'; import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; -import { IRoute , isPathActive } from 'router-slot'; +import { IRoute } from 'router-slot'; import { UUIPopoverElement } from '@umbraco-ui/uui'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbSectionViewUsersElement from './section-view-users.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index eab6228273..b74262689c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -12,7 +12,7 @@ import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; import type { UserDetails, UserEntity } from '../../../../../core/models'; -import type { UmbEditorViewUsersUserDetailsElement } from '../../../../editors/users/views/users/editor-view-users-user-details.element'; +import type { UmbEditorUserElement } from '../../../../editors/user/editor-user.element'; @customElement('umb-section-view-users') export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitElement) { @@ -30,9 +30,9 @@ export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitEleme }, { path: 'details/:key', - component: () => import('../../../../editors/users/views/users/editor-view-users-user-details.element'), + component: () => import('../../../../editors/user/editor-user.element'), setup: (component: unknown, info: IRoutingInfo) => { - const element = component as UmbEditorViewUsersUserDetailsElement; + const element = component as UmbEditorUserElement; element.key = info.match.params.key; }, }, diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index b68838d3e4..56b3e22983 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -343,33 +343,21 @@ export const internalManifests: Array Promise import('./backoffice/sections/users/views/users/section-view-users.element'), + type: 'editor', + alias: 'Umb.Editor.User', + name: 'User Editor', + loader: () => import('./backoffice/editors/user/editor-user.element'), meta: { - editors: ['Umb.Editor.Users'], - pathname: 'users', - weight: 1, - icon: 'document', + entityType: 'user', }, }, { type: 'editorAction', - alias: 'Umb.EditorAction.Users.Save', + alias: 'Umb.EditorAction.User.Save', name: 'EditorActionUserSave', - loader: () => import('./backoffice/editors/users/views/users/actions/editor-action-users-save.element'), + loader: () => import('./backoffice/editors/user/actions/editor-action-user-save.element'), meta: { - editors: ['Umb.Editor.Users'], - }, - }, - { - type: 'editorAction', - alias: 'Umb.EditorAction.Users.Delete', - name: 'EditorActionUserDelete', - loader: () => import('./backoffice/editors/users/views/users/actions/editor-action-users-save.element'), - meta: { - editors: ['Umb.Editor.DataType'], + editors: ['Umb.Editor.User'], }, }, { From a15031efed9c3d0adb327401532b419e4b9f8572 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 14:59:54 +0200 Subject: [PATCH 54/98] render user editor in user section --- .../editors/user/editor-user.element.ts | 23 +++++++++++++++---- .../grid/editor-view-users-grid.element.ts | 2 +- .../views/users/section-view-users.element.ts | 12 ++++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index 8630c3f092..b4bc135e60 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -8,12 +8,18 @@ import '../../property-editors/content-picker/property-editor-content-picker.ele import { UmbUserStore } from '../../../core/stores/user/user.store'; import type { UserDetails } from '../../../core/models'; +import '../shared/editor-entity-layout/editor-entity-layout.element'; + @customElement('umb-editor-user') export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { static styles = [ UUITextStyles, css` :host { + display: block; + } + + #main { display: grid; grid-template-columns: 1fr 350px; gap: var(--uui-size-space-6); @@ -79,8 +85,8 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { @state() private _user?: UserDetails | null; - @property() - public key = ''; + @property({ type: String }) + entityKey = ''; protected _userStore?: UmbUserStore; protected _usersSubscription?: Subscription; @@ -93,7 +99,7 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { this._userStore = usersContext; this._usersSubscription?.unsubscribe(); - this._usersSubscription = this._userStore?.getByKey(this.key).subscribe((user) => { + this._usersSubscription = this._userStore?.getByKey(this.entityKey).subscribe((user) => { this._user = user; }); }); @@ -240,8 +246,15 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { if (!this._user) return html`User not found`; return html` -
${this.renderLeftColumn()}
-
${this.renderRightColumn()}
+ + +
+
${this.renderLeftColumn()}
+
${this.renderRightColumn()}
+
+
`; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index 3f532c60cd..43d96c1001 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -83,7 +83,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl //TODO How should we handle url stuff? private _handleOpenCard(key: string) { - history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO Change to a tag with href and make dynamic + history.pushState(null, '', '/section/users/view/users/user/' + key); //TODO Change to a tag with href and make dynamic } private _selectRowHandler(user: UserEntity) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index b74262689c..b5cb427787 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -13,6 +13,7 @@ import './editor-view-users-invite.element'; import type { UserDetails, UserEntity } from '../../../../../core/models'; import type { UmbEditorUserElement } from '../../../../editors/user/editor-user.element'; +import UmbEditorEntityElement from '../../../../editors/shared/editor-entity/editor-entity.element'; @customElement('umb-section-view-users') export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitElement) { @@ -29,11 +30,12 @@ export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitEleme component: () => import('./editor-view-users-invite.element'), }, { - path: 'details/:key', - component: () => import('../../../../editors/user/editor-user.element'), - setup: (component: unknown, info: IRoutingInfo) => { - const element = component as UmbEditorUserElement; - element.key = info.match.params.key; + path: `:entityType/:key`, + component: () => import('../../../../editors/shared/editor-entity/editor-entity.element'), + setup: (component: HTMLElement, info: IRoutingInfo) => { + const element = component as UmbEditorEntityElement; + element.entityKey = info.match.params.key; + element.entityType = info.match.params.entityType; }, }, { From 0b775df00046729ba6d836e6d0eceedaa01fc301 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 5 Oct 2022 15:39:56 +0200 Subject: [PATCH 55/98] save user --- .../editor-action-user-save.element.ts | 41 +++++++++++-- .../editors/user/editor-user.element.ts | 58 +++++++++++++++---- .../backoffice/editors/user/user.context.ts | 36 ++++++++++++ 3 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts index f15417ceec..ac77da41ef 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/actions/editor-action-user-save.element.ts @@ -5,12 +5,21 @@ import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../core/context'; import { UmbUserStore } from '../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../core/models'; +import { UmbUserContext } from '../user.context'; +import { UUIButtonState } from '@umbraco-ui/uui'; +import { UmbNotificationDefaultData } from '../../../../core/services/notification/layouts/default'; +import { UmbNotificationService } from '../../../../core/services/notification'; @customElement('umb-editor-action-user-save') export class UmbEditorActionUserSaveElement extends UmbContextConsumerMixin(LitElement) { static styles = [UUITextStyles, css``]; + @state() + private _saveButtonState?: UUIButtonState; + private _userStore?: UmbUserStore; + private _userContext?: UmbUserContext; + private _notificationService?: UmbNotificationService; connectedCallback(): void { super.connectedCallback(); @@ -18,15 +27,39 @@ export class UmbEditorActionUserSaveElement extends UmbContextConsumerMixin(LitE this.consumeContext('umbUserStore', (userStore: UmbUserStore) => { this._userStore = userStore; }); + + this.consumeContext('umbUserContext', (userContext: UmbUserContext) => { + this._userContext = userContext; + }); + + this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { + this._notificationService = service; + }); } - private _handleSave() { - // this._userStore.save() - console.log('save'); + private async _handleSave() { + // TODO: What if store is not present, what if node is not loaded.... + if (!this._userStore || !this._userContext) return; + + try { + this._saveButtonState = 'waiting'; + const user = this._userContext.getData(); + await this._userStore.save([user]); + const data: UmbNotificationDefaultData = { message: 'User Saved' }; + this._notificationService?.peek('positive', { data }); + this._saveButtonState = 'success'; + } catch (error) { + this._saveButtonState = 'failed'; + } } render() { - return html``; + return html``; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index b4bc135e60..0ad347b83c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -1,17 +1,18 @@ +import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui'; import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../core/context'; +import { UmbContextProviderMixin, UmbContextConsumerMixin } from '../../../core/context'; import UmbSectionViewUsersElement from '../../sections/users/views/users/section-view-users.element'; import '../../property-editors/content-picker/property-editor-content-picker.element'; import { UmbUserStore } from '../../../core/stores/user/user.store'; import type { UserDetails } from '../../../core/models'; +import { UmbUserContext } from './user.context'; import '../shared/editor-entity-layout/editor-entity-layout.element'; - @customElement('umb-editor-user') -export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { +export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) { static styles = [ UUITextStyles, css` @@ -85,22 +86,47 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { @state() private _user?: UserDetails | null; + @state() + private _userName = ''; + @property({ type: String }) entityKey = ''; protected _userStore?: UmbUserStore; protected _usersSubscription?: Subscription; + private _userContext?: UmbUserContext; + + private _userNameSubscription?: Subscription; private _languages = []; //TODO Add languages connectedCallback(): void { super.connectedCallback(); + this.consumeContext('umbUserStore', (usersContext: UmbUserStore) => { this._userStore = usersContext; + this._observeUser(); + }); + } - this._usersSubscription?.unsubscribe(); - this._usersSubscription = this._userStore?.getByKey(this.entityKey).subscribe((user) => { - this._user = user; + private _observeUser() { + this._usersSubscription?.unsubscribe(); + + this._usersSubscription = this._userStore?.getByKey(this.entityKey).subscribe((user) => { + this._user = user; + if (!this._user) return; + + if (!this._userContext) { + this._userContext = new UmbUserContext(this._user); + this.provideContext('umbUserContext', this._userContext); + } else { + this._userContext.update(this._user); + } + + this._userNameSubscription = this._userContext.data.subscribe((user) => { + if (user && user.name !== this._userName) { + this._userName = user.name; + } }); }); } @@ -109,6 +135,7 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { super.disconnectedCallback(); this._usersSubscription?.unsubscribe(); + this._userNameSubscription?.unsubscribe(); } private _updateUserStatus() { @@ -182,8 +209,6 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { private renderRightColumn() { if (!this._user || !this._userStore) return nothing; - console.log('user', this._user); - // const status = this._userStore.getTagLookAndColor(this._user.status); return html`
@@ -242,14 +267,23 @@ export class UmbEditorUserElement extends UmbContextConsumerMixin(LitElement) { `; } + // TODO. find a way where we don't have to do this for all editors. + private _handleInput(event: UUIInputEvent) { + if (event instanceof UUIInputEvent) { + const target = event.composedPath()[0] as UUIInputElement; + + if (typeof target?.value === 'string') { + this._userContext?.update({ name: target.value }); + } + } + } + render() { if (!this._user) return html`User not found`; return html` - - + +
${this.renderLeftColumn()}
${this.renderRightColumn()}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts new file mode 100644 index 0000000000..8d11cc64e3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts @@ -0,0 +1,36 @@ +import { BehaviorSubject, Observable } from 'rxjs'; +import type { UserDetails } from '../../../core/models'; + +export class UmbUserContext { + // TODO: figure out how fine grained we want to make our observables. + private _data = new BehaviorSubject({ + key: '', + name: '', + icon: '', + type: 'user', + hasChildren: false, + parentKey: '', + isTrashed: false, + email: '', + language: '', + status: '', + updateDate: '8/27/2022', + createDate: '9/19/2022', + failedLoginAttempts: 0, + }); + public readonly data: Observable = this._data.asObservable(); + + constructor(user: UserDetails) { + if (!user) return; + this._data.next(user); + } + + // TODO: figure out how we want to update data + public update(data: Partial) { + this._data.next({ ...this._data.getValue(), ...data }); + } + + public getData() { + return this._data.getValue(); + } +} From f5ad3e3be20b2850569b06202598154e6df7ce5a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Oct 2022 14:41:47 +0200 Subject: [PATCH 56/98] add umb-table element --- .../src/backoffice/backoffice.element.ts | 1 + .../components/table/table.element.ts | 205 ++++++++++++ .../editor-view-users-selection.element.ts | 25 +- .../grid/editor-view-users-grid.element.ts | 2 +- .../user-table-name-column-layout.element.ts | 30 ++ ...user-table-status-column-layout.element.ts | 42 +++ .../table/editor-view-users-table.element.ts | 314 ++++++------------ .../views/users/section-view-users.element.ts | 14 - 8 files changed, 394 insertions(+), 239 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/column-layouts/name/user-table-name-column-layout.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/column-layouts/status/user-table-status-column-layout.element.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 d29aaed274..5ebd610398 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -5,6 +5,7 @@ import './components/backoffice-main.element'; import './components/backoffice-modal-container.element'; import './components/backoffice-notification-container.element'; import './components/node-property/node-property.element'; +import './components/table/table.element'; import './sections/shared/section-layout.element'; import './sections/shared/section-main.element'; import './sections/shared/section-sidebar.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts new file mode 100644 index 0000000000..c9b8e09843 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts @@ -0,0 +1,205 @@ +import { UUITextStyles } from '@umbraco-ui/uui-css'; +import { css, html, LitElement, nothing } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { repeat } from 'lit/directives/repeat.js'; + +export interface UmbTableItem { + key: string; + icon?: string; + data: Array; +} + +export interface UmbTableItemData { + columnAlias: string; + value: any; +} + +export interface UmbTableColumn { + name: string; + alias: string; + elementName?: string; +} + +export interface UmbTableConfig { + allowSelection: boolean; +} + +export class UmbTableSelectedEvent extends Event { + public constructor() { + super('selected', { bubbles: true, composed: true }); + } +} + +export class UmbTableDeselectedEvent extends Event { + public constructor() { + super('deselected', { bubbles: true, composed: true }); + } +} + +@customElement('umb-table') +export class UmbTableElement extends LitElement { + static styles = [ + UUITextStyles, + css` + uui-table-row uui-checkbox { + display: none; + } + + uui-table-row:focus uui-icon, + uui-table-row:focus-within uui-icon, + uui-table-row:hover uui-icon, + uui-table-row[select-only] uui-icon { + display: none; + } + + uui-table-row:focus uui-checkbox, + uui-table-row:focus-within uui-checkbox, + uui-table-row:hover uui-checkbox, + uui-table-row[select-only] uui-checkbox { + display: inline-block; + } + + uui-table-head-cell:focus, + uui-table-head-cell:focus-within, + uui-table-head-cell:hover { + --uui-symbol-sort-hover: 1; + } + + uui-table-head-cell button { + padding: 0; + background-color: transparent; + color: inherit; + border: none; + cursor: pointer; + font-weight: inherit; + font-size: inherit; + display: inline-flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + `, + ]; + + @property({ type: Array, attribute: false }) + public items: Array = []; + + @property({ type: Array, attribute: false }) + public columns: Array = []; + + @property({ type: Object, attribute: false }) + public config: UmbTableConfig = { + allowSelection: false, + }; + + @property({ type: Array, attribute: false }) + public selection: Array = []; + + @state() + private _selectionMode = false; + + private _isSelected(key: string) { + return this.selection.includes(key); + } + + private _handleRowCheckboxChange(event: Event, item: UmbTableItem) { + const checkboxElement = event.target as HTMLInputElement; + checkboxElement.checked ? this._selectRow(item.key) : this._deselectRow(item.key); + } + + private _handleAllRowsCheckboxChange(event: Event) { + const checkboxElement = event.target as HTMLInputElement; + checkboxElement.checked ? this._selectAllRows() : this._deselectAllRows(); + } + + private _selectRow(key: string) { + this.selection = [...this.selection, key]; + this._selectionMode = this.selection.length > 0; + this.dispatchEvent(new UmbTableSelectedEvent()); + } + + private _deselectRow(key: string) { + this.selection = this.selection.filter((selectionKey) => selectionKey !== key); + this._selectionMode = this.selection.length > 0; + this.dispatchEvent(new UmbTableDeselectedEvent()); + } + + private _selectAllRows() { + this.selection = this.items.map((item: UmbTableItem) => item.key); + this._selectionMode = true; + this.dispatchEvent(new UmbTableSelectedEvent()); + } + + private _deselectAllRows() { + this.selection = []; + this._selectionMode = false; + this.dispatchEvent(new UmbTableDeselectedEvent()); + } + + render() { + return html` + + + + + + ${this.columns.map((column) => this._renderHeaderCell(column))} + + ${repeat(this.items, (item) => item.key, this._renderRow)} + `; + } + + private _renderHeaderCell(column: UmbTableColumn) { + return html` ${column.name} `; + } + + private _renderRow = (item: UmbTableItem) => { + return html` this._selectRow(item.key)} + @unselected=${() => this._deselectRow(item.key)}> + + ${item.icon ? html`` : nothing} + e.stopPropagation()} + @change=${(event: Event) => this._handleRowCheckboxChange(event, item)} + ?checked="${this._isSelected(item.key)}"> + + ${this.columns.map((column) => this._renderRowCell(column, item))} + `; + }; + + private _renderRowCell(column: UmbTableColumn, item: UmbTableItem) { + return html`${this._renderCellContent(column, item)} + `; + } + + private _renderCellContent(column: UmbTableColumn, item: UmbTableItem) { + const value = item.data.find((data) => data.columnAlias === column.alias)?.value; + + if (column.elementName) { + const element = document.createElement(column.elementName) as any; // TODO: add interface for UmbTableColumnLayoutElement + element.column = column; + element.item = item; + element.value = value; + return element; + } + + return value; + } +} + +export default UmbTableElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-table': UmbTableElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts index 94dd75b282..64f15a2011 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts @@ -4,6 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbSectionViewUsersElement, { UserItem } from './section-view-users.element'; +import { UmbUserStore } from '../../../../../core/stores/user/user.store'; @customElement('umb-editor-view-users-selection') export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin(LitElement) { @@ -23,37 +24,29 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( `, ]; - @state() - private _users: Array = []; - @state() private _selection: Array = []; private _usersContext?: UmbSectionViewUsersElement; - private _usersSubscription?: Subscription; private _selectionSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbSectionViewUsersElement) => { 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 _observeSelection() { + this._selectionSubscription?.unsubscribe(); + this._selectionSubscription = this._usersContext?.selection.subscribe((selection: Array) => { + this._selection = selection; }); } disconnectedCallback(): void { super.disconnectedCallback(); - - this._usersSubscription?.unsubscribe(); this._selectionSubscription?.unsubscribe(); } @@ -62,7 +55,7 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( } private _renderSelectionCount() { - return html`
${this._selection.length} of ${this._users.length} selected
`; + return html`
${this._selection.length} of [??] selected
`; } render() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index 43d96c1001..7e442d8ed3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -97,7 +97,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl private renderUserCard(user: UserEntity) { if (!this._userStore) return; - const statusLook = this._usersContext?.getTagLookAndColor(user.status ? user.status : ''); + const statusLook = null; //this._usersContext?.getTagLookAndColor(user.status ? user.status : ''); return html` + + ${this.value.name} +
`; + } +} + +export default UmbUserTableNameColumnLayoutElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-table-name-column-layout': UmbUserTableNameColumnLayoutElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/column-layouts/status/user-table-status-column-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/column-layouts/status/user-table-status-column-layout.element.ts new file mode 100644 index 0000000000..8f3856cd10 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/column-layouts/status/user-table-status-column-layout.element.ts @@ -0,0 +1,42 @@ +import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; +import { html, LitElement, nothing } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +@customElement('umb-user-table-status-column-layout') +export class UmbUserTableStatusColumnLayoutElement extends LitElement { + @property({ attribute: false }) + value: any; + + public _getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { + switch ((status || '').toLowerCase()) { + case 'invited': + case 'inactive': + return { look: 'primary', color: 'warning' }; + case 'active': + return { look: 'primary', color: 'positive' }; + case 'disabled': + return { look: 'primary', color: 'danger' }; + default: + return { look: 'secondary', color: 'default' }; + } + } + + render() { + return html`${this.value.status && this.value.status !== 'Enabled' + ? html` + ${this.value.status} + ` + : nothing}`; + } +} + +export default UmbUserTableStatusColumnLayoutElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-table-status-column-layout': UmbUserTableStatusColumnLayoutElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts index 9700a32a98..f4d9d2c107 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts @@ -1,82 +1,60 @@ -import { css, html, LitElement, nothing } from 'lit'; -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; -import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; -import UmbSectionViewUsersElement from '../../section-view-users.element'; +import type { UmbSectionViewUsersElement } from '../../section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; -import type { UserEntity } from '../../../../../../../core/models'; +import type { UserDetails } from '../../../../../../../core/models'; +import { + UmbTableElement, + UmbTableColumn, + UmbTableDeselectedEvent, + UmbTableItem, + UmbTableSelectedEvent, + UmbTableConfig, +} from '../../../../../../components/table/table.element'; -interface TableColumn { - name: string; - sort: (items: Array, desc: boolean) => Array; -} +import './column-layouts/name/user-table-name-column-layout.element'; +import './column-layouts/status/user-table-status-column-layout.element'; @customElement('umb-editor-view-users-table') export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - uui-table { - box-shadow: var(--uui-shadow-depth-1, 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24)); - } - uui-table-row uui-checkbox { - display: none; - } - uui-table-row:hover uui-icon, - uui-table-row[select-only] uui-icon { - display: none; - } - uui-table-row:hover uui-checkbox, - uui-table-row[select-only] uui-checkbox { - display: inline-block; - } - uui-table-head-cell:hover { - --uui-symbol-sort-hover: 1; - } - uui-table-head-cell button { - padding: 0; - background-color: transparent; - color: inherit; - border: none; - cursor: pointer; - font-weight: inherit; - font-size: inherit; - display: inline-flex; - align-items: center; - justify-content: space-between; - width: 100%; - } - .link-button { - font-weight: bold; - color: var(--uui-color-interactive); - } - .link-button:hover { - text-decoration: underline; - color: var(--uui-color-interactive-emphasis); - } - `, + @state() + private _users: Array = []; + + @state() + private _tableColumns: Array = [ + { + name: 'Name', + alias: 'userName', + elementName: 'umb-user-table-name-column-layout', + }, + { + name: 'User group', + alias: 'userGroup', + }, + { + name: 'Last login', + alias: 'userLastLogin', + }, + { + name: 'Status', + alias: 'userStatus', + elementName: 'umb-user-table-status-column-layout', + }, ]; @state() - private _columns: Array = []; + private _tableItems: Array = []; @state() - private _selectionMode = false; + private _tableConfig: UmbTableConfig = { + allowSelection: true, + }; @state() private _selection: Array = []; - @state() - private _sortingColumn: any = ''; - - @state() - private _sortingDesc = false; - - @state() - private _users: Array = []; - private _userStore?: UmbUserStore; private _usersContext?: UmbSectionViewUsersElement; private _usersSubscription?: Subscription; @@ -94,45 +72,66 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE this._usersContext = usersContext; this._observeSelection(); }); + } - this._columns = [ - { - name: 'Name', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => b.name.localeCompare(a.name)) - : [...items].sort((a, b) => a.name.localeCompare(b.name)); - }, - }, - { - name: 'User group', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => b.name.localeCompare(a.name)) - : [...items].sort((a, b) => a.name.localeCompare(b.name)); - }, - }, - { - name: 'Last login', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => +new Date(b.lastLoginDate || 0) - +new Date(a.lastLoginDate || 0)) - : [...items].sort((a, b) => +new Date(a.lastLoginDate || 0) - +new Date(b.lastLoginDate || 0)); - }, - }, - { - name: 'status', - sort: (items: Array, desc: boolean) => { - return desc - ? [...items].sort((a, b) => - b.status && a.status ? b.status.localeCompare(a.status) : (a.status ? 1 : 0) - (b.status ? 1 : 0) - ) - : [...items].sort((a, b) => - a.status && b.status ? a.status.localeCompare(b.status) : (b.status ? 1 : 0) - (a.status ? 1 : 0) - ); - }, - }, - ]; + private _observeUsers() { + this._usersSubscription?.unsubscribe(); + this._usersSubscription = this._userStore?.getAll().subscribe((users) => { + this._users = users; + this._createTableItems(this._users); + }); + } + + private _observeSelection() { + this._selectionSubscription = this._usersContext?.selection.subscribe((selection: Array) => { + if (this._selection === selection) return; + this._selection = selection; + }); + } + + private _createTableItems(users: Array) { + this._tableItems = users.map((user) => { + return { + key: user.key, + icon: 'umb:user', + data: [ + { + columnAlias: 'userName', + value: { + name: user.name, + }, + }, + { + columnAlias: 'userGroup', + value: user.userGroup, + }, + { + columnAlias: 'userLastLogin', + value: user.lastLoginDate, + }, + { + columnAlias: 'userStatus', + value: { + status: user.status, + }, + }, + ], + }; + }); + } + + private _handleSelected(event: UmbTableSelectedEvent) { + event.stopPropagation(); + const table = event.target as UmbTableElement; + const selection = table.selection; + this._usersContext?.setSelection(selection); + } + + private _handleDeselected(event: UmbTableDeselectedEvent) { + event.stopPropagation(); + const table = event.target as UmbTableElement; + const selection = table.selection; + this._usersContext?.setSelection(selection); } disconnectedCallback(): void { @@ -142,116 +141,15 @@ 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'); - } - - //TODO How should we handle url stuff? - private _handleOpenUser(event: Event, key: string) { - event.stopImmediatePropagation(); - history.pushState(null, '', '/section/users/view/users/details' + '/' + key); //TODO: make a tag with href - } - - private _selectRowHandler(user: UserEntity) { - this._usersContext?.select(user.key); - } - - private _deselectRowHandler(user: UserEntity) { - this._usersContext?.deselect(user.key); - } - - private _sortingHandler(column: TableColumn) { - this._sortingDesc = this._sortingColumn === column.name ? !this._sortingDesc : false; - this._sortingColumn = column.name; - this._users = column.sort(this._users, this._sortingDesc); - } - - private _isSelected(key: string) { - return this._selection.includes(key); - } - - renderHeaderCellTemplate(column: TableColumn) { - return html` - - - - `; - } - - protected renderRowTemplate = (user: UserEntity) => { - if (!this._usersContext) return; - - const statusLook = this._usersContext.getTagLookAndColor(user.status ? user.status : ''); - - return html` this._selectRowHandler(user)} - @unselected=${() => this._deselectRowHandler(user)}> - -
- -
-
- -
- -
-
- ${user.userGroup} - ${user.lastLoginDate} - - ${user.status && user.status !== 'Enabled' - ? html` ${user.status} ` - : nothing} - -
`; - }; - render() { return html` - - - - - - - ${this._columns.map((column) => this.renderHeaderCellTemplate(column))} - - ${repeat(this._users, (item) => item.key, this.renderRowTemplate)} - + `; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index b5cb427787..d524f6c198 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -71,20 +71,6 @@ export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitEleme this.requestUpdate('selection'); } - public getTagLookAndColor(status?: string): { color: InterfaceColor; look: InterfaceLook } { - switch ((status || '').toLowerCase()) { - case 'invited': - case 'inactive': - return { look: 'primary', color: 'warning' }; - case 'active': - return { look: 'primary', color: 'positive' }; - case 'disabled': - return { look: 'primary', color: 'danger' }; - default: - return { look: 'secondary', color: 'default' }; - } - } - render() { return html` `; } From 667c930ef5f2a85f953045cca54c0d728af7b9d8 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Oct 2022 15:16:35 +0200 Subject: [PATCH 57/98] add initial stories for table --- .../components/table/table.element.ts | 27 +++++++ .../components/table/table.stories.ts | 79 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.stories.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts index c9b8e09843..cceafe574d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts @@ -36,6 +36,13 @@ export class UmbTableDeselectedEvent extends Event { } } +/** + * @element umb-table + * @description - Element for displaying a table + * @fires {UmbTableSelectedEvent} selected - fires when a row is selected + * @fires {UmbTableDeselectedEvent} deselected - fires when a row is deselected + * @extends LitElement + */ @customElement('umb-table') export class UmbTableElement extends LitElement { static styles = [ @@ -81,17 +88,37 @@ export class UmbTableElement extends LitElement { `, ]; + /** + * Table Items + * @type {Array} + * @memberof UmbTableElement + */ @property({ type: Array, attribute: false }) public items: Array = []; + /** + * @description Table Columns + * @type {Array} + * @memberof UmbTableElement + */ @property({ type: Array, attribute: false }) public columns: Array = []; + /** + * @description Table Config + * @type {UmbTableConfig} + * @memberof UmbTableElement + */ @property({ type: Object, attribute: false }) public config: UmbTableConfig = { allowSelection: false, }; + /** + * @description Table Selection + * @type {Array} + * @memberof UmbTableElement + */ @property({ type: Array, attribute: false }) public selection: Array = []; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.stories.ts new file mode 100644 index 0000000000..329ae94aea --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.stories.ts @@ -0,0 +1,79 @@ +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; +import { v4 as uuidv4 } from 'uuid'; + +import type { UmbTableElement, UmbTableColumn, UmbTableConfig, UmbTableItem } from './table.element'; + +import './table.element'; + +export default { + title: 'Components/Table', + component: 'umb-table', + id: 'umb-table', +} as Meta; + +const columns: Array = [ + { + name: 'Name', + alias: 'name', + }, + { + name: 'Date', + alias: 'date', + }, +]; + +const today = new Intl.DateTimeFormat('en-US').format(new Date()); + +const items: Array = [ + { + key: uuidv4(), + icon: 'umb:wand', + data: [ + { + columnAlias: 'name', + value: 'Item 1', + }, + { + columnAlias: 'date', + value: today, + }, + ], + }, + { + key: uuidv4(), + icon: 'umb:document', + data: [ + { + columnAlias: 'name', + value: 'Item 2', + }, + { + columnAlias: 'date', + value: today, + }, + ], + }, + { + key: uuidv4(), + icon: 'umb:user', + data: [ + { + columnAlias: 'name', + value: 'Item 3', + }, + { + columnAlias: 'date', + value: today, + }, + ], + }, +]; + +const config: UmbTableConfig = { + allowSelection: true, +}; + +export const AAAOverview: Story = () => + html``; +AAAOverview.storyName = 'Overview'; From 37d8c915682ad69db09de9bd58e76d6ecba8277c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Oct 2022 15:52:08 +0200 Subject: [PATCH 58/98] Hack hide label from checkbox with empty space in slot --- .../src/backoffice/components/table/table.element.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts index cceafe574d..b7a54ce5e8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts @@ -169,9 +169,11 @@ export class UmbTableElement extends LitElement { + ?checked="${this.selection.length === this.items.length}"> + ${this.columns.map((column) => this._renderHeaderCell(column))} @@ -193,9 +195,11 @@ export class UmbTableElement extends LitElement { ${item.icon ? html`` : nothing} e.stopPropagation()} @change=${(event: Event) => this._handleRowCheckboxChange(event, item)} - ?checked="${this._isSelected(item.key)}"> + ?checked="${this._isSelected(item.key)}"> + ${this.columns.map((column) => this._renderRowCell(column, item))} `; From d4f117478330e94a8a643564b658d001b0148d88 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 6 Oct 2022 15:53:59 +0200 Subject: [PATCH 59/98] Update mockServiceWorker.js --- src/Umbraco.Web.UI.Client/public/mockServiceWorker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/public/mockServiceWorker.js b/src/Umbraco.Web.UI.Client/public/mockServiceWorker.js index c4138d8b2b..ab63a84955 100644 --- a/src/Umbraco.Web.UI.Client/public/mockServiceWorker.js +++ b/src/Umbraco.Web.UI.Client/public/mockServiceWorker.js @@ -2,7 +2,7 @@ /* tslint:disable */ /** - * Mock Service Worker (0.47.3). + * Mock Service Worker (0.47.4). * @see https://github.com/mswjs/msw * - Please do NOT modify this file. * - Please do NOT serve this file on production. From 9ae9140a1bc374f0f2f76eed11946b83da6402eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Thu, 6 Oct 2022 16:11:13 +0200 Subject: [PATCH 60/98] fixed scrolling --- .../components/backoffice-main.element.ts | 3 +++ .../editors/user/editor-user.element.ts | 1 + .../shared/section-dashboards.element.ts | 8 +++---- .../sections/shared/section-main.element.ts | 5 ++++ .../sections/shared/section.element.ts | 4 ++++ .../editor-view-users-overview.element.ts | 9 ++++++++ .../grid/editor-view-users-grid.element.ts | 23 +++++++++++++------ .../views/users/section-view-users.element.ts | 9 +++++++- 8 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts index 234f88c835..76dd9a45f0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts @@ -23,6 +23,9 @@ export class UmbBackofficeMain extends UmbContextProviderMixin(UmbContextConsume height: 100%; overflow: hidden; } + router-slot { + height: 100%; + } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index 0ad347b83c..110c1efa7c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -18,6 +18,7 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons css` :host { display: block; + height: 100%; } #main { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts index 3f2ec93220..1b50cbd9b5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts @@ -16,7 +16,9 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { UUITextStyles, css` :host { - display: block; + display: flex; + flex-direction: column; + height: 100%; width: 100%; } @@ -31,10 +33,6 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { padding: var(--uui-size-space-5); display: block; } - - #scroll-container { - height: 500px; // TODO: This is a temporary fix to get scrolling to work - } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main.element.ts index 664add7cbb..5a63d970d2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main.element.ts @@ -11,6 +11,11 @@ export class UmbSectionMain extends LitElement { flex: 1 1 auto; height: 100%; } + slot { + display: flex; + flex-direction: column; + height: 100%; + } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 353cc2fad4..6918851c3a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -34,6 +34,10 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { border-left: 1px solid var(--uui-color-border); border-right: 1px solid var(--uui-color-border); } + #router-slot { + overflow: auto; + height: 100%; + } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts index fd6c2a6ae0..8f0b6f58ba 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts @@ -17,6 +17,12 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L static styles = [ UUITextStyles, css` + :host { + height: 100%; + display: flex; + flex-direction: column; + } + #sticky-top { position: sticky; top: -1px; @@ -64,6 +70,9 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L color: inherit; text-decoration: none; } + router-slot { + overflow: hidden; + } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index 43d96c1001..2c117e1fda 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -14,10 +14,17 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl static styles = [ UUITextStyles, css` + :host { + height: 100%; + display: flex; + flex-direction: column; + } + #user-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--uui-size-space-4); + padding: var(--uui-size-space-4); } uui-card-user { @@ -130,13 +137,15 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl render() { return html` -
- ${repeat( - this._users, - (user) => user.key, - (user) => this.renderUserCard(user) - )} -
+ +
+ ${repeat( + this._users, + (user) => user.key, + (user) => this.renderUserCard(user) + )} +
+
`; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index b5cb427787..143bb1d8cf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -17,7 +17,14 @@ import UmbEditorEntityElement from '../../../../editors/shared/editor-entity/edi @customElement('umb-section-view-users') export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitElement) { - static styles = [UUITextStyles, css``]; + static styles = [ + UUITextStyles, + css` + :host { + height: 100%; + } + `, + ]; @state() private _routes: IRoute[] = [ From c00352c15d3dc6294bb6986b3be805acf946b00b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 12:03:00 +0200 Subject: [PATCH 61/98] add events for ordering --- .../components/table/table.element.ts | 30 ++++++++++++++++++- .../table/editor-view-users-table.element.ts | 11 ++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts index b7a54ce5e8..3df83a92f7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts @@ -36,11 +36,18 @@ export class UmbTableDeselectedEvent extends Event { } } +export class UmbTableOrderedEvent extends Event { + public constructor() { + super('ordered', { bubbles: true, composed: true }); + } +} + /** * @element umb-table * @description - Element for displaying a table * @fires {UmbTableSelectedEvent} selected - fires when a row is selected * @fires {UmbTableDeselectedEvent} deselected - fires when a row is deselected + * @fires {UmbTableOrderedEvent} sort - fires when a column order is changed * @extends LitElement */ @customElement('umb-table') @@ -122,6 +129,12 @@ export class UmbTableElement extends LitElement { @property({ type: Array, attribute: false }) public selection: Array = []; + @property({ type: String, attribute: false }) + public orderingColumn = ''; + + @property({ type: String, attribute: false }) + public orderingDesc = false; + @state() private _selectionMode = false; @@ -139,6 +152,12 @@ export class UmbTableElement extends LitElement { checkboxElement.checked ? this._selectAllRows() : this._deselectAllRows(); } + private _handleOrderingChange(column: UmbTableColumn) { + this.orderingDesc = this.orderingColumn === column.alias ? !this.orderingDesc : false; + this.orderingColumn = column.alias; + this.dispatchEvent(new UmbTableOrderedEvent()); + } + private _selectRow(key: string) { this.selection = [...this.selection, key]; this._selectionMode = this.selection.length > 0; @@ -182,7 +201,16 @@ export class UmbTableElement extends LitElement { } private _renderHeaderCell(column: UmbTableColumn) { - return html` ${column.name} `; + return html` + + + `; } private _renderRow = (item: UmbTableItem) => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts index f4d9d2c107..002ef498f3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts @@ -12,6 +12,7 @@ import { UmbTableItem, UmbTableSelectedEvent, UmbTableConfig, + UmbTableOrderEvent, } from '../../../../../../components/table/table.element'; import './column-layouts/name/user-table-name-column-layout.element'; @@ -134,6 +135,13 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE this._usersContext?.setSelection(selection); } + private _handleOrder(event: UmbTableOrderEvent) { + const table = event.target as UmbTableElement; + const orderingColumn = table.orderingColumn; + const orderingDesc = table.orderingDesc; + console.log(`fetch users, order column: ${orderingColumn}, desc: ${orderingDesc}`); + } + disconnectedCallback(): void { super.disconnectedCallback(); @@ -149,7 +157,8 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE .config=${this._tableConfig} .selection=${this._selection} @selected="${this._handleSelected}" - @deselected="${this._handleDeselected}"> + @deselected="${this._handleDeselected}" + @ordered="${this._handleOrder}"> `; } } From 1e2ffa56df9cd889d7784af6fbde79101c6c219c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 12:16:41 +0200 Subject: [PATCH 62/98] clean up --- .../table/editor-view-users-table.element.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts index 002ef498f3..a1d98065ff 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts @@ -12,7 +12,7 @@ import { UmbTableItem, UmbTableSelectedEvent, UmbTableConfig, - UmbTableOrderEvent, + UmbTableOrderedEvent, } from '../../../../../../components/table/table.element'; import './column-layouts/name/user-table-name-column-layout.element'; @@ -23,6 +23,11 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE @state() private _users: Array = []; + @state() + private _tableConfig: UmbTableConfig = { + allowSelection: true, + }; + @state() private _tableColumns: Array = [ { @@ -48,11 +53,6 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE @state() private _tableItems: Array = []; - @state() - private _tableConfig: UmbTableConfig = { - allowSelection: true, - }; - @state() private _selection: Array = []; @@ -135,7 +135,7 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE this._usersContext?.setSelection(selection); } - private _handleOrder(event: UmbTableOrderEvent) { + private _handleOrdering(event: UmbTableOrderedEvent) { const table = event.target as UmbTableElement; const orderingColumn = table.orderingColumn; const orderingDesc = table.orderingDesc; @@ -152,13 +152,13 @@ export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitE render() { return html` + @ordered="${this._handleOrdering}"> `; } } From 3a89decb848f5407cc0017edc6628e343c205b7f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 14:24:47 +0200 Subject: [PATCH 63/98] add total users to the store --- .../editor-view-users-selection.element.ts | 24 ++++++++++++++++--- .../src/core/stores/user/user.store.ts | 8 +++++-- .../src/mocks/domains/users.handlers.ts | 8 ++++--- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts index 64f15a2011..16a5d8c3d8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-selection.element.ts @@ -3,8 +3,8 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import UmbSectionViewUsersElement, { UserItem } from './section-view-users.element'; -import { UmbUserStore } from '../../../../../core/stores/user/user.store'; +import type { UmbUserStore } from '../../../../../core/stores/user/user.store'; +import { UmbSectionViewUsersElement } from './section-view-users.element'; @customElement('umb-editor-view-users-selection') export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin(LitElement) { @@ -27,8 +27,13 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( @state() private _selection: Array = []; + @state() + private _totalUsers = 0; + private _usersContext?: UmbSectionViewUsersElement; private _selectionSubscription?: Subscription; + private _userStore?: UmbUserStore; + private _totalUsersSubscription?: Subscription; connectedCallback(): void { super.connectedCallback(); @@ -36,6 +41,11 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( this._usersContext = usersContext; this._observeSelection(); }); + + this.consumeContext('umbUserStore', (userStore: UmbUserStore) => { + this._userStore = userStore; + this._observeTotalUsers(); + }); } private _observeSelection() { @@ -45,9 +55,17 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( }); } + private _observeTotalUsers() { + this._totalUsersSubscription?.unsubscribe(); + this._userStore?.totalUsers.subscribe((totalUsers: number) => { + this._totalUsers = totalUsers; + }); + } + disconnectedCallback(): void { super.disconnectedCallback(); this._selectionSubscription?.unsubscribe(); + this._totalUsersSubscription?.unsubscribe(); } private _handleClearSelection() { @@ -55,7 +73,7 @@ export class UmbEditorViewUsersSelectionElement extends UmbContextConsumerMixin( } private _renderSelectionCount() { - return html`
${this._selection.length} of [??] selected
`; + return html`
${this._selection.length} of ${this._totalUsers} selected
`; } render() { 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 index 6cbe539c93..e0477ea273 100644 --- 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 @@ -1,4 +1,4 @@ -import { map, Observable } from 'rxjs'; +import { BehaviorSubject, map, Observable } from 'rxjs'; import type { UserDetails, UserEntity } from '../../models'; import { UmbEntityStore } from '../entity.store'; import { UmbDataStoreBase } from '../store'; @@ -12,6 +12,9 @@ import { UmbDataStoreBase } from '../store'; export class UmbUserStore extends UmbDataStoreBase { private _entityStore: UmbEntityStore; + private _totalUsers: BehaviorSubject = new BehaviorSubject(0); + public readonly totalUsers: Observable = this._totalUsers.asObservable(); + constructor(entityStore: UmbEntityStore) { super(); this._entityStore = entityStore; @@ -20,9 +23,10 @@ export class UmbUserStore extends UmbDataStoreBase { getAll(): Observable> { // TODO: use Fetcher API. // TODO: only fetch if the data type is not in the store? - fetch(`/umbraco/backoffice/users`) + fetch(`/umbraco/backoffice/users/list/items`) .then((res) => res.json()) .then((data) => { + this._totalUsers.next(data.total); this.update(data.items); }); 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 index 80f488f39e..6344b9b8d5 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts @@ -4,9 +4,12 @@ import { umbUsersData } from '../data/users.data'; // TODO: add schema export const handlers = [ - rest.get('/umbraco/backoffice/users', (req, res, ctx) => { + rest.get('/umbraco/backoffice/users/list/items', (req, res, ctx) => { + const items = umbUsersData.getItems('user'); + const response = { - items: umbUsersData.getItems('user'), + total: items.length, + items, }; return res(ctx.status(200), ctx.json(response)); @@ -23,7 +26,6 @@ export const handlers = [ rest.post('/umbraco/backoffice/users/save', async (req, res, ctx) => { const data = await req.json(); - console.log('HEJSA'); if (!data) return; const saved = umbUsersData.save(data); From ac8630fd7baabb8904b62310795f90a9bdceb753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Fri, 7 Oct 2022 15:06:13 +0200 Subject: [PATCH 64/98] added scrolling to table --- .../components/table/table.element.ts | 18 ++++++++++++++++++ .../grid/editor-view-users-grid.element.ts | 1 + .../table/editor-view-users-table.element.ts | 14 +++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts index 3df83a92f7..2f3c4c15f1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/table/table.element.ts @@ -55,6 +55,24 @@ export class UmbTableElement extends LitElement { static styles = [ UUITextStyles, css` + :host { + height: 100%; + overflow: auto; + padding: var(--uui-size-space-4); + padding-top: 0; + } + + uui-table { + box-shadow: var(--uui-shadow-depth-1); + } + + uui-table-head { + position: sticky; + top: 0; + background: white; + z-index: 1; + } + uui-table-row uui-checkbox { display: none; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index fb73573366..7611043c05 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -25,6 +25,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--uui-size-space-4); padding: var(--uui-size-space-4); + padding-top: 0; } uui-card-user { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts index a1d98065ff..b68be8bec1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/table/editor-view-users-table.element.ts @@ -1,4 +1,5 @@ -import { html, LitElement } from 'lit'; +import { css, html, LitElement } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; @@ -20,6 +21,17 @@ import './column-layouts/status/user-table-status-column-layout.element'; @customElement('umb-editor-view-users-table') export class UmbEditorViewUsersTableElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + :host { + height: 100%; + display: flex; + flex-direction: column; + } + `, + ]; + @state() private _users: Array = []; From 5e99d6aec7bae68cd00e5b0a77846a7e00b11d36 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 15:52:18 +0200 Subject: [PATCH 65/98] move section views to its own component --- .../src/backoffice/backoffice.element.ts | 4 +- .../backoffice/sections/section.context.ts | 10 +- .../section-dashboards.element.ts | 14 +- .../section-dashboards.stories.ts | 25 ++++ .../section-main.element.ts | 4 +- .../section-main/section-main.stories.ts | 15 +++ .../section-sidebar.element.ts | 10 +- .../section-sidebar.stories.ts | 15 +++ .../section-trees.element.ts | 14 +- .../section-trees/section-trees.stories.ts | 14 ++ .../section-views/section-views.element.ts | 123 ++++++++++++++++++ .../section-views/section-views.stories.ts | 0 .../sections/shared/section.element.ts | 47 +------ 13 files changed, 231 insertions(+), 64 deletions(-) rename src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/{ => section-dashboards}/section-dashboards.element.ts (90%) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards/section-dashboards.stories.ts rename src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/{ => section-main}/section-main.element.ts (82%) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main/section-main.stories.ts rename src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/{ => section-sidebar}/section-sidebar.element.ts (83%) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar/section-sidebar.stories.ts rename src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/{ => section-trees}/section-trees.element.ts (82%) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees/section-trees.stories.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.stories.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 5ebd610398..2841eeddd2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -7,8 +7,8 @@ import './components/backoffice-notification-container.element'; import './components/node-property/node-property.element'; import './components/table/table.element'; import './sections/shared/section-layout.element'; -import './sections/shared/section-main.element'; -import './sections/shared/section-sidebar.element'; +import './sections/shared/section-main/section-main.element'; +import './sections/shared/section-sidebar/section-sidebar.element'; import './sections/shared/section.element'; import './trees/shared/tree-base.element'; import './trees/shared/tree.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts index 63eb9a4725..9828b1a9e0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts @@ -1,6 +1,6 @@ import { BehaviorSubject, ReplaySubject } from 'rxjs'; -import type { ManifestSection, ManifestTree } from '../../core/models'; +import type { ManifestSection, ManifestSectionView, ManifestTree } from '../../core/models'; import { Entity } from '../../mocks/data/entities'; export class UmbSectionContext { @@ -27,6 +27,10 @@ export class UmbSectionContext { private _activeTreeItem = new ReplaySubject(1); public readonly activeTreeItem = this._activeTreeItem.asObservable(); + // TODO: what is the best context to put this in? + private _activeView = new ReplaySubject(1); + public readonly activeView = this._activeView.asObservable(); + constructor(section: ManifestSection) { if (!section) return; this._data.next(section); @@ -48,4 +52,8 @@ export class UmbSectionContext { public setActiveTreeItem(treeItem: Entity) { this._activeTreeItem.next(treeItem); } + + public setActiveView(view: ManifestSectionView) { + this._activeView.next(view); + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards/section-dashboards.element.ts similarity index 90% rename from src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards/section-dashboards.element.ts index 1b50cbd9b5..6155c79d3a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards/section-dashboards.element.ts @@ -4,14 +4,14 @@ import { customElement, state } from 'lit/decorators.js'; import { IRoutingInfo } from 'router-slot'; import { first, map, Subscription } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../core/context'; -import { createExtensionElement, UmbExtensionRegistry } from '../../../core/extension'; -import { UmbSectionContext } from '../section.context'; +import { UmbContextConsumerMixin } from '../../../../core/context'; +import { createExtensionElement, UmbExtensionRegistry } from '../../../../core/extension'; +import { UmbSectionContext } from '../../section.context'; -import type { ManifestDashboard } from '../../../core/models'; +import type { ManifestDashboard } from '../../../../core/models'; @customElement('umb-section-dashboards') -export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { +export class UmbSectionDashboardsElement extends UmbContextConsumerMixin(LitElement) { static styles = [ UUITextStyles, css` @@ -155,10 +155,10 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { } } -export default UmbSectionDashboards; +export default UmbSectionDashboardsElement; declare global { interface HTMLElementTagNameMap { - 'umb-section-dashboards': UmbSectionDashboards; + 'umb-section-dashboards': UmbSectionDashboardsElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards/section-dashboards.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards/section-dashboards.stories.ts new file mode 100644 index 0000000000..d116cc7dfa --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards/section-dashboards.stories.ts @@ -0,0 +1,25 @@ +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; +import { internalManifests } from '../../../../temp-internal-manifests'; +import type { ManifestSection } from '../../../../core/models'; +import { UmbSectionContext } from '../../section.context'; +import type { UmbSectionDashboardsElement } from './section-dashboards.element'; +import './section-dashboards.element'; + +const contentSectionManifest = internalManifests.find((m) => m.alias === 'Umb.Section.Content') as ManifestSection; + +export default { + title: 'Sections/Shared/Section Dashboards', + component: 'umb-section-dashboards', + id: 'umb-section-dashboards', + decorators: [ + (story) => + html` + ${story()} + `, + ], +} as Meta; + +export const AAAOverview: Story = () => + html` `; +AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main/section-main.element.ts similarity index 82% rename from src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main/section-main.element.ts index 5a63d970d2..92fc067235 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main/section-main.element.ts @@ -3,7 +3,7 @@ import { css, html, LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; @customElement('umb-section-main') -export class UmbSectionMain extends LitElement { +export class UmbSectionMainElement extends LitElement { static styles = [ UUITextStyles, css` @@ -26,6 +26,6 @@ export class UmbSectionMain extends LitElement { declare global { interface HTMLElementTagNameMap { - 'umb-section-main': UmbSectionMain; + 'umb-section-main': UmbSectionMainElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main/section-main.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main/section-main.stories.ts new file mode 100644 index 0000000000..37b6555aa0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-main/section-main.stories.ts @@ -0,0 +1,15 @@ +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; + +import type { UmbSectionMainElement } from './section-main.element'; +import './section-main.element'; + +export default { + title: 'Sections/Shared/Section Main', + component: 'umb-section-main', + id: 'umb-section-main', +} as Meta; + +export const AAAOverview: Story = () => + html` Section Main Area `; +AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar/section-sidebar.element.ts similarity index 83% rename from src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar/section-sidebar.element.ts index 984a99eeda..4a308fbf45 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar/section-sidebar.element.ts @@ -2,12 +2,12 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../core/context'; -import { UmbSectionContext } from '../section.context'; -import '../../trees/shared/context-menu/tree-context-menu.service'; +import { UmbContextConsumerMixin } from '../../../../core/context'; +import { UmbSectionContext } from '../../section.context'; +import '../../../trees/shared/context-menu/tree-context-menu.service'; @customElement('umb-section-sidebar') -export class UmbSectionSidebar extends UmbContextConsumerMixin(LitElement) { +export class UmbSectionSidebarElement extends UmbContextConsumerMixin(LitElement) { static styles = [ UUITextStyles, css` @@ -76,6 +76,6 @@ export class UmbSectionSidebar extends UmbContextConsumerMixin(LitElement) { declare global { interface HTMLElementTagNameMap { - 'umb-section-sidebar': UmbSectionSidebar; + 'umb-section-sidebar': UmbSectionSidebarElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar/section-sidebar.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar/section-sidebar.stories.ts new file mode 100644 index 0000000000..4e6b79e49c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-sidebar/section-sidebar.stories.ts @@ -0,0 +1,15 @@ +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; + +import type { UmbSectionSidebarElement } from './section-sidebar.element'; +import './section-sidebar.element'; + +export default { + title: 'Sections/Shared/Section Sidebar', + component: 'umb-section-sidebar', + id: 'umb-section-sidebar', +} as Meta; + +export const AAAOverview: Story = () => + html` Section Sidebar Area `; +AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees/section-trees.element.ts similarity index 82% rename from src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees/section-trees.element.ts index ed9af511ad..dbe3f1c3b6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees/section-trees.element.ts @@ -3,14 +3,14 @@ import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { map, Subscription, switchMap, EMPTY, of } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../core/context'; -import { UmbExtensionRegistry } from '../../../core/extension'; -import { UmbSectionContext } from '../section.context'; +import { UmbContextConsumerMixin } from '../../../../core/context'; +import { UmbExtensionRegistry } from '../../../../core/extension'; +import { UmbSectionContext } from '../../section.context'; -import '../../trees/shared/tree-extension.element'; +import '../../../trees/shared/tree-extension.element'; @customElement('umb-section-trees') -export class UmbSectionTrees extends UmbContextConsumerMixin(LitElement) { +export class UmbSectionTreesElement extends UmbContextConsumerMixin(LitElement) { static styles = [UUITextStyles]; @state() @@ -75,10 +75,10 @@ export class UmbSectionTrees extends UmbContextConsumerMixin(LitElement) { } } -export default UmbSectionTrees; +export default UmbSectionTreesElement; declare global { interface HTMLElementTagNameMap { - 'umb-section-trees': UmbSectionTrees; + 'umb-section-trees': UmbSectionTreesElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees/section-trees.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees/section-trees.stories.ts new file mode 100644 index 0000000000..cd78294f1d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-trees/section-trees.stories.ts @@ -0,0 +1,14 @@ +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; + +import type { UmbSectionTreesElement } from './section-trees.element'; +import './section-trees.element'; + +export default { + title: 'Sections/Shared/Section Sidebar', + component: 'umb-section-sidebar', + id: 'umb-section-sidebar', +} as Meta; + +export const AAAOverview: Story = () => html` `; +AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts new file mode 100644 index 0000000000..f2aaac25f0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts @@ -0,0 +1,123 @@ +import { html, LitElement, nothing } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import { EMPTY, map, of, Subscription, switchMap } from 'rxjs'; +import { UmbContextConsumerMixin } from '../../../../core/context'; +import { UmbExtensionRegistry } from '../../../../core/extension'; +import type { ManifestSectionView } from '../../../../core/models'; +import { UmbSectionContext } from '../../section.context'; + +@customElement('umb-section-views') +export class UmbSectionViewsElement extends UmbContextConsumerMixin(LitElement) { + @state() + private _views: Array = []; + + @state() + private _routerFolder = ''; + + @state() + private _activeView?: ManifestSectionView; + + private _extensionRegistry?: UmbExtensionRegistry; + private _sectionContext?: UmbSectionContext; + private _viewsSubscription?: Subscription; + private _activeViewSubscription?: Subscription; + + constructor() { + super(); + + // TODO: wait for more contexts + this.consumeContext('umbExtensionRegistry', (extensionsRegistry: UmbExtensionRegistry) => { + this._extensionRegistry = extensionsRegistry; + this._observeViews(); + }); + + this.consumeContext('umbSectionContext', (sectionContext: UmbSectionContext) => { + this._sectionContext = sectionContext; + this._observeViews(); + this._observeActiveView(); + }); + } + + connectedCallback(): void { + super.connectedCallback(); + /* TODO: find a way to construct absolute urls */ + this._routerFolder = window.location.pathname.split('/view')[0]; + } + + private _observeViews() { + if (!this._sectionContext || !this._extensionRegistry) return; + + this._viewsSubscription?.unsubscribe(); + + this._viewsSubscription = this._sectionContext?.data + .pipe( + switchMap((section) => { + if (!section) return EMPTY; + + return ( + this._extensionRegistry + ?.extensionsOfType('sectionView') + .pipe( + map((views) => + views + .filter((view) => view.meta.sections.includes(section.alias)) + .sort((a, b) => b.meta.weight - a.meta.weight) + ) + ) ?? of([]) + ); + }) + ) + .subscribe((views) => { + this._views = views; + }); + } + + private _observeActiveView() { + this._activeViewSubscription?.unsubscribe(); + + this._activeViewSubscription = this._sectionContext?.activeView.subscribe((view) => { + this._activeView = view; + }); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + this._viewsSubscription?.unsubscribe(); + this._activeViewSubscription?.unsubscribe(); + } + + render() { + return html` ${this._views.length > 0 ? html` ` : nothing} `; + } + + private _renderViews() { + console.log(this._routerFolder); + return html` + ${this._views?.length > 0 + ? html` + + ${this._views.map( + (view: ManifestSectionView) => html` + + + ${view.meta.label || view.name} + + ` + )} + + ` + : nothing} + `; + } +} + +export default UmbSectionViewsElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-section-views': UmbSectionViewsElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.stories.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 6918851c3a..c9063c7900 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -7,11 +7,12 @@ import { UmbContextConsumerMixin } from '../../../core/context'; import { createExtensionElement, UmbExtensionRegistry } from '../../../core/extension'; import { UmbSectionContext } from '../section.context'; import type { ManifestTree, ManifestEditor, ManifestSectionView } from '../../../core/models'; - -import '../shared/section-trees.element.ts'; import { UmbEditorEntityElement } from '../../editors/shared/editor-entity/editor-entity.element'; import { UmbEntityStore } from '../../../core/stores/entity.store'; +import './section-trees/section-trees.element.ts'; +import '../shared/section-views/section-views.element.ts'; + @customElement('umb-section') export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { static styles = [ @@ -51,12 +52,6 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { @state() private _views: Array = []; - @state() - private _currentViewPath = ''; - - @state() - private _routerFolder = ''; - private _editors?: Array; private _editorsSubscription?: Subscription; @@ -90,12 +85,6 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { }); } - connectedCallback(): void { - super.connectedCallback(); - /* TODO: find a way to construct absolute urls */ - this._routerFolder = window.location.pathname.split('/view')[0]; - } - private _observeTrees() { if (!this._sectionContext || !this._extensionRegistry || !this._entityStore) return; @@ -142,7 +131,7 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { this._routes = [ { path: 'dashboard', - component: () => import('../shared/section-dashboards.element'), + component: () => import('./section-dashboards/section-dashboards.element'), }, ...treeRoutes, { @@ -188,8 +177,8 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { return { path: 'view/' + view.meta.pathname, component: () => createExtensionElement(view), - setup: (component: UmbEditorEntityElement, info: IRoutingInfo) => { - this._currentViewPath = info.match.route.path; + setup: () => { + this._sectionContext?.setActiveView(view); }, }; }) ?? []; @@ -218,34 +207,12 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { ` : nothing} - ${this._views.length > 0 ? html` ` : nothing} + ${this._views.length > 0 ? html`` : nothing} `; } - - private _renderViews() { - return html` - ${this._views?.length > 0 - ? html` - - ${this._views.map( - (view: ManifestSectionView) => html` - - - ${view.meta.label || view.name} - - ` - )} - - ` - : nothing} - `; - } } declare global { From e4558164e866b91f0823ce44fd92f61837744837 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 15:53:53 +0200 Subject: [PATCH 66/98] remove unused --- .../src/backoffice/sections/shared/section.element.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index c9063c7900..47944f46f2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -52,9 +52,6 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { @state() private _views: Array = []; - private _editors?: Array; - private _editorsSubscription?: Subscription; - private _entityStore?: UmbEntityStore; private _sectionContext?: UmbSectionContext; @@ -192,7 +189,6 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { disconnectedCallback(): void { super.disconnectedCallback(); this._treesSubscription?.unsubscribe(); - this._editorsSubscription?.unsubscribe(); this._viewsSubscription?.unsubscribe(); } From 3bab515d3019d040a468e70799b92f2b297742b7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 15:54:27 +0200 Subject: [PATCH 67/98] remove more unused --- .../src/backoffice/sections/shared/section.element.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 47944f46f2..2a9f3d3c7e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -2,11 +2,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { Subscription, map, switchMap, EMPTY, of } from 'rxjs'; -import { IRoutingInfo } from 'router-slot'; import { UmbContextConsumerMixin } from '../../../core/context'; import { createExtensionElement, UmbExtensionRegistry } from '../../../core/extension'; import { UmbSectionContext } from '../section.context'; -import type { ManifestTree, ManifestEditor, ManifestSectionView } from '../../../core/models'; +import type { ManifestTree, ManifestSectionView } from '../../../core/models'; import { UmbEditorEntityElement } from '../../editors/shared/editor-entity/editor-entity.element'; import { UmbEntityStore } from '../../../core/stores/entity.store'; From b809b34c09d07c328dd7b8e82c4bc1159b0258dd Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 16:00:02 +0200 Subject: [PATCH 68/98] remove section layout element --- .../src/backoffice/backoffice.element.ts | 1 - .../packages/packages-editor.element.ts | 12 ++++----- .../sections/shared/section-layout.element.ts | 27 ------------------- .../sections/shared/section.element.ts | 24 ++++++++--------- 4 files changed, 16 insertions(+), 48 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-layout.element.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 2841eeddd2..059399fece 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -6,7 +6,6 @@ import './components/backoffice-modal-container.element'; import './components/backoffice-notification-container.element'; import './components/node-property/node-property.element'; import './components/table/table.element'; -import './sections/shared/section-layout.element'; import './sections/shared/section-main/section-main.element'; import './sections/shared/section-sidebar/section-sidebar.element'; import './sections/shared/section.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/packages/packages-editor.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/packages/packages-editor.element.ts index 046bf338dd..eaf66cbaa9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/packages/packages-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/packages/packages-editor.element.ts @@ -8,13 +8,11 @@ export class UmbPackagesEditor extends LitElement { render() { return html` - - - -

Packages

-
-
-
+ + +

Packages

+
+
`; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-layout.element.ts deleted file mode 100644 index 116fb2bf94..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-layout.element.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; - -@customElement('umb-section-layout') -export class UmbSectionLayout extends LitElement { - static styles = [ - UUITextStyles, - css` - :host { - display: flex; - width: 100%; - height: 100%; - } - `, - ]; - - render() { - return html``; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'umb-section-layout': UmbSectionLayout; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 2a9f3d3c7e..5c1b85e107 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -193,19 +193,17 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { render() { return html` - - ${this._trees.length > 0 - ? html` - - - - ` - : nothing} - - ${this._views.length > 0 ? html`` : nothing} - - - + ${this._trees.length > 0 + ? html` + + + + ` + : nothing} + + ${this._views.length > 0 ? html`` : nothing} + + `; } } From 5498708191db747331a6d3c6387358d9ff603f5f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 7 Oct 2022 16:00:13 +0200 Subject: [PATCH 69/98] remove console.log --- .../sections/shared/section-views/section-views.element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts index f2aaac25f0..6ce42d560b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts @@ -91,7 +91,6 @@ export class UmbSectionViewsElement extends UmbContextConsumerMixin(LitElement) } private _renderViews() { - console.log(this._routerFolder); return html` ${this._views?.length > 0 ? html` From 0b295c29001b143272f571d886799bb692192f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Fri, 7 Oct 2022 17:17:26 +0200 Subject: [PATCH 70/98] added user-extensions with getTagLookAndColor --- .../editors/user/editor-user.element.ts | 9 +++++++-- .../sections/users/user-extensions.ts | 17 ++++++++++++++++ .../editor-view-users-overview.element.ts | 6 +----- .../grid/editor-view-users-grid.element.ts | 5 +++-- ...user-table-status-column-layout.element.ts | 20 +++---------------- 5 files changed, 31 insertions(+), 26 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index 110c1efa7c..dc75855f1e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -3,6 +3,7 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; +import { ifDefined } from 'lit-html/directives/if-defined.js'; import { UmbContextProviderMixin, UmbContextConsumerMixin } from '../../../core/context'; import UmbSectionViewUsersElement from '../../sections/users/views/users/section-view-users.element'; import '../../property-editors/content-picker/property-editor-content-picker.element'; @@ -11,6 +12,7 @@ import type { UserDetails } from '../../../core/models'; import { UmbUserContext } from './user.context'; import '../shared/editor-entity-layout/editor-entity-layout.element'; +import { getTagLookAndColor } from '../../sections/users/user-extensions'; @customElement('umb-editor-user') export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) { static styles = [ @@ -210,7 +212,8 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons private renderRightColumn() { if (!this._user || !this._userStore) return nothing; - // const status = this._userStore.getTagLookAndColor(this._user.status); + const statusLook = getTagLookAndColor(this._user.status); + return html`
@@ -228,7 +231,9 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons
Status: - ${this._user.status} + + ${this._user.status} +
${this._user?.status === 'Invited' ? html` diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts new file mode 100644 index 0000000000..db46adf7a8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts @@ -0,0 +1,17 @@ +import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; + +export type UserStatus = 'Active' | 'Inactive' | 'Invited' | 'Disabled'; + +export const getTagLookAndColor = (status: UserStatus): { look: InterfaceLook; color: InterfaceColor } => { + switch ((status || '').toLowerCase()) { + case 'invited': + case 'inactive': + return { look: 'primary', color: 'warning' }; + case 'active': + return { look: 'primary', color: 'positive' }; + case 'disabled': + return { look: 'primary', color: 'danger' }; + default: + return { look: 'secondary', color: 'default' }; + } +}; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts index 8f0b6f58ba..1a3155e622 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts @@ -203,11 +203,7 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L
- +
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index 7611043c05..0719bef779 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -1,6 +1,6 @@ import { css, html, LitElement, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; +import { customElement, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { Subscription } from 'rxjs'; import { ifDefined } from 'lit-html/directives/if-defined.js'; @@ -8,6 +8,7 @@ import { UmbContextConsumerMixin } from '../../../../../../../core/context'; import UmbSectionViewUsersElement from '../../section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; import type { UserEntity } from '../../../../../../../core/models'; +import { getTagLookAndColor } from '../../../../user-extensions'; @customElement('umb-editor-view-users-grid') export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitElement) { @@ -105,7 +106,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl private renderUserCard(user: UserEntity) { if (!this._userStore) return; - const statusLook = null; //this._usersContext?.getTagLookAndColor(user.status ? user.status : ''); + const statusLook = getTagLookAndColor(user.status); return html` + look="${getTagLookAndColor(this.value.status).look}" + color="${getTagLookAndColor(this.value.status).color}"> ${this.value.status}
` : nothing}`; From 0671b2254e02dc73e2c3fc4babcf6cccd41979d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 09:49:28 +0200 Subject: [PATCH 71/98] added flex to umb-section --- .../src/backoffice/sections/shared/section.element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts index 5c1b85e107..1ee44a95be 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section.element.ts @@ -20,6 +20,7 @@ export class UmbSectionElement extends UmbContextConsumerMixin(LitElement) { :host { flex: 1 1 auto; height: 100%; + display: flex; } #header { From 1f6aa0c80731dd51d473f745c615251e1198212c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 10 Oct 2022 09:52:34 +0200 Subject: [PATCH 72/98] update paths --- .../src/temp-internal-manifests/index.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts index acd0a24526..7442bd6b75 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts @@ -67,7 +67,7 @@ export const internalManifests: Array Promise import('./backoffice/sections/users/users-section.element'), + loader: () => import('../backoffice/sections/users/users-section.element'), meta: { pathname: 'users', weight: 20, @@ -287,7 +287,7 @@ export const internalManifests: Array Promise import('./backoffice/editors/user/editor-user.element'), + loader: () => import('../backoffice/editors/user/editor-user.element'), meta: { entityType: 'user', }, @@ -296,7 +296,7 @@ export const internalManifests: Array Promise import('./backoffice/editors/user/actions/editor-action-user-save.element'), + loader: () => import('../backoffice/editors/user/actions/editor-action-user-save.element'), meta: { editors: ['Umb.Editor.User'], }, @@ -530,7 +530,7 @@ export const internalManifests: Array Promise import('./backoffice/sections/users/views/users/section-view-users.element'), + loader: () => import('../backoffice/sections/users/views/users/section-view-users.element'), meta: { sections: ['Umb.Section.Users'], label: 'Users', @@ -543,7 +543,7 @@ export const internalManifests: Array Promise import('./backoffice/sections/users/views/user-groups/section-view-user-groups.element'), + loader: () => import('../backoffice/sections/users/views/user-groups/section-view-user-groups.element'), meta: { sections: ['Umb.Section.Users'], label: 'User Groups', From 80bae27c8d271c9fd61e766fa26d53091e7b9395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 10:26:23 +0200 Subject: [PATCH 73/98] remove unused code --- .../editor-view-users-overview.element.ts | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts index 1a3155e622..f344d70bdf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts @@ -82,12 +82,6 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L private _usersContext?: UmbSectionViewUsersElement; private _selectionSubscription?: Subscription; - constructor() { - super(); - - this.setupHeaderIntersectionObserver(); - } - connectedCallback(): void { super.connectedCallback(); @@ -107,21 +101,6 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L this._selectionSubscription?.unsubscribe(); } - public setupHeaderIntersectionObserver() { - requestAnimationFrame(() => { - const el = this.shadowRoot?.querySelector('#sticky-top'); - - if (el) { - const options = { threshold: [1] }; - const callback = (entries: IntersectionObserverEntry[]) => - entries[0].target.classList.toggle('header-shadow', entries[0].intersectionRatio < 1); - const observer = new IntersectionObserver(callback, options); - - observer.observe(el); - } - }); - } - private _toggleViewType() { const isList = window.location.pathname.split('/').pop() === 'list'; From 0bfede0bb3273e2b58a1c83d9442546c5ac023d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 10:26:35 +0200 Subject: [PATCH 74/98] fix content picker import and tag --- .../src/backoffice/editors/user/editor-user.element.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index dc75855f1e..49885008df 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -6,10 +6,10 @@ import { Subscription } from 'rxjs'; import { ifDefined } from 'lit-html/directives/if-defined.js'; import { UmbContextProviderMixin, UmbContextConsumerMixin } from '../../../core/context'; import UmbSectionViewUsersElement from '../../sections/users/views/users/section-view-users.element'; -import '../../property-editors/content-picker/property-editor-content-picker.element'; import { UmbUserStore } from '../../../core/stores/user/user.store'; import type { UserDetails } from '../../../core/models'; import { UmbUserContext } from './user.context'; +import '../../property-editor-uis/content-picker/property-editor-ui-content-picker.element'; import '../shared/editor-entity-layout/editor-entity-layout.element'; import { getTagLookAndColor } from '../../sections/users/user-extensions'; @@ -180,12 +180,12 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons
Content start nodes
Limit the content tree to specific start nodes
- +
Media start nodes
Limit the media library to specific start nodes
- +
From 1a74e48af6dd66ca075ce1ae8332fe1bc6ce419e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 10 Oct 2022 10:26:54 +0200 Subject: [PATCH 75/98] rename user section file --- .../{users-section.element.ts => section-users.element.ts} | 0 src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/Umbraco.Web.UI.Client/src/backoffice/sections/users/{users-section.element.ts => section-users.element.ts} (100%) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/section-users.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/backoffice/sections/users/users-section.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/sections/users/section-users.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts index 7442bd6b75..ed15c93ad2 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts @@ -67,7 +67,7 @@ export const internalManifests: Array Promise import('../backoffice/sections/users/users-section.element'), + loader: () => import('../backoffice/sections/users/section-users.element'), meta: { pathname: 'users', weight: 20, From 93ab6ab385d2e84da862497a7bf195e3540501b6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 10 Oct 2022 10:33:59 +0200 Subject: [PATCH 76/98] clean up --- .../users/views/users/section-view-users.element.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index bfd0cf7f08..2a7989265a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -1,20 +1,16 @@ import { css, html, LitElement } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, state } from 'lit/decorators.js'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; -import { IRoute, IRoutingInfo } from 'router-slot'; -import { v4 as uuidv4 } from 'uuid'; +import { BehaviorSubject, Observable } from 'rxjs'; +import type { IRoute, IRoutingInfo } from 'router-slot'; import { UmbContextProviderMixin } from '../../../../../core/context'; +import type { UmbEditorEntityElement } from '../../../../editors/shared/editor-entity/editor-entity.element'; + import './list-view-layouts/table/editor-view-users-table.element'; import './list-view-layouts/grid/editor-view-users-grid.element'; import './editor-view-users-selection.element'; import './editor-view-users-invite.element'; -import type { UserDetails, UserEntity } from '../../../../../core/models'; -import type { UmbEditorUserElement } from '../../../../editors/user/editor-user.element'; -import UmbEditorEntityElement from '../../../../editors/shared/editor-entity/editor-entity.element'; - @customElement('umb-section-view-users') export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitElement) { static styles = [ From f1c98e16a550144dc118a9c7337eadcc894a7415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 13:18:58 +0200 Subject: [PATCH 77/98] WIP Move invite page to dialog --- .../users/editor-view-users-invite.element.ts | 90 +++++++++++++------ .../editor-view-users-overview.element.ts | 48 ++++++---- .../src/core/stores/user/user.store.ts | 20 +++++ .../src/mocks/domains/users.handlers.ts | 29 ++++++ 4 files changed, 139 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts index e51758ed27..33879d9953 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts @@ -1,12 +1,15 @@ -import { css, html, LitElement, nothing } from 'lit'; +import { css, html, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, state } from 'lit/decorators.js'; +import { customElement, query, state } from 'lit/decorators.js'; import { UmbContextConsumerMixin } from '../../../../../core/context'; -import UmbSectionViewUsersElement from './section-view-users.element'; +import { UmbModalLayoutElement } from '../../../../../core/services/modal/layouts/modal-layout.element'; +import { UmbUserStore } from '../../../../../core/stores/user/user.store'; +import type { UserDetails } from '../../../../../core/models'; +import { UmbNotificationService } from '../../../../../core/services/notification'; export type UsersViewType = 'list' | 'grid'; @customElement('umb-editor-view-users-invite') -export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(LitElement) { +export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(UmbModalLayoutElement) { static styles = [ UUITextStyles, css` @@ -27,9 +30,6 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Lit uui-input { width: 100%; } - #post-invite-buttons { - display: flex; - } form { display: flex; flex-direction: column; @@ -45,23 +45,25 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Lit `, ]; + @query('#invite-form') + private _form!: HTMLFormElement; + @state() - private _showPostInvite = false; + private _invitedUser?: UserDetails; - private _usersContext?: UmbSectionViewUsersElement; - - private _invitedUser?: UserItem; + protected _userStore?: UmbUserStore; + private _notificationService?: UmbNotificationService; connectedCallback(): void { super.connectedCallback(); - this.consumeContext('umbUsersContext', (usersContext: UmbSectionViewUsersElement) => { - this._usersContext = usersContext; + this.consumeContext('umbUserStore', (usersContext: UmbUserStore) => { + this._userStore = usersContext; }); - } - disconnectedCallback(): void { - super.disconnectedCallback(); + this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { + this._notificationService = service; + }); } private _handleSubmit(e: Event) { @@ -80,12 +82,20 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Lit const userGroup = formData.get('userGroup') as string; const message = formData.get('message') as string; - this._invitedUser = this._usersContext?.inviteUser(name, email, userGroup, message); - this._showPostInvite = true; + this._userStore?.invite(name, email, message, [userGroup]).then((user) => { + this._invitedUser = user; + }); + } + + private _submitForm() { + this._form?.requestSubmit(); + } + + private _closeModal() { + this.modalHandler?.close(); } private _resetForm() { - this._showPostInvite = false; this._invitedUser = undefined; } @@ -118,7 +128,6 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Lit Message - `; } @@ -129,19 +138,42 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Lit return html`

${this._invitedUser.name} has been invited

An invitation has been sent to the new user with details about how to log in to Umbraco.

-
- - -
`; } render() { - return html`${this._showPostInvite ? this._renderPostInvite() : this._renderForm()}`; + return html` + ${this._invitedUser ? this._renderPostInvite() : this._renderForm()} + ${this._invitedUser + ? html` + + + + ` + : html` + + + `} + `; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts index f344d70bdf..78d78a92c7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-overview.element.ts @@ -10,6 +10,7 @@ import { IRoute } from 'router-slot'; import { UUIPopoverElement } from '@umbraco-ui/uui'; import { UmbContextConsumerMixin } from '../../../../../core/context'; import UmbSectionViewUsersElement from './section-view-users.element'; +import { UmbModalService } from '../../../../../core/services/modal'; export type UsersViewType = 'list' | 'grid'; @customElement('umb-editor-view-users-overview') @@ -79,8 +80,25 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L @state() private _selection: Array = []; + @state() + private _routes: IRoute[] = [ + { + path: 'grid', + component: () => import('./list-view-layouts/grid/editor-view-users-grid.element'), + }, + { + path: 'list', + component: () => import('./list-view-layouts/table/editor-view-users-table.element'), + }, + { + path: '**', + redirectTo: '/section/users/view/users/overview/grid', //TODO: this should be dynamic + }, + ]; + private _usersContext?: UmbSectionViewUsersElement; private _selectionSubscription?: Subscription; + private _modalService?: UmbModalService; connectedCallback(): void { super.connectedCallback(); @@ -93,6 +111,10 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L this._selection = selection; }); }); + + this.consumeContext('umbModalService', (modalService: UmbModalService) => { + this._modalService = modalService; + }); } disconnectedCallback(): void { @@ -115,22 +137,6 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L return html``; } - @state() - private _routes: IRoute[] = [ - { - path: 'grid', - component: () => import('./list-view-layouts/grid/editor-view-users-grid.element'), - }, - { - path: 'list', - component: () => import('./list-view-layouts/table/editor-view-users-table.element'), - }, - { - path: '**', - redirectTo: '/section/users/view/users/overview/grid', //TODO: this should be dynamic - }, - ]; - private _handleTogglePopover(event: PointerEvent) { const composedPath = event.composedPath(); @@ -140,13 +146,17 @@ export class UmbEditorViewUsersOverviewElement extends UmbContextConsumerMixin(L } } + private _showInvite() { + const invite = document.createElement('umb-editor-view-users-invite'); + + this._modalService?.open(invite, { type: 'dialog' }); + } + render() { return html`
- - - +
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 index e0477ea273..3939d9c0f0 100644 --- 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 @@ -2,6 +2,7 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; import type { UserDetails, UserEntity } from '../../models'; import { UmbEntityStore } from '../entity.store'; import { UmbDataStoreBase } from '../store'; +import { v4 as uuidv4 } from 'uuid'; /** * @export @@ -137,6 +138,25 @@ export class UmbUserStore extends UmbDataStoreBase { } } + async invite(name: string, email: string, message: string, userGroups: Array): Promise { + // TODO: use Fetcher API. + try { + const res = await fetch('/umbraco/backoffice/users/invite', { + method: 'POST', + body: JSON.stringify({ name, email, message, userGroups }), + headers: { + 'Content-Type': 'application/json', + }, + }); + const json = (await res.json()) as UserDetails[]; + this.update(json); + this._entityStore.update(json); + return json[0]; + } catch (error) { + console.error('Invite user error', error); + } + } + // public updateUser(user: UserItem) { // const users = this._users.getValue(); // const index = users.findIndex((u) => u.key === user.key); 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 index 6344b9b8d5..c348e312b0 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/users.handlers.ts @@ -1,4 +1,5 @@ import { rest } from 'msw'; +import { v4 as uuidv4 } from 'uuid'; import type { UserDetails } from '../../core/models'; import { umbUsersData } from '../data/users.data'; @@ -35,6 +36,34 @@ export const handlers = [ return res(ctx.status(200), ctx.json(saved)); }), + rest.post('/umbraco/backoffice/users/invite', async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + const newUser: UserDetails = { + key: uuidv4(), + name: data.name, + email: data.email, + status: 'invited', + language: 'en', + updateDate: new Date().toISOString(), + createDate: new Date().toISOString(), + failedLoginAttempts: 0, + parentKey: '', + isTrashed: false, + hasChildren: false, + type: 'user', + icon: 'umb:icon-user', + userGroup: data.userGroups[0], + }; + + const invited = umbUsersData.save([newUser]); + + console.log('invited', invited); + + return res(ctx.status(200), ctx.json(invited)); + }), + rest.post>('/umbraco/backoffice/users/enable', async (req, res, ctx) => { const data = await req.json(); if (!data) return; From 52bbe0f71305a491d07c9e696f702ba0282332c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 13:21:07 +0200 Subject: [PATCH 78/98] remove invite path --- .../sections/users/views/users/section-view-users.element.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts index 2a7989265a..9208c9dd62 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/section-view-users.element.ts @@ -28,10 +28,6 @@ export class UmbSectionViewUsersElement extends UmbContextProviderMixin(LitEleme path: 'overview', component: () => import('./editor-view-users-overview.element'), }, - { - path: 'invite', - component: () => import('./editor-view-users-invite.element'), - }, { path: `:entityType/:key`, component: () => import('../../../../editors/shared/editor-entity/editor-entity.element'), From 71d1a6ac25f55e9a8eb179df1202d9ac552f70e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 13:26:23 +0200 Subject: [PATCH 79/98] Link to invited user --- .../views/users/editor-view-users-invite.element.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts index 33879d9953..815ac8c1ec 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts @@ -52,7 +52,6 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Umb private _invitedUser?: UserDetails; protected _userStore?: UmbUserStore; - private _notificationService?: UmbNotificationService; connectedCallback(): void { super.connectedCallback(); @@ -60,10 +59,6 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Umb this.consumeContext('umbUserStore', (usersContext: UmbUserStore) => { this._userStore = usersContext; }); - - this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { - this._notificationService = service; - }); } private _handleSubmit(e: Event) { @@ -100,7 +95,10 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Umb } private _goToProfile() { - //TODO: navigate to user profile + if (!this._invitedUser) return; + + this._closeModal(); + history.pushState(null, '', '/section/users/view/users/user/' + this._invitedUser?.key); //TODO: URL Should be dynamic } private _renderForm() { From b4ef606b94c7bce587446d263fef84ab0cd09fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 15:05:45 +0200 Subject: [PATCH 80/98] added labels to inputs --- .../src/backoffice/editors/user/editor-user.element.ts | 4 ++-- .../users/views/users/editor-view-users-invite.element.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index 49885008df..ea1feb0bc6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -163,11 +163,11 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons
Profile
Email - + Language - + diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts index 815ac8c1ec..9a77eb5c33 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts @@ -111,11 +111,11 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Umb
Name - + Email - + User group @@ -124,7 +124,7 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Umb Message - +
`; From 37a437933b9f82a386e3f3665c9e596a58bbe476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Mon, 10 Oct 2022 15:17:12 +0200 Subject: [PATCH 81/98] user section views: header background color, border and dividers --- .../section-views/section-views.element.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts index 6ce42d560b..675b95245d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.element.ts @@ -1,4 +1,5 @@ -import { html, LitElement, nothing } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css'; +import { css, html, LitElement, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { EMPTY, map, of, Subscription, switchMap } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../core/context'; @@ -8,6 +9,25 @@ import { UmbSectionContext } from '../../section.context'; @customElement('umb-section-views') export class UmbSectionViewsElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + #header { + background-color: var(--uui-color-surface); + border-bottom: 1px solid var(--uui-color-divider-standalone); + } + + uui-tab-group { + justify-content: flex-end; + --uui-tab-divider: var(--uui-color-divider-standalone); + } + + uui-tab-group uui-tab:first-child { + border-left: 1px solid var(--uui-color-divider-standalone); + } + `, + ]; + @state() private _views: Array = []; From f6dbf24fe62f9a5d54c7e9f8b5cfa4152729348d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 11:06:48 +0200 Subject: [PATCH 82/98] add user-group store --- src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts | 2 ++ 1 file changed, 2 insertions(+) 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 059399fece..dfc0c24313 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -29,6 +29,7 @@ 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'; +import { UmbUserGroupStore } from '../core/stores/user/user-group.store'; @defineElement('umb-backoffice') export class UmbBackofficeElement extends UmbContextConsumerMixin(UmbContextProviderMixin(LitElement)) { @@ -62,6 +63,7 @@ export class UmbBackofficeElement extends UmbContextConsumerMixin(UmbContextProv this.provideContext('umbDataTypeStore', new UmbDataTypeStore(this._umbEntityStore)); this.provideContext('umbDocumentTypeStore', new UmbDocumentTypeStore(this._umbEntityStore)); this.provideContext('umbUserStore', new UmbUserStore(this._umbEntityStore)); + this.provideContext('umbUserGroupStore', new UmbUserGroupStore(this._umbEntityStore)); this.provideContext('umbPropertyEditorStore', new UmbPropertyEditorStore()); this.provideContext('umbPropertyEditorConfigStore', new UmbPropertyEditorConfigStore()); this.provideContext('umbNotificationService', new UmbNotificationService()); From 934465d38cda875c6d66aa182e35171237e0d8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 11:07:14 +0200 Subject: [PATCH 83/98] add user-group store --- .../src/core/stores/user/user-group.store.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts new file mode 100644 index 0000000000..a35c541473 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/stores/user/user-group.store.ts @@ -0,0 +1,32 @@ +import { BehaviorSubject, map, Observable } from 'rxjs'; +import type { UserDetails, UserEntity, UserGroupDetails } from '../../models'; +import { UmbEntityStore } from '../entity.store'; +import { UmbDataStoreBase } from '../store'; +import { v4 as uuidv4 } from 'uuid'; + +/** + * @export + * @class UmbUserGroupStore + * @extends {UmbDataStoreBase} + * @description - Data Store for Users + */ +export class UmbUserGroupStore 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/user-groups/list/items`) + .then((res) => res.json()) + .then((data) => { + this.update(data.items); + }); + + return this.items; + } +} From 8d86aa5c67ade5f540d13b0ec7de4b5cafdfc7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 11:07:41 +0200 Subject: [PATCH 84/98] add user group mocks --- .../src/mocks/browser-handlers.ts | 2 + .../src/mocks/domains/user-groups.handlers.ts | 63 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/domains/user-groups.handlers.ts 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 f89305a8cf..04345b3989 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts @@ -11,6 +11,7 @@ import { handlers as userHandlers } from './domains/user.handlers'; import { handlers as telemetryHandlers } from './domains/telemetry.handlers'; import { handlers as propertyEditorHandlers } from './domains/property-editor.handlers'; import { handlers as usersHandlers } from './domains/users.handlers'; +import { handlers as userGroupsHandlers } from './domains/user-groups.handlers'; const handlers = [ serverHandlers.serverVersionHandler, @@ -26,6 +27,7 @@ const handlers = [ ...telemetryHandlers, ...publishedStatusHandlers, ...usersHandlers, + ...userGroupsHandlers, ]; switch (import.meta.env.VITE_UMBRACO_INSTALL_STATUS) { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/user-groups.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/user-groups.handlers.ts new file mode 100644 index 0000000000..6d596a8a1e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/user-groups.handlers.ts @@ -0,0 +1,63 @@ +import { rest } from 'msw'; +import type { UserGroupDetails } from '../../core/models'; + +export const handlers = [ + rest.get('/umbraco/backoffice/user-groups/list/items', (req, res, ctx) => { + const items = fakeData; + + const response = { + total: items.length, + items, + }; + + return res(ctx.status(200), ctx.json(response)); + }), +]; + +const fakeData: Array = [ + { + key: '10000000-0000-0000-0000-000000000000', + name: 'Administrators', + icon: 'umb:medal', + parentKey: '', + type: 'userGroup', + hasChildren: false, + isTrashed: false, + }, + { + key: '20000000-0000-0000-0000-000000000000', + name: 'Editors', + icon: 'umb:tools', + parentKey: '', + type: 'userGroup', + hasChildren: false, + isTrashed: false, + }, + { + key: '20000000-0000-0000-0000-000000000000', + name: 'Sensitive Data', + icon: 'umb:lock', + parentKey: '', + type: 'userGroup', + hasChildren: false, + isTrashed: false, + }, + { + key: '20000000-0000-0000-0000-000000000000', + name: 'Translators', + icon: 'umb:globe', + parentKey: '', + type: 'userGroup', + hasChildren: false, + isTrashed: false, + }, + { + key: '20000000-0000-0000-0000-000000000000', + name: 'Writers', + icon: 'umb:edit', + parentKey: '', + type: 'userGroup', + hasChildren: false, + isTrashed: false, + }, +]; From 089f97eb1fbb0c4e5ae1b63c913d97acacce90a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 11:08:04 +0200 Subject: [PATCH 85/98] add user-group entity --- src/Umbraco.Web.UI.Client/src/core/models/index.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index 6d2dec396f..f455dc9f62 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -77,3 +77,16 @@ export interface UserDetails extends UserEntity { failedLoginAttempts: number; userGroup?: string; //TODO Implement this } + +export interface UserGroupEntity extends Entity { + type: 'userGroup'; +} + +export interface UserGroupDetails extends UserGroupEntity { + key: string; + name: string; + icon: string; + sections?: Array; + contentStartNode?: string; + mediaStartNode?: string; +} From f4f994f322ab5502dce5ca4e2ef11d949d3abbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 11:08:11 +0200 Subject: [PATCH 86/98] add user-group table --- .../editor-view-user-groups.element.ts | 158 ++++++++++++++++++ .../section-view-user-groups.element.ts | 4 +- 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts new file mode 100644 index 0000000000..710a3c8917 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts @@ -0,0 +1,158 @@ +import { UUITextStyles } from '@umbraco-ui/uui-css'; +import { css, html, LitElement } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import { Subscription } from 'rxjs'; +import { UmbContextConsumerMixin } from '../../../../../core/context'; +import type { UserGroupDetails } from '../../../../../core/models'; +import { UmbUserGroupStore } from '../../../../../core/stores/user/user-group.store'; +import UmbTableElement, { + UmbTableColumn, + UmbTableConfig, + UmbTableDeselectedEvent, + UmbTableItem, + UmbTableOrderedEvent, + UmbTableSelectedEvent, +} from '../../../../components/table/table.element'; + +@customElement('umb-editor-view-user-groups') +export class UmbEditorViewUserGroupsElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + :host { + height: 100%; + display: flex; + flex-direction: column; + } + `, + ]; + + @state() + private _userGroups: Array = []; + + @state() + private _tableConfig: UmbTableConfig = { + allowSelection: true, + }; + + @state() + private _tableColumns: Array = [ + { + name: 'Name', + alias: 'userGroupName', + }, + { + name: 'Sections', + alias: 'userGroupSections', + }, + { + name: 'Content start node', + alias: 'userGroupContentStartNode', + }, + { + name: 'Media start node', + alias: 'userGroupMediaStartNode', + }, + ]; + + @state() + private _tableItems: Array = []; + + @state() + private _selection: Array = []; + + private _userGroupStore?: UmbUserGroupStore; + private _userGroupsSubscription?: Subscription; + private _selectionSubscription?: Subscription; + + connectedCallback(): void { + super.connectedCallback(); + + this.consumeContext('umbUserGroupStore', (userStore: UmbUserGroupStore) => { + this._userGroupStore = userStore; + this._observeUsers(); + }); + } + + private _observeUsers() { + this._userGroupsSubscription?.unsubscribe(); + this._userGroupsSubscription = this._userGroupStore?.getAll().subscribe((userGroups) => { + this._userGroups = userGroups; + console.log('user groups', userGroups); + + this._createTableItems(this._userGroups); + }); + } + + private _createTableItems(userGroups: Array) { + this._tableItems = userGroups.map((userGroup) => { + return { + key: userGroup.key, + icon: userGroup.icon, + data: [ + { + columnAlias: 'userGroupName', + value: userGroup.name, + }, + { + columnAlias: 'userGroupSections', + value: userGroup.sections, + }, + { + columnAlias: 'userGroupContentStartNode', + value: userGroup.contentStartNode, + }, + { + columnAlias: 'userGroupMediaStartNode', + value: userGroup.mediaStartNode, + }, + ], + }; + }); + } + + private _handleSelected(event: UmbTableSelectedEvent) { + event.stopPropagation(); + console.log('HANDLE SELECT'); + } + + private _handleDeselected(event: UmbTableDeselectedEvent) { + event.stopPropagation(); + console.log('HANDLE DESELECT'); + } + + private _handleOrdering(event: UmbTableOrderedEvent) { + const table = event.target as UmbTableElement; + const orderingColumn = table.orderingColumn; + const orderingDesc = table.orderingDesc; + console.log(`fetch users, order column: ${orderingColumn}, desc: ${orderingDesc}`); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + + this._userGroupsSubscription?.unsubscribe(); + this._selectionSubscription?.unsubscribe(); + } + + render() { + return html` + + `; + } +} + +export default UmbEditorViewUserGroupsElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-editor-view-user-groups': UmbEditorViewUserGroupsElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts index af30f3053c..84c808a6bd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/section-view-user-groups.element.ts @@ -1,10 +1,12 @@ import { html, LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; +import './editor-view-user-groups.element'; + @customElement('umb-section-view-user-groups') export class UmbSectionViewUserGroupsElement extends LitElement { render() { - return html`
CONTENT FOR USER GROUPS SECTION VIEW
`; + return html``; } } From 0236d96cf7a49e8f63409bccb94d23026c9960da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 11:36:09 +0200 Subject: [PATCH 87/98] add userGroup editor extension --- .../user-group/editor-user-group.element.ts | 159 +++++++++++++++++- .../src/temp-internal-manifests/index.ts | 9 + 2 files changed, 165 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts index a731b87c06..9bb746b044 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts @@ -1,10 +1,163 @@ -import { html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui'; +import { UUITextStyles } from '@umbraco-ui/uui-css'; +import { css, html, LitElement, nothing } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; @customElement('umb-editor-user-group') export class UmbEditorUserGroupElement extends LitElement { + static styles = [ + UUITextStyles, + css` + :host { + display: block; + height: 100%; + } + + #main { + display: grid; + grid-template-columns: 1fr 350px; + gap: var(--uui-size-space-6); + padding: var(--uui-size-space-6); + } + + #left-column { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-4); + } + #right-column > uui-box > div { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-2); + } + uui-avatar { + font-size: var(--uui-size-16); + place-self: center; + } + hr { + border: none; + border-bottom: 1px solid var(--uui-color-divider); + width: 100%; + } + uui-input { + width: 100%; + } + .faded-text { + color: var(--uui-color-text-alt); + font-size: 0.8rem; + } + uui-tag { + width: fit-content; + } + #user-info { + display: flex; + gap: var(--uui-size-space-6); + } + #user-info > div { + display: flex; + flex-direction: column; + } + #assign-access { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-4); + } + .access-content { + margin-top: var(--uui-size-space-1); + margin-bottom: var(--uui-size-space-4); + display: flex; + align-items: center; + line-height: 1; + gap: var(--uui-size-space-3); + } + .access-content > span { + align-self: end; + } + `, + ]; + + @state() + private _userName = ''; + + @property({ type: String }) + entityKey = ''; + + private _languages = []; //TODO Add languages + + private renderLeftColumn() { + return html` +
Profile
+ + Email + + + + Language + + +
+ +
+
Assign access
+
+ Groups +
Add groups to assign access and permissions
+
+
+ Content start nodes +
Limit the content tree to specific start nodes
+ +
+
+ Media start nodes +
Limit the media library to specific start nodes
+ +
+
+
+ +
Access
+
+ Based on the assigned groups and start nodes, the user has access to the following nodes +
+ + Content +
+ + Content Root +
+ + Media +
+ + Media Root +
+
`; + } + + private renderRightColumn() { + return html` RIGHT `; + } + + // TODO. find a way where we don't have to do this for all editors. + private _handleInput(event: UUIInputEvent) { + if (event instanceof UUIInputEvent) { + const target = event.composedPath()[0] as UUIInputElement; + + console.log('input', target.value); + } + } + render() { - return html`
User Group
`; + return html` + + +
+
${this.renderLeftColumn()}
+
${this.renderRightColumn()}
+
+
+ `; } } diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts index ed15c93ad2..f411b5cb3f 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts @@ -292,6 +292,15 @@ export const internalManifests: Array Promise import('../backoffice/editors/user-group/editor-user-group.element'), + meta: { + entityType: 'userGroup', + }, + }, { type: 'editorAction', alias: 'Umb.EditorAction.User.Save', From b4745cdca506dedba286520c525803704dd42cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 11:38:34 +0200 Subject: [PATCH 88/98] user group editor cleanup --- .../user-group/editor-user-group.element.ts | 85 +------------------ 1 file changed, 2 insertions(+), 83 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts index 9bb746b044..5333cea52c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts @@ -19,7 +19,6 @@ export class UmbEditorUserGroupElement extends LitElement { gap: var(--uui-size-space-6); padding: var(--uui-size-space-6); } - #left-column { display: flex; flex-direction: column; @@ -30,10 +29,6 @@ export class UmbEditorUserGroupElement extends LitElement { flex-direction: column; gap: var(--uui-size-space-2); } - uui-avatar { - font-size: var(--uui-size-16); - place-self: center; - } hr { border: none; border-bottom: 1px solid var(--uui-color-divider); @@ -46,33 +41,6 @@ export class UmbEditorUserGroupElement extends LitElement { color: var(--uui-color-text-alt); font-size: 0.8rem; } - uui-tag { - width: fit-content; - } - #user-info { - display: flex; - gap: var(--uui-size-space-6); - } - #user-info > div { - display: flex; - flex-direction: column; - } - #assign-access { - display: flex; - flex-direction: column; - gap: var(--uui-size-space-4); - } - .access-content { - margin-top: var(--uui-size-space-1); - margin-bottom: var(--uui-size-space-4); - display: flex; - align-items: center; - line-height: 1; - gap: var(--uui-size-space-3); - } - .access-content > span { - align-self: end; - } `, ]; @@ -82,61 +50,12 @@ export class UmbEditorUserGroupElement extends LitElement { @property({ type: String }) entityKey = ''; - private _languages = []; //TODO Add languages - private renderLeftColumn() { - return html` -
Profile
- - Email - - - - Language - - -
- -
-
Assign access
-
- Groups -
Add groups to assign access and permissions
-
-
- Content start nodes -
Limit the content tree to specific start nodes
- -
-
- Media start nodes -
Limit the media library to specific start nodes
- -
-
-
- -
Access
-
- Based on the assigned groups and start nodes, the user has access to the following nodes -
- - Content -
- - Content Root -
- - Media -
- - Media Root -
-
`; + return html` LEFT `; } private renderRightColumn() { - return html` RIGHT `; + return html`
RIGHT
`; } // TODO. find a way where we don't have to do this for all editors. From cf458ef49e8c0aa183612b46ee1cf28c6826853c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 12:07:36 +0200 Subject: [PATCH 89/98] added default permissions UI --- .../user-group/editor-user-group.element.ts | 194 +++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts index 5333cea52c..1d93a65b87 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts @@ -2,6 +2,7 @@ import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui'; import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, LitElement, nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; +import { repeat } from 'lit/directives/repeat.js'; @customElement('umb-editor-user-group') export class UmbEditorUserGroupElement extends LitElement { @@ -41,6 +42,24 @@ export class UmbEditorUserGroupElement extends LitElement { color: var(--uui-color-text-alt); font-size: 0.8rem; } + #default-permissions { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-4); + } + .default-permission { + display: flex; + align-items: center; + gap: var(--uui-size-space-4); + padding: var(--uui-size-space-2); + } + .default-permission:not(:last-child) { + border-bottom: 1px solid var(--uui-color-divider); + } + .permission-info { + display: flex; + flex-direction: column; + } `, ]; @@ -50,8 +69,181 @@ export class UmbEditorUserGroupElement extends LitElement { @property({ type: String }) entityKey = ''; + defaultPermissions: Array<{ + name: string; + permissions: Array<{ name: string; description: string; value: boolean }>; + }> = [ + { + name: 'Administration', + permissions: [ + { + name: 'Culture and Hostnames', + description: 'Allow access to assign culture and hostnames', + value: false, + }, + { + name: 'Restrict Public Access', + description: 'Allow access to set and change access restrictions for a node', + value: false, + }, + { + name: 'Rollback', + description: 'Allow access to roll back a node to a previous state', + value: false, + }, + ], + }, + { + name: 'Content', + permissions: [ + { + name: 'Browse Node', + description: 'Allow access to view a node', + value: false, + }, + { + name: 'Create Content Template', + description: 'Allow access to create a Content Template', + value: false, + }, + { + name: 'Delete', + description: 'Allow access to delete nodes', + value: false, + }, + { + name: 'Create', + description: 'Allow access to create nodes', + value: false, + }, + { + name: 'Publish', + description: 'Allow access to publish nodes', + value: false, + }, + { + name: 'Permissions', + description: 'Allow access to change permissions for a node', + value: false, + }, + { + name: 'Send To Publish', + description: 'Allow access to send a node for approval before publishing', + value: false, + }, + { + name: 'Unpublish', + description: 'Allow access to unpublish a node', + value: false, + }, + { + name: 'Update', + description: 'Allow access to save a node', + value: false, + }, + { + name: 'Full restore', + description: 'Allow the user to restore items', + value: false, + }, + { + name: 'Partial restore', + description: 'Allow the user to partial restore items', + value: false, + }, + { + name: 'Queue for transfer', + description: 'Allow the user to queue item(s)', + value: false, + }, + ], + }, + { + name: 'Structure', + permissions: [ + { + name: 'Copy', + description: 'Allow access to copy a node', + value: false, + }, + { + name: 'Move', + description: 'Allow access to move a node', + value: false, + }, + { + name: 'Sort', + description: 'Allow access to change the sort order for nodes', + value: false, + }, + ], + }, + ]; + private renderLeftColumn() { - return html` LEFT `; + return html` +
Assign access
+
+ Sections +
Add sections to give users access
+
+
+ Content start nodes +
Limit the content tree to specific start nodes
+ +
+
+ Media start nodes +
Limit the media library to specific start nodes
+ +
+ + Content +
+ + Content Root +
+ + Media +
+ + Media Root +
+
+ + +
Default Permissions
+
+ ${repeat( + this.defaultPermissions, + (defaultPermission) => html` +
+ ${defaultPermission.name} + ${repeat( + defaultPermission.permissions, + (permission) => html` +
+ { + permission.value = (e.target as HTMLInputElement).checked; + }}> +
+ ${permission.name} + ${permission.description} +
+
+ ` + )} +
+ ` + )} +
+
+ + +
Granular permissions
+
`; } private renderRightColumn() { From b705e26c8fe64a9959df046d739da3cf1ca6806f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 12:37:59 +0200 Subject: [PATCH 90/98] wip user group editor --- .../editors/user-group/editor-user-group.element.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts index 1d93a65b87..d202b68f11 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user-group/editor-user-group.element.ts @@ -247,7 +247,9 @@ export class UmbEditorUserGroupElement extends LitElement { } private renderRightColumn() { - return html`
RIGHT
`; + return html` +
Users
+
`; } // TODO. find a way where we don't have to do this for all editors. From e2804feb64e88bc3723f3c7409138fe1cfedf5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 12:48:02 +0200 Subject: [PATCH 91/98] removed empty story file --- .../sections/shared/section-views/section-views.stories.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.stories.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-views/section-views.stories.ts deleted file mode 100644 index e69de29bb2..0000000000 From 42296f63fa66b66688817ba2d892584ea7f8be17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 13:18:10 +0200 Subject: [PATCH 92/98] fix build --- .../editors/user/editor-user.element.ts | 10 +- .../backoffice/editors/user/user.context.ts | 2 +- .../sections/users/user-extensions.ts | 4 +- .../users/editor-view-users-invite.element.ts | 4 +- .../grid/editor-view-users-grid.element.ts | 8 +- ...user-table-status-column-layout.element.ts | 2 +- .../src/core/models/index.ts | 3 +- .../src/core/stores/user/user.store.ts | 8 +- .../src/mocks/data/users.data.ts | 204 +++++++++--------- .../src/temp-internal-manifests/index.ts | 1 + 10 files changed, 126 insertions(+), 120 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts index ea1feb0bc6..5361d5d5b1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/editor-user.element.ts @@ -144,7 +144,7 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons private _updateUserStatus() { if (!this._user || !this._userStore) return; - const isDisabled = this._user.status === 'Disabled'; + const isDisabled = this._user.status === 'disabled'; isDisabled ? this._userStore.enableUsers([this._user.key]) : this._userStore.disableUsers([this._user.key]); } @@ -219,13 +219,13 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons
- ${this._user?.status !== 'Invited' + ${this._user?.status !== 'invited' ? html` + color="${this._user.status === 'disabled' ? 'positive' : 'warning'}" + label="${this._user.status === 'disabled' ? 'Enable' : 'Disable'}"> ` : nothing} @@ -235,7 +235,7 @@ export class UmbEditorUserElement extends UmbContextProviderMixin(UmbContextCons ${this._user.status}
- ${this._user?.status === 'Invited' + ${this._user?.status === 'invited' ? html` diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts index 8d11cc64e3..2f27a60a26 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/user/user.context.ts @@ -13,7 +13,7 @@ export class UmbUserContext { isTrashed: false, email: '', language: '', - status: '', + status: 'enabled', updateDate: '8/27/2022', createDate: '9/19/2022', failedLoginAttempts: 0, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts index db46adf7a8..4966053554 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/user-extensions.ts @@ -1,13 +1,13 @@ import { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types'; -export type UserStatus = 'Active' | 'Inactive' | 'Invited' | 'Disabled'; +export type UserStatus = 'enabled' | 'inactive' | 'invited' | 'disabled'; export const getTagLookAndColor = (status: UserStatus): { look: InterfaceLook; color: InterfaceColor } => { switch ((status || '').toLowerCase()) { case 'invited': case 'inactive': return { look: 'primary', color: 'warning' }; - case 'active': + case 'enabled': return { look: 'primary', color: 'positive' }; case 'disabled': return { look: 'primary', color: 'danger' }; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts index 9a77eb5c33..fdedfa1de1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/editor-view-users-invite.element.ts @@ -78,7 +78,9 @@ export class UmbEditorViewUsersInviteElement extends UmbContextConsumerMixin(Umb const message = formData.get('message') as string; this._userStore?.invite(name, email, message, [userGroup]).then((user) => { - this._invitedUser = user; + if (user) { + this._invitedUser = user; + } }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts index 0719bef779..f67c85d3d0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/users/list-view-layouts/grid/editor-view-users-grid.element.ts @@ -7,7 +7,7 @@ import { ifDefined } from 'lit-html/directives/if-defined.js'; import { UmbContextConsumerMixin } from '../../../../../../../core/context'; import UmbSectionViewUsersElement from '../../section-view-users.element'; import { UmbUserStore } from '../../../../../../../core/stores/user/user.store'; -import type { UserEntity } from '../../../../../../../core/models'; +import type { UserDetails, UserEntity } from '../../../../../../../core/models'; import { getTagLookAndColor } from '../../../../user-extensions'; @customElement('umb-editor-view-users-grid') @@ -41,7 +41,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl ]; @state() - private _users: Array = []; + private _users: Array = []; @state() private _selection: Array = []; @@ -103,7 +103,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl this._usersContext?.deselect(user.key); } - private renderUserCard(user: UserEntity) { + private renderUserCard(user: UserDetails) { if (!this._userStore) return; const statusLook = getTagLookAndColor(user.status); @@ -117,7 +117,7 @@ export class UmbEditorViewUsersGridElement extends UmbContextConsumerMixin(LitEl @open=${() => this._handleOpenCard(user.key)} @selected=${() => this._selectRowHandler(user)} @unselected=${() => this._deselectRowHandler(user)}> - ${user.status && user.status !== 'Enabled' + ${user.status && user.status !== 'enabled' ? html` { const storedUsers = this._items.getValue().filter((user) => enabledKeys.includes(user.key)); storedUsers.forEach((user) => { - user.status = 'Enabled'; + user.status = 'enabled'; }); this.update(storedUsers); @@ -92,7 +92,7 @@ export class UmbUserStore extends UmbDataStoreBase { const storedUsers = this._items.getValue().filter((user) => disabledKeys.includes(user.key)); storedUsers.forEach((user) => { - user.status = 'Disabled'; + user.status = 'disabled'; }); this.update(storedUsers); @@ -138,7 +138,7 @@ export class UmbUserStore extends UmbDataStoreBase { } } - async invite(name: string, email: string, message: string, userGroups: Array): Promise { + async invite(name: string, email: string, message: string, userGroups: Array): Promise { // TODO: use Fetcher API. try { const res = await fetch('/umbraco/backoffice/users/invite', { @@ -155,6 +155,8 @@ export class UmbUserStore extends UmbDataStoreBase { } catch (error) { console.error('Invite user error', error); } + + return null; } // public updateUser(user: UserItem) { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts index 76a6956bd4..3d2e36fdca 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts @@ -10,7 +10,7 @@ class UmbUsersData extends UmbEntityData { enable(keys: string[]) { const users = this.data.filter((user) => keys.includes(user.key)); users.forEach((user) => { - user.status = 'Enabled'; + user.status = 'enabled'; this.updateData(user); }); return users.map((user) => user.key); @@ -19,7 +19,7 @@ class UmbUsersData extends UmbEntityData { disable(keys: string[]) { const users = this.data.filter((user) => keys.includes(user.key)); users.forEach((user) => { - user.status = 'Disabled'; + user.status = 'disabled'; this.updateData(user); }); return users.map((user) => user.key); @@ -37,7 +37,7 @@ export const data: Array = [ name: 'Nat Linnane', email: 'nlinnane0@fda.gov', language: 'Greek', - status: 'Inactive', + status: 'inactive', lastLoginDate: '9/11/2022', lastLockoutDate: '5/31/2022', lastPasswordChangeDate: '1/10/2022', @@ -55,7 +55,7 @@ export const data: Array = [ name: 'Tyrus Hows', email: 'thows1@hatena.ne.jp', language: 'Gagauz', - status: 'Inactive', + status: 'inactive', lastLoginDate: '9/1/2022', lastLockoutDate: '2/9/2022', lastPasswordChangeDate: '8/22/2022', @@ -73,7 +73,7 @@ export const data: Array = [ name: 'Nisse Grattan', email: 'ngrattan2@alexa.com', language: 'Tok Pisin', - status: 'Enabled', + status: 'enabled', lastLoginDate: '3/22/2022', lastLockoutDate: '12/2/2021', lastPasswordChangeDate: '5/28/2022', @@ -91,7 +91,7 @@ export const data: Array = [ name: 'Thain Rainville', email: 'trainville3@merriam-webster.com', language: 'Tajik', - status: 'Enabled', + status: 'enabled', lastLoginDate: '2/28/2022', lastLockoutDate: '1/6/2022', lastPasswordChangeDate: '7/1/2022', @@ -109,7 +109,7 @@ export const data: Array = [ name: 'Perren Balsdon', email: 'pbalsdon4@ezinearticles.com', language: 'Somali', - status: 'Enabled', + status: 'enabled', lastLoginDate: '5/6/2022', lastLockoutDate: '11/12/2021', lastPasswordChangeDate: '11/10/2021', @@ -127,7 +127,7 @@ export const data: Array = [ name: 'Athene Bilborough', email: 'abilborough5@princeton.edu', language: 'Tetum', - status: 'Enabled', + status: 'enabled', lastLoginDate: '3/11/2022', lastLockoutDate: '7/7/2022', lastPasswordChangeDate: '3/8/2022', @@ -145,7 +145,7 @@ export const data: Array = [ name: 'Carline Sharp', email: 'csharp6@com.com', language: 'Portuguese', - status: 'Inactive', + status: 'inactive', lastLoginDate: '3/6/2022', lastLockoutDate: '5/20/2022', lastPasswordChangeDate: '10/9/2021', @@ -163,7 +163,7 @@ export const data: Array = [ name: 'Tansy Hanna', email: 'thanna7@google.pl', language: 'Papiamento', - status: 'Enabled', + status: 'enabled', lastLoginDate: '9/10/2022', lastLockoutDate: '10/28/2021', lastPasswordChangeDate: '2/26/2022', @@ -181,7 +181,7 @@ export const data: Array = [ icon: 'umb:user', email: 'hmohan8@google.co.jp', language: 'Montenegrin', - status: 'Enabled', + status: 'enabled', lastLoginDate: '6/16/2022', lastLockoutDate: '3/2/2022', lastPasswordChangeDate: '4/14/2022', @@ -199,7 +199,7 @@ export const data: Array = [ name: 'Alden Blaschke', email: 'ablaschke9@marketwatch.com', language: 'Mongolian', - status: 'Inactive', + status: 'inactive', lastLoginDate: '6/27/2022', lastLockoutDate: '4/16/2022', lastPasswordChangeDate: '12/31/2021', @@ -217,7 +217,7 @@ export const data: Array = [ name: 'Hollis Rouf', email: 'hroufa@irs.gov', language: 'Papiamento', - status: 'Inactive', + status: 'inactive', updateDate: '9/11/2022', createDate: '6/18/2022', failedLoginAttempts: 532, @@ -232,7 +232,7 @@ export const data: Array = [ name: 'Neils Janiak', email: 'njaniakb@indiatimes.com', language: 'Aymara', - status: 'Inactive', + status: 'inactive', updateDate: '11/7/2021', createDate: '12/30/2021', failedLoginAttempts: 800, @@ -247,7 +247,7 @@ export const data: Array = [ name: 'Zarah Slaughter', email: 'zslaughterc@storify.com', language: 'Afrikaans', - status: 'Invited', + status: 'invited', lastLoginDate: '1/1/2022', lastLockoutDate: '5/4/2022', lastPasswordChangeDate: '3/6/2022', @@ -265,7 +265,7 @@ export const data: Array = [ name: 'Elly Corbishley', email: 'ecorbishleyd@hexun.com', language: 'Kyrgyz', - status: 'Invited', + status: 'invited', lastLoginDate: '6/3/2022', lastLockoutDate: '4/4/2022', lastPasswordChangeDate: '12/21/2021', @@ -283,7 +283,7 @@ export const data: Array = [ name: 'Alisander Leupold', email: 'aleupolde@webnode.com', language: 'Nepali', - status: 'Inactive', + status: 'inactive', lastLoginDate: '1/4/2022', lastLockoutDate: '9/15/2022', lastPasswordChangeDate: '5/24/2022', @@ -301,7 +301,7 @@ export const data: Array = [ name: 'Gennie Casaccia', email: 'gcasacciaf@vkontakte.ru', language: 'Catalan', - status: 'Enabled', + status: 'enabled', lastLoginDate: '4/11/2022', lastLockoutDate: '3/17/2022', lastPasswordChangeDate: '4/30/2022', @@ -319,7 +319,7 @@ export const data: Array = [ name: 'Vaughan Longstreet', email: 'vlongstreetg@jugem.jp', language: 'Khmer', - status: 'Enabled', + status: 'enabled', lastLoginDate: '3/16/2022', lastLockoutDate: '11/4/2021', lastPasswordChangeDate: '3/23/2022', @@ -337,7 +337,7 @@ export const data: Array = [ name: 'Vanda Scamadin', email: 'vscamadinh@list-manage.com', language: 'Telugu', - status: 'Inactive', + status: 'inactive', updateDate: '7/16/2022', createDate: '1/5/2022', failedLoginAttempts: 721, @@ -352,7 +352,7 @@ export const data: Array = [ name: 'Reagen Nore', email: 'rnorei@ning.com', language: 'Kyrgyz', - status: 'Disabled', + status: 'disabled', lastLoginDate: '7/10/2022', lastLockoutDate: '4/29/2022', lastPasswordChangeDate: '10/26/2021', @@ -370,7 +370,7 @@ export const data: Array = [ name: 'Crosby Breens', email: 'cbreensj@google.com.br', language: 'Māori', - status: 'Disabled', + status: 'disabled', lastLoginDate: '8/7/2022', lastLockoutDate: '5/23/2022', lastPasswordChangeDate: '1/26/2022', @@ -388,7 +388,7 @@ export const data: Array = [ name: 'Felipe Finicj', email: 'ffinicjk@economist.com', language: 'Latvian', - status: 'Enabled', + status: 'enabled', lastLoginDate: '11/5/2021', lastLockoutDate: '7/12/2022', lastPasswordChangeDate: '4/12/2022', @@ -406,7 +406,7 @@ export const data: Array = [ name: 'Ash Shepstone', email: 'ashepstonel@arizona.edu', language: 'French', - status: 'Invited', + status: 'invited', lastLoginDate: '1/18/2022', lastLockoutDate: '10/17/2021', lastPasswordChangeDate: '11/24/2021', @@ -424,7 +424,7 @@ export const data: Array = [ name: 'Franni Plester', email: 'fplesterm@nytimes.com', language: 'Hungarian', - status: 'Enabled', + status: 'enabled', lastLoginDate: '7/27/2022', lastLockoutDate: '8/17/2022', lastPasswordChangeDate: '3/2/2022', @@ -442,7 +442,7 @@ export const data: Array = [ name: "Pearla O'Cooney", email: 'pocooneyn@hugedomains.com', language: 'Persian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '3/29/2022', lastLockoutDate: '3/18/2022', lastPasswordChangeDate: '11/25/2021', @@ -460,7 +460,7 @@ export const data: Array = [ name: 'Brittaney Linsay', email: 'blinsayo@godaddy.com', language: 'Amharic', - status: 'Disabled', + status: 'disabled', lastLoginDate: '9/21/2022', lastLockoutDate: '1/28/2022', lastPasswordChangeDate: '6/15/2022', @@ -478,7 +478,7 @@ export const data: Array = [ name: 'Terry McCorkell', email: 'tmccorkellp@noaa.gov', language: 'Dhivehi', - status: 'Enabled', + status: 'enabled', lastLoginDate: '7/23/2022', lastLockoutDate: '7/24/2022', lastPasswordChangeDate: '10/11/2021', @@ -496,7 +496,7 @@ export const data: Array = [ name: 'Amalea Barbour', email: 'abarbourq@businesswire.com', language: 'Catalan', - status: 'Invited', + status: 'invited', lastLoginDate: '11/29/2021', lastLockoutDate: '1/17/2022', lastPasswordChangeDate: '2/2/2022', @@ -514,7 +514,7 @@ export const data: Array = [ name: 'Bethena Grewe', email: 'bgrewer@naver.com', language: 'Haitian Creole', - status: 'Enabled', + status: 'enabled', lastLoginDate: '11/12/2021', lastLockoutDate: '6/4/2022', lastPasswordChangeDate: '8/25/2022', @@ -532,7 +532,7 @@ export const data: Array = [ name: 'Yorgos Ferroni', email: 'yferronis@unblog.fr', language: 'Afrikaans', - status: 'Inactive', + status: 'inactive', lastLoginDate: '7/13/2022', lastLockoutDate: '3/16/2022', lastPasswordChangeDate: '2/2/2022', @@ -550,7 +550,7 @@ export const data: Array = [ name: 'Ivar Wisbey', email: 'iwisbeyt@blogspot.com', language: 'Lao', - status: 'Invited', + status: 'invited', lastLoginDate: '6/15/2022', lastLockoutDate: '3/4/2022', lastPasswordChangeDate: '2/1/2022', @@ -568,7 +568,7 @@ export const data: Array = [ name: 'Casie Greatland', email: 'cgreatlandu@google.cn', language: 'Māori', - status: 'Disabled', + status: 'disabled', lastLoginDate: '12/19/2021', lastLockoutDate: '10/15/2021', lastPasswordChangeDate: '3/4/2022', @@ -586,7 +586,7 @@ export const data: Array = [ name: 'Bat Dake', email: 'bdakev@mapy.cz', language: 'Armenian', - status: 'Invited', + status: 'invited', lastLoginDate: '9/17/2022', lastLockoutDate: '12/17/2021', lastPasswordChangeDate: '3/10/2022', @@ -604,7 +604,7 @@ export const data: Array = [ name: 'Chlo Skirven', email: 'cskirvenw@histats.com', language: 'Irish Gaelic', - status: 'Invited', + status: 'invited', lastLoginDate: '6/22/2022', lastLockoutDate: '6/7/2022', lastPasswordChangeDate: '10/27/2021', @@ -622,7 +622,7 @@ export const data: Array = [ name: 'Delmer Porch', email: 'dporchx@newyorker.com', language: 'Punjabi', - status: 'Disabled', + status: 'disabled', lastLoginDate: '1/22/2022', lastLockoutDate: '12/10/2021', lastPasswordChangeDate: '5/24/2022', @@ -640,7 +640,7 @@ export const data: Array = [ name: 'Gussi Lednor', email: 'glednory@google.de', language: 'Romanian', - status: 'Invited', + status: 'invited', lastLoginDate: '6/1/2022', lastLockoutDate: '11/17/2021', lastPasswordChangeDate: '12/25/2021', @@ -658,7 +658,7 @@ export const data: Array = [ name: 'Tish Kubacki', email: 'tkubackiz@gmpg.org', language: 'Bosnian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '11/29/2021', lastLockoutDate: '11/28/2021', lastPasswordChangeDate: '12/1/2021', @@ -676,7 +676,7 @@ export const data: Array = [ name: 'Madelene Le Noury', email: 'mle10@google.com.au', language: 'Punjabi', - status: 'Invited', + status: 'invited', lastLoginDate: '6/8/2022', lastLockoutDate: '11/1/2021', lastPasswordChangeDate: '8/19/2022', @@ -694,7 +694,7 @@ export const data: Array = [ name: 'Alberta Headech', email: 'aheadech11@diigo.com', language: 'Kazakh', - status: 'Enabled', + status: 'enabled', lastLoginDate: '8/12/2022', lastLockoutDate: '8/8/2022', lastPasswordChangeDate: '10/29/2021', @@ -712,7 +712,7 @@ export const data: Array = [ name: 'Kenon Maybey', email: 'kmaybey12@cdbaby.com', language: 'Telugu', - status: 'Enabled', + status: 'enabled', lastLoginDate: '6/11/2022', lastLockoutDate: '3/4/2022', lastPasswordChangeDate: '5/5/2022', @@ -730,7 +730,7 @@ export const data: Array = [ name: 'Brig Totterdill', email: 'btotterdill13@telegraph.co.uk', language: 'Tajik', - status: 'Disabled', + status: 'disabled', lastLoginDate: '8/11/2022', lastLockoutDate: '3/31/2022', lastPasswordChangeDate: '4/30/2022', @@ -748,7 +748,7 @@ export const data: Array = [ name: 'Kore Faragher', email: 'kfaragher14@elpais.com', language: 'Georgian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '5/9/2022', lastLockoutDate: '4/19/2022', lastPasswordChangeDate: '7/26/2022', @@ -766,7 +766,7 @@ export const data: Array = [ name: 'Benedicto Oda', email: 'boda15@zimbio.com', language: 'Hungarian', - status: 'Enabled', + status: 'enabled', lastLoginDate: '7/6/2022', lastLockoutDate: '12/27/2021', lastPasswordChangeDate: '9/15/2022', @@ -784,7 +784,7 @@ export const data: Array = [ name: 'Celinka Gyorffy', email: 'cgyorffy16@godaddy.com', language: 'Punjabi', - status: 'Inactive', + status: 'inactive', lastLoginDate: '7/15/2022', lastLockoutDate: '5/24/2022', lastPasswordChangeDate: '2/26/2022', @@ -802,7 +802,7 @@ export const data: Array = [ name: 'Arri Goretti', email: 'agoretti17@pcworld.com', language: 'Armenian', - status: 'Invited', + status: 'invited', updateDate: '1/24/2022', createDate: '7/11/2022', failedLoginAttempts: 234, @@ -817,7 +817,7 @@ export const data: Array = [ name: 'Giffie Strattan', email: 'gstrattan18@cisco.com', language: 'Maltese', - status: 'Disabled', + status: 'disabled', lastLoginDate: '5/15/2022', lastLockoutDate: '10/21/2021', lastPasswordChangeDate: '2/2/2022', @@ -835,7 +835,7 @@ export const data: Array = [ name: 'Aeriel Webling', email: 'awebling19@usgs.gov', language: 'Dutch', - status: 'Disabled', + status: 'disabled', lastLoginDate: '7/20/2022', lastLockoutDate: '11/17/2021', lastPasswordChangeDate: '8/22/2022', @@ -853,7 +853,7 @@ export const data: Array = [ name: 'Roderic Heckle', email: 'rheckle1a@pbs.org', language: 'Dari', - status: 'Inactive', + status: 'inactive', updateDate: '7/31/2022', createDate: '2/19/2022', failedLoginAttempts: 279, @@ -868,7 +868,7 @@ export const data: Array = [ name: 'Gonzalo Magister', email: 'gmagister1b@jigsy.com', language: 'Hungarian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '8/21/2022', lastLockoutDate: '6/23/2022', lastPasswordChangeDate: '2/11/2022', @@ -886,7 +886,7 @@ export const data: Array = [ name: 'Nickolai Landsborough', email: 'nlandsborough1c@ask.com', language: 'Guaraní', - status: 'Inactive', + status: 'inactive', lastLoginDate: '11/25/2021', lastLockoutDate: '7/24/2022', lastPasswordChangeDate: '4/20/2022', @@ -904,7 +904,7 @@ export const data: Array = [ name: 'Linn Early', email: 'learly1d@msn.com', language: 'Swedish', - status: 'Enabled', + status: 'enabled', lastLoginDate: '10/18/2021', lastLockoutDate: '6/14/2022', lastPasswordChangeDate: '4/10/2022', @@ -922,7 +922,7 @@ export const data: Array = [ name: 'Julianna Jakab', email: 'jjakab1e@cbsnews.com', language: 'Malay', - status: 'Enabled', + status: 'enabled', lastLoginDate: '3/22/2022', lastLockoutDate: '6/2/2022', lastPasswordChangeDate: '9/7/2022', @@ -940,7 +940,7 @@ export const data: Array = [ name: 'Erick Hovell', email: 'ehovell1f@ucoz.com', language: 'New Zealand Sign Language', - status: 'Disabled', + status: 'disabled', updateDate: '11/30/2021', createDate: '3/4/2022', failedLoginAttempts: 150, @@ -955,7 +955,7 @@ export const data: Array = [ name: 'Bondon Berends', email: 'bberends1g@si.edu', language: 'Zulu', - status: 'Invited', + status: 'invited', updateDate: '1/12/2022', createDate: '4/22/2022', failedLoginAttempts: 455, @@ -970,7 +970,7 @@ export const data: Array = [ name: 'Rubie Palluschek', email: 'rpalluschek1h@multiply.com', language: 'Icelandic', - status: 'Disabled', + status: 'disabled', lastLoginDate: '7/18/2022', lastLockoutDate: '1/14/2022', lastPasswordChangeDate: '8/13/2022', @@ -988,7 +988,7 @@ export const data: Array = [ name: 'Kass Gaisford', email: 'kgaisford1i@tiny.cc', language: 'Hiri Motu', - status: 'Invited', + status: 'invited', lastLoginDate: '12/22/2021', lastLockoutDate: '9/10/2022', lastPasswordChangeDate: '6/6/2022', @@ -1006,7 +1006,7 @@ export const data: Array = [ name: 'Eba Fewings', email: 'efewings1j@hexun.com', language: 'Quechua', - status: 'Invited', + status: 'invited', lastLoginDate: '11/30/2021', lastLockoutDate: '4/17/2022', lastPasswordChangeDate: '7/8/2022', @@ -1024,7 +1024,7 @@ export const data: Array = [ name: 'Rand Espadate', email: 'respadate1k@skyrock.com', language: 'Persian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '8/22/2022', lastLockoutDate: '6/14/2022', lastPasswordChangeDate: '9/5/2022', @@ -1042,7 +1042,7 @@ export const data: Array = [ name: 'Bobina Macconachy', email: 'bmacconachy1l@wikipedia.org', language: 'Gujarati', - status: 'Enabled', + status: 'enabled', lastLoginDate: '5/25/2022', lastLockoutDate: '6/28/2022', lastPasswordChangeDate: '6/26/2022', @@ -1060,7 +1060,7 @@ export const data: Array = [ name: 'Walther Pattie', email: 'wpattie1m@example.com', language: 'Zulu', - status: 'Invited', + status: 'invited', updateDate: '3/8/2022', createDate: '10/8/2021', failedLoginAttempts: 381, @@ -1075,7 +1075,7 @@ export const data: Array = [ name: 'Elton Jedrychowski', email: 'ejedrychowski1n@cam.ac.uk', language: 'Greek', - status: 'Invited', + status: 'invited', lastLoginDate: '5/16/2022', lastLockoutDate: '7/18/2022', lastPasswordChangeDate: '11/28/2021', @@ -1093,7 +1093,7 @@ export const data: Array = [ name: 'Melamie Chifney', email: 'mchifney1o@umich.edu', language: 'Albanian', - status: 'Enabled', + status: 'enabled', lastLoginDate: '3/16/2022', lastLockoutDate: '12/22/2021', lastPasswordChangeDate: '1/8/2022', @@ -1111,7 +1111,7 @@ export const data: Array = [ name: 'Auroora Theuff', email: 'atheuff1p@over-blog.com', language: 'Kurdish', - status: 'Inactive', + status: 'inactive', lastLoginDate: '11/28/2021', lastLockoutDate: '11/17/2021', lastPasswordChangeDate: '11/20/2021', @@ -1129,7 +1129,7 @@ export const data: Array = [ name: 'Law Cours', email: 'lcours1q@google.co.uk', language: 'Arabic', - status: 'Invited', + status: 'invited', lastLoginDate: '3/27/2022', lastLockoutDate: '12/2/2021', lastPasswordChangeDate: '3/14/2022', @@ -1147,7 +1147,7 @@ export const data: Array = [ name: 'Clarke Rosenhaus', email: 'crosenhaus1r@globo.com', language: 'Afrikaans', - status: 'Enabled', + status: 'enabled', lastLoginDate: '6/23/2022', lastLockoutDate: '7/4/2022', lastPasswordChangeDate: '12/5/2021', @@ -1165,7 +1165,7 @@ export const data: Array = [ name: 'Nevins Gabler', email: 'ngabler1s@psu.edu', language: 'Korean', - status: 'Invited', + status: 'invited', updateDate: '12/2/2021', createDate: '12/14/2021', failedLoginAttempts: 189, @@ -1180,7 +1180,7 @@ export const data: Array = [ name: 'Bondon Corrin', email: 'bcorrin1t@ustream.tv', language: 'Hiri Motu', - status: 'Enabled', + status: 'enabled', lastLoginDate: '1/14/2022', lastLockoutDate: '6/14/2022', lastPasswordChangeDate: '11/28/2021', @@ -1198,7 +1198,7 @@ export const data: Array = [ name: 'Juli Birtwistle', email: 'jbirtwistle1u@histats.com', language: 'Haitian Creole', - status: 'Enabled', + status: 'enabled', lastLoginDate: '11/25/2021', lastLockoutDate: '3/20/2022', lastPasswordChangeDate: '12/20/2021', @@ -1216,7 +1216,7 @@ export const data: Array = [ name: 'Tomasine Hirsthouse', email: 'thirsthouse1v@ehow.com', language: 'Bosnian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '9/19/2022', lastLockoutDate: '4/21/2022', lastPasswordChangeDate: '2/7/2022', @@ -1234,7 +1234,7 @@ export const data: Array = [ email: 'cflecknell1w@guardian.co.uk', name: 'Barnie Flecknell', language: 'Estonian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '3/25/2022', lastLockoutDate: '10/26/2021', lastPasswordChangeDate: '12/3/2021', @@ -1252,7 +1252,7 @@ export const data: Array = [ name: 'Skelly Hockey', email: 'shockey1x@usa.gov', language: 'Burmese', - status: 'Enabled', + status: 'enabled', updateDate: '8/30/2022', createDate: '1/16/2022', failedLoginAttempts: 211, @@ -1267,7 +1267,7 @@ export const data: Array = [ name: 'Nicholas Woan', email: 'nwoan1y@istockphoto.com', language: 'Māori', - status: 'Invited', + status: 'invited', lastLoginDate: '4/16/2022', lastLockoutDate: '4/17/2022', lastPasswordChangeDate: '7/14/2022', @@ -1285,7 +1285,7 @@ export const data: Array = [ name: 'Asa Kase', email: 'akase1z@scribd.com', language: 'Irish Gaelic', - status: 'Invited', + status: 'invited', updateDate: '7/16/2022', createDate: '10/23/2021', failedLoginAttempts: 790, @@ -1300,7 +1300,7 @@ export const data: Array = [ name: 'Emmerich Sisey', email: 'emm@sis.com', language: 'Tetum', - status: 'Enabled', + status: 'enabled', lastLoginDate: '5/22/2022', lastLockoutDate: '6/26/2022', lastPasswordChangeDate: '5/22/2022', @@ -1318,7 +1318,7 @@ export const data: Array = [ name: 'Trish Cerith', email: 'tcerith21@tuttocitta.it', language: 'Spanish', - status: 'Invited', + status: 'invited', lastLoginDate: '1/11/2022', lastLockoutDate: '9/1/2022', lastPasswordChangeDate: '1/29/2022', @@ -1336,7 +1336,7 @@ export const data: Array = [ name: 'Netty Rudge', email: 'nrudge22@xinhuanet.com', language: 'Fijian', - status: 'Enabled', + status: 'enabled', lastLoginDate: '4/21/2022', lastLockoutDate: '7/21/2022', lastPasswordChangeDate: '11/6/2021', @@ -1354,7 +1354,7 @@ export const data: Array = [ name: 'Joane Kuhne', email: 'jkuhne23@opera.com', language: 'Danish', - status: 'Enabled', + status: 'enabled', lastLoginDate: '1/10/2022', lastLockoutDate: '9/18/2022', lastPasswordChangeDate: '9/6/2022', @@ -1372,7 +1372,7 @@ export const data: Array = [ name: 'Sheilah Nattrass', email: 'snattrass24@sbwire.com', language: 'Korean', - status: 'Invited', + status: 'invited', lastLoginDate: '5/7/2022', lastLockoutDate: '10/20/2021', lastPasswordChangeDate: '11/13/2021', @@ -1390,7 +1390,7 @@ export const data: Array = [ name: "Luella O'Geaney", email: 'logeaney25@foxnews.com', language: 'Arabic', - status: 'Disabled', + status: 'disabled', lastLoginDate: '10/21/2021', lastLockoutDate: '8/12/2022', lastPasswordChangeDate: '7/20/2022', @@ -1408,7 +1408,7 @@ export const data: Array = [ name: 'Cyrille Curm', email: 'ccurm26@forbes.com', language: 'Icelandic', - status: 'Enabled', + status: 'enabled', lastLoginDate: '12/17/2021', lastLockoutDate: '8/9/2022', lastPasswordChangeDate: '10/14/2021', @@ -1426,7 +1426,7 @@ export const data: Array = [ name: 'Leonard Vitall', email: 'lvitall27@clickbank.net', language: 'Haitian Creole', - status: 'Inactive', + status: 'inactive', lastLoginDate: '8/12/2022', lastLockoutDate: '2/26/2022', lastPasswordChangeDate: '10/2/2022', @@ -1444,7 +1444,7 @@ export const data: Array = [ name: 'Nickie Bronger', email: 'nbronger28@xrea.com', language: 'West Frisian', - status: 'Enabled', + status: 'enabled', lastLoginDate: '8/5/2022', lastLockoutDate: '1/21/2022', lastPasswordChangeDate: '4/8/2022', @@ -1462,7 +1462,7 @@ export const data: Array = [ name: 'Annie Butterworth', email: 'abutterworth29@marketwatch.com', language: 'Bulgarian', - status: 'Enabled', + status: 'enabled', lastLoginDate: '10/30/2021', lastLockoutDate: '10/5/2021', lastPasswordChangeDate: '5/3/2022', @@ -1479,7 +1479,7 @@ export const data: Array = [ icon: 'umb:user', name: 'Dasi Ughi', email: 'dughi2a@vimeo.com', - status: 'Disabled', + status: 'disabled', lastLoginDate: '10/14/2021', lastLockoutDate: '1/11/2022', lastPasswordChangeDate: '8/1/2022', @@ -1498,7 +1498,7 @@ export const data: Array = [ name: 'Lawrence Cansfield', email: 'lcansfield2b@istockphoto.com', language: 'Estonian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '3/24/2022', lastLockoutDate: '10/11/2021', lastPasswordChangeDate: '5/20/2022', @@ -1516,7 +1516,7 @@ export const data: Array = [ name: 'Gal Lyster', email: 'glyster2c@google.cn', language: 'Indonesian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '8/29/2022', lastLockoutDate: '9/25/2022', lastPasswordChangeDate: '10/16/2021', @@ -1534,7 +1534,7 @@ export const data: Array = [ name: 'Caron Crolly', email: 'ccrolly2d@jalbum.net', language: 'Italian', - status: 'Disabled', + status: 'disabled', lastLoginDate: '7/12/2022', lastLockoutDate: '3/20/2022', lastPasswordChangeDate: '1/4/2022', @@ -1552,7 +1552,7 @@ export const data: Array = [ name: 'Juliana Clorley', email: 'jclorley2e@mail.ru', language: 'Luxembourgish', - status: 'Enabled', + status: 'enabled', lastLoginDate: '10/17/2021', lastLockoutDate: '8/4/2022', lastPasswordChangeDate: '12/23/2021', @@ -1570,7 +1570,7 @@ export const data: Array = [ name: 'Kylynn Falvey', email: 'kfalvey2f@com.com', language: 'Zulu', - status: 'Inactive', + status: 'inactive', lastLoginDate: '3/4/2022', lastLockoutDate: '6/4/2022', lastPasswordChangeDate: '6/9/2022', @@ -1588,7 +1588,7 @@ export const data: Array = [ name: 'Marty Shurrock', email: 'mshurrock2g@hhs.gov', language: 'Danish', - status: 'Inactive', + status: 'inactive', lastLoginDate: '10/2/2022', lastLockoutDate: '9/16/2022', lastPasswordChangeDate: '12/3/2021', @@ -1606,7 +1606,7 @@ export const data: Array = [ name: 'Goldia Crates', email: 'gcrates2h@privacy.gov.au', language: 'Pashto', - status: 'Inactive', + status: 'inactive', lastLoginDate: '9/27/2022', lastLockoutDate: '2/7/2022', lastPasswordChangeDate: '12/9/2021', @@ -1624,7 +1624,7 @@ export const data: Array = [ name: 'Ted Stratley', email: 'tstratley2i@tinypic.com', language: 'Mongolian', - status: 'Inactive', + status: 'inactive', lastLoginDate: '4/19/2022', lastLockoutDate: '9/24/2022', lastPasswordChangeDate: '10/24/2021', @@ -1642,7 +1642,7 @@ export const data: Array = [ name: 'Rubia Collecott', email: 'rcollecott2j@oaic.gov.au', language: 'Somali', - status: 'Inactive', + status: 'inactive', updateDate: '1/27/2022', createDate: '3/7/2022', failedLoginAttempts: 250, @@ -1657,7 +1657,7 @@ export const data: Array = [ name: 'Nilson Britland', email: 'nbritland2k@facebook.com', language: 'Ndebele', - status: 'Disabled', + status: 'disabled', lastLoginDate: '8/25/2022', lastLockoutDate: '12/31/2021', lastPasswordChangeDate: '8/15/2022', @@ -1675,7 +1675,7 @@ export const data: Array = [ name: 'Johannes Slucock', email: 'jslucock2l@buzzfeed.com', language: 'Malagasy', - status: 'Inactive', + status: 'inactive', lastLoginDate: '1/5/2022', lastLockoutDate: '10/11/2021', lastPasswordChangeDate: '2/17/2022', @@ -1693,7 +1693,7 @@ export const data: Array = [ name: 'Rodrick Twelftree', email: 'rtwelftree2m@nbcnews.com', language: 'Luxembourgish', - status: 'Enabled', + status: 'enabled', lastLoginDate: '5/23/2022', lastLockoutDate: '6/21/2022', lastPasswordChangeDate: '8/27/2022', @@ -1711,7 +1711,7 @@ export const data: Array = [ name: 'Liesa Arnoll', email: 'larnoll2n@webnode.com', language: 'Hebrew', - status: 'Enabled', + status: 'enabled', lastLoginDate: '9/13/2022', lastLockoutDate: '7/14/2022', lastPasswordChangeDate: '2/28/2022', @@ -1729,7 +1729,7 @@ export const data: Array = [ name: 'Cindra Simkiss', email: 'csimkiss2o@google.es', language: 'Gagauz', - status: 'Disabled', + status: 'disabled', lastLoginDate: '4/18/2022', lastLockoutDate: '9/2/2022', lastPasswordChangeDate: '5/5/2022', @@ -1747,7 +1747,7 @@ export const data: Array = [ name: 'Belle Conrard', email: 'bconrard2p@mozilla.org', language: 'Hindi', - status: 'Invited', + status: 'invited', lastLoginDate: '7/18/2022', lastLockoutDate: '6/25/2022', lastPasswordChangeDate: '2/21/2022', @@ -1765,7 +1765,7 @@ export const data: Array = [ name: 'Tremain Minor', email: 'tminor2q@storify.com', language: 'Chinese', - status: 'Invited', + status: 'invited', lastLoginDate: '7/31/2022', lastLockoutDate: '5/11/2022', lastPasswordChangeDate: '11/10/2021', @@ -1783,7 +1783,7 @@ export const data: Array = [ name: 'Isador Tibbles', email: 'itibbles2r@cafepress.com', language: 'Assamese', - status: 'Enabled', + status: 'enabled', lastLoginDate: '4/7/2022', lastLockoutDate: '2/4/2022', lastPasswordChangeDate: '11/14/2021', diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts index f411b5cb3f..e7b541a996 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts @@ -69,6 +69,7 @@ export const internalManifests: Array Promise import('../backoffice/sections/users/section-users.element'), meta: { + label: 'Users', pathname: 'users', weight: 20, }, From f3476744f66dd876c0be9a8e1248be57dffef749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= Date: Wed, 12 Oct 2022 13:23:05 +0200 Subject: [PATCH 93/98] added user group routing --- .../editor-view-user-groups.element.ts | 7 ++++- ...-group-table-name-column-layout.element.ts | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/user-group-table-name-column-layout.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts index 710a3c8917..aba414a2a9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/editor-view-user-groups.element.ts @@ -14,6 +14,8 @@ import UmbTableElement, { UmbTableSelectedEvent, } from '../../../../components/table/table.element'; +import './user-group-table-name-column-layout.element'; + @customElement('umb-editor-view-user-groups') export class UmbEditorViewUserGroupsElement extends UmbContextConsumerMixin(LitElement) { static styles = [ @@ -40,6 +42,7 @@ export class UmbEditorViewUserGroupsElement extends UmbContextConsumerMixin(LitE { name: 'Name', alias: 'userGroupName', + elementName: 'umb-user-group-table-name-column-layout', }, { name: 'Sections', @@ -92,7 +95,9 @@ export class UmbEditorViewUserGroupsElement extends UmbContextConsumerMixin(LitE data: [ { columnAlias: 'userGroupName', - value: userGroup.name, + value: { + name: userGroup.name, + }, }, { columnAlias: 'userGroupSections', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/user-group-table-name-column-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/user-group-table-name-column-layout.element.ts new file mode 100644 index 0000000000..43ba9734eb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/users/views/user-groups/user-group-table-name-column-layout.element.ts @@ -0,0 +1,26 @@ +import { html, LitElement } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { UmbTableItem } from '../../../../components/table/table.element'; + +@customElement('umb-user-group-table-name-column-layout') +export class UmbUserGroupTableNameColumnLayoutElement extends LitElement { + @property({ type: Object, attribute: false }) + item!: UmbTableItem; + + @property({ attribute: false }) + value!: any; + + render() { + return html` + ${this.value.name} + `; + } +} + +export default UmbUserGroupTableNameColumnLayoutElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-group-table-name-column-layout': UmbUserGroupTableNameColumnLayoutElement; + } +} From e045b6bbbbca32e2b12a68c3c9e024ae4b5514c1 Mon Sep 17 00:00:00 2001 From: Filip Bech-Larsen Date: Wed, 12 Oct 2022 13:53:08 +0200 Subject: [PATCH 94/98] Content in the render-method --- .../dashboard-settings-about.element.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.element.ts index 2a4ba7f8a0..11e8ce93bf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.element.ts @@ -9,7 +9,16 @@ export class UmbDashboardSettingsAboutElement extends LitElement { render() { return html` -

Settings

+

Start here

+

This section contains the building blocks for your Umbraco site. Follow the below links to find out more about working with the items in the Settings section.

+

Find out more:

+
`; } From 1d730c06d5f592e5915da95d6ad4a551ab0e3a77 Mon Sep 17 00:00:00 2001 From: Filip Bech-Larsen Date: Wed, 12 Oct 2022 13:58:54 +0200 Subject: [PATCH 95/98] Rename to settings->welcome --- .../dashboard-settings-about.stories.ts | 15 --------------- .../dashboard-settings-welcome.element.ts} | 8 ++++---- .../dashboard-settings-welcome.stories.ts | 15 +++++++++++++++ .../src/temp-internal-manifests.ts | 12 ++++++------ 4 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.stories.ts rename src/Umbraco.Web.UI.Client/src/backoffice/dashboards/{settings-about/dashboard-settings-about.element.ts => settings-welcome/dashboard-settings-welcome.element.ts} (85%) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.stories.ts deleted file mode 100644 index 5f0b1c126d..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.stories.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Meta, Story } from '@storybook/web-components'; -import { html } from 'lit-html'; - -import type { UmbDashboardSettingsAboutElement } from './dashboard-settings-about.element'; -import './dashboard-settings-about.element'; - -export default { - title: 'Dashboards/Settings About', - component: 'umb-dashboard-settings-about', - id: 'umb-dashboard-settings-about', -} as Meta; - -export const AAAOverview: Story = () => - html` `; -AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.element.ts similarity index 85% rename from src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.element.ts index 11e8ce93bf..63fbb3ac21 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-about/dashboard-settings-about.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.element.ts @@ -2,8 +2,8 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement } from 'lit'; import { customElement } from 'lit/decorators.js'; -@customElement('umb-dashboard-settings-about') -export class UmbDashboardSettingsAboutElement extends LitElement { +@customElement('umb-dashboard-settings-welcome') +export class UmbDashboardSettingsWelcomeElement extends LitElement { static styles = [UUITextStyles, css``]; render() { @@ -24,9 +24,9 @@ export class UmbDashboardSettingsAboutElement extends LitElement { } } -export default UmbDashboardSettingsAboutElement; +export default UmbDashboardSettingsWelcomeElement; declare global { interface HTMLElementTagNameMap { - 'umb-dashboard-settings-about': UmbDashboardSettingsAboutElement; + 'umb-dashboard-settings-welcome': UmbDashboardSettingsWelcomeElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts new file mode 100644 index 0000000000..64d8a81c25 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts @@ -0,0 +1,15 @@ +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; + +import type { UmbDashboardSettingsWelcomeElement } from './dashboard-settings-welcome.element'; +import './dashboard-settings-welcome.element'; + +export default { + title: 'Dashboards/Settings Welcome', + component: 'umb-dashboard-settings-welcome', + id: 'umb-dashboard-settings-welcome', +} as Meta; + +export const AAAOverview: Story = () => + html` `; +AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index bc579440a0..08c748790c 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -89,14 +89,14 @@ export const internalManifests: Array Promise import('./backoffice/dashboards/settings-about/dashboard-settings-about.element'), + alias: 'Umb.Dashboard.SettingsWelcome', + name: 'Welcome Settings Dashboard', + elementName: 'umb-dashboard-settings-welcome', + loader: () => import('./backoffice/dashboards/settings-welcome/dashboard-settings-welcome.element'), meta: { - label: 'About', + label: 'Welcome', sections: ['Umb.Section.Settings'], - pathname: 'about', // TODO: how to we want to support pretty urls? + pathname: 'welcome', // TODO: how to we want to support pretty urls? weight: 10, }, }, From 4ebcb7061539625f5ff485c8f1dafa55431aa8d2 Mon Sep 17 00:00:00 2001 From: Filip Bech-Larsen Date: Wed, 12 Oct 2022 14:07:49 +0200 Subject: [PATCH 96/98] fix typo --- .../settings-welcome/dashboard-settings-welcome.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts index 64d8a81c25..a6b3b2a257 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.stories.ts @@ -11,5 +11,5 @@ export default { } as Meta; export const AAAOverview: Story = () => - html` `; + html` `; AAAOverview.storyName = 'Overview'; From 69f902574c439ec627f279145ac2659aea642c04 Mon Sep 17 00:00:00 2001 From: Filip Bech-Larsen Date: Wed, 12 Oct 2022 14:09:34 +0200 Subject: [PATCH 97/98] Add basic test --- .../dashboard-settings-welcome.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.test.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.test.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.test.ts new file mode 100644 index 0000000000..d2db4039cc --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/settings-welcome/dashboard-settings-welcome.test.ts @@ -0,0 +1,20 @@ +import { expect, fixture, html } from '@open-wc/testing'; + +import { defaultA11yConfig } from '../../../core/helpers/chai'; +import { UmbDashboardSettingsWelcomeElement } from './dashboard-settings-welcome.element'; + +describe('UmbDashboardSettingsWelcomeElement', () => { + let element: UmbDashboardSettingsWelcomeElement; + + beforeEach(async () => { + element = await fixture(html``); + }); + + it('is defined with its own instance', () => { + expect(element).to.be.instanceOf(UmbDashboardSettingsWelcomeElement); + }); + + it('passes the a11y audit', async () => { + await expect(element).to.be.accessible(defaultA11yConfig); + }); +}); From 35d9c9ce94e264990704b744fe3b4c472e555c74 Mon Sep 17 00:00:00 2001 From: Filip Bech-Larsen Date: Wed, 12 Oct 2022 14:33:32 +0200 Subject: [PATCH 98/98] stupid merge error --- src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts index c020067548..b0a99190ff 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests/index.ts @@ -94,7 +94,7 @@ export const internalManifests: Array Promise import('./backoffice/dashboards/settings-welcome/dashboard-settings-welcome.element'), + loader: () => import('../backoffice/dashboards/settings-welcome/dashboard-settings-welcome.element'), meta: { label: 'Welcome', sections: ['Umb.Section.Settings'],