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
This commit is contained in:
Mads Rasmussen
2025-10-23 14:43:49 +02:00
committed by GitHub
parent 1d8cadbeee
commit e482976a9d
8 changed files with 444 additions and 321 deletions

View File

@@ -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<UmbExtensionManifest> = [
@@ -30,4 +31,5 @@ export const manifests: Array<UmbExtensionManifest> = [
},
],
},
...viewManifests,
];

View File

@@ -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`
<umb-entity-detail-workspace-editor class="uui-text" back-path=${UMB_USER_GROUP_ROOT_WORKSPACE_PATH}>
${this.#renderHeader()} ${this.#renderMain()}
</umb-entity-detail-workspace-editor>
`;
#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`
<umb-entity-detail-workspace-editor .backPath=${UMB_USER_GROUP_ROOT_WORKSPACE_PATH}>
${this.#renderHeader()}
</umb-entity-detail-workspace-editor>
`;
}
#renderHeader() {
@@ -219,118 +100,12 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
`;
}
#renderMain() {
if (!this._unique) return nothing;
return html`
<div id="main">
<umb-stack>
<uui-box>
<div slot="headline"><umb-localize key="user_assignAccess"></umb-localize></div>
<umb-property-layout
label=${this.localize.term('main_sections')}
description=${this.localize.term('user_sectionsHelp')}>
<umb-input-section
slot="editor"
.selection=${this._sections}
@change=${this.#onSectionsChange}></umb-input-section>
</umb-property-layout>
${this.#renderLanguageAccess()} ${this.#renderDocumentAccess()} ${this.#renderMediaAccess()}
</uui-box>
${this.#renderPermissionGroups()}
</umb-stack>
</div>
`;
}
#renderLanguageAccess() {
return html`
<umb-property-layout
label=${this.localize.term('treeHeaders_languages')}
description=${this.localize.term('user_languagesHelp')}>
<div slot="editor">
<uui-toggle
style="margin-bottom: var(--uui-size-space-3);"
label="${this.localize.term('user_allowAccessToAllLanguages')}"
.checked=${this._hasAccessToAllLanguages}
@change=${this.#onAllowAllLanguagesChange}></uui-toggle>
${this._hasAccessToAllLanguages === false
? html`
<umb-input-language
.selection=${this._languages}
@change=${this.#onLanguagePermissionChange}></umb-input-language>
`
: nothing}
</div>
</umb-property-layout>
`;
}
#renderDocumentAccess() {
return html`
<umb-property-layout
label=${this.localize.term('defaultdialogs_selectContentStartNode')}
description=${this.localize.term('user_startnodehelp')}>
<div slot="editor">
<uui-toggle
style="margin-bottom: var(--uui-size-space-3);"
label="${this.localize.term('user_allowAccessToAllDocuments')}"
.checked=${this._documentRootAccess}
@change=${this.#onAllowAllDocumentsChange}></uui-toggle>
</div>
${this._documentRootAccess === false
? html`
<umb-input-document
slot="editor"
max="1"
.selection=${this._documentStartNode?.unique ? [this._documentStartNode.unique] : []}
@change=${this.#onDocumentStartNodeChange}></umb-input-document>
`
: nothing}
</umb-property-layout>
`;
}
#renderMediaAccess() {
return html`
<umb-property-layout
label=${this.localize.term('defaultdialogs_selectMediaStartNode')}
description=${this.localize.term('user_mediastartnodehelp')}>
<div slot="editor">
<uui-toggle
style="margin-bottom: var(--uui-size-space-3);"
label="${this.localize.term('user_allowAccessToAllMedia')}"
.checked=${this._mediaRootAccess}
@change=${this.#onAllowAllMediaChange}></uui-toggle>
</div>
${this._mediaRootAccess === false
? html`
<umb-input-media
slot="editor"
max="1"
.selection=${this._mediaStartNode?.unique ? [this._mediaStartNode.unique] : []}
@change=${this.#onMediaStartNodeChange}></umb-input-media>
`
: nothing}
</umb-property-layout>
`;
}
#renderPermissionGroups() {
return html`<umb-user-group-entity-type-permission-groups></umb-user-group-entity-type-permission-groups> `;
}
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%;
}
`,
];
}

View File

@@ -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<UmbExtensionManifest> = [
{
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,
},
],
},
];

View File

@@ -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`
<div id="main">
<umb-stack>
<uui-box>
<div slot="headline"><umb-localize key="user_assignAccess"></umb-localize></div>
<umb-property-layout
label=${this.localize.term('main_sections')}
description=${this.localize.term('user_sectionsHelp')}>
<umb-input-section
slot="editor"
.selection=${this._sections}
@change=${this.#onSectionsChange}></umb-input-section>
</umb-property-layout>
${this.#renderLanguageAccess()} ${this.#renderDocumentAccess()} ${this.#renderMediaAccess()}
</uui-box>
${this.#renderPermissionGroups()}
</umb-stack>
</div>
`;
}
#renderLanguageAccess() {
return html`
<umb-property-layout
label=${this.localize.term('treeHeaders_languages')}
description=${this.localize.term('user_languagesHelp')}>
<div slot="editor">
<uui-toggle
style="margin-bottom: var(--uui-size-space-3);"
label="${this.localize.term('user_allowAccessToAllLanguages')}"
.checked=${this._hasAccessToAllLanguages}
@change=${this.#onAllowAllLanguagesChange}></uui-toggle>
${this._hasAccessToAllLanguages === false
? html`
<umb-input-language
.selection=${this._languages}
@change=${this.#onLanguagePermissionChange}></umb-input-language>
`
: nothing}
</div>
</umb-property-layout>
`;
}
#renderDocumentAccess() {
return html`
<umb-property-layout
label=${this.localize.term('defaultdialogs_selectContentStartNode')}
description=${this.localize.term('user_startnodehelp')}>
<div slot="editor">
<uui-toggle
style="margin-bottom: var(--uui-size-space-3);"
label="${this.localize.term('user_allowAccessToAllDocuments')}"
.checked=${this._documentRootAccess}
@change=${this.#onAllowAllDocumentsChange}></uui-toggle>
</div>
${this._documentRootAccess === false
? html`
<umb-input-document
slot="editor"
max="1"
.selection=${this._documentStartNode?.unique ? [this._documentStartNode.unique] : []}
@change=${this.#onDocumentStartNodeChange}></umb-input-document>
`
: nothing}
</umb-property-layout>
`;
}
#renderMediaAccess() {
return html`
<umb-property-layout
label=${this.localize.term('defaultdialogs_selectMediaStartNode')}
description=${this.localize.term('user_mediastartnodehelp')}>
<div slot="editor">
<uui-toggle
style="margin-bottom: var(--uui-size-space-3);"
label="${this.localize.term('user_allowAccessToAllMedia')}"
.checked=${this._mediaRootAccess}
@change=${this.#onAllowAllMediaChange}></uui-toggle>
</div>
${this._mediaRootAccess === false
? html`
<umb-input-media
slot="editor"
max="1"
.selection=${this._mediaStartNode?.unique ? [this._mediaStartNode.unique] : []}
@change=${this.#onMediaStartNodeChange}></umb-input-media>
`
: nothing}
</umb-property-layout>
`;
}
#renderPermissionGroups() {
return html`<umb-user-group-entity-type-permission-groups></umb-user-group-entity-type-permission-groups> `;
}
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;
}
}

View File

@@ -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<UmbExtensionManifest> = [
{
@@ -31,4 +32,5 @@ export const manifests: Array<UmbExtensionManifest> = [
},
],
},
...viewManifests,
];

View File

@@ -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`
<umb-entity-detail-workspace-editor class="uui-text" .backPath=${UMB_USER_ROOT_WORKSPACE_PATH}>
<umb-entity-detail-workspace-editor .backPath=${UMB_USER_ROOT_WORKSPACE_PATH}>
<umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable>
${this._user
? html`<div id="main">
<div id="left-column">${this.#renderLeftColumn()}</div>
<div id="right-column">${this.#renderRightColumn()}</div>
</div>`
: nothing}
</umb-entity-detail-workspace-editor>
`;
}
#renderLeftColumn() {
return html`
<umb-stack>
<umb-user-workspace-profile-settings></umb-user-workspace-profile-settings>
<umb-user-workspace-assign-access></umb-user-workspace-assign-access>
<umb-user-workspace-access></umb-user-workspace-access>
</umb-stack>
`;
}
#renderRightColumn() {
return html`
<umb-stack look="compact">
<umb-user-workspace-avatar></umb-user-workspace-avatar>
<umb-user-workspace-info></umb-user-workspace-info>
<umb-user-workspace-client-credentials></umb-user-workspace-client-credentials>
</umb-stack>
`;
}
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);
}
`,
];
}

View File

@@ -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<UmbExtensionManifest> = [
{
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,
},
],
},
];

View File

@@ -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`<div id="main">
<div id="left-column">${this.#renderLeftColumn()}</div>
<div id="right-column">${this.#renderRightColumn()}</div>
</div>`
: nothing}
`;
}
#renderLeftColumn() {
return html`
<umb-stack>
<umb-user-workspace-profile-settings></umb-user-workspace-profile-settings>
<umb-user-workspace-assign-access></umb-user-workspace-assign-access>
<umb-user-workspace-access></umb-user-workspace-access>
</umb-stack>
`;
}
#renderRightColumn() {
return html`
<umb-stack look="compact">
<umb-user-workspace-avatar></umb-user-workspace-avatar>
<umb-user-workspace-info></umb-user-workspace-info>
<umb-user-workspace-client-credentials></umb-user-workspace-client-credentials>
</umb-stack>
`;
}
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;
}
}