From e482976a9d218b49a7f7712ddb5498fc841ff680 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 23 Oct 2025 14:43:49 +0200 Subject: [PATCH] User And User Group Workspace: Make views extendable (#20548) (#20617) * implement user details as a workspace view * register user group details as a workspace view --- .../workspace/user-group/manifests.ts | 2 + .../user-group-workspace-editor.element.ts | 269 ++--------------- .../workspace/user-group/views/manifests.ts | 23 ++ ...er-group-details-workspace-view.element.ts | 275 ++++++++++++++++++ .../user/user/workspace/user/manifests.ts | 2 + .../user/user-workspace-editor.element.ts | 73 +---- .../user/workspace/user/views/manifests.ts | 23 ++ .../user-details-workspace-view.element.ts | 98 +++++++ 8 files changed, 444 insertions(+), 321 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/user-group-details-workspace-view.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/user-details-workspace-view.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts index 13c3dfb213..ea9c5b869f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/manifests.ts @@ -1,4 +1,5 @@ import { UMB_USER_GROUP_WORKSPACE_ALIAS } from './constants.js'; +import { manifests as viewManifests } from './views/manifests.js'; import { UmbSubmitWorkspaceAction, UMB_WORKSPACE_CONDITION_ALIAS } from '@umbraco-cms/backoffice/workspace'; export const manifests: Array = [ @@ -30,4 +31,5 @@ export const manifests: Array = [ }, ], }, + ...viewManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts index cbbad3824f..08aeea4024 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/user-group-workspace-editor.element.ts @@ -1,27 +1,18 @@ -import type { UmbUserGroupDetailModel } from '../../types.js'; import { UMB_USER_GROUP_ROOT_WORKSPACE_PATH } from '../../paths.js'; +import type { UmbUserGroupDetailModel } from '../../types.js'; import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from './user-group-workspace.context-token.js'; -import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; -import { css, html, nothing, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import { UmbLitElement, umbFocus } from '@umbraco-cms/backoffice/lit-element'; -import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { UmbInputSectionElement } from '@umbraco-cms/backoffice/section'; -import type { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; -import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; -import type { UmbInputLanguageElement } from '@umbraco-cms/backoffice/language'; -import { UMB_ICON_PICKER_MODAL } from '@umbraco-cms/backoffice/icon'; import type { UmbInputWithAliasElement } from '@umbraco-cms/backoffice/components'; - -import './components/user-group-entity-type-permission-groups.element.js'; +import { css, html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; +import { UMB_ICON_PICKER_MODAL } from '@umbraco-cms/backoffice/icon'; +import { umbFocus, UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { umbOpenModal } from '@umbraco-cms/backoffice/modal'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @customElement('umb-user-group-workspace-editor') export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @state() private _isNew?: boolean = false; - @state() - private _unique?: UmbUserGroupDetailModel['unique']; - @state() private _name?: UmbUserGroupDetailModel['name']; @@ -34,41 +25,19 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @state() private _icon?: UmbUserGroupDetailModel['icon']; - @state() - private _sections: UmbUserGroupDetailModel['sections'] = []; - - @state() - private _languages: UmbUserGroupDetailModel['languages'] = []; - - @state() - private _hasAccessToAllLanguages: UmbUserGroupDetailModel['hasAccessToAllLanguages'] = false; - - @state() - private _documentStartNode?: UmbUserGroupDetailModel['documentStartNode']; - - @state() - private _documentRootAccess: UmbUserGroupDetailModel['documentRootAccess'] = false; - - @state() - private _mediaStartNode?: UmbUserGroupDetailModel['mediaStartNode']; - - @state() - private _mediaRootAccess: UmbUserGroupDetailModel['mediaRootAccess'] = false; - #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; constructor() { super(); - this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => { - this.#workspaceContext = instance; + this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (context) => { + this.#workspaceContext = context; this.#observeUserGroup(); }); } #observeUserGroup() { this.observe(this.#workspaceContext?.isNew, (value) => (this._isNew = value), '_observeIsNew'); - this.observe(this.#workspaceContext?.unique, (value) => (this._unique = value ?? undefined), '_observeUnique'); this.observe(this.#workspaceContext?.name, (value) => (this._name = value), '_observeName'); this.observe(this.#workspaceContext?.alias, (value) => (this._alias = value), '_observeAlias'); this.observe( @@ -77,102 +46,11 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { '_observeAliasCanBeChanged', ); this.observe(this.#workspaceContext?.icon, (value) => (this._icon = value), '_observeIcon'); - this.observe(this.#workspaceContext?.sections, (value) => (this._sections = value ?? []), '_observeSections'); - this.observe(this.#workspaceContext?.languages, (value) => (this._languages = value ?? []), '_observeLanguages'); - this.observe( - this.#workspaceContext?.hasAccessToAllLanguages, - (value) => (this._hasAccessToAllLanguages = value ?? false), - '_observeHasAccessToAllLanguages', - ); - - this.observe( - this.#workspaceContext?.documentRootAccess, - (value) => (this._documentRootAccess = value ?? false), - '_observeDocumentRootAccess', - ); - - this.observe( - this.#workspaceContext?.documentStartNode, - (value) => (this._documentStartNode = value), - '_observeDocumentStartNode', - ); - - this.observe( - this.#workspaceContext?.mediaRootAccess, - (value) => (this._mediaRootAccess = value ?? false), - '_observeMediaRootAccess', - ); - - this.observe( - this.#workspaceContext?.mediaStartNode, - (value) => (this._mediaStartNode = value), - '_observeMediaStartNode', - ); } - #onSectionsChange(event: UmbChangeEvent) { - event.stopPropagation(); - const target = event.target as UmbInputSectionElement; - // TODO make contexts method - this.#workspaceContext?.updateProperty('sections', target.selection); - } - - #onAllowAllLanguagesChange(event: UUIBooleanInputEvent) { - event.stopPropagation(); - const target = event.target; - // TODO make contexts method - this.#workspaceContext?.updateProperty('hasAccessToAllLanguages', target.checked); - } - - #onLanguagePermissionChange(event: UmbChangeEvent) { - event.stopPropagation(); - const target = event.target as UmbInputLanguageElement; - // TODO make contexts method - this.#workspaceContext?.updateProperty('languages', target.selection); - } - - #onAllowAllDocumentsChange(event: UUIBooleanInputEvent) { - event.stopPropagation(); - const target = event.target; - // TODO make contexts method - this.#workspaceContext?.updateProperty('documentRootAccess', target.checked); - this.#workspaceContext?.updateProperty('documentStartNode', null); - } - - #onDocumentStartNodeChange(event: CustomEvent) { - event.stopPropagation(); - // TODO: get back to this when documents have been decoupled from users. - // The event target is deliberately set to any to avoid an import cycle with documents. - const target = event.target as any; - const selected = target.selection?.[0]; - // TODO make contexts method - this.#workspaceContext?.updateProperty('documentStartNode', selected ? { unique: selected } : null); - } - - #onAllowAllMediaChange(event: UUIBooleanInputEvent) { - event.stopPropagation(); - const target = event.target; - // TODO make contexts method - this.#workspaceContext?.updateProperty('mediaRootAccess', target.checked); - this.#workspaceContext?.updateProperty('mediaStartNode', null); - } - - #onMediaStartNodeChange(event: CustomEvent) { - event.stopPropagation(); - // TODO: get back to this when media have been decoupled from users. - // The event target is deliberately set to any to avoid an import cycle with media. - const target = event.target as any; - const selected = target.selection?.[0]; - // TODO make contexts method - this.#workspaceContext?.updateProperty('mediaStartNode', selected ? { unique: selected } : null); - } - - override render() { - return html` - - ${this.#renderHeader()} ${this.#renderMain()} - - `; + #onNameAndAliasChange(event: InputEvent & { target: UmbInputWithAliasElement }) { + this.#workspaceContext?.updateProperty('name', event.target.value ?? ''); + this.#workspaceContext?.updateProperty('alias', event.target.alias ?? ''); } async #onIconClick() { @@ -193,9 +71,12 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { } } - #onNameAndAliasChange(event: InputEvent & { target: UmbInputWithAliasElement }) { - this.#workspaceContext?.updateProperty('name', event.target.value ?? ''); - this.#workspaceContext?.updateProperty('alias', event.target.alias ?? ''); + override render() { + return html` + + ${this.#renderHeader()} + + `; } #renderHeader() { @@ -219,118 +100,12 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { `; } - #renderMain() { - if (!this._unique) return nothing; - - return html` -
- - -
- - - - - - ${this.#renderLanguageAccess()} ${this.#renderDocumentAccess()} ${this.#renderMediaAccess()} -
- - ${this.#renderPermissionGroups()} -
-
- `; - } - - #renderLanguageAccess() { - return html` - -
- - - ${this._hasAccessToAllLanguages === false - ? html` - - ` - : nothing} -
-
- `; - } - - #renderDocumentAccess() { - return html` - -
- -
- - ${this._documentRootAccess === false - ? html` - - ` - : nothing} -
- `; - } - - #renderMediaAccess() { - return html` - -
- -
- - ${this._mediaRootAccess === false - ? html` - - ` - : nothing} -
- `; - } - - #renderPermissionGroups() { - return html` `; - } - static override styles = [ UmbTextStyles, css` :host { display: block; + width: 100%; height: 100%; } @@ -352,14 +127,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { flex: 1 1 auto; align-items: center; } - - #main { - padding: var(--uui-size-layout-1); - } - - uui-input { - width: 100%; - } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/manifests.ts new file mode 100644 index 0000000000..91bacd1501 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/manifests.ts @@ -0,0 +1,23 @@ +import { UMB_USER_GROUP_WORKSPACE_ALIAS } from '../constants.js'; +import { UMB_WORKSPACE_CONDITION_ALIAS } from '@umbraco-cms/backoffice/workspace'; + +export const manifests: Array = [ + { + type: 'workspaceView', + alias: 'Umb.WorkspaceView.UserGroup.Details', + name: 'User Group Details Workspace View', + element: () => import('./user-group-details-workspace-view.element.js'), + weight: 90, + meta: { + label: '#general_details', + pathname: 'details', + icon: 'edit', + }, + conditions: [ + { + alias: UMB_WORKSPACE_CONDITION_ALIAS, + match: UMB_USER_GROUP_WORKSPACE_ALIAS, + }, + ], + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/user-group-details-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/user-group-details-workspace-view.element.ts new file mode 100644 index 0000000000..1aaa43beb6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group/views/user-group-details-workspace-view.element.ts @@ -0,0 +1,275 @@ +import type { UmbUserGroupDetailModel } from '../../../types.js'; +import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from '../user-group-workspace.context-token.js'; +import type { UmbInputSectionElement } from '@umbraco-cms/backoffice/section'; +import type { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import type { UmbInputLanguageElement } from '@umbraco-cms/backoffice/language'; +import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/workspace'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; + +import '../components/user-group-entity-type-permission-groups.element.js'; + +@customElement('umb-user-group-details-workspace-view') +export class UmbUserGroupDetailsWorkspaceViewElement extends UmbLitElement implements UmbWorkspaceViewElement { + @state() + private _unique?: UmbUserGroupDetailModel['unique']; + + @state() + private _sections: UmbUserGroupDetailModel['sections'] = []; + + @state() + private _languages: UmbUserGroupDetailModel['languages'] = []; + + @state() + private _hasAccessToAllLanguages: UmbUserGroupDetailModel['hasAccessToAllLanguages'] = false; + + @state() + private _documentStartNode?: UmbUserGroupDetailModel['documentStartNode']; + + @state() + private _documentRootAccess: UmbUserGroupDetailModel['documentRootAccess'] = false; + + @state() + private _mediaStartNode?: UmbUserGroupDetailModel['mediaStartNode']; + + @state() + private _mediaRootAccess: UmbUserGroupDetailModel['mediaRootAccess'] = false; + + #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; + + constructor() { + super(); + + this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => { + this.#workspaceContext = instance; + this.#observeUserGroup(); + }); + } + + #observeUserGroup() { + this.observe(this.#workspaceContext?.unique, (value) => (this._unique = value ?? undefined), '_observeUnique'); + this.observe(this.#workspaceContext?.sections, (value) => (this._sections = value ?? []), '_observeSections'); + this.observe(this.#workspaceContext?.languages, (value) => (this._languages = value ?? []), '_observeLanguages'); + this.observe( + this.#workspaceContext?.hasAccessToAllLanguages, + (value) => (this._hasAccessToAllLanguages = value ?? false), + '_observeHasAccessToAllLanguages', + ); + + this.observe( + this.#workspaceContext?.documentRootAccess, + (value) => (this._documentRootAccess = value ?? false), + '_observeDocumentRootAccess', + ); + + this.observe( + this.#workspaceContext?.documentStartNode, + (value) => (this._documentStartNode = value), + '_observeDocumentStartNode', + ); + + this.observe( + this.#workspaceContext?.mediaRootAccess, + (value) => (this._mediaRootAccess = value ?? false), + '_observeMediaRootAccess', + ); + + this.observe( + this.#workspaceContext?.mediaStartNode, + (value) => (this._mediaStartNode = value), + '_observeMediaStartNode', + ); + } + + #onSectionsChange(event: UmbChangeEvent) { + event.stopPropagation(); + const target = event.target as UmbInputSectionElement; + // TODO make contexts method + this.#workspaceContext?.updateProperty('sections', target.selection); + } + + #onAllowAllLanguagesChange(event: UUIBooleanInputEvent) { + event.stopPropagation(); + const target = event.target; + // TODO make contexts method + this.#workspaceContext?.updateProperty('hasAccessToAllLanguages', target.checked); + } + + #onLanguagePermissionChange(event: UmbChangeEvent) { + event.stopPropagation(); + const target = event.target as UmbInputLanguageElement; + // TODO make contexts method + this.#workspaceContext?.updateProperty('languages', target.selection); + } + + #onAllowAllDocumentsChange(event: UUIBooleanInputEvent) { + event.stopPropagation(); + const target = event.target; + // TODO make contexts method + this.#workspaceContext?.updateProperty('documentRootAccess', target.checked); + this.#workspaceContext?.updateProperty('documentStartNode', null); + } + + #onDocumentStartNodeChange(event: CustomEvent) { + event.stopPropagation(); + // TODO: get back to this when documents have been decoupled from users. + // The event target is deliberately set to any to avoid an import cycle with documents. + const target = event.target as any; + const selected = target.selection?.[0]; + // TODO make contexts method + this.#workspaceContext?.updateProperty('documentStartNode', selected ? { unique: selected } : null); + } + + #onAllowAllMediaChange(event: UUIBooleanInputEvent) { + event.stopPropagation(); + const target = event.target; + // TODO make contexts method + this.#workspaceContext?.updateProperty('mediaRootAccess', target.checked); + this.#workspaceContext?.updateProperty('mediaStartNode', null); + } + + #onMediaStartNodeChange(event: CustomEvent) { + event.stopPropagation(); + // TODO: get back to this when media have been decoupled from users. + // The event target is deliberately set to any to avoid an import cycle with media. + const target = event.target as any; + const selected = target.selection?.[0]; + // TODO make contexts method + this.#workspaceContext?.updateProperty('mediaStartNode', selected ? { unique: selected } : null); + } + + override render() { + if (!this._unique) return nothing; + + return html` +
+ + +
+ + + + + + ${this.#renderLanguageAccess()} ${this.#renderDocumentAccess()} ${this.#renderMediaAccess()} +
+ + ${this.#renderPermissionGroups()} +
+
+ `; + } + + #renderLanguageAccess() { + return html` + +
+ + + ${this._hasAccessToAllLanguages === false + ? html` + + ` + : nothing} +
+
+ `; + } + + #renderDocumentAccess() { + return html` + +
+ +
+ + ${this._documentRootAccess === false + ? html` + + ` + : nothing} +
+ `; + } + + #renderMediaAccess() { + return html` + +
+ +
+ + ${this._mediaRootAccess === false + ? html` + + ` + : nothing} +
+ `; + } + + #renderPermissionGroups() { + return html` `; + } + + static override styles = [ + UmbTextStyles, + css` + :host { + display: block; + height: 100%; + } + + #main { + padding: var(--uui-size-layout-1); + } + + uui-input { + width: 100%; + } + `, + ]; +} + +export { UmbUserGroupDetailsWorkspaceViewElement as element }; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-group-details-workspace-view': UmbUserGroupDetailsWorkspaceViewElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts index 850cee09f9..0dc237d293 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/manifests.ts @@ -1,6 +1,7 @@ import { UMB_USER_ENTITY_TYPE } from '../../entity.js'; import { UMB_USER_WORKSPACE_ALIAS } from './constants.js'; import { UMB_WORKSPACE_CONDITION_ALIAS, UmbSubmitWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; +import { manifests as viewManifests } from './views/manifests.js'; export const manifests: Array = [ { @@ -31,4 +32,5 @@ export const manifests: Array = [ }, ], }, + ...viewManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace-editor.element.ts index d0bf6b4cef..ffc11e434d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/user-workspace-editor.element.ts @@ -1,93 +1,26 @@ -import type { UmbUserDetailModel } from '../../index.js'; import { UMB_USER_ROOT_WORKSPACE_PATH } from '../../paths.js'; -import type { UmbUserWorkspaceContext } from './user-workspace.context.js'; -import { UMB_USER_WORKSPACE_CONTEXT } from './user-workspace.context-token.js'; -import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -// import local components. Theses are not meant to be used outside of this component. -import './components/user-workspace-profile-settings/user-workspace-profile-settings.element.js'; -import './components/user-workspace-access/user-workspace-access.element.js'; -import './components/user-workspace-info/user-workspace-info.element.js'; -import './components/user-workspace-avatar/user-workspace-avatar.element.js'; -import './components/user-workspace-client-credentials/user-workspace-client-credentials.element.js'; - @customElement('umb-user-workspace-editor') export class UmbUserWorkspaceEditorElement extends UmbLitElement { - @state() - private _user?: UmbUserDetailModel; - - #workspaceContext?: UmbUserWorkspaceContext; - - constructor() { - super(); - - this.consumeContext(UMB_USER_WORKSPACE_CONTEXT, (context) => { - this.#workspaceContext = context; - this.#observeUser(); - }); - } - - #observeUser() { - if (!this.#workspaceContext) return; - this.observe(this.#workspaceContext.data, (user) => (this._user = user), 'umbUserObserver'); - } - override render() { return html` - + - ${this._user - ? html`
-
${this.#renderLeftColumn()}
-
${this.#renderRightColumn()}
-
` - : nothing}
`; } - #renderLeftColumn() { - return html` - - - - - - `; - } - - #renderRightColumn() { - return html` - - - - - - `; - } - static override styles = [ UmbTextStyles, css` :host { display: block; + width: 100%; height: 100%; } - - #main { - display: grid; - grid-template-columns: 1fr 350px; - gap: var(--uui-size-layout-1); - padding: var(--uui-size-layout-1); - } - - #left-column { - display: flex; - flex-direction: column; - gap: var(--uui-size-space-4); - } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/manifests.ts new file mode 100644 index 0000000000..3e414288d5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/manifests.ts @@ -0,0 +1,23 @@ +import { UMB_USER_WORKSPACE_ALIAS } from '../constants.js'; +import { UMB_WORKSPACE_CONDITION_ALIAS } from '@umbraco-cms/backoffice/workspace'; + +export const manifests: Array = [ + { + type: 'workspaceView', + alias: 'Umb.WorkspaceView.User.Details', + name: 'User Details Workspace View', + element: () => import('./user-details-workspace-view.element.js'), + weight: 90, + meta: { + label: '#general_details', + pathname: 'details', + icon: 'edit', + }, + conditions: [ + { + alias: UMB_WORKSPACE_CONDITION_ALIAS, + match: UMB_USER_WORKSPACE_ALIAS, + }, + ], + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/user-details-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/user-details-workspace-view.element.ts new file mode 100644 index 0000000000..292639178b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user/views/user-details-workspace-view.element.ts @@ -0,0 +1,98 @@ +import { UMB_USER_WORKSPACE_CONTEXT } from '../user-workspace.context-token.js'; +import type { UmbUserWorkspaceContext } from '../user-workspace.context.js'; +import type { UmbUserDetailModel } from '../../../types.js'; +import { customElement, html, nothing, state, css } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/workspace'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; + +// import local components. Theses are not meant to be used outside of this component. +import '../components/user-workspace-profile-settings/user-workspace-profile-settings.element.js'; +import '../components/user-workspace-access/user-workspace-access.element.js'; +import '../components/user-workspace-info/user-workspace-info.element.js'; +import '../components/user-workspace-avatar/user-workspace-avatar.element.js'; +import '../components/user-workspace-client-credentials/user-workspace-client-credentials.element.js'; + +@customElement('umb-user-details-workspace-view') +export class UmbUserDetailsWorkspaceViewElement extends UmbLitElement implements UmbWorkspaceViewElement { + @state() + private _user?: UmbUserDetailModel; + + #workspaceContext?: UmbUserWorkspaceContext; + + constructor() { + super(); + + this.consumeContext(UMB_USER_WORKSPACE_CONTEXT, (context) => { + this.#workspaceContext = context; + this.#observeUser(); + }); + } + + #observeUser() { + if (!this.#workspaceContext) return; + this.observe(this.#workspaceContext.data, (user) => (this._user = user), 'umbUserObserver'); + } + + override render() { + return html` + ${this._user + ? html`
+
${this.#renderLeftColumn()}
+
${this.#renderRightColumn()}
+
` + : nothing} + `; + } + + #renderLeftColumn() { + return html` + + + + + + `; + } + + #renderRightColumn() { + return html` + + + + + + `; + } + + static override styles = [ + UmbTextStyles, + css` + :host { + display: block; + height: 100%; + } + + #main { + display: grid; + grid-template-columns: 1fr 350px; + gap: var(--uui-size-layout-1); + padding: var(--uui-size-layout-1); + } + + #left-column { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-4); + } + `, + ]; +} + +export { UmbUserDetailsWorkspaceViewElement as element }; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-details-workspace-view': UmbUserDetailsWorkspaceViewElement; + } +}