Merge branch 'chore/update-form-mixin' of https://github.com/umbraco/Umbraco.CMS.Backoffice into chore/update-form-mixin
This commit is contained in:
@@ -1893,6 +1893,8 @@ export default {
|
||||
searchAllChildren: 'Search all children',
|
||||
languagesHelp: 'Limit the languages users have access to edit',
|
||||
allowAccessToAllLanguages: 'Allow access to all languages',
|
||||
allowAccessToAllDocuments: 'Allow access to all documents',
|
||||
allowAccessToAllMedia: 'Allow access to all media',
|
||||
sectionsHelp: 'Add sections to give users access',
|
||||
selectUserGroup: (multiple: boolean) => {
|
||||
return multiple ? 'Select User Groups' : 'Select User Group';
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import type { UmbUserGroupDetailModel } from '../../types.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
|
||||
import { UMB_DEFAULT_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
|
||||
|
||||
import '../components/user-group-table-name-column-layout.element.js';
|
||||
import '../components/user-group-table-sections-column-layout.element.js';
|
||||
|
||||
import type {
|
||||
UmbTableColumn,
|
||||
UmbTableConfig,
|
||||
@@ -15,7 +12,13 @@ import type {
|
||||
UmbTableItem,
|
||||
UmbTableSelectedEvent,
|
||||
} from '@umbraco-cms/backoffice/components';
|
||||
import type { UmbUserGroupDetailModel } from '../../types.js';
|
||||
import { UmbDocumentItemRepository } from '@umbraco-cms/backoffice/document';
|
||||
import { UmbMediaItemRepository } from '@umbraco-cms/backoffice/media';
|
||||
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
|
||||
import type { UmbUniqueItemModel } from '@umbraco-cms/backoffice/models';
|
||||
|
||||
import '../components/user-group-table-name-column-layout.element.js';
|
||||
import '../components/user-group-table-sections-column-layout.element.js';
|
||||
|
||||
@customElement('umb-user-group-collection-table-view')
|
||||
export class UmbUserGroupCollectionTableViewElement extends UmbLitElement {
|
||||
@@ -54,6 +57,13 @@ export class UmbUserGroupCollectionTableViewElement extends UmbLitElement {
|
||||
|
||||
#collectionContext?: UmbDefaultCollectionContext;
|
||||
|
||||
// TODO: hardcoded dependencies on document and media modules. We should figure out how these dependencies can be added through extensions.
|
||||
#documentItemRepository = new UmbDocumentItemRepository(this);
|
||||
#mediaItemRepository = new UmbMediaItemRepository(this);
|
||||
|
||||
#documentStartNodeMap = new Map<string, string>();
|
||||
#mediaStartNodeMap = new Map<string, string>();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -74,7 +84,17 @@ export class UmbUserGroupCollectionTableViewElement extends UmbLitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _createTableItems(userGroups: Array<UmbUserGroupDetailModel>) {
|
||||
private async _createTableItems(userGroups: Array<UmbUserGroupDetailModel>) {
|
||||
await Promise.all([
|
||||
this.#requestAndCacheStartNodes(
|
||||
userGroups,
|
||||
'documentStartNode',
|
||||
this.#documentItemRepository,
|
||||
this.#documentStartNodeMap,
|
||||
),
|
||||
this.#requestAndCacheStartNodes(userGroups, 'mediaStartNode', this.#mediaItemRepository, this.#mediaStartNodeMap),
|
||||
]);
|
||||
|
||||
this._tableItems = userGroups.map((userGroup) => {
|
||||
return {
|
||||
id: userGroup.unique,
|
||||
@@ -92,25 +112,52 @@ export class UmbUserGroupCollectionTableViewElement extends UmbLitElement {
|
||||
},
|
||||
{
|
||||
columnAlias: 'userGroupContentStartNode',
|
||||
value: userGroup.documentStartNode?.unique || this.localize.term('content_contentRoot'),
|
||||
value: userGroup.documentStartNode
|
||||
? this.#documentStartNodeMap.get(userGroup.documentStartNode.unique)
|
||||
: this.localize.term('content_contentRoot'),
|
||||
},
|
||||
{
|
||||
columnAlias: 'userGroupMediaStartNode',
|
||||
value: userGroup.mediaStartNode?.unique || this.localize.term('media_mediaRoot'),
|
||||
value: userGroup.mediaStartNode?.unique
|
||||
? this.#mediaStartNodeMap.get(userGroup.mediaStartNode.unique)
|
||||
: this.localize.term('media_mediaRoot'),
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSelected(event: UmbTableSelectedEvent) {
|
||||
async #requestAndCacheStartNodes(
|
||||
userGroups: Array<UmbUserGroupDetailModel>,
|
||||
startNodeField: 'documentStartNode' | 'mediaStartNode',
|
||||
itemRepository: UmbItemRepository<UmbUniqueItemModel>,
|
||||
map: Map<string, string>,
|
||||
) {
|
||||
const allStartNodes = userGroups.map((userGroup) => userGroup[startNodeField]?.unique).filter(Boolean) as string[];
|
||||
const uniqueStartNodes = [...new Set(allStartNodes)];
|
||||
const uncachedStartNodes = uniqueStartNodes.filter((unique) => !map.has(unique));
|
||||
|
||||
// If there are no uncached start nodes, we don't need to make a request
|
||||
if (uncachedStartNodes.length === 0) return;
|
||||
|
||||
const { data: items } = await itemRepository.requestItems(uncachedStartNodes);
|
||||
|
||||
if (items) {
|
||||
items.forEach((item) => {
|
||||
// cache the start node
|
||||
map.set(item.unique, item.name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#onSelected(event: UmbTableSelectedEvent) {
|
||||
event.stopPropagation();
|
||||
const table = event.target as UmbTableElement;
|
||||
const selection = table.selection;
|
||||
this.#collectionContext?.selection.setSelection(selection);
|
||||
}
|
||||
|
||||
private _handleDeselected(event: UmbTableDeselectedEvent) {
|
||||
#onDeselected(event: UmbTableDeselectedEvent) {
|
||||
event.stopPropagation();
|
||||
const table = event.target as UmbTableElement;
|
||||
const selection = table.selection;
|
||||
@@ -124,8 +171,8 @@ export class UmbUserGroupCollectionTableViewElement extends UmbLitElement {
|
||||
.columns=${this._tableColumns}
|
||||
.items=${this._tableItems}
|
||||
.selection=${this._selection}
|
||||
@selected="${this._handleSelected}"
|
||||
@deselected="${this._handleDeselected}"></umb-table>
|
||||
@selected="${this.#onSelected}"
|
||||
@deselected="${this.#onDeselected}"></umb-table>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,15 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
|
||||
@state()
|
||||
private _documentStartNode?: UmbUserGroupDetailModel['documentStartNode'];
|
||||
|
||||
@state()
|
||||
private _documentRootAccess: UmbUserGroupDetailModel['documentRootAccess'] = false;
|
||||
|
||||
@state()
|
||||
private _mediaStartNode?: UmbUserGroupDetailModel['mediaStartNode'];
|
||||
|
||||
@state()
|
||||
private _mediaRootAccess: UmbUserGroupDetailModel['mediaRootAccess'] = false;
|
||||
|
||||
#workspaceContext?: typeof UMB_USER_GROUP_WORKSPACE_CONTEXT.TYPE;
|
||||
|
||||
constructor() {
|
||||
@@ -66,46 +72,82 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
|
||||
'_observeHasAccessToAllLanguages',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
this.#workspaceContext.documentRootAccess,
|
||||
(value) => (this._documentRootAccess = value),
|
||||
'_observeDocumentRootAccess',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
this.#workspaceContext.documentStartNode,
|
||||
(value) => (this._documentStartNode = value),
|
||||
'_observeDocumentStartNode',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
this.#workspaceContext.mediaRootAccess,
|
||||
(value) => (this._mediaRootAccess = value),
|
||||
'_observeMediaRootAccess',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
this.#workspaceContext.mediaStartNode,
|
||||
(value) => (this._mediaStartNode = value),
|
||||
'_observeDocumentStartNode',
|
||||
'_observeMediaStartNode',
|
||||
);
|
||||
}
|
||||
|
||||
#onSectionsChange(event: UmbChangeEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as UmbInputSectionElement;
|
||||
// TODO make contexts method
|
||||
this.#workspaceContext?.updateProperty('sections', target.selection);
|
||||
}
|
||||
|
||||
#onAllowAllLanguagesChange(event: UUIBooleanInputEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target;
|
||||
// TODO make contexts method
|
||||
this.#workspaceContext?.updateProperty('hasAccessToAllLanguages', target.checked);
|
||||
}
|
||||
|
||||
#onLanguagePermissionChange(event: UmbChangeEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as UmbInputLanguageElement;
|
||||
// TODO make contexts method
|
||||
this.#workspaceContext?.updateProperty('languages', target.selection);
|
||||
}
|
||||
|
||||
#onAllowAllDocumentsChange(event: UUIBooleanInputEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target;
|
||||
// TODO make contexts method
|
||||
this.#workspaceContext?.updateProperty('documentRootAccess', target.checked);
|
||||
this.#workspaceContext?.updateProperty('documentStartNode', null);
|
||||
}
|
||||
|
||||
#onDocumentStartNodeChange(event: CustomEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as UmbInputDocumentElement;
|
||||
this.#workspaceContext?.updateProperty('documentStartNode', { unique: target.selection[0] });
|
||||
const selected = target.selection?.[0];
|
||||
// TODO make contexts method
|
||||
this.#workspaceContext?.updateProperty('documentStartNode', selected ? { unique: selected } : null);
|
||||
}
|
||||
|
||||
#onAllowAllMediaChange(event: UUIBooleanInputEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target;
|
||||
// TODO make contexts method
|
||||
this.#workspaceContext?.updateProperty('mediaRootAccess', target.checked);
|
||||
this.#workspaceContext?.updateProperty('mediaStartNode', null);
|
||||
}
|
||||
|
||||
#onMediaStartNodeChange(event: CustomEvent) {
|
||||
event.stopPropagation();
|
||||
const target = event.target as UmbInputMediaElement;
|
||||
this.#workspaceContext?.updateProperty('mediaStartNode', { unique: target.selection[0] });
|
||||
const selected = target.selection?.[0];
|
||||
// TODO make contexts method
|
||||
this.#workspaceContext?.updateProperty('mediaStartNode', selected ? { unique: selected } : null);
|
||||
}
|
||||
|
||||
#onNameChange(event: UUIInputEvent) {
|
||||
@@ -188,27 +230,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
|
||||
@change=${this.#onSectionsChange}></umb-input-section>
|
||||
</umb-property-layout>
|
||||
|
||||
${this.#renderLanguagePermissions()}
|
||||
|
||||
<umb-property-layout
|
||||
label=${this.localize.term('defaultdialogs_selectContentStartNode')}
|
||||
description=${this.localize.term('user_startnodehelp')}>
|
||||
<umb-input-document
|
||||
slot="editor"
|
||||
max="1"
|
||||
.selection=${this._documentStartNode?.unique ? [this._documentStartNode.unique] : []}
|
||||
@change=${this.#onDocumentStartNodeChange}></umb-input-document>
|
||||
</umb-property-layout>
|
||||
|
||||
<umb-property-layout
|
||||
label=${this.localize.term('defaultdialogs_selectMediaStartNode')}
|
||||
description=${this.localize.term('user_mediastartnodehelp')}>
|
||||
<umb-input-media
|
||||
slot="editor"
|
||||
max="1"
|
||||
.selection=${this._mediaStartNode?.unique ? [this._mediaStartNode.unique] : []}
|
||||
@change=${this.#onMediaStartNodeChange}></umb-input-media>
|
||||
</umb-property-layout>
|
||||
${this.#renderLanguageAccess()} ${this.#renderDocumentAccess()} ${this.#renderMediaAccess()}
|
||||
</uui-box>
|
||||
|
||||
<uui-box>
|
||||
@@ -226,7 +248,7 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
#renderLanguagePermissions() {
|
||||
#renderLanguageAccess() {
|
||||
return html`
|
||||
<umb-property-layout
|
||||
label=${this.localize.term('treeHeaders_languages')}
|
||||
@@ -250,6 +272,58 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
#renderDocumentAccess() {
|
||||
return html`
|
||||
<umb-property-layout
|
||||
label=${this.localize.term('defaultdialogs_selectContentStartNode')}
|
||||
description=${this.localize.term('user_startnodehelp')}>
|
||||
<div slot="editor">
|
||||
<uui-toggle
|
||||
style="margin-bottom: var(--uui-size-space-3);"
|
||||
label="${this.localize.term('user_allowAccessToAllDocuments')}"
|
||||
.checked=${this._documentRootAccess}
|
||||
@change=${this.#onAllowAllDocumentsChange}></uui-toggle>
|
||||
</div>
|
||||
|
||||
${this._documentRootAccess === false
|
||||
? html`
|
||||
<umb-input-document
|
||||
slot="editor"
|
||||
max="1"
|
||||
.selection=${this._documentStartNode?.unique ? [this._documentStartNode.unique] : []}
|
||||
@change=${this.#onDocumentStartNodeChange}></umb-input-document>
|
||||
`
|
||||
: nothing}
|
||||
</umb-property-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderMediaAccess() {
|
||||
return html`
|
||||
<umb-property-layout
|
||||
label=${this.localize.term('defaultdialogs_selectMediaStartNode')}
|
||||
description=${this.localize.term('user_mediastartnodehelp')}>
|
||||
<div slot="editor">
|
||||
<uui-toggle
|
||||
style="margin-bottom: var(--uui-size-space-3);"
|
||||
label="${this.localize.term('user_allowAccessToAllMedia')}"
|
||||
.checked=${this._mediaRootAccess}
|
||||
@change=${this.#onAllowAllMediaChange}></uui-toggle>
|
||||
</div>
|
||||
|
||||
${this._mediaRootAccess === false
|
||||
? html`
|
||||
<umb-input-media
|
||||
slot="editor"
|
||||
max="1"
|
||||
.selection=${this._mediaStartNode?.unique ? [this._mediaStartNode.unique] : []}
|
||||
@change=${this.#onMediaStartNodeChange}></umb-input-media>
|
||||
`
|
||||
: nothing}
|
||||
</umb-property-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderRightColumn() {
|
||||
return html` <uui-box headline="Actions">
|
||||
<umb-entity-action-list .entityType=${UMB_USER_GROUP_ENTITY_TYPE} .unique=${this._unique}></umb-entity-action-list
|
||||
|
||||
Reference in New Issue
Block a user