diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models.ts index bb559217ec..9b65a819dc 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models.ts @@ -385,6 +385,7 @@ key?: string | null export type CreateUserGroupRequestModel = { name: string +alias: string icon?: string | null sections: Array languages: Array @@ -395,6 +396,7 @@ mediaStartNode?: ReferenceByIdModel | null mediaRootAccess: boolean fallbackPermissions: Array permissions: Array +id?: string | null }; export type CreateUserRequestModel = { @@ -2496,6 +2498,7 @@ key: string export type UpdateUserGroupRequestModel = { name: string +alias: string icon?: string | null sections: Array languages: Array @@ -2570,10 +2573,12 @@ export type UserGroupItemResponseModel = { id: string name: string icon?: string | null +alias?: string | null }; export type UserGroupResponseModel = { name: string +alias: string icon?: string | null sections: Array languages: Array @@ -2585,7 +2590,8 @@ mediaRootAccess: boolean fallbackPermissions: Array permissions: Array id: string -isSystemGroup: boolean +isDeletable: boolean +aliasCanBeChanged: boolean }; export type UserInstallRequestModel = { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.data.ts index 10f4fcdda9..07cfdc57f7 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.data.ts @@ -6,6 +6,7 @@ export const data: Array = [ { id: 'user-group-administrators-id', name: 'Administrators', + alias: 'admin', icon: 'icon-medal', documentStartNode: { id: 'all-property-editors-document-id' }, fallbackPermissions: [ @@ -45,11 +46,13 @@ export const data: Array = [ hasAccessToAllLanguages: true, documentRootAccess: true, mediaRootAccess: true, - isSystemGroup: true, + aliasCanBeChanged: false, + isDeletable: false, }, { id: 'user-group-editors-id', name: 'Editors', + alias: 'editors', icon: 'icon-tools', documentStartNode: { id: 'all-property-editors-document-id' }, fallbackPermissions: [ @@ -73,11 +76,13 @@ export const data: Array = [ hasAccessToAllLanguages: true, documentRootAccess: true, mediaRootAccess: true, - isSystemGroup: true, + aliasCanBeChanged: true, + isDeletable: true, }, { id: 'user-group-sensitive-data-id', name: 'Sensitive data', + alias: 'sensitive-data', icon: 'icon-lock', documentStartNode: { id: 'all-property-editors-document-id' }, fallbackPermissions: [], @@ -87,11 +92,13 @@ export const data: Array = [ hasAccessToAllLanguages: true, documentRootAccess: true, mediaRootAccess: true, - isSystemGroup: true, + aliasCanBeChanged: false, + isDeletable: false, }, { id: 'user-group-translators-id', name: 'Translators', + alias: 'translators', icon: 'icon-globe', documentStartNode: { id: 'all-property-editors-document-id' }, fallbackPermissions: ['Umb.Document.Read', 'Umb.Document.Update'], @@ -101,11 +108,13 @@ export const data: Array = [ hasAccessToAllLanguages: true, documentRootAccess: true, mediaRootAccess: true, - isSystemGroup: true, + aliasCanBeChanged: true, + isDeletable: true, }, { id: 'user-group-writers-id', name: 'Writers', + alias: 'writers', icon: 'icon-edit', documentStartNode: { id: 'all-property-editors-document-id' }, fallbackPermissions: [ @@ -120,6 +129,7 @@ export const data: Array = [ hasAccessToAllLanguages: true, documentRootAccess: true, mediaRootAccess: true, - isSystemGroup: false, + aliasCanBeChanged: true, + isDeletable: true, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.db.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.db.ts index 29d72987dc..c6c9fc9bf5 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.db.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/user-group/user-group.db.ts @@ -60,12 +60,12 @@ const itemMapper = (item: UmbMockUserGroupModel): UserGroupItemResponseModel => const createMockMapper = (item: CreateUserGroupRequestModel): UmbMockUserGroupModel => { return { + alias: item.alias, documentRootAccess: item.documentRootAccess, documentStartNode: item.documentStartNode, hasAccessToAllLanguages: item.hasAccessToAllLanguages, icon: item.icon, id: UmbId.new(), - isSystemGroup: false, languages: item.languages, mediaRootAccess: item.mediaRootAccess, mediaStartNode: item.mediaStartNode, @@ -73,17 +73,19 @@ const createMockMapper = (item: CreateUserGroupRequestModel): UmbMockUserGroupMo fallbackPermissions: item.fallbackPermissions, permissions: item.permissions, sections: item.sections, + aliasCanBeChanged: true, + isDeletable: true, }; }; const detailResponseMapper = (item: UmbMockUserGroupModel): UserGroupResponseModel => { return { + alias: item.alias, documentRootAccess: item.documentRootAccess, documentStartNode: item.documentStartNode, hasAccessToAllLanguages: item.hasAccessToAllLanguages, icon: item.icon, id: item.id, - isSystemGroup: item.isSystemGroup, languages: item.languages, mediaRootAccess: item.mediaRootAccess, mediaStartNode: item.mediaStartNode, @@ -91,6 +93,8 @@ const detailResponseMapper = (item: UmbMockUserGroupModel): UserGroupResponseMod fallbackPermissions: item.fallbackPermissions, permissions: item.permissions, sections: item.sections, + aliasCanBeChanged: item.aliasCanBeChanged, + isDeletable: item.isDeletable, }; }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-with-alias/input-with-alias.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-with-alias/input-with-alias.element.ts index fb75b79bdf..0e00a714f6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-with-alias/input-with-alias.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-with-alias/input-with-alias.element.ts @@ -30,14 +30,14 @@ export class UmbInputWithAliasElement extends UmbFormControlMixin(UmbLit return this.shadowRoot?.querySelector('uui-input')?.focus(); } - #onNameChange(event: UUIInputEvent) { - if (event instanceof UUIInputEvent) { - const target = event.composedPath()[0] as UUIInputElement; + #onNameChange(e: UUIInputEvent) { + if (e instanceof UUIInputEvent) { + const target = e.composedPath()[0] as UUIInputElement; if (typeof target?.value === 'string') { const oldName = this.value; const oldAlias = this.alias ?? ''; - this.value = event.target.value.toString(); + this.value = e.target.value.toString(); if (this.autoGenerateAlias && this._aliasLocked) { // If locked we will update the alias, but only if it matches the generated alias of the old name [NL] const expectedOldAlias = generateAlias(oldName ?? ''); @@ -52,10 +52,11 @@ export class UmbInputWithAliasElement extends UmbFormControlMixin(UmbLit } #onAliasChange(e: UUIInputEvent) { - if (event instanceof UUIInputEvent) { - const target = event.composedPath()[0] as UUIInputElement; + if (e instanceof UUIInputEvent) { + const target = e.composedPath()[0] as UUIInputElement; if (typeof target?.value === 'string') { this.alias = target.value; + console.log(this.alias); this.dispatchEvent(new UmbChangeEvent()); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.server.data-source.ts index fa5f6d9b0c..360b8a68a2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/repository/user-group-collection.server.data-source.ts @@ -33,20 +33,22 @@ export class UmbUserGroupCollectionServerDataSource implements UmbCollectionData if (data) { const mappedItems = data.items.map((item) => { const userGroup: UmbUserGroupDetailModel = { - unique: item.id, - entityType: UMB_USER_GROUP_ENTITY_TYPE, - isSystemGroup: item.isSystemGroup, - name: item.name, - icon: item.icon || null, - sections: item.sections, - languages: item.languages, - hasAccessToAllLanguages: item.hasAccessToAllLanguages, - documentStartNode: item.documentStartNode ? { unique: item.documentStartNode.id } : null, + alias: item.alias, + aliasCanBeChanged: item.aliasCanBeChanged, documentRootAccess: item.documentRootAccess, - mediaStartNode: item.mediaStartNode ? { unique: item.mediaStartNode.id } : null, - mediaRootAccess: item.mediaRootAccess, + documentStartNode: item.documentStartNode ? { unique: item.documentStartNode.id } : null, + entityType: UMB_USER_GROUP_ENTITY_TYPE, fallbackPermissions: item.fallbackPermissions, + hasAccessToAllLanguages: item.hasAccessToAllLanguages, + icon: item.icon || null, + isDeletable: item.isDeletable, + languages: item.languages, + mediaRootAccess: item.mediaRootAccess, + mediaStartNode: item.mediaStartNode ? { unique: item.mediaStartNode.id } : null, + name: item.name, permissions: item.permissions, + sections: item.sections, + unique: item.id, }; return userGroup; }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/detail/user-group-detail.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/detail/user-group-detail.server.data-source.ts index ec1fbf77d8..aadae83164 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/detail/user-group-detail.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/repository/detail/user-group-detail.server.data-source.ts @@ -36,20 +36,22 @@ export class UmbUserGroupServerDataSource implements UmbDetailDataSource; - languages: Array; - hasAccessToAllLanguages: boolean; - documentStartNode: { unique: string } | null; + alias: string; + aliasCanBeChanged: boolean; documentRootAccess: boolean; - mediaStartNode: { unique: string } | null; - mediaRootAccess: boolean; + documentStartNode: { unique: string } | null; + entityType: UmbUserGroupEntityType; fallbackPermissions: Array; + hasAccessToAllLanguages: boolean; + icon: string | null; + isDeletable: boolean; + languages: Array; + mediaRootAccess: boolean; + mediaStartNode: { unique: string } | null; + name: string; // TODO: add type permissions: Array; + sections: Array; + unique: string; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts index 462d9c9f0c..1ed416c7bd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace-editor.element.ts @@ -1,8 +1,7 @@ import type { UmbUserGroupDetailModel } from '../index.js'; import { UMB_USER_GROUP_ENTITY_TYPE } from '../index.js'; import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from './user-group-workspace.context-token.js'; -import type { UUIBooleanInputEvent, UUIInputElement } from '@umbraco-cms/backoffice/external/uui'; -import { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +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'; @@ -15,15 +14,25 @@ import type { UmbInputLanguageElement } from '@umbraco-cms/backoffice/language'; import './components/user-group-entity-user-permission-list.element.js'; import './components/user-group-granular-permission-list.element.js'; +import type { UmbInputWithAliasElement } from '@umbraco-cms/backoffice/components'; @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']; + @state() + private _alias?: UmbUserGroupDetailModel['alias']; + + @state() + private _aliasCanBeChanged?: UmbUserGroupDetailModel['aliasCanBeChanged'] = true; + @state() private _icon: UmbUserGroupDetailModel['icon'] = null; @@ -61,8 +70,15 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { #observeUserGroup() { if (!this.#workspaceContext) return; + this.observe(this.#workspaceContext.isNew, (value) => (this._isNew = value), '_observeIsNew'); this.observe(this.#workspaceContext.unique, (value) => (this._unique = value), '_observeUnique'); this.observe(this.#workspaceContext.name, (value) => (this._name = value), '_observeName'); + this.observe(this.#workspaceContext.alias, (value) => (this._alias = value), '_observeAlias'); + this.observe( + this.#workspaceContext.aliasCanBeChanged, + (value) => (this._aliasCanBeChanged = value), + '_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'); @@ -150,16 +166,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext?.updateProperty('mediaStartNode', selected ? { unique: selected } : null); } - #onNameChange(event: UUIInputEvent) { - if (event instanceof UUIInputEvent) { - const target = event.composedPath()[0] as UUIInputElement; - - if (typeof target?.value === 'string') { - this.#workspaceContext?.updateProperty('name', target.value); - } - } - } - render() { if (!this._unique) return nothing; @@ -196,19 +202,27 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { }); } + #onNameAndAliasChange(event: InputEvent & { target: UmbInputWithAliasElement }) { + this.#workspaceContext?.updateProperty('name', event.target.value ?? ''); + this.#workspaceContext?.updateProperty('alias', event.target.alias ?? ''); + } + #renderHeader() { return html` `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context.ts index b39828ffe4..3d9cea828f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/workspace/user-group-workspace.context.ts @@ -23,6 +23,8 @@ export class UmbUserGroupWorkspaceContext readonly unique = this.#data.asObservablePart((data) => data?.unique); readonly name = this.#data.asObservablePart((data) => data?.name || ''); + readonly alias = this.#data.asObservablePart((data) => data?.alias || ''); + readonly aliasCanBeChanged = this.#data.asObservablePart((data) => data?.aliasCanBeChanged); readonly icon = this.#data.asObservablePart((data) => data?.icon || null); readonly sections = this.#data.asObservablePart((data) => data?.sections || []); readonly languages = this.#data.asObservablePart((data) => data?.languages || []);