Merge branch 'main' into bugfix/create-user-updates-after-new-endpoints
This commit is contained in:
@@ -107,6 +107,7 @@ export type { DocumentCollectionResponseModel } from './models/DocumentCollectio
|
||||
export type { DocumentConfigurationResponseModel } from './models/DocumentConfigurationResponseModel';
|
||||
export type { DocumentItemResponseModel } from './models/DocumentItemResponseModel';
|
||||
export type { DocumentNotificationResponseModel } from './models/DocumentNotificationResponseModel';
|
||||
export type { DocumentPermissionPresentationModel } from './models/DocumentPermissionPresentationModel';
|
||||
export type { DocumentRecycleBinItemResponseModel } from './models/DocumentRecycleBinItemResponseModel';
|
||||
export type { DocumentResponseModel } from './models/DocumentResponseModel';
|
||||
export type { DocumentTreeItemResponseModel } from './models/DocumentTreeItemResponseModel';
|
||||
@@ -362,10 +363,10 @@ export type { TemplateQueryResultItemPresentationModel } from './models/Template
|
||||
export type { TemplateQueryResultResponseModel } from './models/TemplateQueryResultResponseModel';
|
||||
export type { TemplateQuerySettingsResponseModel } from './models/TemplateQuerySettingsResponseModel';
|
||||
export type { TemplateResponseModel } from './models/TemplateResponseModel';
|
||||
export type { TemporaryFileConfigurationResponseModel } from './models/TemporaryFileConfigurationResponseModel';
|
||||
export type { TemporaryFileResponseModel } from './models/TemporaryFileResponseModel';
|
||||
export type { TourStatusModel } from './models/TourStatusModel';
|
||||
export type { TreeItemPresentationModel } from './models/TreeItemPresentationModel';
|
||||
export type { UnknownTypePermissionPresentationModel } from './models/UnknownTypePermissionPresentationModel';
|
||||
export type { UnlockUsersRequestModel } from './models/UnlockUsersRequestModel';
|
||||
export type { UnpublishDocumentRequestModel } from './models/UnpublishDocumentRequestModel';
|
||||
export type { UpdateContentForDocumentRequestModel } from './models/UpdateContentForDocumentRequestModel';
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { DocumentPermissionPresentationModel } from './DocumentPermissionPresentationModel';
|
||||
import type { UnknownTypePermissionPresentationModel } from './UnknownTypePermissionPresentationModel';
|
||||
|
||||
export type CurrentUserResponseModel = {
|
||||
id: string;
|
||||
email: string;
|
||||
@@ -14,6 +17,8 @@ export type CurrentUserResponseModel = {
|
||||
avatarUrls: Array<string>;
|
||||
languages: Array<string>;
|
||||
hasAccessToAllLanguages: boolean;
|
||||
permissions: Array<string>;
|
||||
fallbackPermissions: Array<string>;
|
||||
permissions: Array<(DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel)>;
|
||||
allowedSections: Array<string>;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { ReferenceByIdModel } from './ReferenceByIdModel';
|
||||
|
||||
export type DocumentPermissionPresentationModel = {
|
||||
$type: string;
|
||||
document: ReferenceByIdModel;
|
||||
verbs: Array<string>;
|
||||
};
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type TemporaryFileConfigurationResponseModel = {
|
||||
imageFileTypes: Array<string>;
|
||||
disallowedUploadedFilesExtensions: Array<string>;
|
||||
allowedUploadedFileExtensions: Array<string>;
|
||||
maxFileSize?: number | null;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/* generated using openapi-typescript-codegen -- do no edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type UnknownTypePermissionPresentationModel = {
|
||||
$type: string;
|
||||
verbs: Array<string>;
|
||||
context: string;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { DocumentPermissionPresentationModel } from './DocumentPermissionPresentationModel';
|
||||
import type { ReferenceByIdModel } from './ReferenceByIdModel';
|
||||
import type { UnknownTypePermissionPresentationModel } from './UnknownTypePermissionPresentationModel';
|
||||
|
||||
export type UserGroupBaseModel = {
|
||||
name: string;
|
||||
@@ -15,6 +17,7 @@ export type UserGroupBaseModel = {
|
||||
documentRootAccess: boolean;
|
||||
mediaStartNode?: ReferenceByIdModel | null;
|
||||
mediaRootAccess: boolean;
|
||||
permissions: Array<string>;
|
||||
fallbackPermissions: Array<string>;
|
||||
permissions: Array<(DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel)>;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { TemporaryFileConfigurationResponseModel } from '../models/TemporaryFileConfigurationResponseModel';
|
||||
import type { TemporaryFileResponseModel } from '../models/TemporaryFileResponseModel';
|
||||
|
||||
import type { CancelablePromise } from '../core/CancelablePromise';
|
||||
@@ -86,7 +85,7 @@ export class TemporaryFileResource {
|
||||
* @returns any Success
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static getTemporaryFileConfiguration(): CancelablePromise<TemporaryFileConfigurationResponseModel> {
|
||||
public static getTemporaryFileConfiguration(): CancelablePromise<any> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/umbraco/management/api/v1/temporary-file/configuration',
|
||||
|
||||
@@ -47,10 +47,10 @@ const createDetailMockMapper = (request: CreateDataTypeRequestModel): UmbMockDat
|
||||
editorAlias: request.editorAlias,
|
||||
editorUiAlias: request.editorUiAlias,
|
||||
values: request.values,
|
||||
canIgnoreStartNodes: false,
|
||||
isFolder: false,
|
||||
hasChildren: false,
|
||||
isDeletable: true,
|
||||
canIgnoreStartNodes: false,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import type { UserGroupItemResponseModel, UserGroupResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
|
||||
import {
|
||||
UMB_USER_PERMISSION_DOCUMENT_CREATE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_DELETE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_READ,
|
||||
} from '@umbraco-cms/backoffice/document';
|
||||
|
||||
export type UmbMockUserGroupModel = UserGroupResponseModel & UserGroupItemResponseModel;
|
||||
|
||||
@@ -13,10 +8,29 @@ export const data: Array<UmbMockUserGroupModel> = [
|
||||
name: 'Administrators',
|
||||
icon: 'icon-medal',
|
||||
documentStartNode: { id: 'all-property-editors-document-id' },
|
||||
fallbackPermissions: [
|
||||
'Umb.Document.Read',
|
||||
'Umb.Document.Create',
|
||||
'Umb.Document.Update',
|
||||
'Umb.Document.Delete',
|
||||
'Umb.Document.CreateBlueprint',
|
||||
'Umb.Document.Notifications',
|
||||
'Umb.Document.Publish',
|
||||
'Umb.Document.Permissions',
|
||||
'Umb.Document.Unpublish',
|
||||
'Umb.Document.Duplicate',
|
||||
'Umb.Document.Move',
|
||||
'Umb.Document.Sort',
|
||||
'Umb.Document.CultureAndHostnames',
|
||||
'Umb.Document.PublicAccess',
|
||||
'Umb.Document.Rollback',
|
||||
],
|
||||
permissions: [
|
||||
UMB_USER_PERMISSION_DOCUMENT_READ,
|
||||
UMB_USER_PERMISSION_DOCUMENT_CREATE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_DELETE,
|
||||
{
|
||||
$type: 'DocumentPermissionPresentationModel',
|
||||
verbs: ['Umb.Document.Rollback'],
|
||||
document: { id: 'simple-document-id' },
|
||||
},
|
||||
],
|
||||
sections: [],
|
||||
languages: [],
|
||||
@@ -30,7 +44,22 @@ export const data: Array<UmbMockUserGroupModel> = [
|
||||
name: 'Editors',
|
||||
icon: 'icon-tools',
|
||||
documentStartNode: { id: 'all-property-editors-document-id' },
|
||||
permissions: [UMB_USER_PERMISSION_DOCUMENT_CREATE, UMB_USER_PERMISSION_DOCUMENT_DELETE],
|
||||
fallbackPermissions: [
|
||||
'Umb.Document.Read',
|
||||
'Umb.Document.Create',
|
||||
'Umb.Document.Update',
|
||||
'Umb.Document.Delete',
|
||||
'Umb.Document.CreateBlueprint',
|
||||
'Umb.Document.Notifications',
|
||||
'Umb.Document.Publish',
|
||||
'Umb.Document.Unpublish',
|
||||
'Umb.Document.Duplicate',
|
||||
'Umb.Document.Move',
|
||||
'Umb.Document.Sort',
|
||||
'Umb.Document.PublicAccess',
|
||||
'Umb.Document.Rollback',
|
||||
],
|
||||
permissions: [],
|
||||
sections: [],
|
||||
languages: [],
|
||||
hasAccessToAllLanguages: true,
|
||||
@@ -43,7 +72,8 @@ export const data: Array<UmbMockUserGroupModel> = [
|
||||
name: 'Sensitive data',
|
||||
icon: 'icon-lock',
|
||||
documentStartNode: { id: 'all-property-editors-document-id' },
|
||||
permissions: [UMB_USER_PERMISSION_DOCUMENT_CREATE, UMB_USER_PERMISSION_DOCUMENT_DELETE],
|
||||
fallbackPermissions: [],
|
||||
permissions: [],
|
||||
sections: [],
|
||||
languages: [],
|
||||
hasAccessToAllLanguages: true,
|
||||
@@ -56,7 +86,8 @@ export const data: Array<UmbMockUserGroupModel> = [
|
||||
name: 'Translators',
|
||||
icon: 'icon-globe',
|
||||
documentStartNode: { id: 'all-property-editors-document-id' },
|
||||
permissions: [UMB_USER_PERMISSION_DOCUMENT_CREATE, UMB_USER_PERMISSION_DOCUMENT_DELETE],
|
||||
fallbackPermissions: ['Umb.Document.Read', 'Umb.Document.Update'],
|
||||
permissions: [],
|
||||
sections: [],
|
||||
languages: [],
|
||||
hasAccessToAllLanguages: true,
|
||||
@@ -69,7 +100,13 @@ export const data: Array<UmbMockUserGroupModel> = [
|
||||
name: 'Writers',
|
||||
icon: 'icon-edit',
|
||||
documentStartNode: { id: 'all-property-editors-document-id' },
|
||||
permissions: [UMB_USER_PERMISSION_DOCUMENT_CREATE, UMB_USER_PERMISSION_DOCUMENT_DELETE],
|
||||
fallbackPermissions: [
|
||||
'Umb.Document.Read',
|
||||
'Umb.Document.Create',
|
||||
'Umb.Document.Update',
|
||||
'Umb.Document.Notifications',
|
||||
],
|
||||
permissions: [],
|
||||
sections: [],
|
||||
languages: [],
|
||||
hasAccessToAllLanguages: true,
|
||||
|
||||
@@ -5,6 +5,8 @@ import type { UmbMockUserGroupModel } from './user-group.data.js';
|
||||
import { data } from './user-group.data.js';
|
||||
import type {
|
||||
CreateUserGroupRequestModel,
|
||||
DocumentPermissionPresentationModel,
|
||||
UnknownTypePermissionPresentationModel,
|
||||
UserGroupItemResponseModel,
|
||||
UserGroupResponseModel,
|
||||
} from '@umbraco-cms/backoffice/external/backend-api';
|
||||
@@ -24,14 +26,17 @@ export class UmbUserGroupMockDB extends UmbEntityMockDbBase<UmbMockUserGroupMode
|
||||
* @return {*} {string[]}
|
||||
* @memberof UmbUserGroupData
|
||||
*/
|
||||
getPermissions(userGroupIds: string[]): string[] {
|
||||
getPermissions(
|
||||
userGroupIds: string[],
|
||||
): Array<DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel> {
|
||||
const permissions = this.data
|
||||
.filter((userGroup) => userGroupIds.includes(userGroup.id || ''))
|
||||
.filter((userGroup) => userGroupIds.includes(userGroup.id))
|
||||
.map((userGroup) => (userGroup.permissions?.length ? userGroup.permissions : []))
|
||||
.flat();
|
||||
|
||||
// Remove duplicates
|
||||
return [...new Set(permissions)];
|
||||
const uniqueArray = Array.from(new Set(permissions.map((e) => JSON.stringify(e)))).map((e) => JSON.parse(e));
|
||||
return uniqueArray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +60,7 @@ const createMockMapper = (item: CreateUserGroupRequestModel): UmbMockUserGroupMo
|
||||
mediaRootAccess: item.mediaRootAccess,
|
||||
mediaStartNode: item.mediaStartNode,
|
||||
name: item.name,
|
||||
fallbackPermissions: item.fallbackPermissions,
|
||||
permissions: item.permissions,
|
||||
sections: item.sections,
|
||||
};
|
||||
@@ -72,6 +78,7 @@ const detailResponseMapper = (item: UmbMockUserGroupModel): UserGroupResponseMod
|
||||
mediaRootAccess: item.mediaRootAccess,
|
||||
mediaStartNode: item.mediaStartNode,
|
||||
name: item.name,
|
||||
fallbackPermissions: item.fallbackPermissions,
|
||||
permissions: item.permissions,
|
||||
sections: item.sections,
|
||||
};
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import { UmbEntityData } from './entity.data.js';
|
||||
import {
|
||||
UMB_DOCUMENT_ENTITY_TYPE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_CREATE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_READ,
|
||||
} from '@umbraco-cms/backoffice/document';
|
||||
|
||||
export type UserPermissionModel = {
|
||||
id: string;
|
||||
target: unknown;
|
||||
permissions: Array<string>;
|
||||
};
|
||||
|
||||
export const data: Array<UserPermissionModel> = [
|
||||
{
|
||||
id: '408074bb-f776-485e-b85e-c2473e45663b',
|
||||
target: {
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
documentId: 'simple-document-id',
|
||||
userGroupId: 'user-group-administrators-id',
|
||||
},
|
||||
permissions: [UMB_USER_PERMISSION_DOCUMENT_READ],
|
||||
},
|
||||
{
|
||||
id: 'b70b1453-a912-4157-ba62-20c2f0ab6a88',
|
||||
target: {
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
documentId: 'simple-document-id',
|
||||
userGroupId: 'user-group-editors-id',
|
||||
},
|
||||
permissions: [UMB_USER_PERMISSION_DOCUMENT_READ, UMB_USER_PERMISSION_DOCUMENT_CREATE],
|
||||
},
|
||||
{
|
||||
id: 'b70b1453-a912-4157-ba62-20c2f0ab6a88',
|
||||
target: {
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
documentId: 'c05da24d-7740-447b-9cdc-bd8ce2172e38',
|
||||
userGroupId: 'user-group-administrators-id',
|
||||
},
|
||||
permissions: [UMB_USER_PERMISSION_DOCUMENT_READ],
|
||||
},
|
||||
];
|
||||
|
||||
class UmbUserPermissionData extends UmbEntityData<UserPermissionModel> {
|
||||
constructor() {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
export const umbUserPermissionData = new UmbUserPermissionData();
|
||||
@@ -64,7 +64,9 @@ class UmbUserMockDB extends UmbEntityMockDbBase<UmbMockUserModel> {
|
||||
languages: [],
|
||||
documentStartNodeIds: firstUser.documentStartNodeIds,
|
||||
mediaStartNodeIds: firstUser.mediaStartNodeIds,
|
||||
fallbackPermissions: [],
|
||||
permissions,
|
||||
allowedSections: [],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export class UmbDeselectedEvent extends Event {
|
||||
public static readonly TYPE = 'deselected';
|
||||
public unique: string;
|
||||
public unique: string | null;
|
||||
|
||||
public constructor(unique: string) {
|
||||
public constructor(unique: string | null) {
|
||||
// mimics the native change event
|
||||
super(UmbDeselectedEvent.TYPE, { bubbles: true, composed: false, cancelable: false });
|
||||
this.unique = unique;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export class UmbSelectedEvent extends Event {
|
||||
public static readonly TYPE = 'selected';
|
||||
public unique: string;
|
||||
public unique: string | null;
|
||||
|
||||
public constructor(unique: string) {
|
||||
public constructor(unique: string | null) {
|
||||
// mimics the native change event
|
||||
super(UmbSelectedEvent.TYPE, { bubbles: true, composed: false, cancelable: false });
|
||||
this.unique = unique;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type { ManifestBase } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
export interface ManifestUserPermission extends ManifestBase {
|
||||
type: 'userPermission';
|
||||
meta: MetaUserPermission;
|
||||
export interface ManifestEntityUserPermission extends ManifestBase {
|
||||
type: 'entityUserPermission';
|
||||
meta: MetaEntityUserPermission;
|
||||
}
|
||||
|
||||
export interface MetaUserPermission {
|
||||
export interface MetaEntityUserPermission {
|
||||
entityType: string;
|
||||
verbs: Array<string>;
|
||||
label?: string;
|
||||
labelKey?: string;
|
||||
description?: string;
|
||||
@@ -32,8 +32,8 @@ import type { ManifestWorkspaceAction } from './workspace-action.model.js';
|
||||
import type { ManifestWorkspaceContext } from './workspace-context.model.js';
|
||||
import type { ManifestWorkspaceFooterApp } from './workspace-footer-app.model.js';
|
||||
import type { ManifestWorkspaceView } from './workspace-view.model.js';
|
||||
import type { ManifestUserPermission } from './user-permission.model.js';
|
||||
import type { ManifestUserGranularPermission } from './user-granular-permission.model.js';
|
||||
import type { ManifestEntityUserPermission } from './entity-user-permission.model.js';
|
||||
import type { ManifestGranularUserPermission } from './user-granular-permission.model.js';
|
||||
import type { ManifestCollectionAction } from './collection-action.model.js';
|
||||
import type {
|
||||
ManifestBase,
|
||||
@@ -72,7 +72,7 @@ export type * from './tinymce-plugin.model.js';
|
||||
export type * from './tree-item.model.js';
|
||||
export type * from './tree.model.js';
|
||||
export type * from './user-granular-permission.model.js';
|
||||
export type * from './user-permission.model.js';
|
||||
export type * from './entity-user-permission.model.js';
|
||||
export type * from './user-profile-app.model.js';
|
||||
export type * from './workspace-action.model.js';
|
||||
export type * from './workspace-context.model.js';
|
||||
@@ -126,6 +126,6 @@ export type ManifestTypes =
|
||||
| ManifestWorkspaceContext
|
||||
| ManifestWorkspaceFooterApp
|
||||
| ManifestWorkspaceView
|
||||
| ManifestUserPermission
|
||||
| ManifestUserGranularPermission
|
||||
| ManifestEntityUserPermission
|
||||
| ManifestGranularUserPermission
|
||||
| ManifestBase;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import type { ManifestElement } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
export interface ManifestUserGranularPermission extends ManifestElement {
|
||||
export interface ManifestGranularUserPermission extends ManifestElement {
|
||||
type: 'userGranularPermission';
|
||||
meta: MetaUserGranularPermission;
|
||||
meta: MetaGranularUserPermission;
|
||||
}
|
||||
|
||||
export interface MetaUserGranularPermission {
|
||||
entityType: string;
|
||||
export interface MetaGranularUserPermission {
|
||||
schemaType: string;
|
||||
label?: string;
|
||||
labelKey?: string;
|
||||
description?: string;
|
||||
descriptionKey?: string;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbTreePickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbDeselectedEvent, UmbSelectedEvent, UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import type { UmbTreeElement, UmbTreeItemModelBase, UmbTreeSelectionConfiguration } from '@umbraco-cms/backoffice/tree';
|
||||
|
||||
@customElement('umb-tree-picker-modal')
|
||||
@@ -29,11 +29,21 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
||||
this._selectionConfiguration.multiple = this.data?.multiple ?? false;
|
||||
}
|
||||
|
||||
#onSelectionChange(e: CustomEvent) {
|
||||
e.stopPropagation();
|
||||
const element = e.target as UmbTreeElement;
|
||||
#onSelectionChange(event: UmbSelectionChangeEvent) {
|
||||
event.stopPropagation();
|
||||
const element = event.target as UmbTreeElement;
|
||||
this.value = { selection: element.getSelection() };
|
||||
this.dispatchEvent(new UmbSelectionChangeEvent());
|
||||
this.modalContext?.dispatchEvent(new UmbSelectionChangeEvent());
|
||||
}
|
||||
|
||||
#onSelected(event: UmbSelectedEvent) {
|
||||
event.stopPropagation();
|
||||
this.modalContext?.dispatchEvent(new UmbSelectedEvent(event.unique));
|
||||
}
|
||||
|
||||
#onDeselected(event: UmbDeselectedEvent) {
|
||||
event.stopPropagation();
|
||||
this.modalContext?.dispatchEvent(new UmbDeselectedEvent(event.unique));
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -44,6 +54,8 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
||||
?hide-tree-root=${this.data?.hideTreeRoot}
|
||||
alias=${ifDefined(this.data?.treeAlias)}
|
||||
@selection-change=${this.#onSelectionChange}
|
||||
@selected=${this.#onSelected}
|
||||
@deselected=${this.#onDeselected}
|
||||
.selectionConfiguration=${this._selectionConfiguration}
|
||||
.filter=${this.data?.filter}
|
||||
.selectableFilter=${this.data?.pickableFilter}></umb-tree>
|
||||
|
||||
@@ -3,12 +3,11 @@ import { UmbModalToken } from './modal-token.js';
|
||||
export interface UmbEntityUserPermissionSettingsModalData {
|
||||
unique: string;
|
||||
entityType: string;
|
||||
allowedPermissions: Array<string>;
|
||||
headline?: string;
|
||||
}
|
||||
|
||||
export type UmbEntityUserPermissionSettingsModalValue = {
|
||||
allowedPermissions: Array<string>;
|
||||
allowedVerbs: Array<string>;
|
||||
};
|
||||
|
||||
export const UMB_ENTITY_USER_PERMISSION_MODAL = new UmbModalToken<
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbBaseController } from '@umbraco-cms/backoffice/class-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbDeselectedEvent, UmbSelectedEvent, UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbArrayState, UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
|
||||
|
||||
/**
|
||||
@@ -8,7 +8,7 @@ import { UmbArrayState, UmbBooleanState } from '@umbraco-cms/backoffice/observab
|
||||
* @export
|
||||
* @class UmbSelectionManager
|
||||
*/
|
||||
export class UmbSelectionManager<ValueType = string | null> extends UmbBaseController {
|
||||
export class UmbSelectionManager<ValueType extends string | null = string | null> extends UmbBaseController {
|
||||
#selectable = new UmbBooleanState(false);
|
||||
public readonly selectable = this.#selectable.asObservable();
|
||||
|
||||
@@ -105,6 +105,7 @@ export class UmbSelectionManager<ValueType = string | null> extends UmbBaseContr
|
||||
if (this.isSelected(unique)) return;
|
||||
const newSelection = this.getMultiple() ? [...this.getSelection(), unique] : [unique];
|
||||
this.#selection.setValue(newSelection);
|
||||
this.getHostElement().dispatchEvent(new UmbSelectedEvent(unique));
|
||||
this.getHostElement().dispatchEvent(new UmbSelectionChangeEvent());
|
||||
}
|
||||
|
||||
@@ -117,6 +118,7 @@ export class UmbSelectionManager<ValueType = string | null> extends UmbBaseContr
|
||||
if (this.getSelectable() === false) return;
|
||||
const newSelection = this.getSelection().filter((x) => x !== unique);
|
||||
this.#selection.setValue(newSelection);
|
||||
this.getHostElement().dispatchEvent(new UmbDeselectedEvent(unique));
|
||||
this.getHostElement().dispatchEvent(new UmbSelectionChangeEvent());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from './input-document/input-document.element.js';
|
||||
export * from './input-document-granular-permission/input-document-granular-permission.element.js';
|
||||
export * from './input-document-root-picker/input-document-root-picker.element.js';
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
import { UmbDocumentItemRepository } from '../../repository/index.js';
|
||||
import type { UmbDocumentItemModel } from '../../repository/item/types.js';
|
||||
import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||
import type { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT, UMB_DOCUMENT_PICKER_MODAL } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
@customElement('umb-input-document-granular-permission')
|
||||
export class UmbInputDocumentGranularPermissionElement extends FormControlMixin(UmbLitElement) {
|
||||
private _selectedIds: Array<string> = [];
|
||||
public get selectedIds(): Array<string> {
|
||||
return this._selectedIds;
|
||||
}
|
||||
public set selectedIds(ids: Array<string>) {
|
||||
this._selectedIds = ids;
|
||||
super.value = ids.join(',');
|
||||
this.#observePickedDocuments();
|
||||
}
|
||||
|
||||
@property()
|
||||
public set value(idsString: string) {
|
||||
if (idsString !== this._value) {
|
||||
this.selectedIds = splitStringToArray(idsString);
|
||||
}
|
||||
}
|
||||
|
||||
@state()
|
||||
private _items?: Array<UmbDocumentItemModel>;
|
||||
|
||||
#documentItemRepository = new UmbDocumentItemRepository(this);
|
||||
#modalContext?: UmbModalManagerContext;
|
||||
#pickedItemsObserver?: UmbObserverController<Array<UmbDocumentItemModel>>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => (this.#modalContext = instance));
|
||||
}
|
||||
|
||||
protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
|
||||
super.firstUpdated(_changedProperties);
|
||||
this.#observePickedDocuments();
|
||||
}
|
||||
|
||||
protected getFormElement() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async #observePickedDocuments() {
|
||||
this.#pickedItemsObserver?.destroy();
|
||||
|
||||
const { asObservable } = await this.#documentItemRepository.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:
|
||||
// TODO: Use value instead:
|
||||
const modalContext = this.#modalContext?.open(UMB_DOCUMENT_PICKER_MODAL, {
|
||||
value: {
|
||||
selection: [...this._selectedIds],
|
||||
},
|
||||
});
|
||||
|
||||
//modalContext?.onSubmit().then((value) => {
|
||||
//this.#setSelection(selection);
|
||||
//});
|
||||
}
|
||||
|
||||
#setSelection(newSelection: Array<string>) {
|
||||
this.selectedIds = newSelection;
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this.#pickedItemsObserver?.destroy();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${this._items?.map((item) => this.#renderItem(item))}
|
||||
<uui-button id="add-button" look="placeholder" @click=${this.#openDocumentPicker} label="open">Add</uui-button>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderItem(item: UmbDocumentItemModel) {
|
||||
return html` <div>Render something here ${item.unique}</div> `;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
#add-button {
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
export default UmbInputDocumentGranularPermissionElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-input-document-granular-permission': UmbInputDocumentGranularPermissionElement;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { UmbCreateDocumentBlueprintEntityAction } from './create-blueprint.actio
|
||||
import { UmbUnpublishDocumentEntityAction } from './unpublish.action.js';
|
||||
import { UmbRollbackDocumentEntityAction } from './rollback.action.js';
|
||||
import { manifests as createManifests } from './create/manifests.js';
|
||||
import { manifests as permissionManifests } from './permissions/manifests.js';
|
||||
import { manifests as publicAccessManifests } from './public-access/manifests.js';
|
||||
import { manifests as cultureAndHostnamesManifests } from './culture-and-hostnames/manifests.js';
|
||||
import {
|
||||
@@ -17,7 +16,6 @@ import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
const entityActions: Array<ManifestTypes> = [
|
||||
...createManifests,
|
||||
...permissionManifests,
|
||||
...publicAccessManifests,
|
||||
...cultureAndHostnamesManifests,
|
||||
{
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { UMB_DOCUMENT_DETAIL_REPOSITORY_ALIAS } from '../../repository/index.js';
|
||||
import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js';
|
||||
import { UmbDocumentPermissionsEntityAction } from './permissions.action.js';
|
||||
import type { ManifestEntityAction, ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
const entityActions: Array<ManifestEntityAction> = [
|
||||
{
|
||||
type: 'entityAction',
|
||||
alias: 'Umb.EntityAction.Document.Permissions',
|
||||
name: 'Document Permissions Entity Action',
|
||||
api: UmbDocumentPermissionsEntityAction,
|
||||
meta: {
|
||||
icon: 'icon-vcard',
|
||||
label: 'Permissions (TBD)',
|
||||
repositoryAlias: UMB_DOCUMENT_DETAIL_REPOSITORY_ALIAS,
|
||||
entityTypes: [UMB_DOCUMENT_ENTITY_TYPE],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const modals: Array<ManifestModal> = [
|
||||
{
|
||||
type: 'modal',
|
||||
alias: 'Umb.Modal.Permissions',
|
||||
name: 'Permissions Modal',
|
||||
js: () => import('./permissions-modal.element.js'),
|
||||
},
|
||||
];
|
||||
|
||||
export const manifests = [...entityActions, ...modals];
|
||||
@@ -1,170 +0,0 @@
|
||||
import { UmbDocumentPermissionRepository } from '../../user-permissions/index.js';
|
||||
import { UmbDocumentItemRepository } from '../../repository/index.js';
|
||||
import { UmbUserGroupItemRepository, UMB_USER_GROUP_PICKER_MODAL } from '@umbraco-cms/backoffice/user-group';
|
||||
import { html, customElement, property, state, ifDefined, nothing } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import type {
|
||||
UmbEntityUserPermissionSettingsModalData,
|
||||
UmbEntityUserPermissionSettingsModalValue,
|
||||
UmbModalContext,
|
||||
UmbModalManagerContext,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_ENTITY_USER_PERMISSION_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbSelectedEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
type UmbUserGroupRefData = {
|
||||
id: string;
|
||||
name?: string;
|
||||
icon?: string | null;
|
||||
permissions: Array<string>;
|
||||
};
|
||||
|
||||
@customElement('umb-permissions-modal')
|
||||
export class UmbPermissionsModalElement extends UmbLitElement {
|
||||
@property({ attribute: false })
|
||||
modalContext?: UmbModalContext<UmbEntityUserPermissionSettingsModalData, UmbEntityUserPermissionSettingsModalValue>;
|
||||
|
||||
@property({ type: Object })
|
||||
data?: UmbEntityUserPermissionSettingsModalData;
|
||||
|
||||
@state()
|
||||
_entityItem?: any;
|
||||
|
||||
@state()
|
||||
_userGroupRefs: Array<UmbUserGroupRefData> = [];
|
||||
|
||||
#userPermissions: Array<any> = [];
|
||||
#userGroupIemRepository = new UmbUserGroupItemRepository(this);
|
||||
#documentPermissionRepository = new UmbDocumentPermissionRepository(this);
|
||||
#documentItemRepository = new UmbDocumentItemRepository(this);
|
||||
#modalManagerContext?: UmbModalManagerContext;
|
||||
#userGroupPickerModal?: UmbModalContext;
|
||||
|
||||
private _handleConfirm() {
|
||||
this.modalContext?.submit();
|
||||
}
|
||||
|
||||
private _handleCancel() {
|
||||
this.modalContext?.reject();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => {
|
||||
this.#modalManagerContext = instance;
|
||||
});
|
||||
}
|
||||
|
||||
protected async firstUpdated(): Promise<void> {
|
||||
if (!this.data?.unique) throw new Error('Could not load permissions, no unique was provided');
|
||||
this.#getEntityItem(this.data.unique);
|
||||
this.#getEntityPermissions(this.data.unique);
|
||||
}
|
||||
|
||||
async #getEntityItem(unique: string) {
|
||||
const { data } = await this.#documentItemRepository.requestItems([unique]);
|
||||
if (!data) throw new Error('Could not load item');
|
||||
this._entityItem = data[0];
|
||||
}
|
||||
|
||||
async #getEntityPermissions(unique: string) {
|
||||
const { data } = await this.#documentPermissionRepository.requestPermissions(unique);
|
||||
if (data) {
|
||||
this.#userPermissions = data;
|
||||
this.#mapToUserGroupRefs();
|
||||
}
|
||||
}
|
||||
|
||||
async #mapToUserGroupRefs() {
|
||||
const userGroupIds = [...new Set(this.#userPermissions.map((permission) => permission.target.userGroupId))];
|
||||
const { data } = await this.#userGroupIemRepository.requestItems(userGroupIds);
|
||||
|
||||
const userGroups = data ?? [];
|
||||
|
||||
this._userGroupRefs = this.#userPermissions.map((entry) => {
|
||||
const userGroup = userGroups.find((userGroup) => userGroup.unique == entry.target.userGroupId);
|
||||
return {
|
||||
id: entry.target.userGroupId,
|
||||
name: userGroup?.name,
|
||||
icon: userGroup?.icon,
|
||||
permissions: entry.permissions,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
#openUserGroupPickerModal() {
|
||||
if (!this.#modalManagerContext) return;
|
||||
|
||||
this.#userGroupPickerModal = this.#modalManagerContext.open(UMB_USER_GROUP_PICKER_MODAL);
|
||||
|
||||
this.#userGroupPickerModal.addEventListener(UmbSelectedEvent.TYPE, (event) =>
|
||||
this.#openUserPermissionsModal((event as UmbSelectedEvent).unique),
|
||||
);
|
||||
}
|
||||
|
||||
#openUserPermissionsModal(id: string) {
|
||||
if (!id) throw new Error('Could not open permissions modal, no id was provided');
|
||||
if (!this.data?.entityType) throw new Error('Could not open permissions modal, no entity type was provided');
|
||||
|
||||
const userGroupRef = this._userGroupRefs.find((userGroup) => userGroup.id == id);
|
||||
|
||||
const modalContext = this.#modalManagerContext?.open(UMB_ENTITY_USER_PERMISSION_MODAL, {
|
||||
data: {
|
||||
unique: id,
|
||||
entityType: this.data.entityType,
|
||||
allowedPermissions: userGroupRef?.permissions || [],
|
||||
headline: `Permissions for ${userGroupRef?.name}`,
|
||||
},
|
||||
});
|
||||
|
||||
modalContext?.onSubmit().then((value) => {
|
||||
console.log(value);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-body-layout headline="Permissions for ${this._entityItem?.name}">
|
||||
<uui-box>
|
||||
Permissions set for User Groups for document: ${this.data?.entityType}:
|
||||
<uui-ref-list>
|
||||
${this._userGroupRefs.map(
|
||||
(userGroup) =>
|
||||
html`<umb-user-group-ref
|
||||
name=${ifDefined(userGroup.name)}
|
||||
.userPermissionAliases=${userGroup.permissions}
|
||||
@open=${() => this.#openUserPermissionsModal(userGroup.id)}
|
||||
standalone>
|
||||
${userGroup.icon ? html`<uui-icon slot="icon" name=${userGroup.icon}></uui-icon>` : nothing}
|
||||
</umb-user-group-ref>`,
|
||||
)}
|
||||
</uui-ref-list>
|
||||
<uui-button style="width: 100%;" @click=${this.#openUserGroupPickerModal} look="placeholder"
|
||||
>Select user group</uui-button
|
||||
>
|
||||
</uui-box>
|
||||
|
||||
<uui-button slot="actions" id="cancel" label="Cancel" @click="${this._handleCancel}">Cancel</uui-button>
|
||||
<uui-button
|
||||
slot="actions"
|
||||
id="confirm"
|
||||
color="positive"
|
||||
look="primary"
|
||||
label="Save"
|
||||
@click=${this._handleConfirm}></uui-button>
|
||||
</umb-body-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [UmbTextStyles];
|
||||
}
|
||||
|
||||
export default UmbPermissionsModalElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-permissions-modal': UmbPermissionsModalElement;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import type { UmbDocumentDetailRepository } from '../../repository/index.js';
|
||||
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT, UMB_PERMISSIONS_MODAL } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export class UmbDocumentPermissionsEntityAction extends UmbEntityActionBase<UmbDocumentDetailRepository> {
|
||||
#modalManagerContext?: UmbModalManagerContext;
|
||||
|
||||
constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string, entityType: string) {
|
||||
super(host, repositoryAlias, unique, entityType);
|
||||
|
||||
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => {
|
||||
this.#modalManagerContext = instance;
|
||||
});
|
||||
}
|
||||
|
||||
async execute() {
|
||||
if (!this.repository) return;
|
||||
if (!this.#modalManagerContext) return;
|
||||
|
||||
this.#modalManagerContext.open(UMB_PERMISSIONS_MODAL, {
|
||||
data: {
|
||||
unique: this.unique,
|
||||
entityType: 'document',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { UMB_DOCUMENT_ENTITY_TYPE } from '../../entity.js';
|
||||
import type { UmbDocumentItemModel } from './types.js';
|
||||
import type { DocumentItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
|
||||
import { DocumentResource } from '@umbraco-cms/backoffice/external/backend-api';
|
||||
@@ -32,6 +33,7 @@ const getItems = (uniques: Array<string>) => DocumentResource.getItemDocument({
|
||||
|
||||
const mapper = (item: DocumentItemResponseModel): UmbDocumentItemModel => {
|
||||
return {
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
unique: item.id,
|
||||
isTrashed: item.isTrashed,
|
||||
isProtected: item.isProtected,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { UmbDocumentEntityType } from '../../entity.js';
|
||||
import type { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
|
||||
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
|
||||
|
||||
export interface UmbDocumentItemModel {
|
||||
entityType: UmbDocumentEntityType;
|
||||
name: string; // TODO: this is not correct. We need to get it from the variants. This is a temp solution.
|
||||
unique: string;
|
||||
isTrashed: boolean;
|
||||
|
||||
@@ -8,7 +8,7 @@ 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_DUPLICATE = 'Umb.UserPermission.Document.Duplicate';
|
||||
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';
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
import type { UmbDocumentUserPermissionModel } from '../types.js';
|
||||
import { UmbDocumentItemRepository, type UmbDocumentItemModel } from '../../repository/index.js';
|
||||
import { css, customElement, html, repeat, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
|
||||
import {
|
||||
UMB_DOCUMENT_PICKER_MODAL,
|
||||
UMB_ENTITY_USER_PERMISSION_MODAL,
|
||||
UMB_MODAL_MANAGER_CONTEXT,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import type { UmbDeselectedEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbChangeEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event';
|
||||
import type { ManifestEntityUserPermission } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
@customElement('umb-input-document-granular-user-permission')
|
||||
export class UmbInputDocumentGranularUserPermissionElement extends FormControlMixin(UmbLitElement) {
|
||||
_permissions: Array<UmbDocumentUserPermissionModel> = [];
|
||||
public get permissions(): Array<UmbDocumentUserPermissionModel> {
|
||||
return this._permissions;
|
||||
}
|
||||
public set permissions(value: Array<UmbDocumentUserPermissionModel>) {
|
||||
this._permissions = value;
|
||||
const uniques = value.map((item) => item.document.id);
|
||||
this.#observePickedDocuments(uniques);
|
||||
}
|
||||
|
||||
@state()
|
||||
private _items?: Array<UmbDocumentItemModel>;
|
||||
|
||||
#documentItemRepository = new UmbDocumentItemRepository(this);
|
||||
#modalManagerContext?: UmbModalManagerContext;
|
||||
#documentPickerModalContext?: any;
|
||||
#entityUserPermissionModalContext?: any;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => (this.#modalManagerContext = instance));
|
||||
}
|
||||
|
||||
protected getFormElement() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async #observePickedDocuments(uniques: Array<string>) {
|
||||
const { asObservable } = await this.#documentItemRepository.requestItems(uniques);
|
||||
this.observe(asObservable(), (items) => (this._items = items));
|
||||
}
|
||||
|
||||
async #editGranularPermission(item: UmbDocumentItemModel) {
|
||||
const currentPermissionVerbs = this.#getPermissionForDocument(item.unique)?.verbs ?? [];
|
||||
const result = await this.#selectEntityUserPermissionsForDocument(item, currentPermissionVerbs);
|
||||
// don't do anything if the verbs have not been updated
|
||||
if (JSON.stringify(result) === JSON.stringify(currentPermissionVerbs)) return;
|
||||
|
||||
// update permission with new verbs
|
||||
this.permissions = this._permissions.map((permission) => {
|
||||
if (permission.document.id === item.unique) {
|
||||
return {
|
||||
...permission,
|
||||
verbs: result,
|
||||
};
|
||||
}
|
||||
return permission;
|
||||
});
|
||||
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
}
|
||||
|
||||
#addGranularPermission() {
|
||||
this.#documentPickerModalContext = this.#modalManagerContext?.open(UMB_DOCUMENT_PICKER_MODAL, {
|
||||
data: {
|
||||
hideTreeRoot: true,
|
||||
// prevent already selected items to be picked again
|
||||
// TODO: this type is wrong. It should be the tree item type
|
||||
pickableFilter: (treeItem: UmbDocumentItemModel) =>
|
||||
!this._items?.map((i) => i.unique).includes(treeItem.unique),
|
||||
},
|
||||
});
|
||||
|
||||
this.#documentPickerModalContext?.addEventListener(UmbSelectedEvent.TYPE, async (event: UmbDeselectedEvent) => {
|
||||
const selectedEvent = event as UmbSelectedEvent;
|
||||
const unique = selectedEvent.unique;
|
||||
if (!unique) return;
|
||||
|
||||
const documentItem = await this.#requestDocumentItem(unique);
|
||||
const result = await this.#selectEntityUserPermissionsForDocument(documentItem);
|
||||
this.#documentPickerModalContext?.reject();
|
||||
|
||||
const permissionItem: UmbDocumentUserPermissionModel = {
|
||||
$type: 'DocumentPermissionPresentationModel',
|
||||
document: { id: unique },
|
||||
verbs: result,
|
||||
};
|
||||
|
||||
this.permissions = [...this._permissions, permissionItem];
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
});
|
||||
}
|
||||
|
||||
async #requestDocumentItem(unique: string) {
|
||||
if (!unique) throw new Error('Could not open permissions modal, no unique was provided');
|
||||
|
||||
const { data } = await this.#documentItemRepository.requestItems([unique]);
|
||||
|
||||
const documentItem = data?.[0];
|
||||
if (!documentItem) throw new Error('No document item found');
|
||||
return documentItem;
|
||||
}
|
||||
|
||||
async #selectEntityUserPermissionsForDocument(item: UmbDocumentItemModel, allowedVerbs: Array<string> = []) {
|
||||
// TODO: get correct variant name
|
||||
const name = item.variants[0]?.name;
|
||||
const headline = name ? `Permissions for ${name}` : 'Permissions';
|
||||
|
||||
this.#entityUserPermissionModalContext = this.#modalManagerContext?.open(UMB_ENTITY_USER_PERMISSION_MODAL, {
|
||||
data: {
|
||||
unique: item.unique,
|
||||
entityType: item.entityType,
|
||||
headline,
|
||||
},
|
||||
value: {
|
||||
allowedVerbs,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const value = await this.#entityUserPermissionModalContext?.onSubmit();
|
||||
return value?.allowedVerbs;
|
||||
} catch (error) {
|
||||
return allowedVerbs;
|
||||
}
|
||||
}
|
||||
|
||||
#removeGranularPermission(item: UmbDocumentItemModel) {
|
||||
const permission = this.#getPermissionForDocument(item.unique);
|
||||
if (!permission) return;
|
||||
|
||||
this.permissions = this._permissions.filter((v) => JSON.stringify(v) !== JSON.stringify(permission));
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`${this.#renderItems()} ${this.#renderAddButton()}`;
|
||||
}
|
||||
|
||||
#renderItems() {
|
||||
if (!this._items) return;
|
||||
return html`<uui-ref-list>
|
||||
${repeat(
|
||||
this._items,
|
||||
(item) => item.unique,
|
||||
(item) => this.#renderRef(item),
|
||||
)}
|
||||
</uui-ref-list>`;
|
||||
}
|
||||
|
||||
#renderAddButton() {
|
||||
return html`<uui-button
|
||||
id="add-button"
|
||||
look="placeholder"
|
||||
@click=${this.#addGranularPermission}
|
||||
label=${this.localize.term('general_add')}></uui-button>`;
|
||||
}
|
||||
|
||||
#renderRef(item: UmbDocumentItemModel) {
|
||||
if (!item.unique) return;
|
||||
// TODO: get correct variant name
|
||||
const name = item.variants[0]?.name;
|
||||
const permissionNames = this.#getPermissionNamesForDocument(item.unique);
|
||||
|
||||
return html`
|
||||
<uui-ref-node .name=${name} .detail=${permissionNames || ''}>
|
||||
${this.#renderIcon(item)} ${this.#renderIsTrashed(item)}
|
||||
<uui-action-bar slot="actions">
|
||||
${this.#renderEditButton(item)} ${this.#renderRemoveButton(item)}
|
||||
</uui-action-bar>
|
||||
</uui-ref-node>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderIcon(item: UmbDocumentItemModel) {
|
||||
if (!item.documentType.icon) return;
|
||||
return html`<uui-icon slot="icon" name=${item.documentType.icon}></uui-icon>`;
|
||||
}
|
||||
|
||||
#renderIsTrashed(item: UmbDocumentItemModel) {
|
||||
if (!item.isTrashed) return;
|
||||
return html`<uui-tag size="s" slot="tag" color="danger">Trashed</uui-tag>`;
|
||||
}
|
||||
|
||||
#renderEditButton(item: UmbDocumentItemModel) {
|
||||
return html`
|
||||
<uui-button
|
||||
@click=${() => this.#editGranularPermission(item)}
|
||||
label=${this.localize.term('general_edit')}></uui-button>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderRemoveButton(item: UmbDocumentItemModel) {
|
||||
return html`<uui-button
|
||||
@click=${() => this.#removeGranularPermission(item)}
|
||||
label=${this.localize.term('general_remove')}></uui-button>`;
|
||||
}
|
||||
|
||||
#getPermissionForDocument(unique: string) {
|
||||
return this._permissions?.find((permission) => permission.document.id === unique);
|
||||
}
|
||||
|
||||
#getPermissionNamesForDocument(unique: string) {
|
||||
const permission = this.#getPermissionForDocument(unique);
|
||||
if (!permission) return;
|
||||
|
||||
return umbExtensionsRegistry
|
||||
.getAllExtensions()
|
||||
.filter((manifest) => manifest.type === 'entityUserPermission')
|
||||
.filter((manifest) =>
|
||||
(manifest as ManifestEntityUserPermission).meta.verbs.every((verb) => permission.verbs.includes(verb)),
|
||||
)
|
||||
.map((m) => {
|
||||
const manifest = m as ManifestEntityUserPermission;
|
||||
|
||||
if (manifest.meta.labelKey) {
|
||||
return this.localize.term(manifest.meta.labelKey);
|
||||
} else if (manifest.meta.label) {
|
||||
return manifest.meta.label;
|
||||
} else {
|
||||
return manifest.name;
|
||||
}
|
||||
})
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
#add-button {
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
export default UmbInputDocumentGranularUserPermissionElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-document-granular-user-permission': UmbInputDocumentGranularUserPermissionElement;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { UMB_DOCUMENT_ENTITY_TYPE } from '../entity.js';
|
||||
import {
|
||||
UMB_USER_PERMISSION_DOCUMENT_READ,
|
||||
UMB_USER_PERMISSION_DOCUMENT_CREATE_BLUEPRINT,
|
||||
@@ -6,10 +7,9 @@ import {
|
||||
UMB_USER_PERMISSION_DOCUMENT_NOTIFICATIONS,
|
||||
UMB_USER_PERMISSION_DOCUMENT_PUBLISH,
|
||||
UMB_USER_PERMISSION_DOCUMENT_PERMISSIONS,
|
||||
UMB_USER_PERMISSION_DOCUMENT_SEND_FOR_APPROVAL,
|
||||
UMB_USER_PERMISSION_DOCUMENT_UNPUBLISH,
|
||||
UMB_USER_PERMISSION_DOCUMENT_UPDATE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_COPY,
|
||||
UMB_USER_PERMISSION_DOCUMENT_DUPLICATE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_MOVE,
|
||||
UMB_USER_PERMISSION_DOCUMENT_SORT,
|
||||
UMB_USER_PERMISSION_DOCUMENT_CULTURE_AND_HOSTNAMES,
|
||||
@@ -18,172 +18,177 @@ import {
|
||||
} from './constants.js';
|
||||
import { manifests as repositoryManifests } from './repository/manifests.js';
|
||||
import type {
|
||||
ManifestUserGranularPermission,
|
||||
ManifestUserPermission,
|
||||
ManifestGranularUserPermission,
|
||||
ManifestEntityUserPermission,
|
||||
} from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
const permissions: Array<ManifestUserPermission> = [
|
||||
const permissions: Array<ManifestEntityUserPermission> = [
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_READ,
|
||||
name: 'Read Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Read'],
|
||||
labelKey: 'actions_browse',
|
||||
descriptionKey: 'actionDescriptions_browse',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_CREATE_BLUEPRINT,
|
||||
name: 'Create Document Blueprint User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.CreateBlueprint'],
|
||||
labelKey: 'actions_createblueprint',
|
||||
descriptionKey: 'actionDescriptions_createblueprint',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_DELETE,
|
||||
name: 'Delete Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Delete'],
|
||||
labelKey: 'actions_delete',
|
||||
descriptionKey: 'actionDescriptions_delete',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_CREATE,
|
||||
name: 'Create Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Create'],
|
||||
labelKey: 'actions_create',
|
||||
descriptionKey: 'actionDescriptions_create',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_NOTIFICATIONS,
|
||||
name: 'Document Notifications User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Notifications'],
|
||||
labelKey: 'actions_notify',
|
||||
descriptionKey: 'actionDescriptions_notify',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_PUBLISH,
|
||||
name: 'Publish Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Publish'],
|
||||
labelKey: 'actions_publish',
|
||||
descriptionKey: 'actionDescriptions_publish',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_PERMISSIONS,
|
||||
name: 'Document Permissions User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Permissions'],
|
||||
labelKey: 'actions_setPermissions',
|
||||
descriptionKey: 'actionDescriptions_rights',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_SEND_FOR_APPROVAL,
|
||||
name: 'Send Document For Approval User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
labelKey: 'actions_sendtopublish',
|
||||
descriptionKey: 'actionDescriptions_sendtopublish',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_UNPUBLISH,
|
||||
name: 'Unpublish Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Unpublish'],
|
||||
labelKey: 'actions_unpublish',
|
||||
descriptionKey: 'actionDescriptions_unpublish',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_UPDATE,
|
||||
name: 'Update Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Update'],
|
||||
labelKey: 'actions_update',
|
||||
descriptionKey: 'actionDescriptions_update',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_COPY,
|
||||
name: 'Copy Document User Permission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_DUPLICATE,
|
||||
name: 'Duplicate Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Duplicate'],
|
||||
labelKey: 'actions_copy',
|
||||
descriptionKey: 'actionDescriptions_copy',
|
||||
group: 'structure',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_MOVE,
|
||||
name: 'Move Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Move'],
|
||||
labelKey: 'actions_move',
|
||||
descriptionKey: 'actionDescriptions_move',
|
||||
group: 'structure',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_SORT,
|
||||
name: 'Sort Document User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Sort'],
|
||||
labelKey: 'actions_sort',
|
||||
descriptionKey: 'actionDescriptions_sort',
|
||||
group: 'structure',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_CULTURE_AND_HOSTNAMES,
|
||||
name: 'Document Culture And Hostnames User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.CultureAndHostnames'],
|
||||
labelKey: 'actions_assigndomain',
|
||||
descriptionKey: 'actionDescriptions_assignDomain',
|
||||
group: 'administration',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_PUBLIC_ACCESS,
|
||||
name: 'Document Public Access User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.PublicAccess'],
|
||||
labelKey: 'actions_protect',
|
||||
descriptionKey: 'actionDescriptions_protect',
|
||||
group: 'administration',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'userPermission',
|
||||
type: 'entityUserPermission',
|
||||
alias: UMB_USER_PERMISSION_DOCUMENT_ROLLBACK,
|
||||
name: 'Document Rollback User Permission',
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
entityType: UMB_DOCUMENT_ENTITY_TYPE,
|
||||
verbs: ['Umb.Document.Rollback'],
|
||||
labelKey: 'actions_rollback',
|
||||
descriptionKey: 'actionDescriptions_rollback',
|
||||
group: 'administration',
|
||||
@@ -191,14 +196,17 @@ const permissions: Array<ManifestUserPermission> = [
|
||||
},
|
||||
];
|
||||
|
||||
export const granularPermissions: Array<ManifestUserGranularPermission> = [
|
||||
export const granularPermissions: Array<ManifestGranularUserPermission> = [
|
||||
{
|
||||
type: 'userGranularPermission',
|
||||
alias: 'Umb.UserGranularPermission.Document',
|
||||
name: 'Document Granular User Permission',
|
||||
js: () => import('../components/input-document-granular-permission/input-document-granular-permission.element.js'),
|
||||
element: () =>
|
||||
import('./input-document-granular-user-permission/input-document-granular-user-permission.element.js'),
|
||||
meta: {
|
||||
entityType: 'document',
|
||||
schemaType: 'DocumentPermissionPresentationModel',
|
||||
label: 'Documents',
|
||||
description: 'Assign permissions to specific documents',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { UmbUserPermissionModel } from '@umbraco-cms/backoffice/user-permission';
|
||||
|
||||
export interface UmbDocumentUserPermissionModel extends UmbUserPermissionModel {
|
||||
// TODO: this should be unique instead of an id, but we currently have now way to map a mixed server response.
|
||||
document: { id: string };
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
import './components/index.js';
|
||||
|
||||
export * from './repository/index.js';
|
||||
export * from './workspace/index.js';
|
||||
export * from './tracked-reference/index.js';
|
||||
export * from './components/index.js';
|
||||
export * from './entity.js';
|
||||
export * from './repository/index.js';
|
||||
export * from './tracked-reference/index.js';
|
||||
export * from './user-permissions/index.js';
|
||||
export * from './utils/index.js';
|
||||
export * from './workspace/index.js';
|
||||
export * from './conditions/index.js';
|
||||
|
||||
export { UMB_MEDIA_TREE_ALIAS } from './tree/index.js';
|
||||
|
||||
@@ -7,7 +7,6 @@ import { manifests as propertyEditorsManifests } from './property-editors/manife
|
||||
import { manifests as repositoryManifests } from './repository/manifests.js';
|
||||
import { manifests as sectionViewManifests } from './section-view/manifests.js';
|
||||
import { manifests as treeManifests } from './tree/manifests.js';
|
||||
import { manifests as userPermissionManifests } from './user-permissions/manifests.js';
|
||||
import { manifests as workspaceManifests } from './workspace/manifests.js';
|
||||
|
||||
export const manifests = [
|
||||
@@ -20,6 +19,5 @@ export const manifests = [
|
||||
...repositoryManifests,
|
||||
...sectionViewManifests,
|
||||
...treeManifests,
|
||||
...userPermissionManifests,
|
||||
...workspaceManifests,
|
||||
];
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './manifests.js';
|
||||
@@ -1,31 +0,0 @@
|
||||
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<ManifestUserPermission> = [
|
||||
{
|
||||
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',
|
||||
group: 'structure',
|
||||
},
|
||||
},
|
||||
{
|
||||
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',
|
||||
group: 'structure',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const manifests = [...permissions];
|
||||
@@ -40,6 +40,7 @@ export class UmbCurrentUserServerDataSource {
|
||||
avatarUrls: data.avatarUrls,
|
||||
languages: data.languages,
|
||||
hasAccessToAllLanguages: data.hasAccessToAllLanguages,
|
||||
fallbackPermissions: data.fallbackPermissions,
|
||||
permissions: data.permissions,
|
||||
};
|
||||
return { data: user };
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import type {
|
||||
DocumentPermissionPresentationModel,
|
||||
UnknownTypePermissionPresentationModel,
|
||||
} from '@umbraco-cms/backoffice/external/backend-api';
|
||||
|
||||
export interface UmbCurrentUserModel {
|
||||
unique: string;
|
||||
email: string;
|
||||
@@ -9,5 +14,6 @@ export interface UmbCurrentUserModel {
|
||||
avatarUrls: Array<string>;
|
||||
languages: Array<string>;
|
||||
hasAccessToAllLanguages: boolean;
|
||||
permissions: Array<string>;
|
||||
fallbackPermissions: Array<string>;
|
||||
permissions: Array<DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel>;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,16 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
export const isCurrentUser = async (host: UmbControllerHost, userUnique: string) => {
|
||||
const ctrl = new UmbContextConsumerController(host, UMB_CURRENT_USER_CONTEXT);
|
||||
const currentUserContext = await ctrl.asPromise();
|
||||
let currentUserContext = await ctrl.asPromise();
|
||||
ctrl.destroy();
|
||||
|
||||
const controller = new UmbContextConsumerController(host, UMB_CURRENT_USER_CONTEXT, (context) => {
|
||||
currentUserContext = context;
|
||||
});
|
||||
|
||||
await controller.asPromise();
|
||||
|
||||
controller.destroy();
|
||||
|
||||
return await currentUserContext!.isUserCurrentUser(userUnique);
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@ export class UmbUserGroupCollectionServerDataSource implements UmbCollectionData
|
||||
documentRootAccess: item.documentRootAccess,
|
||||
mediaStartNode: item.mediaStartNode ? { unique: item.mediaStartNode.id } : null,
|
||||
mediaRootAccess: item.mediaRootAccess,
|
||||
fallbackPermissions: item.fallbackPermissions,
|
||||
permissions: item.permissions,
|
||||
};
|
||||
return userGroup;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { UUIRefNodeElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
|
||||
import type { ManifestUserPermission } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { ManifestEntityUserPermission } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { map } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
|
||||
@@ -25,7 +25,7 @@ export class UmbUserGroupRefElement extends UmbElementMixin(UUIRefNodeElement) {
|
||||
async #observeUserPermissions(value: Array<string>) {
|
||||
if (value) {
|
||||
this.observe(
|
||||
umbExtensionsRegistry.byType('userPermission').pipe(
|
||||
umbExtensionsRegistry.byType('entityUserPermission').pipe(
|
||||
map((manifests) => {
|
||||
return manifests.filter((manifest) => manifest.alias && value.includes(manifest.alias));
|
||||
}),
|
||||
@@ -38,7 +38,7 @@ export class UmbUserGroupRefElement extends UmbElementMixin(UUIRefNodeElement) {
|
||||
}
|
||||
}
|
||||
|
||||
#setUserPermissionLabels(manifests: Array<ManifestUserPermission>) {
|
||||
#setUserPermissionLabels(manifests: Array<ManifestEntityUserPermission>) {
|
||||
this.#userPermissionLabels = manifests.map((manifest) =>
|
||||
manifest.meta.labelKey ? this.localize.term(manifest.meta.labelKey) : manifest.meta.label ?? '',
|
||||
);
|
||||
|
||||
@@ -48,6 +48,7 @@ export class UmbUserGroupServerDataSource implements UmbDetailDataSource<UmbUser
|
||||
documentRootAccess: false,
|
||||
mediaStartNode: null,
|
||||
mediaRootAccess: false,
|
||||
fallbackPermissions: [],
|
||||
permissions: [],
|
||||
};
|
||||
|
||||
@@ -83,6 +84,7 @@ export class UmbUserGroupServerDataSource implements UmbDetailDataSource<UmbUser
|
||||
documentRootAccess: data.documentRootAccess,
|
||||
mediaStartNode: data.mediaStartNode ? { unique: data.mediaStartNode.id } : null,
|
||||
mediaRootAccess: data.mediaRootAccess,
|
||||
fallbackPermissions: data.fallbackPermissions,
|
||||
permissions: data.permissions,
|
||||
};
|
||||
|
||||
@@ -109,6 +111,7 @@ export class UmbUserGroupServerDataSource implements UmbDetailDataSource<UmbUser
|
||||
documentRootAccess: model.documentRootAccess,
|
||||
mediaStartNode: model.mediaStartNode ? { id: model.mediaStartNode.unique } : null,
|
||||
mediaRootAccess: model.mediaRootAccess,
|
||||
fallbackPermissions: model.fallbackPermissions,
|
||||
permissions: model.permissions,
|
||||
};
|
||||
|
||||
@@ -146,6 +149,7 @@ export class UmbUserGroupServerDataSource implements UmbDetailDataSource<UmbUser
|
||||
documentRootAccess: model.documentRootAccess,
|
||||
mediaStartNode: model.mediaStartNode ? { id: model.mediaStartNode.unique } : null,
|
||||
mediaRootAccess: model.mediaRootAccess,
|
||||
fallbackPermissions: model.fallbackPermissions,
|
||||
permissions: model.permissions,
|
||||
};
|
||||
|
||||
|
||||
@@ -13,5 +13,7 @@ export interface UmbUserGroupDetailModel {
|
||||
documentRootAccess: boolean;
|
||||
mediaStartNode: { unique: string } | null;
|
||||
mediaRootAccess: boolean;
|
||||
permissions: Array<string>;
|
||||
fallbackPermissions: Array<string>;
|
||||
// TODO: add type
|
||||
permissions: Array<any>;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from '../user-group-workspace.context.js';
|
||||
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import type { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
@customElement('umb-user-group-default-permission-list')
|
||||
export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement {
|
||||
@customElement('umb-user-group-entity-user-permission-list')
|
||||
export class UmbUserGroupEntityUserPermissionListElement extends UmbLitElement {
|
||||
@state()
|
||||
private _userGroupDefaultPermissions?: Array<string>;
|
||||
private _fallBackPermissions?: Array<string>;
|
||||
|
||||
@state()
|
||||
private _entityTypes: Array<string> = [];
|
||||
@@ -18,32 +18,36 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.#observeUserPermissions();
|
||||
this.#observeEntityUserPermissions();
|
||||
|
||||
this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => {
|
||||
this.#userGroupWorkspaceContext = instance;
|
||||
this.observe(
|
||||
this.#userGroupWorkspaceContext.data,
|
||||
(userGroup) => (this._userGroupDefaultPermissions = userGroup?.permissions),
|
||||
'umbUserGroupPermissionsObserver',
|
||||
this.#userGroupWorkspaceContext.fallbackPermissions,
|
||||
(fallbackPermissions) => {
|
||||
this._fallBackPermissions = fallbackPermissions;
|
||||
},
|
||||
'umbUserGroupEntityUserPermissionsObserver',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#observeUserPermissions() {
|
||||
#observeEntityUserPermissions() {
|
||||
this.observe(
|
||||
umbExtensionsRegistry.byType('userPermission'),
|
||||
(userPermissionManifests) => {
|
||||
this._entityTypes = [...new Set(userPermissionManifests.map((manifest) => manifest.meta.entityType))];
|
||||
umbExtensionsRegistry.byType('entityUserPermission'),
|
||||
(manifests) => {
|
||||
this._entityTypes = [...new Set(manifests.map((manifest) => manifest.meta.entityType))];
|
||||
},
|
||||
'umbUserPermissionsObserver',
|
||||
);
|
||||
}
|
||||
|
||||
#onSelectedUserPermission(event: UmbSelectionChangeEvent) {
|
||||
#onPermissionChange(event: UmbSelectionChangeEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as any;
|
||||
const selection = target.selectedPermissions;
|
||||
this.#userGroupWorkspaceContext?.setDefaultPermissions(selection);
|
||||
const verbs = target.allowedVerbs;
|
||||
if (verbs === undefined || verbs === null) throw new Error('The verbs are not defined');
|
||||
this.#userGroupWorkspaceContext?.setFallbackPermissions(verbs);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -53,20 +57,20 @@ export class UmbUserGroupDefaultPermissionListElement extends UmbLitElement {
|
||||
#renderPermissionsByEntityType(entityType: string) {
|
||||
return html`
|
||||
<h4><umb-localize .key=${`user_permissionsEntityGroup_${entityType}`}>${entityType}</umb-localize></h4>
|
||||
<umb-entity-user-permission-settings-list
|
||||
<umb-input-entity-user-permission
|
||||
.entityType=${entityType}
|
||||
.selectedPermissions=${this._userGroupDefaultPermissions || []}
|
||||
@selection-change=${this.#onSelectedUserPermission}></umb-entity-user-permission-settings-list>
|
||||
.allowedVerbs=${this._fallBackPermissions || []}
|
||||
@change=${this.#onPermissionChange}></umb-input-entity-user-permission>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [UmbTextStyles];
|
||||
}
|
||||
|
||||
export default UmbUserGroupDefaultPermissionListElement;
|
||||
export default UmbUserGroupEntityUserPermissionListElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-user-group-default-permission-list': UmbUserGroupDefaultPermissionListElement;
|
||||
'umb-user-group-default-permission-list': UmbUserGroupEntityUserPermissionListElement;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
import { UMB_USER_GROUP_WORKSPACE_CONTEXT } from '../user-group-workspace.context.js';
|
||||
import type { UmbUserGroupDetailModel } from '../../types.js';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
|
||||
import type { ManifestGranularUserPermission } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { filterFrozenArray } from '@umbraco-cms/backoffice/observable-api';
|
||||
|
||||
@customElement('umb-user-group-granular-permission-list')
|
||||
export class UmbUserGroupGranularPermissionListElement extends UmbLitElement {
|
||||
@state()
|
||||
private _userGroup?: UmbUserGroupDetailModel;
|
||||
_extensionElements: Array<HTMLElement> = [];
|
||||
|
||||
#workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE;
|
||||
|
||||
@@ -15,12 +19,90 @@ export class UmbUserGroupGranularPermissionListElement extends UmbLitElement {
|
||||
|
||||
this.consumeContext(UMB_USER_GROUP_WORKSPACE_CONTEXT, (instance) => {
|
||||
this.#workspaceContext = instance;
|
||||
this.observe(this.#workspaceContext.data, (userGroup) => (this._userGroup = userGroup), 'umbUserGroupObserver');
|
||||
});
|
||||
|
||||
this.#observeExtensionRegistry();
|
||||
}
|
||||
|
||||
#observeExtensionRegistry() {
|
||||
this.observe(umbExtensionsRegistry.byType('userGranularPermission'), (manifests) => {
|
||||
if (!manifests) {
|
||||
this._extensionElements = [];
|
||||
return;
|
||||
}
|
||||
|
||||
manifests.forEach(async (manifest) => this.#extensionElementSetup(manifest));
|
||||
});
|
||||
}
|
||||
|
||||
async #extensionElementSetup(manifest: ManifestGranularUserPermission) {
|
||||
const element = (await createExtensionElement(manifest)) as any;
|
||||
if (!element) throw new Error(`Failed to create extension element for manifest ${manifest.alias}`);
|
||||
if (!this.#workspaceContext) throw new Error('User Group Workspace context is not available');
|
||||
|
||||
this.observe(
|
||||
this.#workspaceContext.data,
|
||||
(userGroup) => {
|
||||
if (!userGroup) return;
|
||||
|
||||
const schemaType = manifest.meta.schemaType;
|
||||
const permissionsForSchemaType =
|
||||
userGroup.permissions.filter((permission) => permission.$type === schemaType) || [];
|
||||
|
||||
element.permissions = permissionsForSchemaType;
|
||||
element.manifest = manifest;
|
||||
element.addEventListener(UmbChangeEvent.TYPE, this.#onValueChange);
|
||||
},
|
||||
'umbUserGroupGranularPermissionObserver',
|
||||
);
|
||||
|
||||
this._extensionElements.push(element);
|
||||
this.requestUpdate('_extensionElements');
|
||||
}
|
||||
|
||||
#onValueChange = (e: UmbChangeEvent) => {
|
||||
e.stopPropagation();
|
||||
// TODO: make interface
|
||||
const target = e.target as any;
|
||||
const schemaType = target.manifest?.meta.schemaType;
|
||||
if (!schemaType) throw new Error('Schema type is not available');
|
||||
|
||||
/* Remove all permissions of the same schema type from
|
||||
the user group and append the new permissions.
|
||||
We do it this way to support appends, updates and deletion without we know the
|
||||
exact action but on the changed value */
|
||||
const storedValueWithoutSchemaTypeItems = filterFrozenArray(
|
||||
this.#workspaceContext?.getPermissions() || [],
|
||||
(x) => x.$type !== schemaType,
|
||||
);
|
||||
|
||||
const permissions = target.permissions || [];
|
||||
const newCombinedValue = [...storedValueWithoutSchemaTypeItems, ...permissions];
|
||||
|
||||
this.#workspaceContext?.setPermissions(newCombinedValue);
|
||||
};
|
||||
|
||||
render() {
|
||||
return html`<umb-extension-slot type="userGranularPermission"></umb-extension-slot>`;
|
||||
return html`${this._extensionElements.map((element) => this.#renderProperty(element))}`;
|
||||
}
|
||||
|
||||
#renderProperty(element: any) {
|
||||
const manifest = element.manifest as ManifestGranularUserPermission;
|
||||
const label = manifest.meta.labelKey ? this.localize.term(manifest.meta.labelKey) : manifest.meta.label;
|
||||
const description = manifest.meta.descriptionKey
|
||||
? this.localize.term(manifest.meta.descriptionKey)
|
||||
: manifest.meta.description;
|
||||
|
||||
return html`
|
||||
<umb-property-layout .label=${label || ''} .description=${description || ''}>
|
||||
<div slot="editor">${element}</div>
|
||||
</umb-property-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
this._extensionElements.forEach((element) => element.removeEventListener(UmbChangeEvent.TYPE, this.#onValueChange));
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { UmbInputSectionElement } from '@umbraco-cms/backoffice/components'
|
||||
import type { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import type { UmbInputMediaElement } from '@umbraco-cms/backoffice/media';
|
||||
|
||||
import './components/user-group-default-permission-list.element.js';
|
||||
import './components/user-group-entity-user-permission-list.element.js';
|
||||
import './components/user-group-granular-permission-list.element.js';
|
||||
|
||||
@customElement('umb-user-group-workspace-editor')
|
||||
@@ -123,15 +123,16 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
|
||||
|
||||
<uui-box>
|
||||
<div slot="headline"><umb-localize key="user_permissionsDefault"></umb-localize></div>
|
||||
<umb-user-group-default-permission-list></umb-user-group-default-permission-list>
|
||||
|
||||
<umb-property-layout label="Entity permissions" description="Assign permissions for an entity type">
|
||||
<umb-user-group-entity-user-permission-list slot="editor"></umb-user-group-entity-user-permission-list>
|
||||
</umb-property-layout>
|
||||
</uui-box>
|
||||
|
||||
<!-- Temp disabled because it is work in progress
|
||||
<uui-box>
|
||||
<div slot="headline"><umb-localize key="user_permissionsGranular"></umb-localize></div>
|
||||
<umb-user-group-granular-permission-list></umb-user-group-granular-permission-list>
|
||||
</uui-box>
|
||||
-->
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { UmbUserGroupDetailRepository } from '../repository/detail/index.js';
|
||||
import type { UmbUserGroupDetailModel } from '../types.js';
|
||||
import type { UmbUserPermissionModel } from '@umbraco-cms/backoffice/user-permission';
|
||||
import type { UmbSaveableWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbEditableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
@@ -16,6 +17,18 @@ export class UmbUserGroupWorkspaceContext
|
||||
#data = new UmbObjectState<UmbUserGroupDetailModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
|
||||
readonly name = this.#data.asObservablePart((data) => data?.name || '');
|
||||
readonly icon = this.#data.asObservablePart((data) => data?.icon || null);
|
||||
readonly sections = this.#data.asObservablePart((data) => data?.sections || []);
|
||||
readonly languages = this.#data.asObservablePart((data) => data?.languages || []);
|
||||
readonly hasAccessToAllLanguages = this.#data.asObservablePart((data) => data?.hasAccessToAllLanguages || false);
|
||||
readonly documentStartNode = this.#data.asObservablePart((data) => data?.documentStartNode || null);
|
||||
readonly documentRootAccess = this.#data.asObservablePart((data) => data?.documentRootAccess || false);
|
||||
readonly mediaStartNode = this.#data.asObservablePart((data) => data?.mediaStartNode || null);
|
||||
readonly mediaRootAccess = this.#data.asObservablePart((data) => data?.mediaRootAccess || false);
|
||||
readonly fallbackPermissions = this.#data.asObservablePart((data) => data?.fallbackPermissions || []);
|
||||
readonly permissions = this.#data.asObservablePart((data) => data?.permissions || []);
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host, 'Umb.Workspace.UserGroup');
|
||||
}
|
||||
@@ -82,42 +95,37 @@ export class UmbUserGroupWorkspaceContext
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user group default permissions.
|
||||
* @param {Array<string>} permissionAliases
|
||||
* Gets the user group user permissions.
|
||||
* @memberof UmbUserGroupWorkspaceContext
|
||||
*/
|
||||
setDefaultPermissions(permissionAliases: Array<string>) {
|
||||
this.#data.update({ permissions: permissionAliases });
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user group default permissions.
|
||||
* @memberof UmbUserGroupWorkspaceContext
|
||||
*/
|
||||
getDefaultPermissions() {
|
||||
getPermissions() {
|
||||
return this.#data.getValue()?.permissions ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows a default permission on the user group.
|
||||
* @param {string} permissionAlias
|
||||
* Sets the user group user permissions.
|
||||
* @param {Array<UmbUserPermissionModel>} permissions
|
||||
* @memberof UmbUserGroupWorkspaceContext
|
||||
*/
|
||||
allowDefaultPermission(permissionAlias: string) {
|
||||
const permissions = this.#data.getValue()?.permissions ?? [];
|
||||
const newValue = [...permissions, permissionAlias];
|
||||
this.#data.update({ permissions: newValue });
|
||||
setPermissions(permissions: Array<UmbUserPermissionModel>) {
|
||||
this.#data.update({ permissions: permissions });
|
||||
}
|
||||
|
||||
/**
|
||||
* Disallows a default permission on the user group.
|
||||
* @param {string} permissionAlias
|
||||
* Gets the user group fallback permissions.
|
||||
* @memberof UmbUserGroupWorkspaceContext
|
||||
*/
|
||||
disallowDefaultPermission(permissionAlias: string) {
|
||||
const permissions = this.#data.getValue()?.permissions ?? [];
|
||||
const newValue = permissions.filter((alias) => alias !== permissionAlias);
|
||||
this.#data.update({ permissions: newValue });
|
||||
getFallbackPermissions() {
|
||||
return this.#data.getValue()?.fallbackPermissions ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user group fallback permissions.
|
||||
* @param {Array<string>} fallbackPermissions
|
||||
* @memberof UmbUserGroupWorkspaceContext
|
||||
*/
|
||||
setFallbackPermissions(fallbackPermissions: Array<string>) {
|
||||
this.#data.update({ fallbackPermissions });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
import type { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import type { ManifestUserPermission } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { html, customElement, property, state, nothing, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbUserPermissionSettingElement } from '@umbraco-cms/backoffice/user';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
|
||||
@customElement('umb-entity-user-permission-settings-list')
|
||||
export class UmbEntityUserPermissionSettingsListElement extends UmbLitElement {
|
||||
@property({ type: String, attribute: 'entity-type' })
|
||||
public get entityType(): string {
|
||||
return this._entityType;
|
||||
}
|
||||
public set entityType(value: string) {
|
||||
if (value === this._entityType) return;
|
||||
this._entityType = value;
|
||||
this.#observeUserPermissions();
|
||||
}
|
||||
private _entityType: string = '';
|
||||
|
||||
@property({ attribute: false })
|
||||
selectedPermissions: Array<string> = [];
|
||||
|
||||
@state()
|
||||
private _manifests: Array<ManifestUserPermission> = [];
|
||||
|
||||
#manifestObserver?: UmbObserverController<Array<ManifestUserPermission>>;
|
||||
|
||||
#isAllowed(permissionAlias: string) {
|
||||
return this.selectedPermissions?.includes(permissionAlias);
|
||||
}
|
||||
|
||||
#observeUserPermissions() {
|
||||
this.#manifestObserver?.destroy();
|
||||
|
||||
this.#manifestObserver = this.observe(
|
||||
umbExtensionsRegistry.byType('userPermission'),
|
||||
(userPermissionManifests) => {
|
||||
this._manifests = userPermissionManifests.filter((manifest) => manifest.meta.entityType === this.entityType);
|
||||
},
|
||||
'umbUserPermissionManifestsObserver',
|
||||
);
|
||||
}
|
||||
|
||||
#onChangeUserPermission(event: UmbChangeEvent, permissionAlias: string) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as UmbUserPermissionSettingElement;
|
||||
target.allowed ? this.#addUserPermission(permissionAlias) : this.#removeUserPermission(permissionAlias);
|
||||
}
|
||||
|
||||
#addUserPermission(permissionAlias: string) {
|
||||
this.selectedPermissions = [...this.selectedPermissions, permissionAlias];
|
||||
this.dispatchEvent(new UmbSelectionChangeEvent());
|
||||
}
|
||||
|
||||
#removeUserPermission(permissionAlias: string) {
|
||||
this.selectedPermissions = this.selectedPermissions.filter((alias) => alias !== permissionAlias);
|
||||
this.dispatchEvent(new UmbSelectionChangeEvent());
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`${this.#renderGroupedPermissions(this._manifests)} `;
|
||||
}
|
||||
|
||||
#renderGroupedPermissions(permissionManifests: Array<ManifestUserPermission>) {
|
||||
// TODO: groupBy is not known by TS yet
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const groupedPermissions = Object.groupBy(
|
||||
permissionManifests,
|
||||
(manifest: ManifestUserPermission) => manifest.meta.group,
|
||||
) as Record<string, Array<ManifestUserPermission>>;
|
||||
return html`
|
||||
${Object.entries(groupedPermissions).map(
|
||||
([group, manifests]) => html`
|
||||
${group !== 'undefined'
|
||||
? html` <h5><umb-localize .key=${`actionCategories_${group}`}>${group}</umb-localize></h5> `
|
||||
: nothing}
|
||||
${manifests.map((manifest) => html` ${this.#renderPermission(manifest)} `)}
|
||||
`,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
#renderPermission(manifest: ManifestUserPermission) {
|
||||
return html` <umb-user-permission-setting
|
||||
label=${ifDefined(manifest.meta.labelKey ? this.localize.term(manifest.meta.labelKey) : manifest.meta.label)}
|
||||
description=${ifDefined(
|
||||
manifest.meta.descriptionKey ? this.localize.term(manifest.meta.descriptionKey) : manifest.meta.description,
|
||||
)}
|
||||
?allowed=${this.#isAllowed(manifest.alias)}
|
||||
@change=${(event: UmbChangeEvent) =>
|
||||
this.#onChangeUserPermission(event, manifest.alias)}></umb-user-permission-setting>`;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.#manifestObserver?.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
export default UmbEntityUserPermissionSettingsListElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-entity-user-permission-settings-list': UmbEntityUserPermissionSettingsListElement;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import './entity-user-permission-settings-list/entity-user-permission-settings-list.element.js';
|
||||
import './input-entity-user-permission/input-entity-user-permission.element.js';
|
||||
import './input-user-permission-verb/input-user-permission-verb.element.js';
|
||||
|
||||
export * from './entity-user-permission-settings-list/entity-user-permission-settings-list.element.js';
|
||||
export * from './input-entity-user-permission/input-entity-user-permission.element.js';
|
||||
export * from './input-user-permission-verb/input-user-permission-verb.element.js';
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import type { ManifestEntityUserPermission } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { html, customElement, property, state, nothing, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbUserPermissionVerbElement } from '@umbraco-cms/backoffice/user';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
@customElement('umb-input-entity-user-permission')
|
||||
export class UmbInputEntityUserPermissionElement extends FormControlMixin(UmbLitElement) {
|
||||
@property({ type: String, attribute: 'entity-type' })
|
||||
public get entityType(): string {
|
||||
return this._entityType;
|
||||
}
|
||||
public set entityType(value: string) {
|
||||
if (value === this._entityType) return;
|
||||
this._entityType = value;
|
||||
this.#observeEntityUserPermissions();
|
||||
}
|
||||
private _entityType: string = '';
|
||||
|
||||
@property({ attribute: false })
|
||||
allowedVerbs: Array<string> = [];
|
||||
|
||||
@state()
|
||||
private _manifests: Array<ManifestEntityUserPermission> = [];
|
||||
|
||||
#manifestObserver?: UmbObserverController<Array<ManifestEntityUserPermission>>;
|
||||
|
||||
protected getFormElement() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
#isAllowed(permissionVerbs: Array<string>) {
|
||||
return permissionVerbs.every((verb) => this.allowedVerbs.includes(verb));
|
||||
}
|
||||
|
||||
#observeEntityUserPermissions() {
|
||||
this.#manifestObserver?.destroy();
|
||||
|
||||
this.#manifestObserver = this.observe(
|
||||
umbExtensionsRegistry.byType('entityUserPermission'),
|
||||
(userPermissionManifests) => {
|
||||
this._manifests = userPermissionManifests.filter((manifest) => manifest.meta.entityType === this.entityType);
|
||||
},
|
||||
'umbUserPermissionManifestsObserver',
|
||||
);
|
||||
}
|
||||
|
||||
#onChangeUserPermission(event: UmbChangeEvent, permissionVerbs: Array<string>) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as UmbUserPermissionVerbElement;
|
||||
target.allowed ? this.#addUserPermission(permissionVerbs) : this.#removeUserPermission(permissionVerbs);
|
||||
}
|
||||
|
||||
#addUserPermission(permissionVerbs: Array<string>) {
|
||||
const verbs = [...this.allowedVerbs, ...permissionVerbs];
|
||||
// ensure we only have unique verbs
|
||||
this.allowedVerbs = [...new Set(verbs)];
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
}
|
||||
|
||||
#removeUserPermission(permissionVerbs: Array<string>) {
|
||||
this.allowedVerbs = this.allowedVerbs.filter((p) => !permissionVerbs.includes(p));
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`${this.#renderGroupedPermissions(this._manifests)} `;
|
||||
}
|
||||
|
||||
#renderGroupedPermissions(permissionManifests: Array<ManifestEntityUserPermission>) {
|
||||
// TODO: groupBy is not known by TS yet
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const groupedPermissions = Object.groupBy(
|
||||
permissionManifests,
|
||||
(manifest: ManifestEntityUserPermission) => manifest.meta.group,
|
||||
) as Record<string, Array<ManifestEntityUserPermission>>;
|
||||
return html`
|
||||
${Object.entries(groupedPermissions).map(
|
||||
([group, manifests]) => html`
|
||||
${group !== 'undefined'
|
||||
? html` <h5><umb-localize .key=${`actionCategories_${group}`}>${group}</umb-localize></h5> `
|
||||
: nothing}
|
||||
${manifests.map((manifest) => html` ${this.#renderPermission(manifest)} `)}
|
||||
`,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
#renderPermission(manifest: ManifestEntityUserPermission) {
|
||||
return html` <umb-input-user-permission-verb
|
||||
label=${ifDefined(manifest.meta.labelKey ? this.localize.term(manifest.meta.labelKey) : manifest.meta.label)}
|
||||
description=${ifDefined(
|
||||
manifest.meta.descriptionKey ? this.localize.term(manifest.meta.descriptionKey) : manifest.meta.description,
|
||||
)}
|
||||
?allowed=${this.#isAllowed(manifest.meta.verbs)}
|
||||
@change=${(event: UmbChangeEvent) =>
|
||||
this.#onChangeUserPermission(event, manifest.meta.verbs)}></umb-input-user-permission-verb>`;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.#manifestObserver?.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
export default UmbInputEntityUserPermissionElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-input-entity-user-permission': UmbInputEntityUserPermissionElement;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
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/backoffice/lit-element';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
@customElement('umb-user-permission-setting')
|
||||
export class UmbUserPermissionSettingElement extends UmbLitElement {
|
||||
@customElement('umb-input-user-permission-verb')
|
||||
export class UmbUserPermissionVerbElement extends UmbLitElement {
|
||||
@property({ type: String, attribute: true })
|
||||
label: string = '';
|
||||
|
||||
@@ -54,10 +54,10 @@ export class UmbUserPermissionSettingElement extends UmbLitElement {
|
||||
];
|
||||
}
|
||||
|
||||
export default UmbUserPermissionSettingElement;
|
||||
export default UmbUserPermissionVerbElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-user-permission-setting': UmbUserPermissionSettingElement;
|
||||
'umb-input-user-permission-verb': UmbUserPermissionVerbElement;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export class UmbUserPermissionCondition extends UmbBaseController implements Umb
|
||||
this.observe(
|
||||
context.currentUser,
|
||||
(currentUser) => {
|
||||
this.permitted = currentUser?.permissions?.includes(this.config.match) || false;
|
||||
//this.permitted = currentUser?.permissions?.includes(this.config.match) || false;
|
||||
this.#onChange();
|
||||
},
|
||||
'umbUserPermissionConditionObserver',
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
export * from './components/index.js';
|
||||
export * from './conditions/index.js';
|
||||
|
||||
export type UserPermissionModel<PermissionTargetType> = {
|
||||
id: string;
|
||||
target: PermissionTargetType;
|
||||
permissions: Array<string>;
|
||||
};
|
||||
|
||||
// TODO: this should only be known by the document
|
||||
export type UmbDocumentGranularPermission = {
|
||||
entityType: 'document';
|
||||
documentId: string;
|
||||
userGroupId: string;
|
||||
};
|
||||
export type { UmbUserPermissionModel } from './types.js';
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { html, customElement, css, nothing, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { html, customElement, css, nothing, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type {
|
||||
UmbEntityUserPermissionSettingsModalData,
|
||||
UmbEntityUserPermissionSettingsModalValue} from '@umbraco-cms/backoffice/modal';
|
||||
import {
|
||||
UmbModalBaseElement,
|
||||
UmbEntityUserPermissionSettingsModalValue,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import type { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
@customElement('umb-entity-user-permission-settings-modal')
|
||||
@@ -16,7 +15,6 @@ export class UmbEntityUserPermissionSettingsModalElement extends UmbModalBaseEle
|
||||
set data(data: UmbEntityUserPermissionSettingsModalData | undefined) {
|
||||
super.data = data;
|
||||
this._entityType = data?.entityType;
|
||||
this._allowedPermissions = data?.allowedPermissions ?? [];
|
||||
this._headline = data?.headline ?? this._headline;
|
||||
}
|
||||
|
||||
@@ -26,17 +24,9 @@ export class UmbEntityUserPermissionSettingsModalElement extends UmbModalBaseEle
|
||||
@state()
|
||||
_entityType?: string;
|
||||
|
||||
@state()
|
||||
_allowedPermissions: Array<string> = [];
|
||||
|
||||
private _handleConfirm() {
|
||||
this.value = { allowedPermissions: this._allowedPermissions };
|
||||
this.modalContext?.submit();
|
||||
}
|
||||
|
||||
#onSelectedUserPermission(event: UmbSelectionChangeEvent) {
|
||||
#onPermissionChange(event: UmbSelectionChangeEvent) {
|
||||
const target = event.target as any;
|
||||
this._allowedPermissions = target.selectedPermissions;
|
||||
this.updateValue({ allowedVerbs: target.allowedVerbs });
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -44,10 +34,10 @@ export class UmbEntityUserPermissionSettingsModalElement extends UmbModalBaseEle
|
||||
<umb-body-layout headline=${this._headline}>
|
||||
<uui-box>
|
||||
${this._entityType
|
||||
? html` <umb-entity-user-permission-settings-list
|
||||
? html` <umb-input-entity-user-permission
|
||||
.entityType=${this._entityType}
|
||||
.selectedPermissions=${this._allowedPermissions}
|
||||
@selection-change=${this.#onSelectedUserPermission}></umb-entity-user-permission-settings-list>`
|
||||
.allowedVerbs=${this.value?.allowedVerbs ?? []}
|
||||
@change=${this.#onPermissionChange}></umb-input-entity-user-permission>`
|
||||
: nothing}
|
||||
</uui-box>
|
||||
|
||||
@@ -58,7 +48,7 @@ export class UmbEntityUserPermissionSettingsModalElement extends UmbModalBaseEle
|
||||
color="positive"
|
||||
look="primary"
|
||||
label="Confirm"
|
||||
@click=${this._handleConfirm}></uui-button>
|
||||
@click=${this._submitModal}></uui-button>
|
||||
</umb-body-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface UmbUserPermissionModel {
|
||||
$type: string;
|
||||
verbs: Array<string>;
|
||||
}
|
||||
@@ -34,40 +34,36 @@ export class UmbUserCollectionServerDataSource implements UmbCollectionDataSourc
|
||||
async getCollection(filter: UmbUserCollectionFilterModel) {
|
||||
const { data, error } = await tryExecuteAndNotify(this.#host, UserResource.getFilterUser(filter));
|
||||
|
||||
if (error) {
|
||||
return { error };
|
||||
if (data) {
|
||||
const { items, total } = data;
|
||||
|
||||
const mappedItems: Array<UmbUserDetailModel> = items.map((item: UserResponseModel) => {
|
||||
const userDetail: UmbUserDetailModel = {
|
||||
entityType: UMB_USER_ENTITY_TYPE,
|
||||
email: item.email,
|
||||
userName: item.userName,
|
||||
name: item.name,
|
||||
userGroupUniques: item.userGroupIds,
|
||||
unique: item.id,
|
||||
languageIsoCode: item.languageIsoCode || null,
|
||||
documentStartNodeUniques: item.documentStartNodeIds,
|
||||
mediaStartNodeUniques: item.mediaStartNodeIds,
|
||||
avatarUrls: item.avatarUrls,
|
||||
state: item.state,
|
||||
failedLoginAttempts: item.failedLoginAttempts,
|
||||
createDate: item.createDate,
|
||||
updateDate: item.updateDate,
|
||||
lastLoginDate: item.lastLoginDate || null,
|
||||
lastLockoutDate: item.lastLockoutDate || null,
|
||||
lastPasswordChangeDate: item.lastPasswordChangeDate || null,
|
||||
};
|
||||
|
||||
return userDetail;
|
||||
});
|
||||
|
||||
return { data: { items: mappedItems, total } };
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return { data: { items: [], total: 0 } };
|
||||
}
|
||||
|
||||
const { items, total } = data;
|
||||
|
||||
const mappedItems: Array<UmbUserDetailModel> = items.map((item: UserResponseModel) => {
|
||||
const userDetail: UmbUserDetailModel = {
|
||||
entityType: UMB_USER_ENTITY_TYPE,
|
||||
email: item.email,
|
||||
userName: item.userName,
|
||||
name: item.name,
|
||||
userGroupUniques: item.userGroupIds,
|
||||
unique: item.id,
|
||||
languageIsoCode: item.languageIsoCode || null,
|
||||
documentStartNodeUniques: item.documentStartNodeIds,
|
||||
mediaStartNodeUniques: item.mediaStartNodeIds,
|
||||
avatarUrls: item.avatarUrls,
|
||||
state: item.state,
|
||||
failedLoginAttempts: item.failedLoginAttempts,
|
||||
createDate: item.createDate,
|
||||
updateDate: item.updateDate,
|
||||
lastLoginDate: item.lastLoginDate || null,
|
||||
lastLockoutDate: item.lastLockoutDate || null,
|
||||
lastPasswordChangeDate: item.lastPasswordChangeDate || null,
|
||||
};
|
||||
|
||||
return userDetail;
|
||||
});
|
||||
|
||||
return { data: { items: mappedItems, total } };
|
||||
return { error };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import './user-input/user-input.element.js';
|
||||
import './user-permission-setting/user-permission-setting.element.js';
|
||||
import './user-document-start-node/user-document-start-node.element.js';
|
||||
import './user-media-start-node/user-media-start-node.element.js';
|
||||
|
||||
export * from './user-input/user-input.element.js';
|
||||
export * from './user-permission-setting/user-permission-setting.element.js';
|
||||
export * from '../../user-permission/components/input-user-permission-verb/input-user-permission-verb.element.js';
|
||||
|
||||
Reference in New Issue
Block a user