From c12fa8f7d1dc3237b60b85f8f7a1a465e6b5c52a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 12:24:09 +0200 Subject: [PATCH 01/97] set up new permission extension model --- src/packages/core/extension-registry/models/index.ts | 3 +++ .../extension-registry/models/permission.model.ts | 12 ++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/packages/core/extension-registry/models/permission.model.ts diff --git a/src/packages/core/extension-registry/models/index.ts b/src/packages/core/extension-registry/models/index.ts index ff6dcfd29c..85e77b5622 100644 --- a/src/packages/core/extension-registry/models/index.ts +++ b/src/packages/core/extension-registry/models/index.ts @@ -28,6 +28,7 @@ import type { ManifestWorkspace } from './workspace.model.js'; import type { ManifestWorkspaceAction } from './workspace-action.model.js'; import type { ManifestWorkspaceEditorView } from './workspace-editor-view.model.js'; import type { ManifestWorkspaceViewCollection } from './workspace-view-collection.model.js'; +import type { ManifestPermission } from './permission.model.js'; import type { ManifestBase, ManifestBundle, @@ -65,6 +66,7 @@ export * from './workspace-action.model.js'; export * from './workspace-view-collection.model.js'; export * from './workspace-editor-view.model.js'; export * from './workspace.model.js'; +export * from './permission.model.js'; export type ManifestTypes = | ManifestBundle @@ -106,4 +108,5 @@ export type ManifestTypes = | ManifestWorkspaceAction | ManifestWorkspaceEditorView | ManifestWorkspaceViewCollection + | ManifestPermission | ManifestBase; diff --git a/src/packages/core/extension-registry/models/permission.model.ts b/src/packages/core/extension-registry/models/permission.model.ts new file mode 100644 index 0000000000..0b54e1f925 --- /dev/null +++ b/src/packages/core/extension-registry/models/permission.model.ts @@ -0,0 +1,12 @@ +import type { ManifestBase } from '@umbraco-cms/backoffice/extension-api'; + +export interface ManifestPermission extends ManifestBase { + type: 'permission'; + meta: MetaPermission; +} + +export interface MetaPermission { + label: string; + description?: string; + group?: string; +} From 388e7ae3bfb9b0368025a128ba01619dfc777b28 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 12:24:27 +0200 Subject: [PATCH 02/97] register first document permissions --- src/packages/documents/manifests.ts | 2 ++ .../documents/permissions/manifests.ts | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/packages/documents/permissions/manifests.ts diff --git a/src/packages/documents/manifests.ts b/src/packages/documents/manifests.ts index 17fc8e51b5..49c966d8ac 100644 --- a/src/packages/documents/manifests.ts +++ b/src/packages/documents/manifests.ts @@ -4,6 +4,7 @@ import { manifests as contentMenuManifest } from './menu.manifests.js'; import { manifests as documentBlueprintManifests } from './document-blueprints/manifests.js'; import { manifests as documentTypeManifests } from './document-types/manifests.js'; import { manifests as documentManifests } from './documents/manifests.js'; +import { manifests as permissionManifests } from './permissions/manifests.js'; export const manifests = [ ...dashboardManifests, @@ -12,4 +13,5 @@ export const manifests = [ ...documentBlueprintManifests, ...documentTypeManifests, ...documentManifests, + ...permissionManifests, ]; diff --git a/src/packages/documents/permissions/manifests.ts b/src/packages/documents/permissions/manifests.ts new file mode 100644 index 0000000000..151e17d6db --- /dev/null +++ b/src/packages/documents/permissions/manifests.ts @@ -0,0 +1,33 @@ +import type { ManifestPermission } from '@umbraco-cms/backoffice/extension-registry'; + +const permissions: Array = [ + { + type: 'permission', + alias: 'Umb.Permission.BrowseDocument', + name: 'Read Document Permission', + meta: { + label: 'Read', + description: 'Allow access to browse documents', + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.CreateDocumentBlueprint', + name: 'Create Document Blueprint Permission', + meta: { + label: 'Create Content Template', + description: 'Allow access to create a Content Template' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.DeleteDocument', + name: 'Delete Document Permission', + meta: { + label: 'Delete', + description: 'Allow access to create a Content Template' + }, + }, +]; + +export const manifests = [...permissions]; From e500b962b3117ee122cf1ca5b2c3586a63ec8e32 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 13:40:19 +0200 Subject: [PATCH 03/97] temp render registered permissions --- .../user-group-workspace-editor.element.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 7fa3faf4ed..6bebbc75de 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -4,7 +4,6 @@ import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffic // TODO: import from package when available //import { UmbUserInputElement } from '../../users/components/user-input/user-input.element.js'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; - import { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_CONFIRM_MODAL, @@ -12,6 +11,9 @@ import { UmbModalManagerContext, } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbExtensionElementController } from '@umbraco-cms/backoffice/extension-api'; +import { ManifestPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; + @customElement('umb-user-group-workspace-editor') export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @@ -21,6 +23,9 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @state() private _userKeys?: Array; + @state() + private _userPermissions: Array = []; + #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; #modalContext?: UmbModalManagerContext; @@ -31,6 +36,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext = instance; this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); this.observe(this.#workspaceContext.userIds, (userKeys) => (this._userKeys = userKeys)); + this.observe(umbExtensionsRegistry.extensionsOfType('permission'), (permissionManifests) => this._userPermissions = permissionManifests); }); this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { @@ -105,6 +111,16 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { `; } + #renderPermission(permissionManifest: ManifestPermission) { + return html`
+ +
+
${ permissionManifest.meta.label }
+ ${ permissionManifest.meta.description } +
+
`; + } + #renderLeftColumn() { if (!this._userGroup) return nothing; @@ -130,7 +146,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
Default Permissions
- PERMISSIONS NOT IMPLEMENTED YET + ${ this._userPermissions.map((permission) => this.#renderPermission(permission)) }
From 3dc8d82d98935393bc21f179e6a80a285d8580a5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 13:40:51 +0200 Subject: [PATCH 04/97] remove unused import --- .../user-groups/workspace/user-group-workspace-editor.element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 6bebbc75de..f2f063bf62 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -11,7 +11,6 @@ import { UmbModalManagerContext, } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { UmbExtensionElementController } from '@umbraco-cms/backoffice/extension-api'; import { ManifestPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; From 5ea9b08f3e3ee83aadb0f8f9eb6db647bc77184c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 14:01:57 +0200 Subject: [PATCH 05/97] add more document permissions --- .../documents/permissions/manifests.ts | 71 +++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/src/packages/documents/permissions/manifests.ts b/src/packages/documents/permissions/manifests.ts index 151e17d6db..6b22f6e7e8 100644 --- a/src/packages/documents/permissions/manifests.ts +++ b/src/packages/documents/permissions/manifests.ts @@ -3,7 +3,7 @@ import type { ManifestPermission } from '@umbraco-cms/backoffice/extension-regis const permissions: Array = [ { type: 'permission', - alias: 'Umb.Permission.BrowseDocument', + alias: 'Umb.Permission.Document.Browse', name: 'Read Document Permission', meta: { label: 'Read', @@ -12,7 +12,7 @@ const permissions: Array = [ }, { type: 'permission', - alias: 'Umb.Permission.CreateDocumentBlueprint', + alias: 'Umb.Permission.Document.CreateBlueprint', name: 'Create Document Blueprint Permission', meta: { label: 'Create Content Template', @@ -21,11 +21,74 @@ const permissions: Array = [ }, { type: 'permission', - alias: 'Umb.Permission.DeleteDocument', + alias: 'Umb.Permission.Document.Delete', name: 'Delete Document Permission', meta: { label: 'Delete', - description: 'Allow access to create a Content Template' + description: 'Allow access to delete a document' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.Document.Create', + name: 'Create Document Permission', + meta: { + label: 'Create', + description: 'Allow access to create a document' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.Document.Notifications', + name: 'Document Notifications Permission', + meta: { + label: 'Notifications', + description: 'Allow access to setup notifications for documents' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.Document.Publish', + name: 'Publish Document Permission', + meta: { + label: 'Publish', + description: 'Allow access to publish a document' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.Document.Permissions', + name: 'Document Permissions Permission', + meta: { + label: 'Permissions', + description: 'Allow access to change permissions for a document' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.Document.SendForApproval', + name: 'Send Document For Approval Permission', + meta: { + label: 'Permissions', + description: 'Allow access to send a document for approval before publishing' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.Document.Unpublish', + name: 'Unpublish Document Permission', + meta: { + label: 'Unpublish', + description: 'Allow access to unpublish a document' + }, + }, + { + type: 'permission', + alias: 'Umb.Permission.Document.Update', + name: 'Update Document Permission', + meta: { + label: 'Update', + description: 'Allow access to save a document' }, }, ]; From e3fbe207bc4b68badae226e20bbad732e4a728a1 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 14:02:43 +0200 Subject: [PATCH 06/97] update label --- src/packages/documents/permissions/manifests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/documents/permissions/manifests.ts b/src/packages/documents/permissions/manifests.ts index 6b22f6e7e8..bf93e6ae5e 100644 --- a/src/packages/documents/permissions/manifests.ts +++ b/src/packages/documents/permissions/manifests.ts @@ -69,7 +69,7 @@ const permissions: Array = [ alias: 'Umb.Permission.Document.SendForApproval', name: 'Send Document For Approval Permission', meta: { - label: 'Permissions', + label: 'Send For Approval', description: 'Allow access to send a document for approval before publishing' }, }, From 69825ea916325609d37a683c3fd7517fb4b3340e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 14:07:36 +0200 Subject: [PATCH 07/97] rename to user permission --- src/packages/documents/manifests.ts | 2 +- .../manifests.ts | 60 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) rename src/packages/documents/{permissions => user-permissions}/manifests.ts (50%) diff --git a/src/packages/documents/manifests.ts b/src/packages/documents/manifests.ts index 49c966d8ac..f0ae1be146 100644 --- a/src/packages/documents/manifests.ts +++ b/src/packages/documents/manifests.ts @@ -4,7 +4,7 @@ import { manifests as contentMenuManifest } from './menu.manifests.js'; import { manifests as documentBlueprintManifests } from './document-blueprints/manifests.js'; import { manifests as documentTypeManifests } from './document-types/manifests.js'; import { manifests as documentManifests } from './documents/manifests.js'; -import { manifests as permissionManifests } from './permissions/manifests.js'; +import { manifests as permissionManifests } from './user-permissions/manifests.js'; export const manifests = [ ...dashboardManifests, diff --git a/src/packages/documents/permissions/manifests.ts b/src/packages/documents/user-permissions/manifests.ts similarity index 50% rename from src/packages/documents/permissions/manifests.ts rename to src/packages/documents/user-permissions/manifests.ts index bf93e6ae5e..65a723424a 100644 --- a/src/packages/documents/permissions/manifests.ts +++ b/src/packages/documents/user-permissions/manifests.ts @@ -2,90 +2,90 @@ import type { ManifestPermission } from '@umbraco-cms/backoffice/extension-regis const permissions: Array = [ { - type: 'permission', - alias: 'Umb.Permission.Document.Browse', - name: 'Read Document Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Browse', + name: 'Read Document User Permission', meta: { label: 'Read', description: 'Allow access to browse documents', }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.CreateBlueprint', - name: 'Create Document Blueprint Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.CreateBlueprint', + name: 'Create Document Blueprint User Permission', meta: { label: 'Create Content Template', description: 'Allow access to create a Content Template' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.Delete', - name: 'Delete Document Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Delete', + name: 'Delete Document User Permission', meta: { label: 'Delete', description: 'Allow access to delete a document' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.Create', - name: 'Create Document Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Create', + name: 'Create Document User Permission', meta: { label: 'Create', description: 'Allow access to create a document' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.Notifications', - name: 'Document Notifications Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Notifications', + name: 'Document Notifications User Permission', meta: { label: 'Notifications', description: 'Allow access to setup notifications for documents' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.Publish', - name: 'Publish Document Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Publish', + name: 'Publish Document User Permission', meta: { label: 'Publish', description: 'Allow access to publish a document' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.Permissions', - name: 'Document Permissions Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Permissions', + name: 'Document Permissions User Permission', meta: { label: 'Permissions', description: 'Allow access to change permissions for a document' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.SendForApproval', - name: 'Send Document For Approval Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.SendForApproval', + name: 'Send Document For Approval User Permission', meta: { label: 'Send For Approval', description: 'Allow access to send a document for approval before publishing' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.Unpublish', - name: 'Unpublish Document Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Unpublish', + name: 'Unpublish Document User Permission', meta: { label: 'Unpublish', description: 'Allow access to unpublish a document' }, }, { - type: 'permission', - alias: 'Umb.Permission.Document.Update', - name: 'Update Document Permission', + type: 'userPermission', + alias: 'Umb.UserPermission.Document.Update', + name: 'Update Document User Permission', meta: { label: 'Update', description: 'Allow access to save a document' From db3e7ada0eebc7bcaed8de4d79142578cd55f8ac Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 14:08:15 +0200 Subject: [PATCH 08/97] move into document folder --- .../documents/{ => documents}/user-permissions/manifests.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/packages/documents/{ => documents}/user-permissions/manifests.ts (100%) diff --git a/src/packages/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts similarity index 100% rename from src/packages/documents/user-permissions/manifests.ts rename to src/packages/documents/documents/user-permissions/manifests.ts From 528a4c542b8b2c56837316783cf4fcdd5ce70895 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 14:10:09 +0200 Subject: [PATCH 09/97] rename extension type to user permission --- src/packages/core/extension-registry/models/index.ts | 6 +++--- .../extension-registry/models/permission.model.ts | 12 ------------ .../models/user-permission.model.ts | 12 ++++++++++++ .../documents/user-permissions/manifests.ts | 4 ++-- .../workspace/user-group-workspace-editor.element.ts | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 src/packages/core/extension-registry/models/permission.model.ts create mode 100644 src/packages/core/extension-registry/models/user-permission.model.ts diff --git a/src/packages/core/extension-registry/models/index.ts b/src/packages/core/extension-registry/models/index.ts index 85e77b5622..9a03228df5 100644 --- a/src/packages/core/extension-registry/models/index.ts +++ b/src/packages/core/extension-registry/models/index.ts @@ -28,7 +28,7 @@ import type { ManifestWorkspace } from './workspace.model.js'; import type { ManifestWorkspaceAction } from './workspace-action.model.js'; import type { ManifestWorkspaceEditorView } from './workspace-editor-view.model.js'; import type { ManifestWorkspaceViewCollection } from './workspace-view-collection.model.js'; -import type { ManifestPermission } from './permission.model.js'; +import type { ManifestUserPermission } from './user-permission.model.js'; import type { ManifestBase, ManifestBundle, @@ -66,7 +66,7 @@ export * from './workspace-action.model.js'; export * from './workspace-view-collection.model.js'; export * from './workspace-editor-view.model.js'; export * from './workspace.model.js'; -export * from './permission.model.js'; +export * from './user-permission.model.js'; export type ManifestTypes = | ManifestBundle @@ -108,5 +108,5 @@ export type ManifestTypes = | ManifestWorkspaceAction | ManifestWorkspaceEditorView | ManifestWorkspaceViewCollection - | ManifestPermission + | ManifestUserPermission | ManifestBase; diff --git a/src/packages/core/extension-registry/models/permission.model.ts b/src/packages/core/extension-registry/models/permission.model.ts deleted file mode 100644 index 0b54e1f925..0000000000 --- a/src/packages/core/extension-registry/models/permission.model.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ManifestBase } from '@umbraco-cms/backoffice/extension-api'; - -export interface ManifestPermission extends ManifestBase { - type: 'permission'; - meta: MetaPermission; -} - -export interface MetaPermission { - label: string; - description?: string; - group?: string; -} diff --git a/src/packages/core/extension-registry/models/user-permission.model.ts b/src/packages/core/extension-registry/models/user-permission.model.ts new file mode 100644 index 0000000000..8f9738a373 --- /dev/null +++ b/src/packages/core/extension-registry/models/user-permission.model.ts @@ -0,0 +1,12 @@ +import type { ManifestBase } from '@umbraco-cms/backoffice/extension-api'; + +export interface ManifestUserPermission extends ManifestBase { + type: 'userPermission'; + meta: MetaUserPermission; +} + +export interface MetaUserPermission { + label: string; + description?: string; + group?: string; +} diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index 65a723424a..4e5c1434d4 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -1,6 +1,6 @@ -import type { ManifestPermission } from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestUserPermission } from '@umbraco-cms/backoffice/extension-registry'; -const permissions: Array = [ +const permissions: Array = [ { type: 'userPermission', alias: 'Umb.UserPermission.Document.Browse', diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index f2f063bf62..3cdbeeae16 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -11,7 +11,7 @@ import { UmbModalManagerContext, } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { ManifestPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { ManifestUserPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; @customElement('umb-user-group-workspace-editor') @@ -23,7 +23,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { private _userKeys?: Array; @state() - private _userPermissions: Array = []; + private _userPermissions: Array = []; #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; #modalContext?: UmbModalManagerContext; @@ -110,7 +110,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { `; } - #renderPermission(permissionManifest: ManifestPermission) { + #renderPermission(permissionManifest: ManifestUserPermission) { return html`
From 0dcd726b513e594f723adf998fa37c7ebbbe1171 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 14:15:21 +0200 Subject: [PATCH 10/97] move renaming --- src/packages/documents/documents/manifests.ts | 2 ++ src/packages/documents/manifests.ts | 2 -- .../workspace/user-group-workspace-editor.element.ts | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/packages/documents/documents/manifests.ts b/src/packages/documents/documents/manifests.ts index ea4d0dc985..6c302fc17d 100644 --- a/src/packages/documents/documents/manifests.ts +++ b/src/packages/documents/documents/manifests.ts @@ -6,6 +6,7 @@ import { manifests as workspaceManifests } from './workspace/manifests.js'; import { manifests as entityActionManifests } from './entity-actions/manifests.js'; import { manifests as entityBulkActionManifests } from './entity-bulk-actions/manifests.js'; import { manifests as propertyEditorManifests } from './property-editors/manifests.js'; +import { manifests as userPermissionManifests } from './user-permissions/manifests.js'; export const manifests = [ ...collectionManifests, @@ -16,4 +17,5 @@ export const manifests = [ ...entityActionManifests, ...entityBulkActionManifests, ...propertyEditorManifests, + ...userPermissionManifests, ]; diff --git a/src/packages/documents/manifests.ts b/src/packages/documents/manifests.ts index f0ae1be146..17fc8e51b5 100644 --- a/src/packages/documents/manifests.ts +++ b/src/packages/documents/manifests.ts @@ -4,7 +4,6 @@ import { manifests as contentMenuManifest } from './menu.manifests.js'; import { manifests as documentBlueprintManifests } from './document-blueprints/manifests.js'; import { manifests as documentTypeManifests } from './document-types/manifests.js'; import { manifests as documentManifests } from './documents/manifests.js'; -import { manifests as permissionManifests } from './user-permissions/manifests.js'; export const manifests = [ ...dashboardManifests, @@ -13,5 +12,4 @@ export const manifests = [ ...documentBlueprintManifests, ...documentTypeManifests, ...documentManifests, - ...permissionManifests, ]; diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 3cdbeeae16..9e8893c8e4 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -35,7 +35,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext = instance; this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); this.observe(this.#workspaceContext.userIds, (userKeys) => (this._userKeys = userKeys)); - this.observe(umbExtensionsRegistry.extensionsOfType('permission'), (permissionManifests) => this._userPermissions = permissionManifests); + this.observe(umbExtensionsRegistry.extensionsOfType('userPermission'), (userPermissionManifests) => this._userPermissions = userPermissionManifests); }); this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { @@ -110,12 +110,12 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { `; } - #renderPermission(permissionManifest: ManifestUserPermission) { + #renderPermission(userPermissionManifest: ManifestUserPermission) { return html`
-
${ permissionManifest.meta.label }
- ${ permissionManifest.meta.description } +
${ userPermissionManifest.meta.label }
+ ${ userPermissionManifest.meta.description }
`; } From 253f2e37e97b82dd4265b1102f75906d0deeff1d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 15:08:14 +0200 Subject: [PATCH 11/97] add methods to update user group permissions --- .../user-group-workspace-editor.element.ts | 30 ++++++++++++----- .../workspace/user-group-workspace.context.ts | 33 ++++++++++++++++--- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 9e8893c8e4..8654ca3491 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -1,6 +1,6 @@ import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from './user-group-workspace.context.js'; -import { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; -import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UUIBooleanInputEvent, UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import { css, html, nothing, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; // TODO: import from package when available //import { UmbUserInputElement } from '../../users/components/user-input/user-input.element.js'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @@ -13,7 +13,6 @@ import { import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { ManifestUserPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; - @customElement('umb-user-group-workspace-editor') export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @state() @@ -23,7 +22,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { private _userKeys?: Array; @state() - private _userPermissions: Array = []; + private _userPermissionManifests: Array = []; #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; #modalContext?: UmbModalManagerContext; @@ -35,7 +34,10 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext = instance; this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); this.observe(this.#workspaceContext.userIds, (userKeys) => (this._userKeys = userKeys)); - this.observe(umbExtensionsRegistry.extensionsOfType('userPermission'), (userPermissionManifests) => this._userPermissions = userPermissionManifests); + this.observe( + umbExtensionsRegistry.extensionsOfType('userPermission'), + (userPermissionManifests) => (this._userPermissionManifests = userPermissionManifests), + ); }); this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { @@ -112,14 +114,24 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { #renderPermission(userPermissionManifest: ManifestUserPermission) { return html`
- + + this.#changeUserPermission(event, userPermissionManifest)}>
-
${ userPermissionManifest.meta.label }
- ${ userPermissionManifest.meta.description } +
${userPermissionManifest.meta.label}
+ ${userPermissionManifest.meta.description}
`; } + #changeUserPermission(event: UUIBooleanInputEvent, userPermissionManifest: ManifestUserPermission) { + event.target.checked + ? this.#workspaceContext?.addPermission(userPermissionManifest.alias) + : this.#workspaceContext?.removePermission(userPermissionManifest.alias); + } + #renderLeftColumn() { if (!this._userGroup) return nothing; @@ -145,7 +157,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
Default Permissions
- ${ this._userPermissions.map((permission) => this.#renderPermission(permission)) } + ${this._userPermissionManifests.map((permission) => this.#renderPermission(permission))}
diff --git a/src/packages/users/user-groups/workspace/user-group-workspace.context.ts b/src/packages/users/user-groups/workspace/user-group-workspace.context.ts index 04b1193c9a..d750f28faf 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace.context.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace.context.ts @@ -55,7 +55,7 @@ export class UmbUserGroupWorkspaceContext getEntityId(): string | undefined { throw new Error('Method not implemented.'); } - + getEntityType(): string { return 'user-group'; } @@ -63,6 +63,7 @@ export class UmbUserGroupWorkspaceContext getData(): UserGroupResponseModel | undefined { throw new Error('Method not implemented.'); } + async save() { if (!this.#data.value) return; @@ -104,10 +105,34 @@ export class UmbUserGroupWorkspaceContext updateUserKeys(keys: Array) { this.#userIds.next(keys); } -} + /** + * Adds a permission to the user group permission array. + * @param {string} permissionAlias + * @memberof UmbUserGroupWorkspaceContext + */ + addPermission(permissionAlias: string) { + const permissions = this.#data.getValue()?.permissions ?? []; + const newValue = [...permissions, permissionAlias]; + this.#data.update({ permissions: newValue }); + } + + /** + * Removes a permission from the user group permission array. + * @param {string} permissionAlias + * @memberof UmbUserGroupWorkspaceContext + */ + removePermission(permissionAlias: string) { + const permissions = this.#data.getValue()?.permissions ?? []; + const newValue = permissions.filter((alias) => alias !== permissionAlias); + this.#data.update({ permissions: newValue }); + } +} -export const UMB_USER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken( +export const UMB_USER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken< + UmbSaveableWorkspaceContextInterface, + UmbUserGroupWorkspaceContext +>( 'UmbWorkspaceContext', - (context): context is UmbUserGroupWorkspaceContext => context.getEntityType?.() === 'user-group' + (context): context is UmbUserGroupWorkspaceContext => context.getEntityType?.() === 'user-group', ); From b83811a74e1f6cb15d3a8e582df3f97b5c25ee10 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 7 Sep 2023 18:37:42 +0200 Subject: [PATCH 12/97] move permission list to component + add mock data to persist save --- ...user-groups.data.ts => user-group.data.ts} | 5 +- src/mocks/handlers/user-group.handlers.ts | 17 ++++- ...r-group-default-permission-list.element.ts | 70 +++++++++++++++++++ .../user-group-workspace-editor.element.ts | 38 ++-------- 4 files changed, 92 insertions(+), 38 deletions(-) rename src/mocks/data/{user-groups.data.ts => user-group.data.ts} (73%) create mode 100644 src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts diff --git a/src/mocks/data/user-groups.data.ts b/src/mocks/data/user-group.data.ts similarity index 73% rename from src/mocks/data/user-groups.data.ts rename to src/mocks/data/user-group.data.ts index 968fb0919d..a8fa9a70ce 100644 --- a/src/mocks/data/user-groups.data.ts +++ b/src/mocks/data/user-group.data.ts @@ -2,7 +2,7 @@ import { UmbEntityData } from './entity.data.js'; import { PagedUserGroupResponseModel, UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; // Temp mocked database -class UmbUserGroupsData extends UmbEntityData { +class UmbUserGroupData extends UmbEntityData { constructor(data: Array) { super(data); } @@ -20,7 +20,8 @@ export const data: Array = [ id: 'c630d49e-4e7b-42ea-b2bc-edc0edacb6b1', name: 'Administrators', icon: 'umb:medal', + permissions: ['Umb.UserPermission.Document.Delete'], }, ]; -export const umbUserGroupsData = new UmbUserGroupsData(data); +export const umbUserGroupData = new UmbUserGroupData(data); diff --git a/src/mocks/handlers/user-group.handlers.ts b/src/mocks/handlers/user-group.handlers.ts index 571943d163..d0efce58b4 100644 --- a/src/mocks/handlers/user-group.handlers.ts +++ b/src/mocks/handlers/user-group.handlers.ts @@ -1,12 +1,12 @@ const { rest } = window.MockServiceWorker; -import { umbUserGroupsData } from '../data/user-groups.data.js'; +import { umbUserGroupData } from '../data/user-group.data.js'; import { umbracoPath } from '@umbraco-cms/backoffice/utils'; const slug = '/user-group'; export const handlers = [ rest.get(umbracoPath(`${slug}`), (req, res, ctx) => { - const response = umbUserGroupsData.getAll(); + const response = umbUserGroupData.getAll(); return res(ctx.status(200), ctx.json(response)); }), @@ -14,8 +14,19 @@ export const handlers = [ rest.get(umbracoPath(`${slug}/:id`), (req, res, ctx) => { const id = req.params.id as string; if (!id) return; - const userGroup = umbUserGroupsData.getById(id); + const userGroup = umbUserGroupData.getById(id); return res(ctx.status(200), ctx.json(userGroup)); }), + + rest.put(umbracoPath(`${slug}/:id`), async (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return; + const data = await req.json(); + if (!data) return; + + umbUserGroupData.save(id, data); + + return res(ctx.status(200)); + }), ]; diff --git a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts new file mode 100644 index 0000000000..0a0c09d09e --- /dev/null +++ b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts @@ -0,0 +1,70 @@ +import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from '../user-group-workspace.context.js'; +import { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { ManifestUserPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; + +@customElement('umb-user-group-default-permission-list') +export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { + @state() + private _userGroup?: UserGroupResponseModel; + + @state() + private _userPermissionManifests: Array = []; + + #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; + + constructor() { + super(); + + this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => { + this.#workspaceContext = instance; + this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); + this.observe( + umbExtensionsRegistry.extensionsOfType('userPermission'), + (userPermissionManifests) => (this._userPermissionManifests = userPermissionManifests), + ); + }); + } + + #onChangeUserPermission(event: UUIBooleanInputEvent, userPermissionManifest: ManifestUserPermission) { + event.target.checked + ? this.#workspaceContext?.addPermission(userPermissionManifest.alias) + : this.#workspaceContext?.removePermission(userPermissionManifest.alias); + } + + #isAllowed(userPermissionManifest: ManifestUserPermission) { + console.log(this._userGroup?.permissions?.includes(userPermissionManifest.alias)); + return this._userGroup?.permissions?.includes(userPermissionManifest.alias); + } + + render() { + return html` ${this._userPermissionManifests.map((permission) => this.#renderPermission(permission))} `; + } + + #renderPermission(userPermissionManifest: ManifestUserPermission) { + return html`
+ + this.#onChangeUserPermission(event, userPermissionManifest)}> +
+
${userPermissionManifest.meta.label}
+ ${userPermissionManifest.meta.description} +
+
`; + } + + static styles = [UmbTextStyles, css``]; +} + +export default UmbUserGroupDefaultPermissionListElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-group-default-permission-list': UmbUserGroupDefaultPermissionListElement; + } +} diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 8654ca3491..f54b6b9dd2 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -1,8 +1,6 @@ import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from './user-group-workspace.context.js'; -import { UUIBooleanInputEvent, UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; -import { css, html, nothing, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -// TODO: import from package when available -//import { UmbUserInputElement } from '../../users/components/user-input/user-input.element.js'; +import { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { @@ -11,7 +9,8 @@ import { UmbModalManagerContext, } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { ManifestUserPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; + +import './components/user-group-default-permission-list.element.js'; @customElement('umb-user-group-workspace-editor') export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @@ -21,9 +20,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @state() private _userKeys?: Array; - @state() - private _userPermissionManifests: Array = []; - #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; #modalContext?: UmbModalManagerContext; @@ -34,10 +30,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext = instance; this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); this.observe(this.#workspaceContext.userIds, (userKeys) => (this._userKeys = userKeys)); - this.observe( - umbExtensionsRegistry.extensionsOfType('userPermission'), - (userPermissionManifests) => (this._userPermissionManifests = userPermissionManifests), - ); }); this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { @@ -112,26 +104,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { `; } - #renderPermission(userPermissionManifest: ManifestUserPermission) { - return html`
- - this.#changeUserPermission(event, userPermissionManifest)}> -
-
${userPermissionManifest.meta.label}
- ${userPermissionManifest.meta.description} -
-
`; - } - - #changeUserPermission(event: UUIBooleanInputEvent, userPermissionManifest: ManifestUserPermission) { - event.target.checked - ? this.#workspaceContext?.addPermission(userPermissionManifest.alias) - : this.#workspaceContext?.removePermission(userPermissionManifest.alias); - } - #renderLeftColumn() { if (!this._userGroup) return nothing; @@ -157,7 +129,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
Default Permissions
- ${this._userPermissionManifests.map((permission) => this.#renderPermission(permission))} +
From ed4df8924f3843555430090490ab27cd4cc2b234 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 11:13:07 +0200 Subject: [PATCH 13/97] add type to import --- src/packages/core/extension-registry/conditions/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/core/extension-registry/conditions/types.ts b/src/packages/core/extension-registry/conditions/types.ts index 2a6e1f5d74..292b07c760 100644 --- a/src/packages/core/extension-registry/conditions/types.ts +++ b/src/packages/core/extension-registry/conditions/types.ts @@ -1,7 +1,7 @@ import type { SectionAliasConditionConfig } from './section-alias.condition.js'; import type { SwitchConditionConfig } from './switch.condition.js'; import type { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; -import { UmbConditionConfigBase } from '@umbraco-cms/backoffice/extension-api'; +import type { UmbConditionConfigBase } from '@umbraco-cms/backoffice/extension-api'; export type ConditionTypes = | SectionAliasConditionConfig From c6569f8b7635a0198b2f4a67dffba911a0292a2a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 11:13:32 +0200 Subject: [PATCH 14/97] add condition to entity action --- .../documents/documents/entity-actions/manifests.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/packages/documents/documents/entity-actions/manifests.ts b/src/packages/documents/documents/entity-actions/manifests.ts index cdcdced821..c15e4864cb 100644 --- a/src/packages/documents/documents/entity-actions/manifests.ts +++ b/src/packages/documents/documents/entity-actions/manifests.ts @@ -42,6 +42,12 @@ const entityActions: Array = [ api: UmbTrashEntityAction, entityTypes: [DOCUMENT_ENTITY_TYPE], }, + conditions: [ + { + alias: 'Umb.Condition.UserPermission', + match: 'Umb.UserPermission.Document.Trash', + }, + ], }, { type: 'entityAction', From 860e66c3f049f466dd40bc4a8b5d34e2326a196a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 11:13:56 +0200 Subject: [PATCH 15/97] scaffold user permission condition --- .../conditions/user-permission.condition.ts | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/packages/users/current-user/conditions/user-permission.condition.ts diff --git a/src/packages/users/current-user/conditions/user-permission.condition.ts b/src/packages/users/current-user/conditions/user-permission.condition.ts new file mode 100644 index 0000000000..cf27817a27 --- /dev/null +++ b/src/packages/users/current-user/conditions/user-permission.condition.ts @@ -0,0 +1,49 @@ +import { UmbBaseController } from '@umbraco-cms/backoffice/controller-api'; +import { + ManifestCondition, + UmbConditionConfigBase, + UmbConditionControllerArguments, + UmbExtensionCondition, +} from '@umbraco-cms/backoffice/extension-api'; + +export class UmbUserPermissionCondition extends UmbBaseController implements UmbExtensionCondition { + config: UserPermissionConditionConfig; + permitted = false; + #onChange: () => void; + + constructor(args: UmbConditionControllerArguments) { + super(args.host); + this.config = args.config; + this.#onChange = args.onChange; + + console.log('HELLO FROM MY CONDITION'); + console.log('GET CURRENT USER CONTEXT'); + this.permitted = true; + + /* + this.consumeContext(UMB_SECTION_CONTEXT_TOKEN, (context) => { + this.observe(context.alias, (sectionAlias) => { + this.permitted = sectionAlias === this.config.match; + this.#onChange(); + }); + }); + */ + } +} + +export type UserPermissionConditionConfig = UmbConditionConfigBase<'Umb.Condition.UserPermission'> & { + /** + * + * + * @example + * "Umb.UserPermission.Document.Create" + */ + match: string; +}; + +export const manifest: ManifestCondition = { + type: 'condition', + name: 'User Permission Condition', + alias: 'Umb.Condition.UserPermission', + class: UmbUserPermissionCondition, +}; From 69a199f87b93b74d2ed04819708e03a567247cb9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 11:17:07 +0200 Subject: [PATCH 16/97] expose manifest --- src/packages/users/current-user/manifests.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/packages/users/current-user/manifests.ts b/src/packages/users/current-user/manifests.ts index f6fe418913..8765bc4d95 100644 --- a/src/packages/users/current-user/manifests.ts +++ b/src/packages/users/current-user/manifests.ts @@ -1,5 +1,6 @@ import { manifests as modalManifests } from './modals/manifests.js'; import { manifests as userProfileAppsManifests } from './user-profile-apps/manifests.js'; +import { manifest as userPermissionConditionManifest } from './conditions/user-permission.condition.js'; import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; export const headerApps: Array = [ @@ -23,4 +24,9 @@ export const headerApps: Array = [ }, ]; -export const manifests = [...headerApps, ...modalManifests, ...userProfileAppsManifests]; +export const manifests = [ + ...headerApps, + ...modalManifests, + ...userProfileAppsManifests, + userPermissionConditionManifest, +]; From 3d149fbf51627db6a9b77b74100d9dbe56676ed3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 11:20:17 +0200 Subject: [PATCH 17/97] rename to auth context --- .../current-user/current-user-modal.element.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts b/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts index a337952acc..9b9ed9f88b 100644 --- a/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts +++ b/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts @@ -1,6 +1,6 @@ import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { UMB_APP } from '@umbraco-cms/backoffice/context'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, CSSResultGroup, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbModalContext } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @@ -13,7 +13,7 @@ export class UmbCurrentUserModalElement extends UmbLitElement { @state() private _currentUser?: UmbLoggedInUser; - #auth?: typeof UMB_AUTH.TYPE; + #authContext?: typeof UMB_AUTH.TYPE; #appContext?: typeof UMB_APP.TYPE; @@ -21,7 +21,7 @@ export class UmbCurrentUserModalElement extends UmbLitElement { super(); this.consumeContext(UMB_AUTH, (instance) => { - this.#auth = instance; + this.#authContext = instance; this._observeCurrentUser(); }); @@ -31,9 +31,9 @@ export class UmbCurrentUserModalElement extends UmbLitElement { } private async _observeCurrentUser() { - if (!this.#auth) return; + if (!this.#authContext) return; - this.observe(this.#auth.currentUser, (currentUser) => { + this.observe(this.#authContext.currentUser, (currentUser) => { this._currentUser = currentUser; }); } @@ -43,9 +43,9 @@ export class UmbCurrentUserModalElement extends UmbLitElement { } private async _logout() { - if (!this.#auth) return; - this.#auth.performWithFreshTokens; - await this.#auth.signOut(); + if (!this.#authContext) return; + this.#authContext.performWithFreshTokens; + await this.#authContext.signOut(); let newUrl = this.#appContext ? `${this.#appContext.getBackofficePath()}/login` : '/'; newUrl = newUrl.replace(/\/\//g, '/'); location.href = newUrl; From 62d809cc95cb7c2208d04f7728045917a82b2c8f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 13:42:09 +0200 Subject: [PATCH 18/97] format --- .../documents/user-permissions/manifests.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index 4e5c1434d4..012e214e7b 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -7,25 +7,25 @@ const permissions: Array = [ name: 'Read Document User Permission', meta: { label: 'Read', - description: 'Allow access to browse documents', + description: 'Allow access to browse documents', }, }, - { + { type: 'userPermission', alias: 'Umb.UserPermission.Document.CreateBlueprint', name: 'Create Document Blueprint User Permission', meta: { label: 'Create Content Template', - description: 'Allow access to create a Content Template' + description: 'Allow access to create a Content Template', }, }, - { + { type: 'userPermission', alias: 'Umb.UserPermission.Document.Delete', name: 'Delete Document User Permission', meta: { label: 'Delete', - description: 'Allow access to delete a document' + description: 'Allow access to delete a document', }, }, { @@ -34,7 +34,7 @@ const permissions: Array = [ name: 'Create Document User Permission', meta: { label: 'Create', - description: 'Allow access to create a document' + description: 'Allow access to create a document', }, }, { @@ -43,7 +43,7 @@ const permissions: Array = [ name: 'Document Notifications User Permission', meta: { label: 'Notifications', - description: 'Allow access to setup notifications for documents' + description: 'Allow access to setup notifications for documents', }, }, { @@ -52,7 +52,7 @@ const permissions: Array = [ name: 'Publish Document User Permission', meta: { label: 'Publish', - description: 'Allow access to publish a document' + description: 'Allow access to publish a document', }, }, { @@ -61,7 +61,7 @@ const permissions: Array = [ name: 'Document Permissions User Permission', meta: { label: 'Permissions', - description: 'Allow access to change permissions for a document' + description: 'Allow access to change permissions for a document', }, }, { @@ -70,7 +70,7 @@ const permissions: Array = [ name: 'Send Document For Approval User Permission', meta: { label: 'Send For Approval', - description: 'Allow access to send a document for approval before publishing' + description: 'Allow access to send a document for approval before publishing', }, }, { @@ -79,7 +79,7 @@ const permissions: Array = [ name: 'Unpublish Document User Permission', meta: { label: 'Unpublish', - description: 'Allow access to unpublish a document' + description: 'Allow access to unpublish a document', }, }, { @@ -88,7 +88,7 @@ const permissions: Array = [ name: 'Update Document User Permission', meta: { label: 'Update', - description: 'Allow access to save a document' + description: 'Allow access to save a document', }, }, ]; From 4529321b19e8f3c1862cb152ee93442bf2e93141 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 13:42:36 +0200 Subject: [PATCH 19/97] check for user permission in condition --- .../conditions/user-permission.condition.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/packages/users/current-user/conditions/user-permission.condition.ts b/src/packages/users/current-user/conditions/user-permission.condition.ts index cf27817a27..1beb530856 100644 --- a/src/packages/users/current-user/conditions/user-permission.condition.ts +++ b/src/packages/users/current-user/conditions/user-permission.condition.ts @@ -1,3 +1,4 @@ +import { UMB_AUTH } from '@umbraco-cms/backoffice/auth'; import { UmbBaseController } from '@umbraco-cms/backoffice/controller-api'; import { ManifestCondition, @@ -16,18 +17,12 @@ export class UmbUserPermissionCondition extends UmbBaseController implements Umb this.config = args.config; this.#onChange = args.onChange; - console.log('HELLO FROM MY CONDITION'); - console.log('GET CURRENT USER CONTEXT'); - this.permitted = true; - - /* - this.consumeContext(UMB_SECTION_CONTEXT_TOKEN, (context) => { - this.observe(context.alias, (sectionAlias) => { - this.permitted = sectionAlias === this.config.match; + this.consumeContext(UMB_AUTH, (context) => { + this.observe(context.currentUser, (currentUser) => { + this.permitted = currentUser?.permissions?.includes(this.config.match) || false; this.#onChange(); }); }); - */ } } From bf5103fa31a99a1c9b7f18a89b5eb42c4579e0dd Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 8 Sep 2023 13:42:41 +0200 Subject: [PATCH 20/97] clean up --- .../documents/documents/entity-actions/manifests.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/packages/documents/documents/entity-actions/manifests.ts b/src/packages/documents/documents/entity-actions/manifests.ts index c15e4864cb..2fb056364c 100644 --- a/src/packages/documents/documents/entity-actions/manifests.ts +++ b/src/packages/documents/documents/entity-actions/manifests.ts @@ -29,6 +29,12 @@ const entityActions: Array = [ api: UmbCreateDocumentEntityAction, entityTypes: [DOCUMENT_ROOT_ENTITY_TYPE, DOCUMENT_ENTITY_TYPE], }, + conditions: [ + { + alias: 'Umb.Condition.UserPermission', + match: 'Umb.UserPermission.Document.Create', + }, + ], }, { type: 'entityAction', @@ -45,7 +51,7 @@ const entityActions: Array = [ conditions: [ { alias: 'Umb.Condition.UserPermission', - match: 'Umb.UserPermission.Document.Trash', + match: 'Umb.UserPermission.Document.Delete', }, ], }, From a5c0248824b8fb1bd0b18e57a09a062396706299 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 11:32:42 +0200 Subject: [PATCH 21/97] manual merge --- .../documents/documents/entity-actions/create/manifests.ts | 6 ++++++ .../documents/recycle-bin/entity-action/manifests.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/packages/documents/documents/entity-actions/create/manifests.ts b/src/packages/documents/documents/entity-actions/create/manifests.ts index 65b4364c99..ee35698c4e 100644 --- a/src/packages/documents/documents/entity-actions/create/manifests.ts +++ b/src/packages/documents/documents/entity-actions/create/manifests.ts @@ -16,6 +16,12 @@ const entityActions: Array = [ api: UmbCreateDocumentEntityAction, entityTypes: [DOCUMENT_ROOT_ENTITY_TYPE, DOCUMENT_ENTITY_TYPE], }, + conditions: [ + { + alias: 'Umb.Condition.UserPermission', + match: 'Umb.UserPermission.Document.Create', + }, + ], }, ]; diff --git a/src/packages/documents/documents/recycle-bin/entity-action/manifests.ts b/src/packages/documents/documents/recycle-bin/entity-action/manifests.ts index 50e4624dd0..e46239cc87 100644 --- a/src/packages/documents/documents/recycle-bin/entity-action/manifests.ts +++ b/src/packages/documents/documents/recycle-bin/entity-action/manifests.ts @@ -15,5 +15,11 @@ export const manifests = [ api: UmbTrashEntityAction, entityTypes: [DOCUMENT_ENTITY_TYPE], }, + conditions: [ + { + alias: 'Umb.Condition.UserPermission', + match: 'Umb.UserPermission.Document.Delete', + }, + ], }, ]; From 6bf3b993cf4ae956d52352c85648ac40fe50aab6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 12:00:37 +0200 Subject: [PATCH 22/97] remove s from file name --- src/mocks/data/{users.data.ts => user.data.ts} | 0 src/mocks/handlers/user.handlers.ts | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/mocks/data/{users.data.ts => user.data.ts} (100%) diff --git a/src/mocks/data/users.data.ts b/src/mocks/data/user.data.ts similarity index 100% rename from src/mocks/data/users.data.ts rename to src/mocks/data/user.data.ts diff --git a/src/mocks/handlers/user.handlers.ts b/src/mocks/handlers/user.handlers.ts index 9da37812be..bca0b8b026 100644 --- a/src/mocks/handlers/user.handlers.ts +++ b/src/mocks/handlers/user.handlers.ts @@ -1,6 +1,6 @@ const { rest } = window.MockServiceWorker; -import { umbUsersData } from '../data/users.data.js'; +import { umbUsersData } from '../data/user.data.js'; import { umbracoPath } from '@umbraco-cms/backoffice/utils'; const slug = '/user'; @@ -23,7 +23,7 @@ export const handlers = [ ctx.status(200), ctx.json({ sections: ['Umb.Section.Content', 'Umb.Section.Media', 'Umb.Section.Settings', 'My.Section.Custom'], - }) + }), ); }), From 91438fd35ddfa430086b4c74f718a47c8742c3e0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 12:01:15 +0200 Subject: [PATCH 23/97] use singular form --- src/mocks/data/user.data.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mocks/data/user.data.ts b/src/mocks/data/user.data.ts index c3ace50024..640dbf56bc 100644 --- a/src/mocks/data/user.data.ts +++ b/src/mocks/data/user.data.ts @@ -3,7 +3,7 @@ import { UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { PagedUserResponseModel, UserResponseModel, UserStateModel } from '@umbraco-cms/backoffice/backend-api'; // Temp mocked database -class UmbUsersData extends UmbData { +class UmbUserData extends UmbData { constructor(data: UserResponseModel[]) { super(data); } @@ -196,4 +196,4 @@ export const data: Array = [ }, ]; -export const umbUsersData = new UmbUsersData(data); +export const umbUsersData = new UmbUserData(data); From 1bba4243593ec73ec46866395faf59d8f975a6b0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 13:05:58 +0200 Subject: [PATCH 24/97] clean up --- src/mocks/data/user.data.ts | 88 +++++-------------------------------- 1 file changed, 10 insertions(+), 78 deletions(-) diff --git a/src/mocks/data/user.data.ts b/src/mocks/data/user.data.ts index 640dbf56bc..5428df3e45 100644 --- a/src/mocks/data/user.data.ts +++ b/src/mocks/data/user.data.ts @@ -1,9 +1,10 @@ -import { UmbData } from './data.js'; +import { UmbEntityData } from './entity.data.js'; +import { umbUserGroupData } from './user-group.data.js'; import { UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { PagedUserResponseModel, UserResponseModel, UserStateModel } from '@umbraco-cms/backoffice/backend-api'; // Temp mocked database -class UmbUserData extends UmbData { +class UmbUserData extends UmbEntityData { constructor(data: UserResponseModel[]) { super(data); } @@ -15,12 +16,9 @@ class UmbUserData extends UmbData { }; } - getById(id: string): UserResponseModel | undefined { - return this.data.find((user) => user.id === id); - } - getCurrentUser(): UmbLoggedInUser { const firstUser = this.data[0]; + const permissions = firstUser.userGroupIds?.length ? umbUserGroupData.getPermissions(firstUser.userGroupIds) : []; return { id: firstUser.id, @@ -33,79 +31,9 @@ class UmbUserData extends UmbData { languages: [], contentStartNodeIds: firstUser.contentStartNodeIds, mediaStartNodeIds: firstUser.mediaStartNodeIds, - permissions: [], + permissions, }; } - - save(id: string, saveItem: UserResponseModel) { - const foundIndex = this.data.findIndex((item) => item.id === id); - if (foundIndex !== -1) { - // update - this.data[foundIndex] = saveItem; - this.updateData(saveItem); - } else { - // new - this.data.push(saveItem); - } - - return saveItem; - } - - protected updateData(updateItem: UserResponseModel) { - const itemIndex = this.data.findIndex((item) => item.id === updateItem.id); - const item = this.data[itemIndex]; - - console.log('updateData', updateItem, itemIndex, item); - - if (!item) return; - - const itemKeys = Object.keys(item); - const newItem = {}; - - for (const [key] of Object.entries(updateItem)) { - if (itemKeys.indexOf(key) !== -1) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - newItem[key] = updateItem[key]; - } - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.data[itemIndex] = newItem; - - console.log('updateData', this.data[itemIndex]); - } - - // updateUserGroup(ids: string[], userGroup: string) { - // this.data.forEach((user) => { - // if (ids.includes(user.id)) { - // } else { - // } - - // this.updateData(user); - // }); - - // return this.data.map((user) => user.id); - // } - - // enable(ids: string[]) { - // const users = this.data.filter((user) => ids.includes(user.id)); - // users.forEach((user) => { - // user.status = 'enabled'; - // this.updateData(user); - // }); - // return users.map((user) => user.id); - // } - - // disable(ids: string[]) { - // const users = this.data.filter((user) => ids.includes(user.id)); - // users.forEach((user) => { - // user.status = 'disabled'; - // this.updateData(user); - // }); - // return users.map((user) => user.id); - // } } export const data: Array = [ @@ -124,7 +52,11 @@ export const data: Array = [ updateDate: '2/10/2022', createDate: '3/13/2022', failedLoginAttempts: 946, - userGroupIds: ['c630d49e-4e7b-42ea-b2bc-edc0edacb6b1'], + userGroupIds: [ + 'c630d49e-4e7b-42ea-b2bc-edc0edacb6b1', + '9d24dc47-a4bf-427f-8a4a-b900f03b8a12', + 'f4626511-b0d7-4ab1-aebc-a87871a5dcfa', + ], }, { id: '82e11d3d-b91d-43c9-9071-34d28e62e81d', From cc34f458ae7a1d88a8773f861d44dadc2159f72e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 13:06:16 +0200 Subject: [PATCH 25/97] add method to get permissions --- src/mocks/data/user-group.data.ts | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/mocks/data/user-group.data.ts b/src/mocks/data/user-group.data.ts index a8fa9a70ce..bffe4852d2 100644 --- a/src/mocks/data/user-group.data.ts +++ b/src/mocks/data/user-group.data.ts @@ -13,6 +13,22 @@ class UmbUserGroupData extends UmbEntityData { items: this.data, }; } + + /** + * Returns a list of permissions for the given user group ids + * @param {string[]} userGroupIds + * @return {*} {string[]} + * @memberof UmbUserGroupData + */ + getPermissions(userGroupIds: string[]): string[] { + const permissions = this.data + .filter((userGroup) => userGroupIds.includes(userGroup.id || '')) + .map((userGroup) => (userGroup.permissions?.length ? userGroup.permissions : [])) + .flat(); + + // Remove duplicates + return [...new Set(permissions)]; + } } export const data: Array = [ @@ -20,7 +36,19 @@ export const data: Array = [ id: 'c630d49e-4e7b-42ea-b2bc-edc0edacb6b1', name: 'Administrators', icon: 'umb:medal', - permissions: ['Umb.UserPermission.Document.Delete'], + permissions: ['Umb.UserPermission.Create', 'Umb.UserPermission.Delete'], + }, + { + id: '9d24dc47-a4bf-427f-8a4a-b900f03b8a12', + name: 'User Group 1', + icon: 'umb:star', + permissions: ['Umb.UserPermission.Delete'], + }, + { + id: 'f4626511-b0d7-4ab1-aebc-a87871a5dcfa', + name: 'User Group 2', + icon: 'umb:star', + permissions: ['Umb.UserPermission.Read'], }, ]; From b7d8be25c1956d59208d71a6df58539ff7c56fbc Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 13:13:28 +0200 Subject: [PATCH 26/97] add const for document user permission alias' --- src/packages/documents/documents/index.ts | 1 + .../documents/user-permissions/index.ts | 1 + .../documents/user-permissions/manifests.ts | 31 +++++++++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 src/packages/documents/documents/user-permissions/index.ts diff --git a/src/packages/documents/documents/index.ts b/src/packages/documents/documents/index.ts index 661e019300..c1efa8caac 100644 --- a/src/packages/documents/documents/index.ts +++ b/src/packages/documents/documents/index.ts @@ -1,6 +1,7 @@ export * from './repository/index.js'; export * from './workspace/index.js'; export * from './recycle-bin/index.js'; +export * from './user-permissions/index.js'; import './components/index.js'; diff --git a/src/packages/documents/documents/user-permissions/index.ts b/src/packages/documents/documents/user-permissions/index.ts new file mode 100644 index 0000000000..1e95b5d703 --- /dev/null +++ b/src/packages/documents/documents/user-permissions/index.ts @@ -0,0 +1 @@ +export * from './manifests.js'; diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index 012e214e7b..9d5d04f95a 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -1,9 +1,20 @@ import type { ManifestUserPermission } from '@umbraco-cms/backoffice/extension-registry'; +export const UMB_USER_PERMISSION_DOCUMENT_CREATE = 'Umb.UserPermission.Document.Create'; +export const UMB_USER_PERMISSION_DOCUMENT_READ = 'Umb.UserPermission.Document.Read'; +export const UMB_USER_PERMISSION_DOCUMENT_UPDATE = 'Umb.UserPermission.Document.Update'; +export const UMB_USER_PERMISSION_DOCUMENT_DELETE = 'Umb.UserPermission.Document.Delete'; +export const UMB_USER_PERMISSION_DOCUMENT_CREATE_BLUEPRINT = 'Umb.UserPermission.Document.CreateBlueprint'; +export const UMB_USER_PERMISSION_DOCUMENT_NOTIFICATIONS = 'Umb.UserPermission.Document.Notifications'; +export const UMB_USER_PERMISSION_DOCUMENT_PUBLISH = 'Umb.UserPermission.Document.Publish'; +export const UMB_USER_PERMISSION_DOCUMENT_PERMISSIONS = 'Umb.UserPermission.Document.Permissions'; +export const UMB_USER_PERMISSION_DOCUMENT_SEND_FOR_APPROVAL = 'Umb.UserPermission.Document.SendForApproval'; +export const UMB_USER_PERMISSION_DOCUMENT_UNPUBLISH = 'Umb.UserPermission.Document.Unpublish'; + const permissions: Array = [ { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Browse', + alias: UMB_USER_PERMISSION_DOCUMENT_READ, name: 'Read Document User Permission', meta: { label: 'Read', @@ -12,7 +23,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.CreateBlueprint', + alias: UMB_USER_PERMISSION_DOCUMENT_CREATE_BLUEPRINT, name: 'Create Document Blueprint User Permission', meta: { label: 'Create Content Template', @@ -21,7 +32,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Delete', + alias: UMB_USER_PERMISSION_DOCUMENT_DELETE, name: 'Delete Document User Permission', meta: { label: 'Delete', @@ -30,7 +41,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Create', + alias: UMB_USER_PERMISSION_DOCUMENT_CREATE, name: 'Create Document User Permission', meta: { label: 'Create', @@ -39,7 +50,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Notifications', + alias: UMB_USER_PERMISSION_DOCUMENT_NOTIFICATIONS, name: 'Document Notifications User Permission', meta: { label: 'Notifications', @@ -48,7 +59,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Publish', + alias: UMB_USER_PERMISSION_DOCUMENT_PUBLISH, name: 'Publish Document User Permission', meta: { label: 'Publish', @@ -57,7 +68,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Permissions', + alias: UMB_USER_PERMISSION_DOCUMENT_PERMISSIONS, name: 'Document Permissions User Permission', meta: { label: 'Permissions', @@ -66,7 +77,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.SendForApproval', + alias: UMB_USER_PERMISSION_DOCUMENT_SEND_FOR_APPROVAL, name: 'Send Document For Approval User Permission', meta: { label: 'Send For Approval', @@ -75,7 +86,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Unpublish', + alias: UMB_USER_PERMISSION_DOCUMENT_UNPUBLISH, name: 'Unpublish Document User Permission', meta: { label: 'Unpublish', @@ -84,7 +95,7 @@ const permissions: Array = [ }, { type: 'userPermission', - alias: 'Umb.UserPermission.Document.Update', + alias: UMB_USER_PERMISSION_DOCUMENT_UPDATE, name: 'Update Document User Permission', meta: { label: 'Update', From 265508da90f63493f9338305c074f780ea5db3d2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 13:33:06 +0200 Subject: [PATCH 27/97] use permission const in mock data --- src/mocks/data/user-group.data.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/mocks/data/user-group.data.ts b/src/mocks/data/user-group.data.ts index bffe4852d2..dc30f14544 100644 --- a/src/mocks/data/user-group.data.ts +++ b/src/mocks/data/user-group.data.ts @@ -1,4 +1,9 @@ import { UmbEntityData } from './entity.data.js'; +import { + UMB_USER_PERMISSION_DOCUMENT_CREATE, + UMB_USER_PERMISSION_DOCUMENT_DELETE, + UMB_USER_PERMISSION_DOCUMENT_READ, +} from '@umbraco-cms/backoffice/document'; import { PagedUserGroupResponseModel, UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; // Temp mocked database @@ -36,19 +41,19 @@ export const data: Array = [ id: 'c630d49e-4e7b-42ea-b2bc-edc0edacb6b1', name: 'Administrators', icon: 'umb:medal', - permissions: ['Umb.UserPermission.Create', 'Umb.UserPermission.Delete'], + permissions: [UMB_USER_PERMISSION_DOCUMENT_CREATE, UMB_USER_PERMISSION_DOCUMENT_DELETE], }, { id: '9d24dc47-a4bf-427f-8a4a-b900f03b8a12', name: 'User Group 1', - icon: 'umb:star', - permissions: ['Umb.UserPermission.Delete'], + icon: 'umb:bell', + permissions: [UMB_USER_PERMISSION_DOCUMENT_DELETE], }, { id: 'f4626511-b0d7-4ab1-aebc-a87871a5dcfa', name: 'User Group 2', - icon: 'umb:star', - permissions: ['Umb.UserPermission.Read'], + icon: 'umb:ball', + permissions: [UMB_USER_PERMISSION_DOCUMENT_READ], }, ]; From 4ffa8ba0ea6fc88c3bacd5b0ac5f95817dd110b2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 14:13:16 +0200 Subject: [PATCH 28/97] fix styling --- ...r-group-default-permission-list.element.ts | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts index 0a0c09d09e..51738c068b 100644 --- a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts +++ b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts @@ -45,20 +45,40 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { } #renderPermission(userPermissionManifest: ManifestUserPermission) { - return html`
+ return html`
- this.#onChangeUserPermission(event, userPermissionManifest)}> -
-
${userPermissionManifest.meta.label}
- ${userPermissionManifest.meta.description} -
+ @change=${(event: UUIBooleanInputEvent) => this.#onChangeUserPermission(event, userPermissionManifest)}> +
+
${userPermissionManifest.meta.label}
+ ${userPermissionManifest.meta.description} +
+
`; } - static styles = [UmbTextStyles, css``]; + static styles = [ + UmbTextStyles, + css` + .permission-toggle { + display: flex; + align-items: center; + border-bottom: 1px solid var(--uui-color-divider); + padding: var(--uui-size-space-3) 0 var(--uui-size-space-4) 0; + } + + .permission-meta { + margin-left: var(--uui-size-space-4); + line-height: 1.2em; + } + + .permission-name { + font-weight: bold; + } + `, + ]; } export default UmbUserGroupDefaultPermissionListElement; From d35167e8e218a0ac952257253865cbeb7b2f06b9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 16:35:29 +0200 Subject: [PATCH 29/97] add new granular user permission extension type --- src/packages/core/extension-registry/models/index.ts | 3 +++ .../models/user-granular-permission.model.ts | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/packages/core/extension-registry/models/user-granular-permission.model.ts diff --git a/src/packages/core/extension-registry/models/index.ts b/src/packages/core/extension-registry/models/index.ts index 9a03228df5..65ba8fdb27 100644 --- a/src/packages/core/extension-registry/models/index.ts +++ b/src/packages/core/extension-registry/models/index.ts @@ -29,6 +29,7 @@ import type { ManifestWorkspaceAction } from './workspace-action.model.js'; import type { ManifestWorkspaceEditorView } from './workspace-editor-view.model.js'; import type { ManifestWorkspaceViewCollection } from './workspace-view-collection.model.js'; import type { ManifestUserPermission } from './user-permission.model.js'; +import type { ManifestUserGranularPermission } from './user-granular-permission.model.js'; import type { ManifestBase, ManifestBundle, @@ -67,6 +68,7 @@ export * from './workspace-view-collection.model.js'; export * from './workspace-editor-view.model.js'; export * from './workspace.model.js'; export * from './user-permission.model.js'; +export * from './user-granular-permission.model.js'; export type ManifestTypes = | ManifestBundle @@ -109,4 +111,5 @@ export type ManifestTypes = | ManifestWorkspaceEditorView | ManifestWorkspaceViewCollection | ManifestUserPermission + | ManifestUserGranularPermission | ManifestBase; diff --git a/src/packages/core/extension-registry/models/user-granular-permission.model.ts b/src/packages/core/extension-registry/models/user-granular-permission.model.ts new file mode 100644 index 0000000000..22f8dfd41c --- /dev/null +++ b/src/packages/core/extension-registry/models/user-granular-permission.model.ts @@ -0,0 +1,10 @@ +import type { ManifestElement } from '@umbraco-cms/backoffice/extension-api'; + +export interface ManifestUserGranularPermission extends ManifestElement { + type: 'userGranularPermission'; + meta: MetaUserGranularPermission; +} + +export interface MetaUserGranularPermission { + entityType: Array; +} From 686bb56415c6873488b9c47713aab710f4c1480d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 16:35:56 +0200 Subject: [PATCH 30/97] register granular permission for documents --- .../documents/user-permissions/manifests.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index 9d5d04f95a..099f937223 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -1,4 +1,7 @@ -import type { ManifestUserPermission } from '@umbraco-cms/backoffice/extension-registry'; +import type { + ManifestUserGranularPermission, + ManifestUserPermission, +} from '@umbraco-cms/backoffice/extension-registry'; export const UMB_USER_PERMISSION_DOCUMENT_CREATE = 'Umb.UserPermission.Document.Create'; export const UMB_USER_PERMISSION_DOCUMENT_READ = 'Umb.UserPermission.Document.Read'; @@ -104,4 +107,15 @@ const permissions: Array = [ }, ]; +export const granularPermissions: Array = [ + { + type: 'userGranularPermission', + alias: 'Umb.UserGranularPermission.Document', + name: 'Document Granular User Permission', + meta: { + entityType: ['document'], + }, + }, +]; + export const manifests = [...permissions]; From 94e9dce19c9911f1a428df922b486555e87fe24e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 18 Sep 2023 16:36:50 +0200 Subject: [PATCH 31/97] export granular permission manifest --- src/packages/documents/documents/user-permissions/manifests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index 099f937223..ec071ddf2f 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -118,4 +118,4 @@ export const granularPermissions: Array = [ }, ]; -export const manifests = [...permissions]; +export const manifests = [...permissions, ...granularPermissions]; From 2312e4f52180404cb8fc15dd5810098bcd532219 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 19 Sep 2023 20:14:24 +0200 Subject: [PATCH 32/97] render granular permission extensions --- .../documents/documents/components/index.ts | 1 + src/packages/users/index.ts | 7 ++-- ...-group-granular-permission-list.element.ts | 36 +++++++++++++++++++ .../user-group-workspace-editor.element.ts | 3 +- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/packages/users/user-groups/workspace/components/user-group-granular-permission-list.element.ts diff --git a/src/packages/documents/documents/components/index.ts b/src/packages/documents/documents/components/index.ts index 339d030d1d..a644a4c547 100644 --- a/src/packages/documents/documents/components/index.ts +++ b/src/packages/documents/documents/components/index.ts @@ -1 +1,2 @@ export * from './input-document/input-document.element.js'; +export * from './input-document-granular-permission/input-document-granular-permission.element.js'; diff --git a/src/packages/users/index.ts b/src/packages/users/index.ts index 8fb22d2dd6..78a5dac9ba 100644 --- a/src/packages/users/index.ts +++ b/src/packages/users/index.ts @@ -1,2 +1,5 @@ -export * from './users/components/index.js'; -export * from './user-groups/components/index.js'; +export * from './components/index.js'; +export * from './current-user/index.js'; +export * from './user-groups/index.js'; +export * from './users/index.js'; +export * from './manifests.js'; diff --git a/src/packages/users/user-groups/workspace/components/user-group-granular-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-granular-permission-list.element.ts new file mode 100644 index 0000000000..57d87998b1 --- /dev/null +++ b/src/packages/users/user-groups/workspace/components/user-group-granular-permission-list.element.ts @@ -0,0 +1,36 @@ +import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from '../user-group-workspace.context.js'; +import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; + +@customElement('umb-user-group-granular-permission-list') +export class UmbUserGroupGranularPermissionListElement extends UmbLitElement { + @state() + private _userGroup?: UserGroupResponseModel; + + #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; + + constructor() { + super(); + + this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => { + this.#workspaceContext = instance; + this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); + }); + } + + render() { + return html``; + } + + static styles = [UmbTextStyles, css``]; +} + +export default UmbUserGroupGranularPermissionListElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-group-granular-permission-list': UmbUserGroupGranularPermissionListElement; + } +} diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index f54b6b9dd2..27dd5f0d92 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -11,6 +11,7 @@ import { import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import './components/user-group-default-permission-list.element.js'; +import './components/user-group-granular-permission-list.element.js'; @customElement('umb-user-group-workspace-editor') export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @@ -134,7 +135,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
Granular permissions
- PERMISSIONS NOT IMPLEMENTED YET +
`; } From 47a052a2082ad4922f0d8f450c51a4d70a56e1ca Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 19 Sep 2023 20:19:33 +0200 Subject: [PATCH 33/97] add entity type to document permissions --- .../models/user-permission.model.ts | 5 +++-- .../documents/user-permissions/manifests.ts | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/packages/core/extension-registry/models/user-permission.model.ts b/src/packages/core/extension-registry/models/user-permission.model.ts index 8f9738a373..5b15a1712f 100644 --- a/src/packages/core/extension-registry/models/user-permission.model.ts +++ b/src/packages/core/extension-registry/models/user-permission.model.ts @@ -7,6 +7,7 @@ export interface ManifestUserPermission extends ManifestBase { export interface MetaUserPermission { label: string; - description?: string; - group?: string; + entityType: Array; + description?: string; + group?: string; } diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index ec071ddf2f..f3f983a2e6 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -20,6 +20,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_READ, name: 'Read Document User Permission', meta: { + entityType: ['document'], label: 'Read', description: 'Allow access to browse documents', }, @@ -29,6 +30,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_CREATE_BLUEPRINT, name: 'Create Document Blueprint User Permission', meta: { + entityType: ['document'], label: 'Create Content Template', description: 'Allow access to create a Content Template', }, @@ -38,6 +40,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_DELETE, name: 'Delete Document User Permission', meta: { + entityType: ['document'], label: 'Delete', description: 'Allow access to delete a document', }, @@ -47,6 +50,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_CREATE, name: 'Create Document User Permission', meta: { + entityType: ['document'], label: 'Create', description: 'Allow access to create a document', }, @@ -56,6 +60,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_NOTIFICATIONS, name: 'Document Notifications User Permission', meta: { + entityType: ['document'], label: 'Notifications', description: 'Allow access to setup notifications for documents', }, @@ -65,6 +70,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_PUBLISH, name: 'Publish Document User Permission', meta: { + entityType: ['document'], label: 'Publish', description: 'Allow access to publish a document', }, @@ -74,6 +80,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_PERMISSIONS, name: 'Document Permissions User Permission', meta: { + entityType: ['document'], label: 'Permissions', description: 'Allow access to change permissions for a document', }, @@ -83,6 +90,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_SEND_FOR_APPROVAL, name: 'Send Document For Approval User Permission', meta: { + entityType: ['document'], label: 'Send For Approval', description: 'Allow access to send a document for approval before publishing', }, @@ -92,6 +100,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_UNPUBLISH, name: 'Unpublish Document User Permission', meta: { + entityType: ['document'], label: 'Unpublish', description: 'Allow access to unpublish a document', }, @@ -101,6 +110,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_UPDATE, name: 'Update Document User Permission', meta: { + entityType: ['document'], label: 'Update', description: 'Allow access to save a document', }, @@ -112,6 +122,8 @@ export const granularPermissions: Array = [ type: 'userGranularPermission', alias: 'Umb.UserGranularPermission.Document', name: 'Document Granular User Permission', + loader: () => + import('../components/input-document-granular-permission/input-document-granular-permission.element.js'), meta: { entityType: ['document'], }, From 94ef966c791fb9f2a7c2c8e0d6807b8a6a8694ae Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 25 Sep 2023 13:07:34 +0200 Subject: [PATCH 34/97] add scaffold for common dialog to get permission based on an entity type and unique --- ...-user-permission-settings-modal.element.ts | 112 ++++++++++++++++++ src/packages/core/modal/common/manifests.ts | 6 + ...ty-user-permission-settings-modal.token.ts | 15 +++ src/packages/core/modal/token/index.ts | 1 + .../entity-actions/permissions.action.ts | 32 ++++- 5 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 src/packages/core/modal/common/entity-user-permission-settings/entity-user-permission-settings-modal.element.ts create mode 100644 src/packages/core/modal/token/entity-user-permission-settings-modal.token.ts diff --git a/src/packages/core/modal/common/entity-user-permission-settings/entity-user-permission-settings-modal.element.ts b/src/packages/core/modal/common/entity-user-permission-settings/entity-user-permission-settings-modal.element.ts new file mode 100644 index 0000000000..cacdb22527 --- /dev/null +++ b/src/packages/core/modal/common/entity-user-permission-settings/entity-user-permission-settings-modal.element.ts @@ -0,0 +1,112 @@ +import { html, customElement, property, state, css } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { + UmbEntityUserPermissionSettingsModalData, + UmbEntityUserPermissionSettingsModalResult, + UmbModalContext, +} from '@umbraco-cms/backoffice/modal'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { ManifestUserPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; + +@customElement('umb-entity-user-permission-settings-modal') +export class UmbEntityUserPermissionSettingsModalElement extends UmbLitElement { + @property({ attribute: false }) + modalContext?: UmbModalContext; + + @property({ type: Object }) + data?: UmbEntityUserPermissionSettingsModalData; + + @state() + private _userPermissionManifests: Array = []; + + private _handleConfirm() { + this.modalContext?.submit(); + } + + private _handleCancel() { + this.modalContext?.reject(); + } + + constructor() { + super(); + this.observe( + umbExtensionsRegistry.extensionsOfType('userPermission'), + (userPermissionManifests) => (this._userPermissionManifests = userPermissionManifests), + ); + } + + render() { + return html` + + + Render user permissions for ${this.data?.entityType} ${this.data?.unique} + ${this._userPermissionManifests.map((permission) => this.#renderPermission(permission))} + + Cancel + + + + `; + } + + #onChangeUserPermission(event: UUIBooleanInputEvent, userPermissionManifest: ManifestUserPermission) { + console.log(userPermissionManifest); + console.log(event.target.checked); + } + + #isAllowed(userPermissionManifest: ManifestUserPermission) { + return true; + //return this._userGroup?.permissions?.includes(userPermissionManifest.alias); + } + + #renderPermission(userPermissionManifest: ManifestUserPermission) { + return html`
+ this.#onChangeUserPermission(event, userPermissionManifest)}> +
+
${userPermissionManifest.meta.label}
+ ${userPermissionManifest.meta.description} +
+
+
`; + } + + static styles = [ + UmbTextStyles, + css` + .permission-toggle { + display: flex; + align-items: center; + border-bottom: 1px solid var(--uui-color-divider); + padding: var(--uui-size-space-3) 0 var(--uui-size-space-4) 0; + } + + .permission-meta { + margin-left: var(--uui-size-space-4); + line-height: 1.2em; + } + + .permission-name { + font-weight: bold; + } + `, + ]; +} + +export default UmbEntityUserPermissionSettingsModalElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-entity-user-permission-modal': UmbEntityUserPermissionSettingsModalElement; + } +} diff --git a/src/packages/core/modal/common/manifests.ts b/src/packages/core/modal/common/manifests.ts index 6d7044fd52..9f8b55d4f9 100644 --- a/src/packages/core/modal/common/manifests.ts +++ b/src/packages/core/modal/common/manifests.ts @@ -61,6 +61,12 @@ const modals: Array = [ name: 'Tree Picker Modal', loader: () => import('./tree-picker/tree-picker-modal.element.js'), }, + { + type: 'modal', + alias: 'Umb.Modal.EntityUserPermissionSettings', + name: 'Entity User Permission Settings Modal', + loader: () => import('./entity-user-permission-settings/entity-user-permission-settings-modal.element.js'), + }, ]; export const manifests = [...modals]; diff --git a/src/packages/core/modal/token/entity-user-permission-settings-modal.token.ts b/src/packages/core/modal/token/entity-user-permission-settings-modal.token.ts new file mode 100644 index 0000000000..62553352fb --- /dev/null +++ b/src/packages/core/modal/token/entity-user-permission-settings-modal.token.ts @@ -0,0 +1,15 @@ +import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; + +export interface UmbEntityUserPermissionSettingsModalData { + unique: string; + entityType: Array; +} + +export type UmbEntityUserPermissionSettingsModalResult = undefined; + +export const UMB_ENTITY_USER_PERMISSION_MODAL = new UmbModalToken< + UmbEntityUserPermissionSettingsModalData, + UmbEntityUserPermissionSettingsModalResult +>('Umb.Modal.EntityUserPermissionSettings', { + type: 'sidebar', +}); diff --git a/src/packages/core/modal/token/index.ts b/src/packages/core/modal/token/index.ts index 63163c3cb8..6871d578f7 100644 --- a/src/packages/core/modal/token/index.ts +++ b/src/packages/core/modal/token/index.ts @@ -33,3 +33,4 @@ export * from './data-type-picker-modal.token.js'; export * from './workspace-modal.token.js'; export * from './data-type-picker-flow-modal.token.js'; export * from './data-type-picker-flow-data-type-picker-modal.token.js'; +export * from './entity-user-permission-settings-modal.token.js'; diff --git a/src/packages/documents/documents/entity-actions/permissions.action.ts b/src/packages/documents/documents/entity-actions/permissions.action.ts index 36f3549ca1..bea922e1af 100644 --- a/src/packages/documents/documents/entity-actions/permissions.action.ts +++ b/src/packages/documents/documents/entity-actions/permissions.action.ts @@ -1,14 +1,40 @@ -import { UmbDocumentRepository } from '../repository/document.repository.js'; +import { type UmbDocumentRepository } from '../repository/document.repository.js'; import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; +import { + UMB_MODAL_MANAGER_CONTEXT_TOKEN, + UmbModalManagerContext, + UMB_ENTITY_USER_PERMISSION_MODAL, +} from '@umbraco-cms/backoffice/modal'; export class UmbDocumentPermissionsEntityAction extends UmbEntityActionBase { + #modalContext?: UmbModalManagerContext; + constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { super(host, repositoryAlias, unique); + + new UmbContextConsumerController(this.host, UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { + this.#modalContext = instance; + }); } async execute() { - console.log(`execute for: ${this.unique}`); - await this.repository?.setPermissions(); + if (!this.repository) return; + if (!this.#modalContext) return; + + // TODO: we don't get "type" as part of the item + const { data, error } = await this.repository.requestItems([this.unique]); + + const modalContext = this.#modalContext.open(UMB_ENTITY_USER_PERMISSION_MODAL, { + unique: this.unique, + entityType: ['document'], + }); + + const { selection } = await modalContext.onSubmit(); + console.log(selection); + debugger; + + //await this.repository?.setPermissions(); } } From a0dea29574f77eab97eba68cddd0f908ee0c5b34 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 25 Sep 2023 13:08:12 +0200 Subject: [PATCH 35/97] wip granular permissions for documents --- ...ut-document-granular-permission.element.ts | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts diff --git a/src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts b/src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts new file mode 100644 index 0000000000..af6d9ad5d0 --- /dev/null +++ b/src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts @@ -0,0 +1,123 @@ +import { css, html, customElement, property, state, PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; +import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui'; +import { + UmbModalManagerContext, + UMB_MODAL_MANAGER_CONTEXT_TOKEN, + UMB_CONFIRM_MODAL, + UMB_DOCUMENT_PICKER_MODAL, +} from '@umbraco-cms/backoffice/modal'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import type { DocumentItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbDocumentRepository } from '@umbraco-cms/backoffice/document'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; +import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; + +@customElement('umb-input-document-granular-permission') +export class UmbInputDocumentGranularPermissionElement extends FormControlMixin(UmbLitElement) { + private _selectedIds: Array = []; + public get selectedIds(): Array { + return this._selectedIds; + } + public set selectedIds(ids: Array) { + this._selectedIds = ids; + super.value = ids.join(','); + this.#observePickedDocuments(); + } + + @property() + public set value(idsString: string) { + if (idsString !== this._value) { + this.selectedIds = idsString.split(/[ ,]+/); + } + } + + @state() + private _items?: Array; + + #documentRepository = new UmbDocumentRepository(this); + #modalContext?: UmbModalManagerContext; + #pickedItemsObserver?: UmbObserverController>; + + constructor() { + super(); + this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => (this.#modalContext = instance)); + } + + protected firstUpdated(_changedProperties: PropertyValueMap | Map): void { + super.firstUpdated(_changedProperties); + this.#observePickedDocuments(); + } + + protected getFormElement() { + return undefined; + } + + async #observePickedDocuments() { + this.#pickedItemsObserver?.destroy(); + + const { asObservable } = await this.#documentRepository.requestItems(this._selectedIds); + this.#pickedItemsObserver = this.observe(asObservable(), (items) => (this._items = items)); + } + + #openDocumentPicker() { + // We send a shallow copy(good enough as its just an array of ids) of our this._selectedIds, as we don't want the modal to manipulate our data: + const modalContext = this.#modalContext?.open(UMB_DOCUMENT_PICKER_MODAL, { + selection: [...this._selectedIds], + }); + + modalContext?.onSubmit().then(({ selection }: any) => { + debugger; + //this.#setSelection(selection); + }); + } + + async #removeItem(item: DocumentItemResponseModel) { + const modalContext = this.#modalContext?.open(UMB_CONFIRM_MODAL, { + color: 'danger', + headline: `Remove ${item.name}?`, + content: 'Are you sure you want to remove this item', + confirmLabel: 'Remove', + }); + + await modalContext?.onSubmit(); + const newSelection = this._selectedIds.filter((value) => value !== item.id); + this.#setSelection(newSelection); + } + + #setSelection(newSelection: Array) { + this.selectedIds = newSelection; + this.dispatchEvent(new UmbChangeEvent()); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + this.#pickedItemsObserver?.destroy(); + } + + render() { + return html` + ${this._items?.map((item) => this.#renderItem(item))} + Add + `; + } + + #renderItem(item: DocumentItemResponseModel) { + return html`
Render something here
`; + } + + static styles = [ + css` + #add-button { + width: 100%; + } + `, + ]; +} + +export default UmbInputDocumentGranularPermissionElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-input-document-granular-permission': UmbInputDocumentGranularPermissionElement; + } +} From 6045387617a7efc5fa3634633a06a5bd4976361d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 25 Sep 2023 16:25:31 +0200 Subject: [PATCH 36/97] add selected event --- src/shared/umb-events/index.ts | 1 + src/shared/umb-events/selected.event.ts | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 src/shared/umb-events/selected.event.ts diff --git a/src/shared/umb-events/index.ts b/src/shared/umb-events/index.ts index 3bcae218c6..5835784021 100644 --- a/src/shared/umb-events/index.ts +++ b/src/shared/umb-events/index.ts @@ -2,3 +2,4 @@ export * from './input.event.js'; export * from './change.event.js'; export * from './delete.event.js'; export * from './executed.event.js'; +export * from './selected.event.js'; diff --git a/src/shared/umb-events/selected.event.ts b/src/shared/umb-events/selected.event.ts new file mode 100644 index 0000000000..9ecf5d7767 --- /dev/null +++ b/src/shared/umb-events/selected.event.ts @@ -0,0 +1,6 @@ +export class UmbSelectedEvent extends Event { + public constructor() { + // mimics the native change event + super('selected', { bubbles: true, composed: false, cancelable: false }); + } +} From 1d16f342e819155f17fcb1fba0fed659a906af09 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 25 Sep 2023 16:25:52 +0200 Subject: [PATCH 37/97] use selected event when selecting tree items --- src/packages/core/tree/tree.context.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/packages/core/tree/tree.context.ts b/src/packages/core/tree/tree.context.ts index ef94d2f024..1e9c5fe3a6 100644 --- a/src/packages/core/tree/tree.context.ts +++ b/src/packages/core/tree/tree.context.ts @@ -1,12 +1,12 @@ -import { Observable, map } from '@umbraco-cms/backoffice/external/rxjs'; +import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; import { UmbPagedData, UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; import { ManifestTree, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api'; import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api'; import { ProblemDetails, TreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api'; -import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api'; import { UmbSelectionManagerBase } from '@umbraco-cms/backoffice/utils'; +import { UmbSelectedEvent } from '@umbraco-cms/backoffice/events'; // TODO: update interface export interface UmbTreeContext extends UmbBaseController { @@ -102,12 +102,12 @@ export class UmbTreeContextBase public select(unique: string | null) { if (!this.getSelectable()) return; this.#selectionManager.select(unique); - this._host.getHostElement().dispatchEvent(new CustomEvent('selected')); + this._host.getHostElement().dispatchEvent(new UmbSelectedEvent()); } public deselect(unique: string | null) { this.#selectionManager.deselect(unique); - this._host.getHostElement().dispatchEvent(new CustomEvent('selected')); + this._host.getHostElement().dispatchEvent(new UmbSelectedEvent()); } public async requestTreeRoot() { @@ -144,7 +144,7 @@ export class UmbTreeContextBase if (!treeManifest) return; this.#observeRepository(treeManifest); }, - '_observeTreeManifest' + '_observeTreeManifest', ); } } @@ -166,7 +166,7 @@ export class UmbTreeContextBase throw new Error('Could not create repository with alias: ' + repositoryAlias + ''); } }, - '_observeRepository' + '_observeRepository', ); } } From d036b107dfbfa3cadf0195802449e18731fb286d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 25 Sep 2023 16:25:59 +0200 Subject: [PATCH 38/97] format --- src/packages/core/tree/tree.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/core/tree/tree.element.ts b/src/packages/core/tree/tree.element.ts index de7c270b54..aa06b67efa 100644 --- a/src/packages/core/tree/tree.element.ts +++ b/src/packages/core/tree/tree.element.ts @@ -119,7 +119,7 @@ export class UmbTreeElement extends UmbLitElement { this._items, // TODO: use unique here: (item, index) => item.name + '___' + index, - (item) => html`` + (item) => html``, )} `; } From 738010d2f3c00c28899886a1a12c44c6b81be92e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 25 Sep 2023 16:26:40 +0200 Subject: [PATCH 39/97] dispatch selected event from tree picker modal --- .../modal/common/tree-picker/tree-picker-modal.element.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts b/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts index e0199b2663..3ecae28a7d 100644 --- a/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts +++ b/src/packages/core/modal/common/tree-picker/tree-picker-modal.element.ts @@ -1,9 +1,10 @@ import type { UmbTreeElement } from '../../../tree/tree.element.js'; -import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; +import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbTreePickerModalData, UmbPickerModalResult } from '@umbraco-cms/backoffice/modal'; import { UmbModalBaseElement } from '@umbraco-cms/internal/modal'; import { TreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbSelectedEvent } from '@umbraco-cms/backoffice/events'; @customElement('umb-tree-picker-modal') export class UmbTreePickerModalElement extends UmbModalBaseElement< @@ -27,6 +28,7 @@ export class UmbTreePickerModalElement Date: Mon, 25 Sep 2023 19:38:57 +0200 Subject: [PATCH 40/97] format --- src/shared/modal/modal-element.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/modal/modal-element.element.ts b/src/shared/modal/modal-element.element.ts index f48b660d33..cd85083498 100644 --- a/src/shared/modal/modal-element.element.ts +++ b/src/shared/modal/modal-element.element.ts @@ -6,7 +6,7 @@ import type { ManifestModal, UmbModalExtensionElement } from '@umbraco-cms/backo export abstract class UmbModalBaseElement< ModalDataType extends object = object, ModalResultType = unknown, - ModalManifestType extends ManifestModal = ManifestModal + ModalManifestType extends ManifestModal = ManifestModal, > extends UmbLitElement implements UmbModalExtensionElement From a0dfc9e170e8b3b60cd9813052d67e8db1e25ad0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 09:38:18 +0200 Subject: [PATCH 41/97] export modules in user package --- src/packages/users/index.ts | 1 - src/packages/users/user-groups/components/index.ts | 2 ++ src/packages/users/user-groups/index.ts | 1 + src/packages/users/users/components/index.ts | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/packages/users/index.ts b/src/packages/users/index.ts index 78a5dac9ba..2f1673f76b 100644 --- a/src/packages/users/index.ts +++ b/src/packages/users/index.ts @@ -1,4 +1,3 @@ -export * from './components/index.js'; export * from './current-user/index.js'; export * from './user-groups/index.js'; export * from './users/index.js'; diff --git a/src/packages/users/user-groups/components/index.ts b/src/packages/users/user-groups/components/index.ts index 087396e3a3..11d389d6f6 100644 --- a/src/packages/users/user-groups/components/index.ts +++ b/src/packages/users/user-groups/components/index.ts @@ -1 +1,3 @@ import './input-user-group/user-group-input.element.js'; + +export * from './input-user-group/user-group-input.element.js'; diff --git a/src/packages/users/user-groups/index.ts b/src/packages/users/user-groups/index.ts index d4702960d5..a63600bee5 100644 --- a/src/packages/users/user-groups/index.ts +++ b/src/packages/users/user-groups/index.ts @@ -1 +1,2 @@ export * from './types.js'; +export * from './components/index.js'; diff --git a/src/packages/users/users/components/index.ts b/src/packages/users/users/components/index.ts index 9166992fcc..c5a96c894c 100644 --- a/src/packages/users/users/components/index.ts +++ b/src/packages/users/users/components/index.ts @@ -1 +1,3 @@ import './user-input/user-input.element.js'; + +export * from './user-input/user-input.element.js'; From 04c7ed6a22aea22ae72c74efa9cf5bfaf4fc23ad Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 09:38:31 +0200 Subject: [PATCH 42/97] register entry point --- src/packages/users/umbraco-package.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/packages/users/umbraco-package.ts b/src/packages/users/umbraco-package.ts index 7418be463d..4d2c28d65c 100644 --- a/src/packages/users/umbraco-package.ts +++ b/src/packages/users/umbraco-package.ts @@ -7,4 +7,10 @@ export const extensions = [ type: 'bundle', loader: () => import('./manifests.js'), }, + { + name: 'User Management Entry Point', + alias: 'Umb.EntryPoint.UserManagement', + type: 'entryPoint', + loader: () => import('./index.js'), + }, ]; From d5d6b7b73a1520843fd554b523a020ee39df043f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 09:45:19 +0200 Subject: [PATCH 43/97] clean up --- .../user-workspace-editor.element.ts | 82 +++++++++++-------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/src/packages/users/users/workspace/user-workspace-editor.element.ts b/src/packages/users/users/workspace/user-workspace-editor.element.ts index 843fdc6ca4..606f8df7be 100644 --- a/src/packages/users/users/workspace/user-workspace-editor.element.ts +++ b/src/packages/users/users/workspace/user-workspace-editor.element.ts @@ -1,6 +1,6 @@ +import { UmbUserRepository } from '@umbraco-cms/backoffice/user'; import { getDisplayStateFromUserStatus } from '../../utils.js'; import { UmbUserRepository } from '../repository/user.repository.js'; -import { UmbUserGroupInputElement } from '../../user-groups/components/input-user-group/user-group-input.element.js'; import { type UmbUserDetail } from '../index.js'; import { UmbUserWorkspaceContext } from './user-workspace.context.js'; import { UUIInputElement, UUIInputEvent, UUISelectElement } from '@umbraco-cms/backoffice/external/uui'; @@ -15,17 +15,14 @@ import { repeat, } from '@umbraco-cms/backoffice/external/lit'; import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; - -import { UMB_CHANGE_PASSWORD_MODAL } from '@umbraco-cms/backoffice/modal'; -import type { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; +import { UMB_CHANGE_PASSWORD_MODAL, type UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; - import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; -import { UserStateModel } from '@umbraco-cms/backoffice/backend-api'; +import { type UserStateModel } from '@umbraco-cms/backoffice/backend-api'; import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; -import { UMB_AUTH, UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; +import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @customElement('umb-user-workspace-editor') @@ -43,7 +40,7 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { #modalContext?: UmbModalManagerContext; #workspaceContext?: UmbUserWorkspaceContext; - #userRepository?: UmbUserRepository; + #userRepository = new UmbUserRepository(this); constructor() { super(); @@ -54,25 +51,9 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { }); this.consumeContext(UMB_WORKSPACE_CONTEXT, (workspaceContext) => { - this.#workspaceContext = workspaceContext as UmbUserWorkspaceContext; + this.#workspaceContext = workspaceContext; this.#observeUser(); }); - - // TODO: this code is reused in multiple places, so it should be extracted to a function - new UmbObserverController( - this, - umbExtensionsRegistry.getByTypeAndAlias('repository', 'Umb.Repository.User'), - async (repositoryManifest) => { - if (!repositoryManifest) return; - - try { - const result = await createExtensionClass(repositoryManifest, [this]); - this.#userRepository = result; - } catch (error) { - throw new Error('Could not create repository with alias: Umb.Repository.User'); - } - }, - ); } #observeUser() { @@ -198,9 +179,16 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { return html`
Profile
- + - +
Assign Access
- +
- Based on the assigned groups and start nodes, the user has access to the following nodes - + Based on the assigned groups and start nodes, the user has access to the following nodes
Content @@ -267,7 +258,7 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement {
Status: - ${this.localize.term('user_'+displayState.key)} + ${this.localize.term('user_' + displayState.key)}
@@ -277,7 +268,11 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { ` : nothing} - ${this.#renderInfoItem('user_lastLogin', this.localize.date(this._user.lastLoginDate!) || `${this._user.name + ' ' + this.localize.term('user_noLogin') } `)} + ${this.#renderInfoItem( + 'user_lastLogin', + this.localize.date(this._user.lastLoginDate!) || + `${this._user.name + ' ' + this.localize.term('user_noLogin')} `, + )} ${this.#renderInfoItem('user_failedPasswordAttempts', this._user.failedLoginAttempts)} ${this.#renderInfoItem( 'user_lastLockoutDate', @@ -313,26 +308,41 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { if (this._user.state === UserStateModel.DISABLED) { buttons.push(html` - + `); } if (this._user.state === UserStateModel.ACTIVE || this._user.state === UserStateModel.INACTIVE) { buttons.push(html` - + `); } if (this._currentUser?.id !== this._user?.id) { const button = html` - + `; buttons.push(button); } buttons.push( - html``, + html``, ); return buttons; From ec7f84d91aed3f275fd3fa8585f153c898e930cf Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 09:49:19 +0200 Subject: [PATCH 44/97] don't add type to UserStateModel --- .../users/users/workspace/user-workspace-editor.element.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/packages/users/users/workspace/user-workspace-editor.element.ts b/src/packages/users/users/workspace/user-workspace-editor.element.ts index 606f8df7be..59be1e904d 100644 --- a/src/packages/users/users/workspace/user-workspace-editor.element.ts +++ b/src/packages/users/users/workspace/user-workspace-editor.element.ts @@ -1,8 +1,7 @@ -import { UmbUserRepository } from '@umbraco-cms/backoffice/user'; import { getDisplayStateFromUserStatus } from '../../utils.js'; -import { UmbUserRepository } from '../repository/user.repository.js'; import { type UmbUserDetail } from '../index.js'; import { UmbUserWorkspaceContext } from './user-workspace.context.js'; +import { UmbUserRepository } from '@umbraco-cms/backoffice/users'; import { UUIInputElement, UUIInputEvent, UUISelectElement } from '@umbraco-cms/backoffice/external/uui'; import { css, @@ -18,10 +17,8 @@ import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; import { UMB_CHANGE_PASSWORD_MODAL, type UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; -import { type UserStateModel } from '@umbraco-cms/backoffice/backend-api'; -import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api'; +import { UserStateModel } from '@umbraco-cms/backoffice/backend-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; -import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; From 95165b8a49566c7c2bb170d48d803f57db8b621e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 10:01:16 +0200 Subject: [PATCH 45/97] format --- src/packages/core/picker-input/picker-input.context.ts | 2 +- src/shared/repository/repository-items.manager.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/core/picker-input/picker-input.context.ts b/src/packages/core/picker-input/picker-input.context.ts index b10586a5de..2800d55146 100644 --- a/src/packages/core/picker-input/picker-input.context.ts +++ b/src/packages/core/picker-input/picker-input.context.ts @@ -37,7 +37,7 @@ export class UmbPickerInputContext host: UmbControllerHostElement, repositoryAlias: string, modalAlias: string | UmbModalToken, - getUniqueMethod?: (entry: ItemType) => string | undefined + getUniqueMethod?: (entry: ItemType) => string | undefined, ) { this.host = host; this.modalAlias = modalAlias; diff --git a/src/shared/repository/repository-items.manager.ts b/src/shared/repository/repository-items.manager.ts index 75f08fb040..ee2b154ae7 100644 --- a/src/shared/repository/repository-items.manager.ts +++ b/src/shared/repository/repository-items.manager.ts @@ -29,7 +29,7 @@ export class UmbRepositoryItemsManager string | undefined + getUniqueMethod?: (entry: ItemType) => string | undefined, ) { this.host = host; this.#getUnique = getUniqueMethod || ((entry) => entry.id || ''); From 3a18351c577c5d3a2c6e5d25dee2d3893fd47e4e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 10:01:34 +0200 Subject: [PATCH 46/97] add user group item handler --- src/mocks/handlers/user-group.handlers.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mocks/handlers/user-group.handlers.ts b/src/mocks/handlers/user-group.handlers.ts index d0efce58b4..c18f37bdd9 100644 --- a/src/mocks/handlers/user-group.handlers.ts +++ b/src/mocks/handlers/user-group.handlers.ts @@ -5,6 +5,14 @@ import { umbracoPath } from '@umbraco-cms/backoffice/utils'; const slug = '/user-group'; export const handlers = [ + rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => { + const ids = req.url.searchParams.getAll('id'); + if (!ids) return; + const items = umbUserGroupData.getItems(ids); + + return res(ctx.status(200), ctx.json(items)); + }), + rest.get(umbracoPath(`${slug}`), (req, res, ctx) => { const response = umbUserGroupData.getAll(); From 7a39d55ba9071efa4a011728ed64458885422a9a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 10:01:52 +0200 Subject: [PATCH 47/97] add methods to get user group items --- src/mocks/data/user-group.data.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/mocks/data/user-group.data.ts b/src/mocks/data/user-group.data.ts index dc30f14544..390acf9c59 100644 --- a/src/mocks/data/user-group.data.ts +++ b/src/mocks/data/user-group.data.ts @@ -4,7 +4,19 @@ import { UMB_USER_PERMISSION_DOCUMENT_DELETE, UMB_USER_PERMISSION_DOCUMENT_READ, } from '@umbraco-cms/backoffice/document'; -import { PagedUserGroupResponseModel, UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { + PagedUserGroupResponseModel, + UserGroupItemResponseModel, + UserGroupResponseModel, +} from '@umbraco-cms/backoffice/backend-api'; + +const createUserGroupItem = (item: UserGroupResponseModel): UserGroupItemResponseModel => { + return { + name: item.name, + id: item.id, + icon: item.icon, + }; +}; // Temp mocked database class UmbUserGroupData extends UmbEntityData { @@ -19,6 +31,11 @@ class UmbUserGroupData extends UmbEntityData { }; } + getItems(ids: Array): Array { + const items = this.data.filter((item) => ids.includes(item.id ?? '')); + return items.map((item) => createUserGroupItem(item)); + } + /** * Returns a list of permissions for the given user group ids * @param {string[]} userGroupIds From 4cc351f470e44f6a6aff42effeffcd818ce246f9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 10:06:40 +0200 Subject: [PATCH 48/97] export components from user module --- src/packages/users/users/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packages/users/users/index.ts b/src/packages/users/users/index.ts index a58e6a45e7..966b5e5d2d 100644 --- a/src/packages/users/users/index.ts +++ b/src/packages/users/users/index.ts @@ -1,2 +1,3 @@ -export * from './types.js'; +export * from './components/index.js'; export * from './repository/index.js'; +export * from './types.js'; From cf6ace7e3c983302a50d0fc9ef984ddf85d8e281 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 10:10:41 +0200 Subject: [PATCH 49/97] add handlers to get user items --- src/mocks/data/user.data.ts | 19 ++++++++++++++++++- src/mocks/handlers/user.handlers.ts | 8 ++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/mocks/data/user.data.ts b/src/mocks/data/user.data.ts index 5428df3e45..9c95f2c825 100644 --- a/src/mocks/data/user.data.ts +++ b/src/mocks/data/user.data.ts @@ -1,7 +1,19 @@ import { UmbEntityData } from './entity.data.js'; import { umbUserGroupData } from './user-group.data.js'; import { UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; -import { PagedUserResponseModel, UserResponseModel, UserStateModel } from '@umbraco-cms/backoffice/backend-api'; +import { + PagedUserResponseModel, + UserItemResponseModel, + UserResponseModel, + UserStateModel, +} from '@umbraco-cms/backoffice/backend-api'; + +const createUserItem = (item: UserResponseModel): UserItemResponseModel => { + return { + name: item.name, + id: item.id, + }; +}; // Temp mocked database class UmbUserData extends UmbEntityData { @@ -16,6 +28,11 @@ class UmbUserData extends UmbEntityData { }; } + getItems(ids: Array): Array { + const items = this.data.filter((item) => ids.includes(item.id ?? '')); + return items.map((item) => createUserItem(item)); + } + getCurrentUser(): UmbLoggedInUser { const firstUser = this.data[0]; const permissions = firstUser.userGroupIds?.length ? umbUserGroupData.getPermissions(firstUser.userGroupIds) : []; diff --git a/src/mocks/handlers/user.handlers.ts b/src/mocks/handlers/user.handlers.ts index bca0b8b026..a45d1fcf42 100644 --- a/src/mocks/handlers/user.handlers.ts +++ b/src/mocks/handlers/user.handlers.ts @@ -6,6 +6,14 @@ import { umbracoPath } from '@umbraco-cms/backoffice/utils'; const slug = '/user'; export const handlers = [ + rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => { + const ids = req.url.searchParams.getAll('id'); + if (!ids) return; + const items = umbUsersData.getItems(ids); + + return res(ctx.status(200), ctx.json(items)); + }), + rest.get(umbracoPath(`${slug}/filter`), (req, res, ctx) => { //TODO: Implementer filter const response = umbUsersData.getAll(); From 82dc218e863d792cfea2ee7123952575c3ad9a70 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 10:15:20 +0200 Subject: [PATCH 50/97] we don't need the repository here --- src/packages/core/picker-input/picker-input.context.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/packages/core/picker-input/picker-input.context.ts b/src/packages/core/picker-input/picker-input.context.ts index 2800d55146..a2eac80a8a 100644 --- a/src/packages/core/picker-input/picker-input.context.ts +++ b/src/packages/core/picker-input/picker-input.context.ts @@ -83,9 +83,6 @@ export class UmbPickerInputContext } async requestRemoveItem(unique: string) { - await this.#init; - if (!this.repository) throw new Error('Repository is not initialized'); - // TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository? const item = this.#itemManager.getItems().find((item) => this.#getUnique(item) === unique); if (!item) throw new Error('Could not find item with unique: ' + unique); From aa30a019364a491baed659c878cef12a179d9b26 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 10:42:57 +0200 Subject: [PATCH 51/97] add mocks --- src/mocks/data/user.data.ts | 8 ++++++++ src/mocks/handlers/user.handlers.ts | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/mocks/data/user.data.ts b/src/mocks/data/user.data.ts index 9c95f2c825..18dbc0ce37 100644 --- a/src/mocks/data/user.data.ts +++ b/src/mocks/data/user.data.ts @@ -3,6 +3,7 @@ import { umbUserGroupData } from './user-group.data.js'; import { UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { PagedUserResponseModel, + UpdateUserGroupsOnUserRequestModel, UserItemResponseModel, UserResponseModel, UserStateModel, @@ -33,6 +34,13 @@ class UmbUserData extends UmbEntityData { return items.map((item) => createUserItem(item)); } + setUserGroups(data: UpdateUserGroupsOnUserRequestModel): void { + const users = this.data.filter((user) => data.userIds?.includes(user.id ?? '')); + users.forEach((user) => { + user.userGroupIds = data.userGroupIds; + }); + } + getCurrentUser(): UmbLoggedInUser { const firstUser = this.data[0]; const permissions = firstUser.userGroupIds?.length ? umbUserGroupData.getPermissions(firstUser.userGroupIds) : []; diff --git a/src/mocks/handlers/user.handlers.ts b/src/mocks/handlers/user.handlers.ts index a45d1fcf42..175f439d69 100644 --- a/src/mocks/handlers/user.handlers.ts +++ b/src/mocks/handlers/user.handlers.ts @@ -14,6 +14,15 @@ export const handlers = [ return res(ctx.status(200), ctx.json(items)); }), + rest.post(umbracoPath(`${slug}/set-user-groups`), async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; + + umbUsersData.setUserGroups(data); + + return res(ctx.status(200)); + }), + rest.get(umbracoPath(`${slug}/filter`), (req, res, ctx) => { //TODO: Implementer filter const response = umbUsersData.getAll(); From a387681b513795b6808d7ec3c266852634410b8b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 11:13:51 +0200 Subject: [PATCH 52/97] load components as part of manifest ts --- src/packages/users/manifests.ts | 4 ++++ src/packages/users/umbraco-package.ts | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/packages/users/manifests.ts b/src/packages/users/manifests.ts index 75aecdcb8b..74b7562a5d 100644 --- a/src/packages/users/manifests.ts +++ b/src/packages/users/manifests.ts @@ -3,4 +3,8 @@ import { manifests as userManifests } from './users/manifests.js'; import { manifests as userSectionManifests } from './user-section/manifests.js'; import { manifests as currentUserManifests } from './current-user/manifests.js'; +// We need to load any components that are not loaded by the user management bundle to register them in the browser. +import './user-groups/components/index.js'; +import './users/components/index.js'; + export const manifests = [...userGroupManifests, ...userManifests, ...userSectionManifests, ...currentUserManifests]; diff --git a/src/packages/users/umbraco-package.ts b/src/packages/users/umbraco-package.ts index 4d2c28d65c..7418be463d 100644 --- a/src/packages/users/umbraco-package.ts +++ b/src/packages/users/umbraco-package.ts @@ -7,10 +7,4 @@ export const extensions = [ type: 'bundle', loader: () => import('./manifests.js'), }, - { - name: 'User Management Entry Point', - alias: 'Umb.EntryPoint.UserManagement', - type: 'entryPoint', - loader: () => import('./index.js'), - }, ]; From 42b2559e2e2b7607f0560eb5307f1859d68f1e00 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 11:38:30 +0200 Subject: [PATCH 53/97] fix ts erros --- .../users/users/workspace/user-workspace-editor.element.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packages/users/users/workspace/user-workspace-editor.element.ts b/src/packages/users/users/workspace/user-workspace-editor.element.ts index 59be1e904d..f832bb498e 100644 --- a/src/packages/users/users/workspace/user-workspace-editor.element.ts +++ b/src/packages/users/users/workspace/user-workspace-editor.element.ts @@ -21,6 +21,7 @@ import { UserStateModel } from '@umbraco-cms/backoffice/backend-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { type UmbUserGroupInputElement } from '@umbraco-cms/backoffice/user-group'; @customElement('umb-user-workspace-editor') export class UmbUserWorkspaceEditorElement extends UmbLitElement { @@ -48,7 +49,7 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { }); this.consumeContext(UMB_WORKSPACE_CONTEXT, (workspaceContext) => { - this.#workspaceContext = workspaceContext; + this.#workspaceContext = workspaceContext as UmbUserWorkspaceContext; this.#observeUser(); }); } From c702d69dec2e689f26a500006dba52bbfa6bb67e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 11:38:46 +0200 Subject: [PATCH 54/97] only allow one entityType per permission --- .../models/user-granular-permission.model.ts | 2 +- .../models/user-permission.model.ts | 2 +- .../documents/user-permissions/manifests.ts | 22 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/packages/core/extension-registry/models/user-granular-permission.model.ts b/src/packages/core/extension-registry/models/user-granular-permission.model.ts index 22f8dfd41c..fc6698a802 100644 --- a/src/packages/core/extension-registry/models/user-granular-permission.model.ts +++ b/src/packages/core/extension-registry/models/user-granular-permission.model.ts @@ -6,5 +6,5 @@ export interface ManifestUserGranularPermission extends ManifestElement { } export interface MetaUserGranularPermission { - entityType: Array; + entityType: string; } diff --git a/src/packages/core/extension-registry/models/user-permission.model.ts b/src/packages/core/extension-registry/models/user-permission.model.ts index 5b15a1712f..19825ab970 100644 --- a/src/packages/core/extension-registry/models/user-permission.model.ts +++ b/src/packages/core/extension-registry/models/user-permission.model.ts @@ -7,7 +7,7 @@ export interface ManifestUserPermission extends ManifestBase { export interface MetaUserPermission { label: string; - entityType: Array; + entityType: string; description?: string; group?: string; } diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index f3f983a2e6..12f5d92be8 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -20,7 +20,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_READ, name: 'Read Document User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Read', description: 'Allow access to browse documents', }, @@ -30,7 +30,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_CREATE_BLUEPRINT, name: 'Create Document Blueprint User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Create Content Template', description: 'Allow access to create a Content Template', }, @@ -40,7 +40,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_DELETE, name: 'Delete Document User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Delete', description: 'Allow access to delete a document', }, @@ -50,7 +50,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_CREATE, name: 'Create Document User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Create', description: 'Allow access to create a document', }, @@ -60,7 +60,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_NOTIFICATIONS, name: 'Document Notifications User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Notifications', description: 'Allow access to setup notifications for documents', }, @@ -70,7 +70,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_PUBLISH, name: 'Publish Document User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Publish', description: 'Allow access to publish a document', }, @@ -80,7 +80,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_PERMISSIONS, name: 'Document Permissions User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Permissions', description: 'Allow access to change permissions for a document', }, @@ -90,7 +90,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_SEND_FOR_APPROVAL, name: 'Send Document For Approval User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Send For Approval', description: 'Allow access to send a document for approval before publishing', }, @@ -100,7 +100,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_UNPUBLISH, name: 'Unpublish Document User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Unpublish', description: 'Allow access to unpublish a document', }, @@ -110,7 +110,7 @@ const permissions: Array = [ alias: UMB_USER_PERMISSION_DOCUMENT_UPDATE, name: 'Update Document User Permission', meta: { - entityType: ['document'], + entityType: 'document', label: 'Update', description: 'Allow access to save a document', }, @@ -125,7 +125,7 @@ export const granularPermissions: Array = [ loader: () => import('../components/input-document-granular-permission/input-document-granular-permission.element.js'), meta: { - entityType: ['document'], + entityType: 'document', }, }, ]; From e1e95d5019d11e18c69d089987abfe9887945d4c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 14:21:25 +0200 Subject: [PATCH 55/97] add a couple of media user permissions --- src/packages/media/media/manifests.ts | 2 ++ .../media/media/user-permissions/index.ts | 1 + .../media/media/user-permissions/manifests.ts | 29 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/packages/media/media/user-permissions/index.ts create mode 100644 src/packages/media/media/user-permissions/manifests.ts diff --git a/src/packages/media/media/manifests.ts b/src/packages/media/media/manifests.ts index cf5eb52e5f..43a93dafbb 100644 --- a/src/packages/media/media/manifests.ts +++ b/src/packages/media/media/manifests.ts @@ -5,6 +5,7 @@ import { manifests as treeManifests } from './tree/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; import { manifests as entityActionsManifests } from './entity-actions/manifests.js'; import { manifests as entityBulkActionsManifests } from './entity-bulk-actions/manifests.js'; +import { manifests as userPermissionManifests } from './user-permissions/manifests.js'; export const manifests = [ ...collectionViewManifests, @@ -14,4 +15,5 @@ export const manifests = [ ...workspaceManifests, ...entityActionsManifests, ...entityBulkActionsManifests, + ...userPermissionManifests, ]; diff --git a/src/packages/media/media/user-permissions/index.ts b/src/packages/media/media/user-permissions/index.ts new file mode 100644 index 0000000000..1e95b5d703 --- /dev/null +++ b/src/packages/media/media/user-permissions/index.ts @@ -0,0 +1 @@ +export * from './manifests.js'; diff --git a/src/packages/media/media/user-permissions/manifests.ts b/src/packages/media/media/user-permissions/manifests.ts new file mode 100644 index 0000000000..ba3784ae61 --- /dev/null +++ b/src/packages/media/media/user-permissions/manifests.ts @@ -0,0 +1,29 @@ +import type { ManifestUserPermission } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_USER_PERMISSION_MEDIA_MOVE = 'Umb.UserPermission.Media.Move'; +export const UMB_USER_PERMISSION_MEDIA_COPY = 'Umb.UserPermission.Media.Copy'; + +const permissions: Array = [ + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_MEDIA_MOVE, + name: 'Move Media Item User Permission', + meta: { + entityType: 'media', + label: 'Move', + description: 'Allow access to move media items', + }, + }, + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_MEDIA_COPY, + name: 'Copy Media Item User Permission', + meta: { + entityType: 'media', + label: 'Copy', + description: 'Allow access to copy a media item', + }, + }, +]; + +export const manifests = [...permissions]; From df0ee427282092eeec2c86a1c122f1d03b3b94b2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 14:21:45 +0200 Subject: [PATCH 56/97] render entity type for user permissions --- ...r-group-default-permission-list.element.ts | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts index 51738c068b..cdf54147c5 100644 --- a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts +++ b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts @@ -5,6 +5,7 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { ManifestUserPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { groupBy } from '@umbraco-cms/backoffice/external/lodash'; @customElement('umb-user-group-default-permission-list') export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { @@ -12,20 +13,24 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { private _userGroup?: UserGroupResponseModel; @state() - private _userPermissionManifests: Array = []; + private _groupedUserPermissionManifests: Record> = {}; #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; constructor() { super(); + this.#observeUserPermissions(); + this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => { this.#workspaceContext = instance; this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); - this.observe( - umbExtensionsRegistry.extensionsOfType('userPermission'), - (userPermissionManifests) => (this._userPermissionManifests = userPermissionManifests), - ); + }); + } + + #observeUserPermissions() { + this.observe(umbExtensionsRegistry.extensionsOfType('userPermission'), (userPermissionManifests) => { + this._groupedUserPermissionManifests = groupBy(userPermissionManifests, (manifest) => manifest.meta.entityType); }); } @@ -36,12 +41,20 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { } #isAllowed(userPermissionManifest: ManifestUserPermission) { - console.log(this._userGroup?.permissions?.includes(userPermissionManifest.alias)); return this._userGroup?.permissions?.includes(userPermissionManifest.alias); } render() { - return html` ${this._userPermissionManifests.map((permission) => this.#renderPermission(permission))} `; + const entityGroups = []; + + for (const [key, value] of Object.entries(this._groupedUserPermissionManifests)) { + entityGroups.push( + html`

${key}

+ ${value.map((permission) => this.#renderPermission(permission))}`, + ); + } + + return html`${entityGroups}`; } #renderPermission(userPermissionManifest: ManifestUserPermission) { From 94b8c325003501f85098dc3683db5d523fdb09b7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 14:53:04 +0200 Subject: [PATCH 57/97] localize entity groups --- src/assets/lang/da-dk.ts | 3 +++ src/assets/lang/en-us.ts | 3 +++ .../components/user-group-default-permission-list.element.ts | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/assets/lang/da-dk.ts b/src/assets/lang/da-dk.ts index f226748e64..acd5f33aae 100644 --- a/src/assets/lang/da-dk.ts +++ b/src/assets/lang/da-dk.ts @@ -1822,6 +1822,9 @@ export default { permissionsDefault: 'Standardrettigheder', permissionsGranular: 'Granulære rettigheder', permissionsGranularHelp: 'Sæt rettigheder for specifikke noder', + permissionsEntityGroup_document: 'Indhold', + permissionsEntityGroup_media: 'Medie', + permissionsEntityGroup_member: 'Medlemmer', profile: 'Profil', searchAllChildren: "Søg alle 'børn'", languagesHelp: 'Tilføj sprog for at give brugerne adgang til at redigere', diff --git a/src/assets/lang/en-us.ts b/src/assets/lang/en-us.ts index a860981f33..37adbf86e2 100644 --- a/src/assets/lang/en-us.ts +++ b/src/assets/lang/en-us.ts @@ -1822,6 +1822,9 @@ export default { permissionsDefault: 'Default permissions', permissionsGranular: 'Granular permissions', permissionsGranularHelp: 'Set permissions for specific nodes', + permissionsEntityGroup_document: 'Content', + permissionsEntityGroup_media: 'Media', + permissionsEntityGroup_member: 'Member', profile: 'Profile', searchAllChildren: 'Search all children', languagesHelp: 'Limit the languages users have access to edit', diff --git a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts index cdf54147c5..33a75c3e4c 100644 --- a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts +++ b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts @@ -49,7 +49,7 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { for (const [key, value] of Object.entries(this._groupedUserPermissionManifests)) { entityGroups.push( - html`

${key}

+ html`

${key}

${value.map((permission) => this.#renderPermission(permission))}`, ); } From d720ffb3fb5d4dca20c5785837dd29153628b56c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 15:12:41 +0200 Subject: [PATCH 58/97] Update user-group-default-permission-list.element.ts --- .../components/user-group-default-permission-list.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts index 33a75c3e4c..653b6c154e 100644 --- a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts +++ b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts @@ -49,7 +49,7 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { for (const [key, value] of Object.entries(this._groupedUserPermissionManifests)) { entityGroups.push( - html`

${key}

+ html`
${key}
${value.map((permission) => this.#renderPermission(permission))}`, ); } From 6fa7c06f827bc0836dcefc73cca00783ddc81ad5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 15:59:11 +0200 Subject: [PATCH 59/97] add element to render a user-permission-setting --- ...r-group-default-permission-list.element.ts | 64 +++++++------------ src/packages/users/users/components/index.ts | 2 + .../user-permission-setting.element.ts | 63 ++++++++++++++++++ 3 files changed, 88 insertions(+), 41 deletions(-) create mode 100644 src/packages/users/users/components/user-permission-setting/user-permission-setting.element.ts diff --git a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts index 653b6c154e..776d6250a7 100644 --- a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts +++ b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts @@ -1,11 +1,12 @@ import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from '../user-group-workspace.context.js'; -import { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; -import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { ManifestUserPermission, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { groupBy } from '@umbraco-cms/backoffice/external/lodash'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; +import { type UmbUserPermissionSettingElement } from '@umbraco-cms/backoffice/users'; @customElement('umb-user-group-default-permission-list') export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { @@ -15,7 +16,7 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { @state() private _groupedUserPermissionManifests: Record> = {}; - #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; + #userGroupWorkspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; constructor() { super(); @@ -23,8 +24,8 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { this.#observeUserPermissions(); this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => { - this.#workspaceContext = instance; - this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); + this.#userGroupWorkspaceContext = instance; + this.observe(this.#userGroupWorkspaceContext.data, (userGroup) => (this._userGroup = userGroup)); }); } @@ -34,10 +35,12 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { }); } - #onChangeUserPermission(event: UUIBooleanInputEvent, userPermissionManifest: ManifestUserPermission) { - event.target.checked - ? this.#workspaceContext?.addPermission(userPermissionManifest.alias) - : this.#workspaceContext?.removePermission(userPermissionManifest.alias); + #onChangeUserPermission(event: UmbChangeEvent, userPermissionManifest: ManifestUserPermission) { + const target = event.target as UmbUserPermissionSettingElement; + + target.allowed + ? this.#userGroupWorkspaceContext?.addPermission(userPermissionManifest.alias) + : this.#userGroupWorkspaceContext?.removePermission(userPermissionManifest.alias); } #isAllowed(userPermissionManifest: ManifestUserPermission) { @@ -45,6 +48,10 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { } render() { + return html`${this.#renderEntityGroups()}`; + } + + #renderEntityGroups() { const entityGroups = []; for (const [key, value] of Object.entries(this._groupedUserPermissionManifests)) { @@ -58,40 +65,15 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { } #renderPermission(userPermissionManifest: ManifestUserPermission) { - return html`
- this.#onChangeUserPermission(event, userPermissionManifest)}> -
-
${userPermissionManifest.meta.label}
- ${userPermissionManifest.meta.description} -
-
-
`; + return html` + this.#onChangeUserPermission(event, userPermissionManifest)}>`; } - static styles = [ - UmbTextStyles, - css` - .permission-toggle { - display: flex; - align-items: center; - border-bottom: 1px solid var(--uui-color-divider); - padding: var(--uui-size-space-3) 0 var(--uui-size-space-4) 0; - } - - .permission-meta { - margin-left: var(--uui-size-space-4); - line-height: 1.2em; - } - - .permission-name { - font-weight: bold; - } - `, - ]; + static styles = [UmbTextStyles]; } export default UmbUserGroupDefaultPermissionListElement; diff --git a/src/packages/users/users/components/index.ts b/src/packages/users/users/components/index.ts index c5a96c894c..2a4312053b 100644 --- a/src/packages/users/users/components/index.ts +++ b/src/packages/users/users/components/index.ts @@ -1,3 +1,5 @@ import './user-input/user-input.element.js'; +import './user-permission-setting/user-permission-setting.element.js'; export * from './user-input/user-input.element.js'; +export * from './user-permission-setting/user-permission-setting.element.js'; diff --git a/src/packages/users/users/components/user-permission-setting/user-permission-setting.element.ts b/src/packages/users/users/components/user-permission-setting/user-permission-setting.element.ts new file mode 100644 index 0000000000..2231e11f10 --- /dev/null +++ b/src/packages/users/users/components/user-permission-setting/user-permission-setting.element.ts @@ -0,0 +1,63 @@ +import { type UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; + +@customElement('umb-user-permission-setting') +export class UmbUserPermissionSettingElement extends UmbLitElement { + @property({ type: String, attribute: true }) + label: string = ''; + + @property({ type: String, attribute: true }) + description?: string = ''; + + @property({ type: Boolean, attribute: true }) + allowed: boolean = false; + + #onChange(event: UUIBooleanInputEvent) { + event.stopPropagation(); + this.allowed = event.target.checked; + this.dispatchEvent(new UmbChangeEvent()); + } + + render() { + return html`
+ +
+
${this.label}
+ ${this.description} +
+
+
`; + } + + static styles = [ + UmbTextStyles, + css` + #setting { + display: flex; + align-items: center; + border-bottom: 1px solid var(--uui-color-divider); + padding: var(--uui-size-space-3) 0 var(--uui-size-space-4) 0; + } + + #meta { + margin-left: var(--uui-size-space-4); + line-height: 1.2em; + } + + #name { + font-weight: bold; + } + `, + ]; +} + +export default UmbUserPermissionSettingElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-user-permission-setting': UmbUserPermissionSettingElement; + } +} From 630f5a118bd8a09aae825c31e566f74546dbed70 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 26 Sep 2023 21:02:47 +0200 Subject: [PATCH 60/97] add missing user permissions + add groups --- .../documents/user-permissions/manifests.ts | 72 +++++++++++++++++++ .../media/media/user-permissions/manifests.ts | 2 + 2 files changed, 74 insertions(+) diff --git a/src/packages/documents/documents/user-permissions/manifests.ts b/src/packages/documents/documents/user-permissions/manifests.ts index 12f5d92be8..f3269f9701 100644 --- a/src/packages/documents/documents/user-permissions/manifests.ts +++ b/src/packages/documents/documents/user-permissions/manifests.ts @@ -13,6 +13,12 @@ export const UMB_USER_PERMISSION_DOCUMENT_PUBLISH = 'Umb.UserPermission.Document export const UMB_USER_PERMISSION_DOCUMENT_PERMISSIONS = 'Umb.UserPermission.Document.Permissions'; export const UMB_USER_PERMISSION_DOCUMENT_SEND_FOR_APPROVAL = 'Umb.UserPermission.Document.SendForApproval'; export const UMB_USER_PERMISSION_DOCUMENT_UNPUBLISH = 'Umb.UserPermission.Document.Unpublish'; +export const UMB_USER_PERMISSION_DOCUMENT_COPY = 'Umb.UserPermission.Document.Copy'; +export const UMB_USER_PERMISSION_DOCUMENT_MOVE = 'Umb.UserPermission.Document.Move'; +export const UMB_USER_PERMISSION_DOCUMENT_SORT = 'Umb.UserPermission.Document.Sort'; +export const UMB_USER_PERMISSION_DOCUMENT_CULTURE_AND_HOSTNAMES = 'Umb.UserPermission.Document.CultureAndHostnames'; +export const UMB_USER_PERMISSION_DOCUMENT_PUBLIC_ACCESS = 'Umb.UserPermission.Document.PublicAccess'; +export const UMB_USER_PERMISSION_DOCUMENT_ROLLBACK = 'Umb.UserPermission.Document.Rollback'; const permissions: Array = [ { @@ -115,6 +121,72 @@ const permissions: Array = [ description: 'Allow access to save a document', }, }, + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_DOCUMENT_COPY, + name: 'Copy Document User Permission', + meta: { + entityType: 'document', + label: 'Copy', + description: 'Allow access to copy a document', + group: 'structure', + }, + }, + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_DOCUMENT_MOVE, + name: 'Move Document User Permission', + meta: { + entityType: 'document', + label: 'Move', + description: 'Allow access to move a document', + group: 'structure', + }, + }, + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_DOCUMENT_SORT, + name: 'Sort Document User Permission', + meta: { + entityType: 'document', + label: 'Sort', + description: 'Allow access to sort documents', + group: 'structure', + }, + }, + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_DOCUMENT_CULTURE_AND_HOSTNAMES, + name: 'Document Culture And Hostnames User Permission', + meta: { + entityType: 'document', + label: 'Culture And Hostnames', + description: 'Allow access to set culture and hostnames for documents', + group: 'administration', + }, + }, + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_DOCUMENT_PUBLIC_ACCESS, + name: 'Document Public Access User Permission', + meta: { + entityType: 'document', + label: 'Public Access', + description: 'Allow access to set and change access restrictions for a document', + group: 'administration', + }, + }, + { + type: 'userPermission', + alias: UMB_USER_PERMISSION_DOCUMENT_ROLLBACK, + name: 'Document Rollback User Permission', + meta: { + entityType: 'document', + label: 'Rollback', + description: 'Allow access to roll back a document to a previous state', + group: 'administration', + }, + }, ]; export const granularPermissions: Array = [ diff --git a/src/packages/media/media/user-permissions/manifests.ts b/src/packages/media/media/user-permissions/manifests.ts index ba3784ae61..3ddbb9b526 100644 --- a/src/packages/media/media/user-permissions/manifests.ts +++ b/src/packages/media/media/user-permissions/manifests.ts @@ -12,6 +12,7 @@ const permissions: Array = [ entityType: 'media', label: 'Move', description: 'Allow access to move media items', + group: 'structure', }, }, { @@ -22,6 +23,7 @@ const permissions: Array = [ entityType: 'media', label: 'Copy', description: 'Allow access to copy a media item', + group: 'structure', }, }, ]; From 75fe7cf05e7edb5bbe899c788b25df2ea5617d47 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 09:17:11 +0200 Subject: [PATCH 61/97] Update user-group-default-permission-list.element.ts --- ...r-group-default-permission-list.element.ts | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts index 776d6250a7..b6920fc87c 100644 --- a/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts +++ b/src/packages/users/user-groups/workspace/components/user-group-default-permission-list.element.ts @@ -14,7 +14,10 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { private _userGroup?: UserGroupResponseModel; @state() - private _groupedUserPermissionManifests: Record> = {}; + private _manifests: Array = []; + + @state() + private _entityTypes: Array = []; #userGroupWorkspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; @@ -31,7 +34,8 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { #observeUserPermissions() { this.observe(umbExtensionsRegistry.extensionsOfType('userPermission'), (userPermissionManifests) => { - this._groupedUserPermissionManifests = groupBy(userPermissionManifests, (manifest) => manifest.meta.entityType); + this._manifests = userPermissionManifests; + this._entityTypes = [...new Set(userPermissionManifests.map((manifest) => manifest.meta.entityType))]; }); } @@ -48,29 +52,23 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement { } render() { - return html`${this.#renderEntityGroups()}`; + return html` ${this._entityTypes.map((entityType) => this.#renderPermissionsForEntityType(entityType))} `; } - #renderEntityGroups() { - const entityGroups = []; - - for (const [key, value] of Object.entries(this._groupedUserPermissionManifests)) { - entityGroups.push( - html`
${key}
- ${value.map((permission) => this.#renderPermission(permission))}`, - ); - } - - return html`${entityGroups}`; + #renderPermissionsForEntityType(entityType: string) { + return html`

${entityType}

+ ${this._manifests + .filter((manifest) => manifest.meta.entityType === entityType) + .map((manifest) => this.#renderPermission(manifest))}`; } - #renderPermission(userPermissionManifest: ManifestUserPermission) { + #renderPermission(manifest: ManifestUserPermission) { return html` - this.#onChangeUserPermission(event, userPermissionManifest)}>`; + this.#onChangeUserPermission(event, manifest)}>`; } static styles = [UmbTextStyles]; From f6ddc1462b16ea54208a17c9491eca2ac498013e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 09:30:30 +0200 Subject: [PATCH 62/97] format --- src/mocks/data/user-group.data.ts | 1 + .../components/input-document/input-document.element.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mocks/data/user-group.data.ts b/src/mocks/data/user-group.data.ts index 390acf9c59..4fea6c2999 100644 --- a/src/mocks/data/user-group.data.ts +++ b/src/mocks/data/user-group.data.ts @@ -58,6 +58,7 @@ export const data: Array = [ id: 'c630d49e-4e7b-42ea-b2bc-edc0edacb6b1', name: 'Administrators', icon: 'umb:medal', + documentStartNodeId: 'all-property-editors-document-id', permissions: [UMB_USER_PERMISSION_DOCUMENT_CREATE, UMB_USER_PERMISSION_DOCUMENT_DELETE], }, { diff --git a/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/packages/documents/documents/components/input-document/input-document.element.ts index 210ebfd7db..f76c73039e 100644 --- a/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -81,12 +81,12 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) { this.addValidator( 'rangeUnderflow', () => this.minMessage, - () => !!this.min && this._selectedIds.length < this.min + () => !!this.min && this._selectedIds.length < this.min, ); this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this._selectedIds.length > this.max + () => !!this.max && this._selectedIds.length > this.max, ); this.consumeContext(UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN, (instance) => { From 1d41368e26f512ca129fe847349b2a123db2d2c4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 09:30:53 +0200 Subject: [PATCH 63/97] render document input on user group --- .../workspace/user-group-workspace-editor.element.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 6007d7d84e..cac7e82517 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -121,7 +121,11 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { - CONTENT START NODE PICKER NOT IMPLEMENTED YET + this.#onSectionsChange(e.target.value)} + multiple> Date: Wed, 27 Sep 2023 20:46:02 +1300 Subject: [PATCH 64/97] dont show disable and enable button on current user profile page --- .../user-workspace-editor.element.ts | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/packages/users/users/workspace/user-workspace-editor.element.ts b/src/packages/users/users/workspace/user-workspace-editor.element.ts index f832bb498e..ed3b4afb6b 100644 --- a/src/packages/users/users/workspace/user-workspace-editor.element.ts +++ b/src/packages/users/users/workspace/user-workspace-editor.element.ts @@ -304,24 +304,26 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { const buttons: TemplateResult[] = []; - if (this._user.state === UserStateModel.DISABLED) { - buttons.push(html` - - `); - } + if (this._user.id !== this._currentUser?.id) { + if (this._user.state === UserStateModel.DISABLED) { + buttons.push(html` + + `); + } - if (this._user.state === UserStateModel.ACTIVE || this._user.state === UserStateModel.INACTIVE) { - buttons.push(html` - - `); + if (this._user.state === UserStateModel.ACTIVE || this._user.state === UserStateModel.INACTIVE) { + buttons.push(html` + + `); + } } if (this._currentUser?.id !== this._user?.id) { From 441dcba194afc1adfb3bea9166217dec70f81e88 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 09:51:18 +0200 Subject: [PATCH 65/97] us ifDefined --- .../users/components/user-input/user-input.element.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/packages/users/users/components/user-input/user-input.element.ts b/src/packages/users/users/components/user-input/user-input.element.ts index 69db7f7311..15d6f274b4 100644 --- a/src/packages/users/users/components/user-input/user-input.element.ts +++ b/src/packages/users/users/components/user-input/user-input.element.ts @@ -1,5 +1,5 @@ import { UmbUserPickerContext } from './user-input.context.js'; -import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { css, html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { UserItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; @@ -76,13 +76,13 @@ export class UmbUserInputElement extends FormControlMixin(UmbLitElement) { this.addValidator( 'rangeUnderflow', () => this.minMessage, - () => !!this.min && this.#pickerContext.getSelection().length < this.min + () => !!this.min && this.#pickerContext.getSelection().length < this.min, ); this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this.#pickerContext.getSelection().length > this.max + () => !!this.max && this.#pickerContext.getSelection().length > this.max, ); this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(','))); @@ -105,7 +105,7 @@ export class UmbUserInputElement extends FormControlMixin(UmbLitElement) { private _renderItem(item: UserItemResponseModel) { if (!item.id) return; return html` - + this.#pickerContext.requestRemoveItem(item.id!)} label="Remove ${item.name}" >Remove Date: Wed, 27 Sep 2023 09:51:46 +0200 Subject: [PATCH 66/97] remove debuggers --- .../input-document-granular-permission.element.ts | 1 - .../documents/documents/entity-actions/permissions.action.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts b/src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts index af6d9ad5d0..1ab33f7290 100644 --- a/src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts +++ b/src/packages/documents/documents/components/input-document-granular-permission/input-document-granular-permission.element.ts @@ -66,7 +66,6 @@ export class UmbInputDocumentGranularPermissionElement extends FormControlMixin( }); modalContext?.onSubmit().then(({ selection }: any) => { - debugger; //this.#setSelection(selection); }); } diff --git a/src/packages/documents/documents/entity-actions/permissions.action.ts b/src/packages/documents/documents/entity-actions/permissions.action.ts index bea922e1af..9362d92e4c 100644 --- a/src/packages/documents/documents/entity-actions/permissions.action.ts +++ b/src/packages/documents/documents/entity-actions/permissions.action.ts @@ -33,8 +33,6 @@ export class UmbDocumentPermissionsEntityAction extends UmbEntityActionBase Date: Wed, 27 Sep 2023 09:52:08 +0200 Subject: [PATCH 67/97] update document input to use document input context --- .../input-document/input-document.context.ts | 10 ++ .../input-document/input-document.element.ts | 128 ++++++------------ 2 files changed, 51 insertions(+), 87 deletions(-) create mode 100644 src/packages/documents/documents/components/input-document/input-document.context.ts diff --git a/src/packages/documents/documents/components/input-document/input-document.context.ts b/src/packages/documents/documents/components/input-document/input-document.context.ts new file mode 100644 index 0000000000..640649a706 --- /dev/null +++ b/src/packages/documents/documents/components/input-document/input-document.context.ts @@ -0,0 +1,10 @@ +import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UMB_DOCUMENT_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; +import { DocumentItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; + +export class UmbDocumentPickerContext extends UmbPickerInputContext { + constructor(host: UmbControllerHostElement) { + super(host, 'Umb.Repository.Document', UMB_DOCUMENT_PICKER_MODAL); + } +} diff --git a/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/packages/documents/documents/components/input-document/input-document.element.ts index f76c73039e..01df812944 100644 --- a/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -1,16 +1,8 @@ -import { UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN } from '../../repository/document.tree.store.js'; -import type { UmbDocumentTreeStore } from '../../repository/document.tree.store.js'; -import { css, html, nothing, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; +import { UmbDocumentPickerContext } from './input-document.context.js'; +import { css, html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui'; -import { - UmbModalManagerContext, - UMB_MODAL_MANAGER_CONTEXT_TOKEN, - UMB_CONFIRM_MODAL, - UMB_DOCUMENT_PICKER_MODAL, -} from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import type { DocumentTreeItemResponseModel, EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import type { DocumentItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; @customElement('umb-input-document') export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) { @@ -18,10 +10,15 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) { * This is a minimum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default 0 */ @property({ type: Number }) - min?: number; + public get min(): number { + return this.#pickerContext.min; + } + public set min(value: number) { + this.#pickerContext.min = value; + } /** * Min validation message. @@ -36,10 +33,15 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) { * This is a maximum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default Infinity */ @property({ type: Number }) - max?: number; + public get max(): number { + return this.#pickerContext.max; + } + public set max(value: number) { + this.#pickerContext.max = value; + } /** * Max validation message. @@ -50,30 +52,23 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) { @property({ type: String, attribute: 'min-message' }) maxMessage = 'This field exceeds the allowed amount of items'; - // TODO: do we need both selectedIds and value? If we just use value we follow the same pattern as native form controls. - private _selectedIds: Array = []; public get selectedIds(): Array { - return this._selectedIds; + return this.#pickerContext.getSelection(); } public set selectedIds(ids: Array) { - this._selectedIds = ids; - super.value = ids.join(','); - this._observePickedDocuments(); + this.#pickerContext.setSelection(ids); } @property() public set value(idsString: string) { - if (idsString !== this._value) { - this.selectedIds = idsString.split(/[ ,]+/); - } + // Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection. + this.selectedIds = idsString.split(/[ ,]+/); } @state() - private _items?: Array; + private _items?: Array; - private _modalContext?: UmbModalManagerContext; - private _documentStore?: UmbDocumentTreeStore; - private _pickedItemsObserver?: UmbObserverController; + #pickerContext = new UmbDocumentPickerContext(this); constructor() { super(); @@ -81,84 +76,43 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) { this.addValidator( 'rangeUnderflow', () => this.minMessage, - () => !!this.min && this._selectedIds.length < this.min, + () => !!this.min && this.#pickerContext.getSelection().length < this.min, ); + this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this._selectedIds.length > this.max, + () => !!this.max && this.#pickerContext.getSelection().length > this.max, ); - this.consumeContext(UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN, (instance) => { - this._documentStore = instance; - this._observePickedDocuments(); - }); - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { - this._modalContext = instance; - }); + this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(','))); + this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } protected getFormElement() { return undefined; } - private _observePickedDocuments() { - this._pickedItemsObserver?.destroy(); - - if (!this._documentStore) return; - - // TODO: consider changing this to the list data endpoint when it is available - this._pickedItemsObserver = this.observe(this._documentStore.items(this._selectedIds), (items) => { - this._items = items; - }); - } - - private _openPicker() { - // We send a shallow copy(good enough as its just an array of ids) of our this._selectedIds, as we don't want the modal to manipulate our data: - const modalContext = this._modalContext?.open(UMB_DOCUMENT_PICKER_MODAL, { - multiple: this.max === 1 ? false : true, - selection: [...this._selectedIds], - }); - - modalContext?.onSubmit().then(({ selection }: any) => { - this._setSelection(selection); - }); - } - - private async _removeItem(item: EntityTreeItemResponseModel) { - const modalContext = this._modalContext?.open(UMB_CONFIRM_MODAL, { - color: 'danger', - headline: `Remove ${item.name}?`, - content: 'Are you sure you want to remove this item', - confirmLabel: 'Remove', - }); - - await modalContext?.onSubmit(); - const newSelection = this._selectedIds.filter((value) => value !== item.id); - this._setSelection(newSelection); - } - - private _setSelection(newSelection: Array) { - this.selectedIds = newSelection; - this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true })); - } - render() { return html` - ${this._items?.map((item) => this._renderItem(item))} - Add + ${this._items?.map((item) => this._renderItem(item))} + this.#pickerContext.openPicker()} label="open" + >Add `; } - private _renderItem(item: EntityTreeItemResponseModel) { - // TODO: remove when we have a way to handle trashed items - const tempItem = item as EntityTreeItemResponseModel & { isTrashed: boolean }; - + private _renderItem(item: DocumentItemResponseModel) { + if (!item.id) return; return html` - - ${tempItem.isTrashed ? html` Trashed ` : nothing} + + - this._removeItem(item)} label="Remove document ${item.name}">Remove + this.#pickerContext.requestRemoveItem(item.id!)} + label="Remove document ${item.name}" + >Remove `; From 8b7c82c9d0c2856c8dd5c3039b5048295968240f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 09:52:27 +0200 Subject: [PATCH 68/97] make init wait for promises --- .../documents/documents/repository/document.repository.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/packages/documents/documents/repository/document.repository.ts b/src/packages/documents/documents/repository/document.repository.ts index 01331c1443..b2a7216326 100644 --- a/src/packages/documents/documents/repository/document.repository.ts +++ b/src/packages/documents/documents/repository/document.repository.ts @@ -46,19 +46,19 @@ export class UmbDocumentRepository this.#init = Promise.all([ new UmbContextConsumerController(this.#host, UMB_DOCUMENT_TREE_STORE_CONTEXT_TOKEN, (instance) => { this.#treeStore = instance; - }), + }).asPromise(), new UmbContextConsumerController(this.#host, UMB_DOCUMENT_STORE_CONTEXT_TOKEN, (instance) => { this.#store = instance; - }), + }).asPromise(), new UmbContextConsumerController(this.#host, UMB_DOCUMENT_ITEM_STORE_CONTEXT_TOKEN, (instance) => { this.#itemStore = instance; - }), + }).asPromise(), new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { this.#notificationContext = instance; - }), + }).asPromise(), ]); } From b2931d141c104c49513222cd5888b4b14d47ad83 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 09:52:37 +0200 Subject: [PATCH 69/97] register document item store --- .../documents/repository/manifests.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/packages/documents/documents/repository/manifests.ts b/src/packages/documents/documents/repository/manifests.ts index a66e493a3a..adcaa16ab0 100644 --- a/src/packages/documents/documents/repository/manifests.ts +++ b/src/packages/documents/documents/repository/manifests.ts @@ -1,7 +1,13 @@ import { UmbDocumentRepository } from '../repository/document.repository.js'; +import { UmbDocumentItemStore } from './document-item.store.js'; import { UmbDocumentStore } from './document.store.js'; import { UmbDocumentTreeStore } from './document.tree.store.js'; -import type { ManifestRepository, ManifestStore, ManifestTreeStore } from '@umbraco-cms/backoffice/extension-registry'; +import type { + ManifestItemStore, + ManifestRepository, + ManifestStore, + ManifestTreeStore, +} from '@umbraco-cms/backoffice/extension-registry'; export const DOCUMENT_REPOSITORY_ALIAS = 'Umb.Repository.Document'; @@ -14,6 +20,7 @@ const repository: ManifestRepository = { export const DOCUMENT_STORE_ALIAS = 'Umb.Store.Document'; export const DOCUMENT_TREE_STORE_ALIAS = 'Umb.Store.DocumentTree'; +export const DOCUMENT_ITEM_STORE_ALIAS = 'Umb.Store.DocumentItem'; const store: ManifestStore = { type: 'store', @@ -29,4 +36,11 @@ const treeStore: ManifestTreeStore = { class: UmbDocumentTreeStore, }; -export const manifests = [repository, store, treeStore]; +const itemStore: ManifestItemStore = { + type: 'itemStore', + alias: DOCUMENT_ITEM_STORE_ALIAS, + name: 'Document Item Store', + class: UmbDocumentItemStore, +}; + +export const manifests = [repository, store, treeStore, itemStore]; From b095a1dc4bea9685a3caeb8764df0d569bea2559 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:03:37 +0200 Subject: [PATCH 70/97] align naming of element --- .../components/input-section/input-section.element.ts | 8 ++++---- .../components/input-section/input-section.stories.ts | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/packages/core/components/input-section/input-section.element.ts b/src/packages/core/components/input-section/input-section.element.ts index a93649fa3e..73427c9aca 100644 --- a/src/packages/core/components/input-section/input-section.element.ts +++ b/src/packages/core/components/input-section/input-section.element.ts @@ -1,11 +1,11 @@ import { UmbInputListBaseElement } from '../input-list-base/input-list-base.js'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UMB_SECTION_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; import { ManifestSection, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; @customElement('umb-input-section') -export class UmbInputPickerSectionElement extends UmbInputListBaseElement { +export class UmbInputSectionElement extends UmbInputListBaseElement { @state() private _sections: Array = []; @@ -47,7 +47,7 @@ export class UmbInputPickerSectionElement extends UmbInputListBaseElement { label="remove" color="danger">
- ` + `, )}
`; @@ -85,6 +85,6 @@ export class UmbInputPickerSectionElement extends UmbInputListBaseElement { declare global { interface HTMLElementTagNameMap { - 'umb-input-section': UmbInputPickerSectionElement; + 'umb-input-section': UmbInputSectionElement; } } diff --git a/src/packages/core/components/input-section/input-section.stories.ts b/src/packages/core/components/input-section/input-section.stories.ts index 30367b89ae..b39e4966d8 100644 --- a/src/packages/core/components/input-section/input-section.stories.ts +++ b/src/packages/core/components/input-section/input-section.stories.ts @@ -1,8 +1,8 @@ import { Meta, StoryObj } from '@storybook/web-components'; import './input-section.element.js'; -import type { UmbInputPickerSectionElement } from './input-section.element.js'; +import type { UmbInputSectionElement } from './input-section.element.js'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Inputs/Section', component: 'umb-input-section', argTypes: { @@ -22,7 +22,7 @@ const meta: Meta = { }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Overview: Story = { args: { From ef60560c899dd8c6d041a43c306d0a460a5ce6b9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:03:52 +0200 Subject: [PATCH 71/97] export components from module --- src/packages/documents/documents/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/documents/documents/index.ts b/src/packages/documents/documents/index.ts index c1efa8caac..cce7f7a361 100644 --- a/src/packages/documents/documents/index.ts +++ b/src/packages/documents/documents/index.ts @@ -2,6 +2,7 @@ export * from './repository/index.js'; export * from './workspace/index.js'; export * from './recycle-bin/index.js'; export * from './user-permissions/index.js'; +export * from './components/index.js'; import './components/index.js'; From 8e112fe5205b769e86104a3b2675facaae79393b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:04:02 +0200 Subject: [PATCH 72/97] update value on model --- .../user-group-workspace-editor.element.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index cac7e82517..393834be8e 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -9,6 +9,8 @@ import { UmbModalManagerContext, } from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document'; +import { UmbInputSectionElement } from '@umbraco-cms/backoffice/components'; import './components/user-group-default-permission-list.element.js'; import './components/user-group-granular-permission-list.element.js'; @@ -42,8 +44,14 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext?.updateUserKeys(userIds); } - #onSectionsChange(value: string[]) { - this.#workspaceContext?.updateProperty('sections', value); + #onSectionsChange(event: CustomEvent) { + const target = event.target as UmbInputSectionElement; + this.#workspaceContext?.updateProperty('sections', target.value); + } + + #onDocumentStartNodeChange(event: CustomEvent) { + const target = event.target as UmbInputDocumentElement; + this.#workspaceContext?.updateProperty('documentStartNodeId', target.selectedIds[0]); } async #onDelete() { @@ -116,7 +124,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#onSectionsChange(e.target.value)}> + @change=${this.#onSectionsChange}> this.#onSectionsChange(e.target.value)} + @change=${this.#onDocumentStartNodeChange} multiple> Date: Wed, 27 Sep 2023 21:08:57 +1300 Subject: [PATCH 73/97] add max 1 to document selector in user group workspace --- .../user-groups/workspace/user-group-workspace-editor.element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index cac7e82517..ec692a61a6 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -123,6 +123,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { description=${this.localize.term('user_startnodehelp')}> this.#onSectionsChange(e.target.value)} multiple> From b51deb16a9ef8b8d04cb122c559a3c91a25d07ef Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:13:11 +0200 Subject: [PATCH 74/97] dispatch event when items are removed from a picker --- src/packages/core/picker-input/picker-input.context.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/core/picker-input/picker-input.context.ts b/src/packages/core/picker-input/picker-input.context.ts index a2eac80a8a..a77b907fee 100644 --- a/src/packages/core/picker-input/picker-input.context.ts +++ b/src/packages/core/picker-input/picker-input.context.ts @@ -101,5 +101,6 @@ export class UmbPickerInputContext #removeItem(unique: string) { const newSelection = this.getSelection().filter((value) => value !== unique); this.setSelection(newSelection); + this.host.dispatchEvent(new UmbChangeEvent()); } } From 59d35b5473ba4b9fdba88f0bd95826c0eb0d00f3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:13:26 +0200 Subject: [PATCH 75/97] align methods --- .../user-group-workspace-editor.element.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 393834be8e..a52dccfb17 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -11,6 +11,8 @@ import { import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document'; import { UmbInputSectionElement } from '@umbraco-cms/backoffice/components'; +import { UmbUserInputElement } from '@umbraco-cms/backoffice/users'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; import './components/user-group-default-permission-list.element.js'; import './components/user-group-granular-permission-list.element.js'; @@ -40,11 +42,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { }); } - #onUsersChange(userIds: Array) { - this.#workspaceContext?.updateUserKeys(userIds); - } - - #onSectionsChange(event: CustomEvent) { + #onSectionsChange(event: UmbChangeEvent) { const target = event.target as UmbInputSectionElement; this.#workspaceContext?.updateProperty('sections', target.value); } @@ -54,6 +52,11 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext?.updateProperty('documentStartNodeId', target.selectedIds[0]); } + #onUsersChange(event: UmbChangeEvent) { + const target = event.target as UmbUserInputElement; + this.#workspaceContext?.updateUserKeys(target.selectedIds); + } + async #onDelete() { if (!this.#modalContext || !this.#workspaceContext) return; @@ -156,10 +159,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { #renderRightColumn() { return html`
- - this.#onUsersChange((e.target as any).selectedIds)} - .selectedIds=${this._userKeys ?? []}> +
From cd9a15f70927f5ccb2099e7fcbe56382dbb2ae3a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:26:31 +0200 Subject: [PATCH 76/97] marked pre selected user in user picker modal --- .../user-picker/user-picker-modal.element.ts | 48 +++++++------------ .../users/users/repository/user.repository.ts | 2 +- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/packages/users/users/modals/user-picker/user-picker-modal.element.ts b/src/packages/users/users/modals/user-picker/user-picker-modal.element.ts index 9196cf8391..52f6217bec 100644 --- a/src/packages/users/users/modals/user-picker/user-picker-modal.element.ts +++ b/src/packages/users/users/modals/user-picker/user-picker-modal.element.ts @@ -1,46 +1,34 @@ import { UmbUserRepository } from '../../repository/user.repository.js'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; -import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { css, html, customElement, state, ifDefined, PropertyValueMap } from '@umbraco-cms/backoffice/external/lit'; import { UmbUserPickerModalData, UmbUserPickerModalResult } from '@umbraco-cms/backoffice/modal'; -import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api'; -import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; -import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; import { UmbModalBaseElement } from '@umbraco-cms/internal/modal'; import { UmbSelectionManagerBase } from '@umbraco-cms/backoffice/utils'; -import { type UmbUserDetail } from '@umbraco-cms/backoffice/users'; +import { UserItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; @customElement('umb-user-picker-modal') export class UmbUserPickerModalElement extends UmbModalBaseElement { @state() - private _users: Array = []; + private _users: Array = []; #selectionManager = new UmbSelectionManagerBase(); - #userRepository?: UmbUserRepository; + #userRepository = new UmbUserRepository(this); - constructor() { - super(); + connectedCallback(): void { + super.connectedCallback(); - // TODO: this code is reused in multiple places, so it should be extracted to a function - new UmbObserverController( - this, - umbExtensionsRegistry.getByTypeAndAlias('repository', 'Umb.Repository.User'), - async (repositoryManifest) => { - if (!repositoryManifest) return; + // TODO: in theory this config could change during the lifetime of the modal, so we could observe it + this.#selectionManager.setMultiple(this.data?.multiple ?? false); + this.#selectionManager.setSelection(this.data?.selection ?? []); + } - try { - const result = await createExtensionClass(repositoryManifest, [this]); - this.#userRepository = result; - this.#observeUsers(); - } catch (error) { - throw new Error('Could not create repository with alias: Umb.Repository.User'); - } - } - ); + protected firstUpdated(_changedProperties: PropertyValueMap | Map): void { + super.firstUpdated(_changedProperties); + this.#requestUsers(); } - async #observeUsers() { + async #requestUsers() { if (!this.#userRepository) return; - // TODO is this the correct end point? const { data } = await this.#userRepository.requestCollection(); if (data) { @@ -63,14 +51,14 @@ export class UmbUserPickerModalElement extends UmbModalBaseElement html` this.#selectionManager.select(user.id!)} @deselected=${() => this.#selectionManager.deselect(user.id!)} ?selected=${this.#selectionManager.isSelected(user.id!)}> - + - ` + `, )}
diff --git a/src/packages/users/users/repository/user.repository.ts b/src/packages/users/users/repository/user.repository.ts index 02aeb397b7..946820c8ca 100644 --- a/src/packages/users/users/repository/user.repository.ts +++ b/src/packages/users/users/repository/user.repository.ts @@ -80,7 +80,7 @@ export class UmbUserRepository } // COLLECTION - async requestCollection(filter: UmbUserCollectionFilterModel = { skip: 0, take: 100 }) { + async requestCollection(filter: UmbUserCollectionFilterModel = { skip: 0, take: 100000 }) { //TODO: missing observable return this.#collectionSource.filterCollection(filter); } From 6473eae6754476b72398b853edc3c7a343063de0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:31:53 +0200 Subject: [PATCH 77/97] render input media on user group --- .../workspace/user-group-workspace-editor.element.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 376216dd81..db69770e55 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -136,13 +136,16 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { slot="editor" max="1" .selectedIds=${this._userGroup.documentStartNodeId ? [this._userGroup.documentStartNodeId] : []} - @change=${this.#onDocumentStartNodeChange} - multiple> + @change=${this.#onDocumentStartNodeChange}> - MEDIA START NODE PICKER NOT IMPLEMENTED YET + From 89b9f967be5679423ca0ba3a6246797a91122d12 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:32:08 +0200 Subject: [PATCH 78/97] export / import input media from media package --- src/packages/media/manifests.ts | 2 ++ src/packages/media/media/components/index.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/packages/media/manifests.ts b/src/packages/media/manifests.ts index 138fdd7f88..940d82b7ca 100644 --- a/src/packages/media/manifests.ts +++ b/src/packages/media/manifests.ts @@ -3,4 +3,6 @@ import { manifests as mediaMenuManifests } from './menu.manifests.js'; import { manifests as mediaManifests } from './media/manifests.js'; import { manifests as mediaTypesManifests } from './media-types/manifests.js'; +import './media/components/index.js'; + export const manifests = [...mediaSectionManifests, ...mediaMenuManifests, ...mediaManifests, ...mediaTypesManifests]; diff --git a/src/packages/media/media/components/index.ts b/src/packages/media/media/components/index.ts index f744600b4e..b0cd856c7d 100644 --- a/src/packages/media/media/components/index.ts +++ b/src/packages/media/media/components/index.ts @@ -1 +1,3 @@ import './input-media/input-media.element.js'; + +export * from './input-media/input-media.element.js'; From 4b256a616ff923c86852e28dd5ccbd489f4fa102 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:46:56 +0200 Subject: [PATCH 79/97] update media input to use picker context --- .../input-media/input-media.context.ts | 10 ++ .../input-media/input-media.element.ts | 137 ++++++------------ 2 files changed, 53 insertions(+), 94 deletions(-) create mode 100644 src/packages/media/media/components/input-media/input-media.context.ts diff --git a/src/packages/media/media/components/input-media/input-media.context.ts b/src/packages/media/media/components/input-media/input-media.context.ts new file mode 100644 index 0000000000..cb668fd2f2 --- /dev/null +++ b/src/packages/media/media/components/input-media/input-media.context.ts @@ -0,0 +1,10 @@ +import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UMB_MEDIA_TREE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal'; +import { MediaItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; + +export class UmbMediaPickerContext extends UmbPickerInputContext { + constructor(host: UmbControllerHostElement) { + super(host, 'Umb.Repository.Media', UMB_MEDIA_TREE_PICKER_MODAL); + } +} diff --git a/src/packages/media/media/components/input-media/input-media.element.ts b/src/packages/media/media/components/input-media/input-media.element.ts index a6cc059d08..21749f87f5 100644 --- a/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/packages/media/media/components/input-media/input-media.element.ts @@ -1,15 +1,8 @@ -import { UmbMediaRepository } from '../../repository/media.repository.js'; -import { css, html, nothing, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; +import { UmbMediaPickerContext } from './input-media.context.js'; +import { css, html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui'; -import { - UmbModalManagerContext, - UMB_MODAL_MANAGER_CONTEXT_TOKEN, - UMB_CONFIRM_MODAL, - UMB_MEDIA_TREE_PICKER_MODAL, -} from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import type { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import type { MediaItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; @customElement('umb-input-media') export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { @@ -17,10 +10,15 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { * This is a minimum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default 0 */ @property({ type: Number }) - min?: number; + public get min(): number { + return this.#pickerContext.min; + } + public set min(value: number) { + this.#pickerContext.min = value; + } /** * Min validation message. @@ -35,10 +33,15 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { * This is a maximum amount of selected items in this input. * @type {number} * @attr - * @default undefined + * @default Infinity */ @property({ type: Number }) - max?: number; + public get max(): number { + return this.#pickerContext.max; + } + public set max(value: number) { + this.#pickerContext.max = value; + } /** * Max validation message. @@ -49,30 +52,23 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { @property({ type: String, attribute: 'min-message' }) maxMessage = 'This field exceeds the allowed amount of items'; - // TODO: do we need both selectedIds and value? If we just use value we follow the same pattern as native form controls. - private _selectedIds: Array = []; public get selectedIds(): Array { - return this._selectedIds; + return this.#pickerContext.getSelection(); } public set selectedIds(ids: Array) { - this._selectedIds = ids; - super.value = ids.join(','); - this._observePickedMedias(); + this.#pickerContext.setSelection(ids); } @property() public set value(idsString: string) { - if (idsString !== this._value) { - this.selectedIds = idsString.split(/[ ,]+/); - } + // Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection. + this.selectedIds = idsString.split(/[ ,]+/); } @state() - private _items?: Array; + private _items?: Array; - private _modalContext?: UmbModalManagerContext; - private _pickedItemsObserver?: UmbObserverController; - private _repository = new UmbMediaRepository(this); + #pickerContext = new UmbMediaPickerContext(this); constructor() { super(); @@ -80,104 +76,56 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { this.addValidator( 'rangeUnderflow', () => this.minMessage, - () => !!this.min && this._selectedIds.length < this.min + () => !!this.min && this.#pickerContext.getSelection().length < this.min, ); + this.addValidator( 'rangeOverflow', () => this.maxMessage, - () => !!this.max && this._selectedIds.length > this.max + () => !!this.max && this.#pickerContext.getSelection().length > this.max, ); - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { - this._modalContext = instance; - }); - } - - connectedCallback(): void { - super.connectedCallback(); - this._observePickedMedias(); + this.observe(this.#pickerContext.selection, (selection) => (super.value = selection.join(','))); + this.observe(this.#pickerContext.selectedItems, (selectedItems) => (this._items = selectedItems)); } protected getFormElement() { return undefined; } - private async _observePickedMedias() { - this._pickedItemsObserver?.destroy(); - - // TODO: consider changing this to the list data endpoint when it is available - const { asObservable } = await this._repository.requestItemsLegacy(this._selectedIds); - - if (!asObservable) return; - - this._pickedItemsObserver = this.observe(asObservable(), (items) => { - this._items = items; - }); - } - - private _openPicker() { - // We send a shallow copy(good enough as its just an array of ids) of our this._selectedIds, as we don't want the modal to manipulate our data: - const modalContext = this._modalContext?.open(UMB_MEDIA_TREE_PICKER_MODAL, { - multiple: this.max === 1 ? false : true, - selection: [...this._selectedIds], - }); - - modalContext?.onSubmit().then(({ selection }: any) => { - this._setSelection(selection); - }); - } - - private _removeItem(item: EntityTreeItemResponseModel) { - const modalContext = this._modalContext?.open(UMB_CONFIRM_MODAL, { - color: 'danger', - headline: `Remove ${item.name}?`, - content: 'Are you sure you want to remove this item', - confirmLabel: 'Remove', - }); - - modalContext?.onSubmit().then(() => { - const newSelection = this._selectedIds.filter((value) => value !== item.id); - this._setSelection(newSelection); - }); - } - - private _setSelection(newSelection: Array) { - this.selectedIds = newSelection; - this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true })); - } - render() { - return html` ${this._items?.map((item) => this._renderItem(item))} ${this._renderButton()} `; + return html` + ${this._items?.map((item) => this.#renderItem(item))} ${this.#renderButton()} + `; } - private _renderButton() { + + #renderButton() { if (this._items && this.max && this._items.length >= this.max) return; - return html` - - Add - `; + return html` + this.#pickerContext.openPicker()} label="open"> + + Add + + `; } - private _renderItem(item: EntityTreeItemResponseModel) { - // TODO: remove when we have a way to handle trashed items - const tempItem = item as EntityTreeItemResponseModel & { isTrashed: boolean }; - + #renderItem(item: MediaItemResponseModel) { return html` - ${tempItem.isTrashed ? html` Trashed ` : nothing} + - this._removeItem(item)} label="Remove media ${item.name}"> + this.#pickerContext.requestRemoveItem(item.id!)} label="Remove media ${item.name}"> `; - //TODO: } static styles = [ @@ -187,6 +135,7 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { gap: var(--uui-size-space-3); grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); } + #add-button { text-align: center; height: 160px; From 7f8857b988f3a2b38c9dbdfc1d9ad71c675b1d2e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 10:48:51 +0200 Subject: [PATCH 80/97] don't wrap in ref list --- .../media/media/components/input-media/input-media.element.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/packages/media/media/components/input-media/input-media.element.ts b/src/packages/media/media/components/input-media/input-media.element.ts index 21749f87f5..193cce9c7c 100644 --- a/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/packages/media/media/components/input-media/input-media.element.ts @@ -94,9 +94,7 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { } render() { - return html` - ${this._items?.map((item) => this.#renderItem(item))} ${this.#renderButton()} - `; + return html` ${this._items?.map((item) => this.#renderItem(item))} ${this.#renderButton()} `; } #renderButton() { From 6025bf7658ae35fa392d4d26246eb0cf64396eae Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 11:21:43 +0200 Subject: [PATCH 81/97] handle media items --- src/mocks/data/media.data.ts | 19 +++++++++- src/mocks/handlers/media.handlers.ts | 8 ++++ src/packages/media/media/index.ts | 1 + .../media/media/repository/manifests.ts | 18 ++++++++- .../media/repository/media-item.store.ts | 36 ++++++++++++++++++ .../media/repository/media.repository.ts | 29 ++++++++++++++ .../sources/media-item.server.data.ts | 38 +++++++++++++++++++ 7 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 src/packages/media/media/repository/media-item.store.ts create mode 100644 src/packages/media/media/repository/sources/media-item.server.data.ts diff --git a/src/mocks/data/media.data.ts b/src/mocks/data/media.data.ts index fd24e3d456..973dd02a2e 100644 --- a/src/mocks/data/media.data.ts +++ b/src/mocks/data/media.data.ts @@ -2,7 +2,11 @@ import type { MediaDetails } from '../../packages/media/media/index.js'; import { UmbEntityTreeData } from './entity-tree.data.js'; import { UmbEntityData } from './entity.data.js'; import { createContentTreeItem } from './utils.js'; -import { ContentTreeItemResponseModel, PagedMediaTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { + ContentTreeItemResponseModel, + MediaItemResponseModel, + PagedMediaTreeItemResponseModel, +} from '@umbraco-cms/backoffice/backend-api'; export const data: Array = [ { @@ -183,6 +187,14 @@ export const data: Array = [ }, ]; +const createMediaItem = (item: MediaDetails): MediaItemResponseModel => { + return { + id: item.id, + name: item.name, + icon: item.icon, + }; +}; + // Temp mocked database // TODO: all properties are optional in the server schema. I don't think this is correct. // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -194,6 +206,11 @@ class UmbMediaData extends UmbEntityData { super(data); } + getItems(ids: Array): Array { + const items = this.data.filter((item) => ids.includes(item.id ?? '')); + return items.map((item) => createMediaItem(item)); + } + getTreeRoot(): PagedMediaTreeItemResponseModel { const items = this.data.filter((item) => item.parentId === null); const treeItems = items.map((item) => createContentTreeItem(item)); diff --git a/src/mocks/handlers/media.handlers.ts b/src/mocks/handlers/media.handlers.ts index 4b15c2d898..6ec9a61774 100644 --- a/src/mocks/handlers/media.handlers.ts +++ b/src/mocks/handlers/media.handlers.ts @@ -1,8 +1,16 @@ const { rest } = window.MockServiceWorker; import { umbMediaData } from '../data/media.data.js'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; // TODO: add schema export const handlers = [ + rest.get(umbracoPath('/media/item'), (req, res, ctx) => { + const ids = req.url.searchParams.getAll('id'); + if (!ids) return; + const items = umbMediaData.getItems(ids); + return res(ctx.status(200), ctx.json(items)); + }), + rest.get('/umbraco/management/api/v1/media/details/:id', (req, res, ctx) => { console.warn('Please move to schema'); const id = req.params.id as string; diff --git a/src/packages/media/media/index.ts b/src/packages/media/media/index.ts index 203cdbb451..e976097f3b 100644 --- a/src/packages/media/media/index.ts +++ b/src/packages/media/media/index.ts @@ -21,4 +21,5 @@ export interface MediaDetails extends ContentTreeItemResponseModel { data: Array; variants: Array; // TODO: define variant data //layout?: any; // TODO: define layout type - make it non-optional + icon?: string; } diff --git a/src/packages/media/media/repository/manifests.ts b/src/packages/media/media/repository/manifests.ts index 5e2530f6b1..1602d61aac 100644 --- a/src/packages/media/media/repository/manifests.ts +++ b/src/packages/media/media/repository/manifests.ts @@ -1,7 +1,13 @@ +import { UmbMediaItemStore } from './media-item.store.js'; import { UmbMediaRepository } from './media.repository.js'; import { UmbMediaStore } from './media.store.js'; import { UmbMediaTreeStore } from './media.tree.store.js'; -import type { ManifestStore, ManifestTreeStore, ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; +import type { + ManifestStore, + ManifestTreeStore, + ManifestRepository, + ManifestItemStore, +} from '@umbraco-cms/backoffice/extension-registry'; export const MEDIA_REPOSITORY_ALIAS = 'Umb.Repository.Media'; @@ -14,6 +20,7 @@ const repository: ManifestRepository = { export const MEDIA_STORE_ALIAS = 'Umb.Store.Media'; export const MEDIA_TREE_STORE_ALIAS = 'Umb.Store.MediaTree'; +export const MEDIA_ITEM_STORE_ALIAS = 'Umb.Store.MediaItem'; const store: ManifestStore = { type: 'store', @@ -29,4 +36,11 @@ const treeStore: ManifestTreeStore = { class: UmbMediaTreeStore, }; -export const manifests = [store, treeStore, repository]; +const itemStore: ManifestItemStore = { + type: 'itemStore', + alias: MEDIA_ITEM_STORE_ALIAS, + name: 'Media Item Store', + class: UmbMediaItemStore, +}; + +export const manifests = [store, treeStore, itemStore, repository]; diff --git a/src/packages/media/media/repository/media-item.store.ts b/src/packages/media/media/repository/media-item.store.ts new file mode 100644 index 0000000000..87578dcbb7 --- /dev/null +++ b/src/packages/media/media/repository/media-item.store.ts @@ -0,0 +1,36 @@ +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UmbItemStore, UmbStoreBase } from '@umbraco-cms/backoffice/store'; +import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; +import { MediaItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; + +/** + * @export + * @class UmbMediaItemStore + * @extends {UmbStoreBase} + * @description - Data Store for Media items + */ + +export class UmbMediaItemStore + extends UmbStoreBase + implements UmbItemStore +{ + /** + * Creates an instance of UmbMediaItemStore. + * @param {UmbControllerHostElement} host + * @memberof UmbMediaItemStore + */ + constructor(host: UmbControllerHostElement) { + super( + host, + UMB_Media_ITEM_STORE_CONTEXT_TOKEN.toString(), + new UmbArrayState([], (x) => x.id), + ); + } + + items(ids: Array) { + return this._data.asObservablePart((items) => items.filter((item) => ids.includes(item.id ?? ''))); + } +} + +export const UMB_Media_ITEM_STORE_CONTEXT_TOKEN = new UmbContextToken('UmbMediaItemStore'); diff --git a/src/packages/media/media/repository/media.repository.ts b/src/packages/media/media/repository/media.repository.ts index 64730ae059..0f27f0c7b5 100644 --- a/src/packages/media/media/repository/media.repository.ts +++ b/src/packages/media/media/repository/media.repository.ts @@ -3,6 +3,8 @@ import { UmbMediaTreeServerDataSource } from './sources/media.tree.server.data.j import { UmbMediaTreeStore, UMB_MEDIA_TREE_STORE_CONTEXT_TOKEN } from './media.tree.store.js'; import { UmbMediaStore, UMB_MEDIA_STORE_CONTEXT_TOKEN } from './media.store.js'; import { UmbMediaDetailServerDataSource } from './sources/media.detail.server.data.js'; +import { UmbMediaItemServerDataSource } from './sources/media-item.server.data.js'; +import { UmbMediaItemStore } from './media-item.store.js'; import type { UmbTreeRepository, UmbTreeDataSource } from '@umbraco-cms/backoffice/repository'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; @@ -28,6 +30,9 @@ export class UmbMediaRepository #detailDataSource: UmbMediaDetailServerDataSource; #store?: UmbMediaStore; + #itemSource: UmbMediaItemServerDataSource; + #itemStore?: UmbMediaItemStore; + #notificationContext?: UmbNotificationContext; constructor(host: UmbControllerHostElement) { @@ -36,6 +41,7 @@ export class UmbMediaRepository // TODO: figure out how spin up get the correct data source this.#treeSource = new UmbMediaTreeServerDataSource(this.#host); this.#detailDataSource = new UmbMediaDetailServerDataSource(this.#host); + this.#itemSource = new UmbMediaItemServerDataSource(this.#host); this.#init = Promise.all([ new UmbContextConsumerController(this.#host, UMB_MEDIA_TREE_STORE_CONTEXT_TOKEN, (instance) => { @@ -46,6 +52,10 @@ export class UmbMediaRepository this.#store = instance; }).asPromise(), + new UmbContextConsumerController(this.#host, UMB_MEDIA_TREE_STORE_CONTEXT_TOKEN, (instance) => { + this.#itemStore = instance; + }).asPromise(), + new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { this.#notificationContext = instance; }).asPromise(), @@ -119,6 +129,25 @@ export class UmbMediaRepository return this.#treeStore!.items(ids); } + // ITEMS: + async requestItems(ids: Array) { + if (!ids) throw new Error('Keys are missing'); + await this.#init; + + const { data, error } = await this.#itemSource.getItems(ids); + + if (data) { + this.#itemStore?.appendItems(data); + } + + return { data, error, asObservable: () => this.#itemStore!.items(ids) }; + } + + async items(ids: Array) { + await this.#init; + return this.#itemStore!.items(ids); + } + // DETAILS: async createScaffold(parentId: string | null) { diff --git a/src/packages/media/media/repository/sources/media-item.server.data.ts b/src/packages/media/media/repository/sources/media-item.server.data.ts new file mode 100644 index 0000000000..7457bcd79f --- /dev/null +++ b/src/packages/media/media/repository/sources/media-item.server.data.ts @@ -0,0 +1,38 @@ +import type { UmbItemDataSource } from '@umbraco-cms/backoffice/repository'; +import { MediaResource, MediaItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source for Media items that fetches data from the server + * @export + * @class UmbMediaItemServerDataSource + * @implements {MediaItemDataSource} + */ +export class UmbMediaItemServerDataSource implements UmbItemDataSource { + #host: UmbControllerHostElement; + + /** + * Creates an instance of UmbMediaItemServerDataSource. + * @param {UmbControllerHostElement} host + * @memberof UmbMediaItemServerDataSource + */ + constructor(host: UmbControllerHostElement) { + this.#host = host; + } + + /** + * Fetches the items for the given ids from the server + * @param {Array} ids + * @memberof UmbMediaItemServerDataSource + */ + async getItems(ids: Array) { + if (!ids) throw new Error('Ids are missing'); + return tryExecuteAndNotify( + this.#host, + MediaResource.getMediaItem({ + id: ids, + }), + ); + } +} From ff2588e9b242e353282ed64f55bf82083d95c4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller=20Jensen?= <26099018+JesmoDev@users.noreply.github.com> Date: Wed, 27 Sep 2023 22:28:03 +1300 Subject: [PATCH 82/97] add media change event --- .../workspace/user-group-workspace-editor.element.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index db69770e55..9747936536 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -17,6 +17,8 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; import './components/user-group-default-permission-list.element.js'; import './components/user-group-granular-permission-list.element.js'; +import { UmbInputMediaElement } from 'src/packages/media/media/components/index.js'; + @customElement('umb-user-group-workspace-editor') export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @state() @@ -52,6 +54,11 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext?.updateProperty('documentStartNodeId', target.selectedIds[0]); } + #onMediaStartNodeChange(event: CustomEvent) { + const target = event.target as UmbInputMediaElement; + this.#workspaceContext?.updateProperty('mediaStartNodeId', target.selectedIds[0]); + } + #onUsersChange(event: UmbChangeEvent) { const target = event.target as UmbUserInputElement; this.#workspaceContext?.updateUserKeys(target.selectedIds); @@ -145,7 +152,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { slot="editor" max="1" .selectedIds=${this._userGroup.mediaStartNodeId ? [this._userGroup.mediaStartNodeId] : []} - @change=${this.#onDocumentStartNodeChange}> + @change=${this.#onMediaStartNodeChange}> From f4fc1b7e602d7a5a561b4e69035a99d55e2f58a6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 11:31:43 +0200 Subject: [PATCH 83/97] export components from media module --- src/packages/media/media/index.ts | 2 ++ .../workspace/user-group-workspace-editor.element.ts | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/packages/media/media/index.ts b/src/packages/media/media/index.ts index e976097f3b..acd16c9b4f 100644 --- a/src/packages/media/media/index.ts +++ b/src/packages/media/media/index.ts @@ -1,5 +1,7 @@ import { ContentTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +export * from './components/index.js'; + // Content export interface ContentProperty { alias: string; diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 9747936536..1d00330f37 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -13,12 +13,11 @@ import { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document'; import { UmbInputSectionElement } from '@umbraco-cms/backoffice/components'; import { UmbUserInputElement } from '@umbraco-cms/backoffice/users'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/events'; +import { UmbInputMediaElement } from '@umbraco-cms/backoffice/media'; import './components/user-group-default-permission-list.element.js'; import './components/user-group-granular-permission-list.element.js'; -import { UmbInputMediaElement } from 'src/packages/media/media/components/index.js'; - @customElement('umb-user-group-workspace-editor') export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { @state() From c10a08f476df5c52002ca86b82d438f3fb56c3b7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 13:25:32 +0200 Subject: [PATCH 84/97] don't request items if the array is empty --- src/shared/repository/repository-items.manager.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shared/repository/repository-items.manager.ts b/src/shared/repository/repository-items.manager.ts index ee2b154ae7..1a76b26341 100644 --- a/src/shared/repository/repository-items.manager.ts +++ b/src/shared/repository/repository-items.manager.ts @@ -46,8 +46,9 @@ export class UmbRepositoryItemsManager Date: Wed, 27 Sep 2023 13:26:14 +0200 Subject: [PATCH 85/97] init first --- src/shared/repository/repository-items.manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/repository/repository-items.manager.ts b/src/shared/repository/repository-items.manager.ts index 1a76b26341..c2f2342159 100644 --- a/src/shared/repository/repository-items.manager.ts +++ b/src/shared/repository/repository-items.manager.ts @@ -57,8 +57,8 @@ export class UmbRepositoryItemsManager Date: Wed, 27 Sep 2023 14:50:57 +0200 Subject: [PATCH 86/97] format --- .../user-groups/workspace/user-group-workspace.element.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace.element.ts index d4064d4457..861d9e3ebf 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace.element.ts @@ -1,6 +1,6 @@ import { UmbUserGroupWorkspaceContext } from './user-group-workspace.context.js'; import { UmbUserGroupWorkspaceEditorElement } from './user-group-workspace-editor.element.js'; -import { UmbTextStyles } from "@umbraco-cms/backoffice/style"; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { UmbRoute } from '@umbraco-cms/backoffice/router'; @@ -22,7 +22,7 @@ export class UmbUserGroupWorkspaceElement extends UmbLitElement { new UmbWorkspaceIsNewRedirectController( this, this.#workspaceContext, - this.shadowRoot!.querySelector('umb-router-slot')! + this.shadowRoot!.querySelector('umb-router-slot')!, ); }, }, From 0f2d4031b966ba991a08baf987c47195b97c79e4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 14:51:06 +0200 Subject: [PATCH 87/97] stop events --- .../workspace/user-group-workspace-editor.element.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 1d00330f37..ec044ddde6 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -44,21 +44,25 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { } #onSectionsChange(event: UmbChangeEvent) { + event.stopPropagation(); const target = event.target as UmbInputSectionElement; this.#workspaceContext?.updateProperty('sections', target.value); } #onDocumentStartNodeChange(event: CustomEvent) { + event.stopPropagation(); const target = event.target as UmbInputDocumentElement; this.#workspaceContext?.updateProperty('documentStartNodeId', target.selectedIds[0]); } #onMediaStartNodeChange(event: CustomEvent) { + event.stopPropagation(); const target = event.target as UmbInputMediaElement; this.#workspaceContext?.updateProperty('mediaStartNodeId', target.selectedIds[0]); } #onUsersChange(event: UmbChangeEvent) { + event.stopPropagation(); const target = event.target as UmbUserInputElement; this.#workspaceContext?.updateUserKeys(target.selectedIds); } From db6e7c09a2e523a7101a38fe0846675432bb6124 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 15:46:11 +0200 Subject: [PATCH 88/97] update items when unique is empty --- src/shared/repository/repository-items.manager.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/shared/repository/repository-items.manager.ts b/src/shared/repository/repository-items.manager.ts index c2f2342159..991d1aa290 100644 --- a/src/shared/repository/repository-items.manager.ts +++ b/src/shared/repository/repository-items.manager.ts @@ -48,7 +48,11 @@ export class UmbRepositoryItemsManager Date: Wed, 27 Sep 2023 16:36:37 +0200 Subject: [PATCH 89/97] change user group actions to use entity actions --- .../user-groups/entity-actions/manifests.ts | 22 +++++++++ src/packages/users/user-groups/index.ts | 2 + src/packages/users/user-groups/manifests.ts | 2 + .../user-group-workspace-editor.element.ts | 48 +++---------------- 4 files changed, 32 insertions(+), 42 deletions(-) create mode 100644 src/packages/users/user-groups/entity-actions/manifests.ts diff --git a/src/packages/users/user-groups/entity-actions/manifests.ts b/src/packages/users/user-groups/entity-actions/manifests.ts new file mode 100644 index 0000000000..0c67c05e58 --- /dev/null +++ b/src/packages/users/user-groups/entity-actions/manifests.ts @@ -0,0 +1,22 @@ +import { USER_GROUP_REPOSITORY_ALIAS } from '../repository/manifests.js'; +import { UMB_USER_GROUP_ENTITY_TYPE } from '../index.js'; +import { UmbDeleteEntityAction } from '@umbraco-cms/backoffice/entity-action'; +import { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; + +const entityActions: Array = [ + { + type: 'entityAction', + alias: 'Umb.EntityAction.UserGroup.Delete', + name: 'Delete User Group Entity Action', + weight: 900, + meta: { + icon: 'umb:trash', + label: 'Delete...', + repositoryAlias: USER_GROUP_REPOSITORY_ALIAS, + api: UmbDeleteEntityAction, + entityTypes: [UMB_USER_GROUP_ENTITY_TYPE], + }, + }, +]; + +export const manifests = [...entityActions]; diff --git a/src/packages/users/user-groups/index.ts b/src/packages/users/user-groups/index.ts index a63600bee5..81c17a6f51 100644 --- a/src/packages/users/user-groups/index.ts +++ b/src/packages/users/user-groups/index.ts @@ -1,2 +1,4 @@ export * from './types.js'; export * from './components/index.js'; + +export const UMB_USER_GROUP_ENTITY_TYPE = 'user-group'; diff --git a/src/packages/users/user-groups/manifests.ts b/src/packages/users/user-groups/manifests.ts index 7772c9b787..5d01d53186 100644 --- a/src/packages/users/user-groups/manifests.ts +++ b/src/packages/users/user-groups/manifests.ts @@ -2,6 +2,7 @@ import { manifests as repositoryManifests } from './repository/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; import { manifests as modalManifests } from './modals/manifests.js'; import { manifests as sectionViewManifests } from './section-view/manifests.js'; +import { manifests as entityActionManifests } from './entity-actions/manifests.js'; import { manifests as entityBulkActionManifests } from './entity-bulk-actions/manifests.js'; export const manifests = [ @@ -9,5 +10,6 @@ export const manifests = [ ...workspaceManifests, ...modalManifests, ...sectionViewManifests, + ...entityActionManifests, ...entityBulkActionManifests, ]; diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index ec044ddde6..27b86b1f40 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -1,13 +1,9 @@ +import { UMB_USER_GROUP_ENTITY_TYPE } from '../index.js'; import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from './user-group-workspace.context.js'; import { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; import { css, html, nothing, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api'; -import { - UMB_CONFIRM_MODAL, - UMB_MODAL_MANAGER_CONTEXT_TOKEN, - UmbModalManagerContext, -} from '@umbraco-cms/backoffice/modal'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document'; import { UmbInputSectionElement } from '@umbraco-cms/backoffice/components'; @@ -27,7 +23,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { private _userKeys?: Array; #workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE; - #modalContext?: UmbModalManagerContext; constructor() { super(); @@ -37,10 +32,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup)); this.observe(this.#workspaceContext.userIds, (userKeys) => (this._userKeys = userKeys)); }); - - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { - this.#modalContext = instance; - }); } #onSectionsChange(event: UmbChangeEvent) { @@ -67,26 +58,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { this.#workspaceContext?.updateUserKeys(target.selectedIds); } - async #onDelete() { - if (!this.#modalContext || !this.#workspaceContext) return; - - const modalContext = this.#modalContext.open(UMB_CONFIRM_MODAL, { - color: 'danger', - headline: `Delete user group ${this._userGroup?.name}?`, - content: html`Are you sure you want to delete ${this._userGroup?.name} user group?`, - confirmLabel: 'Delete', - }); - - await modalContext.onSubmit(); - - if (!this._userGroup || !this._userGroup.id) return; - - await this.#workspaceContext.delete(this._userGroup?.id); - //TODO: should we check if it actually succeeded in deleting the user group? - - history.pushState(null, '', 'section/users/view/user-groups'); - } - #onNameChange(event: UUIInputEvent) { if (event instanceof UUIInputEvent) { const target = event.composedPath()[0] as UUIInputElement; @@ -175,18 +146,11 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
- -
- - -
- -
`; + + `; } static styles = [ From 906161a51b6f83bd221bf36f45beca2b3699bc12 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 16:50:07 +0200 Subject: [PATCH 90/97] add delete mock handler for user groups --- src/mocks/handlers/user-group.handlers.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mocks/handlers/user-group.handlers.ts b/src/mocks/handlers/user-group.handlers.ts index c18f37bdd9..f4f8f7d76c 100644 --- a/src/mocks/handlers/user-group.handlers.ts +++ b/src/mocks/handlers/user-group.handlers.ts @@ -37,4 +37,13 @@ export const handlers = [ return res(ctx.status(200)); }), + + rest.delete(umbracoPath(`${slug}/:id`), async (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return; + + umbUserGroupData.delete([id]); + + return res(ctx.status(200)); + }), ]; From 8c1f4d6b25ad40c24e1d43fe13d34bf3afb69276 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 16:50:23 +0200 Subject: [PATCH 91/97] fix mock db delete method --- src/mocks/data/entity.data.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/mocks/data/entity.data.ts b/src/mocks/data/entity.data.ts index 6be5d293fe..d6c442fe89 100644 --- a/src/mocks/data/entity.data.ts +++ b/src/mocks/data/entity.data.ts @@ -75,19 +75,10 @@ export class UmbEntityData extends UmbData { } delete(ids: Array) { - const deletedKeys = this.data - .filter((item) => { - if (!item.id) throw new Error('Item has no id'); - ids.includes(item.id); - }) - .map((item) => item.id); - this.data = this.data.filter((item) => { if (!item.id) throw new Error('Item has no id'); - ids.indexOf(item.id) === -1; + return !ids.includes(item.id); }); - - return deletedKeys; } updateData(updateItem: T) { From e65536b633607572d677dbe69c9beb01383e88f9 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 16:59:07 +0200 Subject: [PATCH 92/97] split user group mocks into separate files --- src/mocks/browser-handlers.ts | 2 +- .../user-group/collection.handlers.ts | 11 ++++++++ .../detail.handlers.ts} | 27 ++++++++----------- src/mocks/handlers/user-group/index.ts | 5 ++++ .../handlers/user-group/item.handlers.ts | 14 ++++++++++ src/mocks/handlers/user-group/slug.ts | 1 + 6 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 src/mocks/handlers/user-group/collection.handlers.ts rename src/mocks/handlers/{user-group.handlers.ts => user-group/detail.handlers.ts} (53%) create mode 100644 src/mocks/handlers/user-group/index.ts create mode 100644 src/mocks/handlers/user-group/item.handlers.ts create mode 100644 src/mocks/handlers/user-group/slug.ts diff --git a/src/mocks/browser-handlers.ts b/src/mocks/browser-handlers.ts index d6cc08b4c8..32e57dfdb8 100644 --- a/src/mocks/browser-handlers.ts +++ b/src/mocks/browser-handlers.ts @@ -8,7 +8,7 @@ import * as serverHandlers from './handlers/server.handlers.js'; import { handlers as upgradeHandlers } from './handlers/upgrade.handlers.js'; import { handlers as userHandlers } from './handlers/user.handlers.js'; import { handlers as telemetryHandlers } from './handlers/telemetry.handlers.js'; -import { handlers as userGroupsHandlers } from './handlers/user-group.handlers.js'; +import { handlers as userGroupsHandlers } from './handlers/user-group/index.js'; import { handlers as examineManagementHandlers } from './handlers/examine-management.handlers.js'; import { handlers as modelsBuilderHandlers } from './handlers/modelsbuilder.handlers.js'; import { handlers as healthCheckHandlers } from './handlers/health-check.handlers.js'; diff --git a/src/mocks/handlers/user-group/collection.handlers.ts b/src/mocks/handlers/user-group/collection.handlers.ts new file mode 100644 index 0000000000..56ffe6f449 --- /dev/null +++ b/src/mocks/handlers/user-group/collection.handlers.ts @@ -0,0 +1,11 @@ +const { rest } = window.MockServiceWorker; +import { umbUserGroupData } from '../../data/user-group.data.js'; +import { slug } from './slug.js'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; + +export const collectionHandlers = [ + rest.get(umbracoPath(`${slug}`), (req, res, ctx) => { + const response = umbUserGroupData.getAll(); + return res(ctx.status(200), ctx.json(response)); + }), +]; diff --git a/src/mocks/handlers/user-group.handlers.ts b/src/mocks/handlers/user-group/detail.handlers.ts similarity index 53% rename from src/mocks/handlers/user-group.handlers.ts rename to src/mocks/handlers/user-group/detail.handlers.ts index f4f8f7d76c..100493e1c8 100644 --- a/src/mocks/handlers/user-group.handlers.ts +++ b/src/mocks/handlers/user-group/detail.handlers.ts @@ -1,30 +1,25 @@ const { rest } = window.MockServiceWorker; -import { umbUserGroupData } from '../data/user-group.data.js'; +import { umbUserGroupData } from '../../data/user-group.data.js'; +import { slug } from './slug.js'; import { umbracoPath } from '@umbraco-cms/backoffice/utils'; -const slug = '/user-group'; - -export const handlers = [ - rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => { - const ids = req.url.searchParams.getAll('id'); - if (!ids) return; - const items = umbUserGroupData.getItems(ids); - - return res(ctx.status(200), ctx.json(items)); - }), +export const detailHandlers = [ + rest.post(umbracoPath(`${slug}`), async (req, res, ctx) => { + const data = await req.json(); + if (!data) return; - rest.get(umbracoPath(`${slug}`), (req, res, ctx) => { - const response = umbUserGroupData.getAll(); + umbUserGroupData.insert(data); - return res(ctx.status(200), ctx.json(response)); + return res(ctx.status(200)); }), rest.get(umbracoPath(`${slug}/:id`), (req, res, ctx) => { const id = req.params.id as string; if (!id) return; - const userGroup = umbUserGroupData.getById(id); - return res(ctx.status(200), ctx.json(userGroup)); + const dataType = umbUserGroupData.getById(id); + + return res(ctx.status(200), ctx.json(dataType)); }), rest.put(umbracoPath(`${slug}/:id`), async (req, res, ctx) => { diff --git a/src/mocks/handlers/user-group/index.ts b/src/mocks/handlers/user-group/index.ts new file mode 100644 index 0000000000..c49236b99a --- /dev/null +++ b/src/mocks/handlers/user-group/index.ts @@ -0,0 +1,5 @@ +import { collectionHandlers } from './collection.handlers.js'; +import { detailHandlers } from './detail.handlers.js'; +import { itemHandlers } from './item.handlers.js'; + +export const handlers = [...itemHandlers, ...collectionHandlers, ...detailHandlers]; diff --git a/src/mocks/handlers/user-group/item.handlers.ts b/src/mocks/handlers/user-group/item.handlers.ts new file mode 100644 index 0000000000..c0d7a0e52d --- /dev/null +++ b/src/mocks/handlers/user-group/item.handlers.ts @@ -0,0 +1,14 @@ +const { rest } = window.MockServiceWorker; +import { umbUserGroupData } from '../../data/user-group.data.js'; +import { slug } from './slug.js'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; + +export const itemHandlers = [ + rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => { + const ids = req.url.searchParams.getAll('id'); + if (!ids) return; + const items = umbUserGroupData.getItems(ids); + + return res(ctx.status(200), ctx.json(items)); + }), +]; diff --git a/src/mocks/handlers/user-group/slug.ts b/src/mocks/handlers/user-group/slug.ts new file mode 100644 index 0000000000..25f6d8e6d1 --- /dev/null +++ b/src/mocks/handlers/user-group/slug.ts @@ -0,0 +1 @@ +export const slug = '/user-group'; From 8354d6f3a8bd002a9c49556ed62f0b780c8d707a Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 21:26:39 +0200 Subject: [PATCH 93/97] don't return anything when deleting --- src/mocks/handlers/dictionary.handlers.ts | 6 +++--- src/mocks/handlers/partial-views.handlers.ts | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/mocks/handlers/dictionary.handlers.ts b/src/mocks/handlers/dictionary.handlers.ts index 874bb40a16..69da232146 100644 --- a/src/mocks/handlers/dictionary.handlers.ts +++ b/src/mocks/handlers/dictionary.handlers.ts @@ -151,9 +151,9 @@ export const handlers = [ const id = req.params.id as string; if (!id) return; - const deletedKeys = umbDictionaryData.delete([id]); + umbDictionaryData.delete([id]); - return res(ctx.status(200), ctx.json(deletedKeys)); + return res(ctx.status(200)); }), // TODO => handle properly, querystring breaks handler @@ -165,7 +165,7 @@ export const handlers = [ const item = umbDictionaryData.getById(id); alert( - `Downloads file for dictionary "${item?.name}", ${includeChildren === 'true' ? 'with' : 'without'} children.` + `Downloads file for dictionary "${item?.name}", ${includeChildren === 'true' ? 'with' : 'without'} children.`, ); return res(ctx.status(200)); }), diff --git a/src/mocks/handlers/partial-views.handlers.ts b/src/mocks/handlers/partial-views.handlers.ts index b51faa885a..12112a7b34 100644 --- a/src/mocks/handlers/partial-views.handlers.ts +++ b/src/mocks/handlers/partial-views.handlers.ts @@ -45,16 +45,17 @@ const detailHandlers: RestHandler>[] = [ rest.delete(umbracoPath('/partial-view'), (req, res, ctx) => { const path = req.url.searchParams.get('path'); if (!path) return res(ctx.status(400)); - const response = umbPartialViewsData.delete([path]); - return res(ctx.status(200), ctx.json(response)); + umbPartialViewsData.delete([path]); + return res(ctx.status(200)); }), + rest.put(umbracoPath('/partial-view'), (req, res, ctx) => { const requestBody = req.json() as CreateTextFileViewModelBaseModel; if (!requestBody) return res(ctx.status(400, 'no body found')); - const response = umbPartialViewsData.updateData(requestBody); + umbPartialViewsData.updateData(requestBody); return res(ctx.status(200)); }), ]; const folderHandlers: RestHandler>[] = []; -export const handlers = [...treeHandlers, ...detailHandlers, ...folderHandlers] \ No newline at end of file +export const handlers = [...treeHandlers, ...detailHandlers, ...folderHandlers]; From 2b215bdeeb4daf7b50207152d74d454d1896c8c1 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 21:28:33 +0200 Subject: [PATCH 94/97] add wip alert --- .../documents/entity-actions/permissions.action.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/packages/documents/documents/entity-actions/permissions.action.ts b/src/packages/documents/documents/entity-actions/permissions.action.ts index 9362d92e4c..b7f53612c2 100644 --- a/src/packages/documents/documents/entity-actions/permissions.action.ts +++ b/src/packages/documents/documents/entity-actions/permissions.action.ts @@ -20,19 +20,22 @@ export class UmbDocumentPermissionsEntityAction extends UmbEntityActionBase Date: Wed, 27 Sep 2023 21:46:20 +0200 Subject: [PATCH 95/97] add condition config to types --- src/packages/core/extension-registry/conditions/types.ts | 4 ++++ src/packages/users/current-user/conditions/index.ts | 1 + src/packages/users/current-user/index.ts | 1 + 3 files changed, 6 insertions(+) create mode 100644 src/packages/users/current-user/conditions/index.ts diff --git a/src/packages/core/extension-registry/conditions/types.ts b/src/packages/core/extension-registry/conditions/types.ts index 292b07c760..943dbe8d41 100644 --- a/src/packages/core/extension-registry/conditions/types.ts +++ b/src/packages/core/extension-registry/conditions/types.ts @@ -2,9 +2,13 @@ import type { SectionAliasConditionConfig } from './section-alias.condition.js'; import type { SwitchConditionConfig } from './switch.condition.js'; import type { WorkspaceAliasConditionConfig } from '@umbraco-cms/backoffice/workspace'; import type { UmbConditionConfigBase } from '@umbraco-cms/backoffice/extension-api'; +import type { UserPermissionConditionConfig } from '@umbraco-cms/backoffice/current-user'; +/* TODO: in theory should't the core package import from other packages. +Are there any other way we can do this? */ export type ConditionTypes = | SectionAliasConditionConfig | WorkspaceAliasConditionConfig | SwitchConditionConfig + | UserPermissionConditionConfig | UmbConditionConfigBase; diff --git a/src/packages/users/current-user/conditions/index.ts b/src/packages/users/current-user/conditions/index.ts new file mode 100644 index 0000000000..64b786466c --- /dev/null +++ b/src/packages/users/current-user/conditions/index.ts @@ -0,0 +1 @@ +export * from './user-permission.condition.js'; diff --git a/src/packages/users/current-user/index.ts b/src/packages/users/current-user/index.ts index 0b68da794d..4cbce7fc3e 100644 --- a/src/packages/users/current-user/index.ts +++ b/src/packages/users/current-user/index.ts @@ -1,2 +1,3 @@ // TODO:Do not export store, but instead export future repository export * from './current-user-history.store.js'; +export * from './conditions/index.js'; From 3702397d8aadc674b7d3184c65068bcbe062df31 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 21:46:29 +0200 Subject: [PATCH 96/97] temo ts-ignore --- .../documents/documents/entity-actions/create/manifests.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/packages/documents/documents/entity-actions/create/manifests.ts b/src/packages/documents/documents/entity-actions/create/manifests.ts index ee35698c4e..99a21a0d53 100644 --- a/src/packages/documents/documents/entity-actions/create/manifests.ts +++ b/src/packages/documents/documents/entity-actions/create/manifests.ts @@ -19,6 +19,9 @@ const entityActions: Array = [ conditions: [ { alias: 'Umb.Condition.UserPermission', + // TODO: investigate why the match property is not typed + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore match: 'Umb.UserPermission.Document.Create', }, ], From f5fb8cee6ad2e50b68c4155e7d49904bcb80b80c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 27 Sep 2023 21:49:58 +0200 Subject: [PATCH 97/97] comment out granular permission UI --- .../workspace/user-group-workspace-editor.element.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts index 27b86b1f40..7b7453b3b2 100644 --- a/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts +++ b/src/packages/users/user-groups/workspace/user-group-workspace-editor.element.ts @@ -100,7 +100,8 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement { #renderLeftColumn() { if (!this._userGroup) return nothing; - return html` + return html` +
+ + `; } #renderRightColumn() {