diff --git a/cms-oss-changelog/src/changelog/entries/2025/06/8297.SUP-18506.bugfix b/cms-oss-changelog/src/changelog/entries/2025/06/8297.SUP-18506.bugfix new file mode 100644 index 000000000..e1533058e --- /dev/null +++ b/cms-oss-changelog/src/changelog/entries/2025/06/8297.SUP-18506.bugfix @@ -0,0 +1,2 @@ +Administrator User Interface: Fixed an issue of adding or removing links to elements, when managing the assignment of multiple elements. For example, when managing multiple templates and their assignment to nodes. + \ No newline at end of file diff --git a/cms-oss-changelog/src/changelog/entries/2025/06/8298.SUP-18506.enhancement b/cms-oss-changelog/src/changelog/entries/2025/06/8298.SUP-18506.enhancement new file mode 100644 index 000000000..821a47be9 --- /dev/null +++ b/cms-oss-changelog/src/changelog/entries/2025/06/8298.SUP-18506.enhancement @@ -0,0 +1 @@ +UI Core: Tables have an additional way to handle selection, in the form of a Map. Has to be enabled per table with the @useSelectionMap@ Input. Allows for the @indeterminate@ state to be set and correctly handled. diff --git a/cms-ui/apps/admin-ui/src/app/core/providers/i18n/translations/shared.translations.json b/cms-ui/apps/admin-ui/src/app/core/providers/i18n/translations/shared.translations.json index c611a3cc7..0d913718b 100644 --- a/cms-ui/apps/admin-ui/src/app/core/providers/i18n/translations/shared.translations.json +++ b/cms-ui/apps/admin-ui/src/app/core/providers/i18n/translations/shared.translations.json @@ -56,8 +56,8 @@ "de": "Einschränkungen zuweisen" }, "assign_objectProperty_to_nodes_title": { - "en": "Assign objectProperty \"{{ entityName }}\" to Nodes", - "de": "Objekteigenschaft „{{ entityName }}“ zu Nodes zuweisen" + "en": "Restrict Object Properties to Nodes", + "de": "Objekt-Eigenschaften auf Nodes einschränken" }, "assign_user_to_roles": { "en": "Assign User to Roles", diff --git a/cms-ui/apps/admin-ui/src/app/core/providers/object-property-handler/object-property-handler.service.ts b/cms-ui/apps/admin-ui/src/app/core/providers/object-property-handler/object-property-handler.service.ts index e76ccd80d..fe641881c 100644 --- a/cms-ui/apps/admin-ui/src/app/core/providers/object-property-handler/object-property-handler.service.ts +++ b/cms-ui/apps/admin-ui/src/app/core/providers/object-property-handler/object-property-handler.service.ts @@ -29,8 +29,8 @@ import { } from '@admin-ui/common'; import { Injectable } from '@angular/core'; import { EntityIdType, Node, Raw } from '@gentics/cms-models'; -import { GcmsApi } from '@gentics/cms-rest-clients-angular'; -import { Observable, forkJoin, of } from 'rxjs'; +import { GCMSRestClientService } from '@gentics/cms-rest-client-angular'; +import { Observable } from 'rxjs'; import { map, tap } from 'rxjs/operators'; import { BaseEntityHandlerService } from '../base-entity-handler/base-entity-handler'; import { ErrorHandler } from '../error-handler'; @@ -45,7 +45,7 @@ export class ObjectPropertyHandlerService constructor( errorHandler: ErrorHandler, - protected api: GcmsApi, + protected client: GCMSRestClientService, protected notification: I18nNotificationService, ) { super(errorHandler); @@ -71,7 +71,7 @@ export class ObjectPropertyHandlerService data: EntityCreateRequestModel, params?: EntityCreateRequestParams, ): Observable> { - return this.api.objectproperties.createObjectProperty(data).pipe( + return this.client.objectProperty.create(data).pipe( tap(res => { const name = this.displayName(res.objectProperty); this.nameMap[res.objectProperty.id] = name; @@ -101,7 +101,7 @@ export class ObjectPropertyHandlerService id: string | number, params?: EntityLoadRequestParams, ): Observable> { - return this.api.objectproperties.getObjectProperty(id).pipe( + return this.client.objectProperty.get(id).pipe( tap(res => { const name = this.displayName(res.objectProperty); this.nameMap[res.objectProperty.id] = name; @@ -124,7 +124,7 @@ export class ObjectPropertyHandlerService data: EntityUpdateRequestModel, params?: EntityUpdateRequestParams, ): Observable> { - return this.api.objectproperties.updateObjectProperty(id, data).pipe( + return this.client.objectProperty.update(id, data).pipe( tap(res => { const name = this.displayName(res.objectProperty); this.nameMap[res.objectProperty.id] = name; @@ -152,8 +152,8 @@ export class ObjectPropertyHandlerService } delete(id: string | number, params?: EntityDeleteRequestParams): Observable { - return this.api.objectproperties.deleteObjectProperty(id).pipe( - tap(() => { + return this.client.objectProperty.delete(id).pipe( + discard(() => { const name = this.nameMap[id]; if (!name) { @@ -177,7 +177,7 @@ export class ObjectPropertyHandlerService body?: EntityListRequestModel, params?: EntityListRequestParams, ): Observable> { - return this.api.objectproperties.getObjectProperties(params).pipe( + return this.client.objectProperty.list(params).pipe( tap(res => { res.items.forEach(objCat => { const name = this.displayName(objCat); @@ -204,8 +204,8 @@ export class ObjectPropertyHandlerService devtoolPackage: string, entityId: string | number, ): Observable { - return this.api.devTools.addObjectPropertyToPackage(devtoolPackage, entityId).pipe( - tap(() => { + return this.client.devTools.assignObjectProperty(devtoolPackage, entityId).pipe( + discard(() => { this.notification.show({ message: 'objectProperty.objectProperty_successfully_added_to_package', type: 'success', @@ -222,8 +222,8 @@ export class ObjectPropertyHandlerService devtoolPackage: string, entityId: string | number, ): Observable { - return this.api.devTools.removeObjectPropertyFromPackage(devtoolPackage, entityId).pipe( - tap(() => { + return this.client.devTools.unassignObjectProperty(devtoolPackage, entityId).pipe( + discard(() => { this.notification.show({ message: 'objectProperty.objectProperty_successfully_removed_from_package', type: 'success', @@ -241,7 +241,7 @@ export class ObjectPropertyHandlerService body?: DevToolEntityListRequestModel, params?: DevToolEntityListRequestParams, ): Observable> { - return this.api.devTools.getObjectproperties(devtoolPackage, params).pipe( + return this.client.devTools.listObjectProperties(devtoolPackage, params).pipe( tap(res => { res.items.forEach(objCat => { const name = this.displayName(objCat); @@ -266,48 +266,32 @@ export class ObjectPropertyHandlerService } getLinkedNodes(objectPropertyId: EntityIdType): Observable[]> { - return this.api.objectproperties.getObjectPropertyLinkedNodes(objectPropertyId).pipe( + return this.client.objectProperty.listNodes(objectPropertyId).pipe( map(res => res.items), ); } - changeNodeRestrictions( - objectPropertyId: EntityIdType, - nodeIdsToRestrict: EntityIdType[] = [], - nodesCurrentlyRestricted: EntityIdType[] = [], - ): Observable { - const reqs = []; - const execute = (): Observable => { - if (reqs.length === 0) { - // do nothing - return of(); - } - return forkJoin(reqs).pipe( - // no need for explicit return value - discard(), - // display toast notification - tap(() => this.notification.show({ - type: 'success', - message: 'objectProperty.operation_linked_to_nodes_successful', - })), - this.catchAndRethrowError(), - ); - }; - - if (nodeIdsToRestrict.length === 0) { - // if none selected - reqs.push(this.api.objectproperties.unlinkObjectPropertiesFromNodes([objectPropertyId], nodesCurrentlyRestricted)); - return execute(); - } - if (nodesCurrentlyRestricted.length > 0) { - // don't remove nodes supposed to remain linked - const filteredNodes = nodesCurrentlyRestricted.filter(i => nodeIdsToRestrict.some(j => i !== j)); - reqs.push(this.api.objectproperties.unlinkObjectPropertiesFromNodes([objectPropertyId], filteredNodes)); - } - if (nodeIdsToRestrict.length > 0) { - reqs.push(this.api.objectproperties.linkObjectPropertiesToNodes([objectPropertyId], nodeIdsToRestrict)); - } + addNodeRestriction(objectPropertyIds: number[], nodeIds: number[]): Observable { + return this.client.objectProperty.linkToNode({ + targetIds: objectPropertyIds, + ids: nodeIds, + }).pipe(discard(() => { + this.notification.show({ + type: 'success', + message: 'objectProperty.operation_linked_to_nodes_successful', + }); + })); + } - return execute(); + removeNodeRestriction(objectPropertyIds: number[], nodeIds: number[]): Observable { + return this.client.objectProperty.unlinkFromNode({ + ids: nodeIds, + targetIds: objectPropertyIds, + }).pipe(discard(() => { + this.notification.show({ + type: 'success', + message: 'objectProperty.operation_linked_to_nodes_successful', + }); + })); } } diff --git a/cms-ui/apps/admin-ui/src/app/core/providers/operations/group/group.operations.ts b/cms-ui/apps/admin-ui/src/app/core/providers/operations/group/group.operations.ts index 8f176b2c7..0b1e9b6c2 100644 --- a/cms-ui/apps/admin-ui/src/app/core/providers/operations/group/group.operations.ts +++ b/cms-ui/apps/admin-ui/src/app/core/providers/operations/group/group.operations.ts @@ -134,7 +134,7 @@ export class GroupOperations extends ExtendedEntityOperationsBase<'group'> { * @param id The ID of the `Group` to be moved. * @param parentTargetId The ID of the `Group` that should be the new parent group. */ - moveSubgroup(id: number, parentTargetId: number): Observable> { + moveSubgroup(id: string | number, parentTargetId: number): Observable> { return this.api.group.moveSubgroup(id, parentTargetId).pipe( map(response => response.group), switchMap(movedGroup => diff --git a/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.html b/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.html index ffeb813b4..91fdaee4c 100644 --- a/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.html @@ -8,8 +8,8 @@
{{ constructs?.length === 1 ? ('modal.assign_construct_to_nodes_title' | i18 [showSearch]="true" [hideActions]="true" [disabled]="loading" - [selected]="selectedIds" - (selectedChange)="selectionChange($event)" + [useSelectionMap]="true" + [(selected)]="selected" > diff --git a/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.ts b/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.ts index 3b335e442..f36e15b27 100644 --- a/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.ts +++ b/cms-ui/apps/admin-ui/src/app/features/construct/components/assign-constructs-to-nodes-modal/assign-constructs-to-nodes-modal.component.ts @@ -1,9 +1,8 @@ import { ConstructBO } from '@admin-ui/common'; import { ConstructHandlerService, I18nNotificationService, NodeOperations } from '@admin-ui/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { EntityIdType, IndexById, Node, Raw, TagTypeBO } from '@gentics/cms-models'; -import { BaseModal } from '@gentics/ui-core'; -import { intersection } from'lodash-es' +import { IndexById, Node, Raw } from '@gentics/cms-models'; +import { BaseModal, CHECKBOX_STATE_INDETERMINATE, TableSelection, toSelectionArray } from '@gentics/ui-core'; import { Subscription, forkJoin } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -13,18 +12,21 @@ import { map } from 'rxjs/operators'; styleUrls: ['./assign-constructs-to-nodes-modal.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class AssignConstructsToNodesModalComponent extends BaseModal implements OnInit, OnDestroy { +export class AssignConstructsToNodesModalComponent extends BaseModal implements OnInit, OnDestroy { @Input() - public constructs: (TagTypeBO | ConstructBO)[] = []; + public constructs: ConstructBO[] = []; public loading = false; - public selectedIds: string[] = []; + public selected: TableSelection = {}; protected nodes: IndexById> = {}; - protected selectedPerConstruct: { [constructId: EntityIdType]: string[] } = {}; + /** + * @key nodeId + */ + protected currentAssignment: Record> = null; - private subscription: Subscription = new Subscription(); + private subscriptions: Subscription[] = []; constructor( private changeDetector: ChangeDetectorRef, @@ -36,77 +38,81 @@ export class AssignConstructsToNodesModalComponent extends BaseModal imple } ngOnInit(): void { - this.loadNodes(); - } + this.subscriptions.push(forkJoin([ + this.nodeOperations.getAll(), + forkJoin(this.constructs.map(con => this.handler.getLinkedNodes(con.id).pipe( + map(linked => [con.id, linked]), + ))), + ]).subscribe(([loadedNodes, links]: [Node[], [number, Node[]][]]) => { + const assignment: Record> = {}; + const newSelection: TableSelection = {}; + + // Create a reverse mapping + for (const [constructId, linkedNodes] of links) { + for (const linkedNode of linkedNodes) { + if (!assignment[linkedNode.id]) { + assignment[linkedNode.id] = new Set(); + } + assignment[linkedNode.id].add(constructId); + } + } - ngOnDestroy(): void { - if (this.subscription) { - this.subscription.unsubscribe(); - } - } + // Check each selection state + for (const node of loadedNodes) { + this.nodes[node.id] = node; + const assignCount = assignment[node.id]?.size ?? 0; - loadNodes(): void { - this.loading = true; - this.selectedPerConstruct = {}; - this.changeDetector.markForCheck(); + switch (assignCount) { + case 0: + newSelection[node.id] = false; + break; - // Nodes are loaded here since this might be the first module which is being opened, - // and the nodes are therefore not yet in the state. Would otherwise not display anything - // in the list then. - this.subscription.add(forkJoin([ - this.nodeOperations.getAll(), - ...this.constructs.map(con => this.handler.getLinkedNodes(con.id).pipe( - map(linked => ([con.id, linked])), - )), - ]).subscribe(([nodes, ...linkedNodesPerConstruct]) => { - this.nodes = {}; - nodes.forEach(node => this.nodes[node.id] = node); - - const links = (linkedNodesPerConstruct as [EntityIdType, Node[]][]).map(([constructId, linkedNodes]) => { - const nodeIds = linkedNodes.map(node => `${node.id}`); - this.selectedPerConstruct[constructId] = nodeIds; - return nodeIds; - }); - - // Gives us a unique list of all nodes which are selected by all constructs - this.selectedIds = Array.from(new Set(intersection(...links))); - this.loading = false; + case this.constructs.length: + newSelection[node.id] = true; + break; + + default: + newSelection[node.id] = CHECKBOX_STATE_INDETERMINATE; + break; + } + } + + // Apply new values + this.selected = newSelection; + this.currentAssignment = assignment; this.changeDetector.markForCheck(); - }, err => { - console.error(err); - this.notification.show({ - type: 'alert', - message: 'common.loading_error', - }); - this.cancelFn(); })); } - selectionChange(newSelection: string[]): void { - this.selectedIds = newSelection; + ngOnDestroy(): void { + this.subscriptions.forEach(s => s.unsubscribe()); } async okButtonClicked(): Promise { + this.closeFn(await this.applySelection()); + } + + async applySelection(): Promise { this.loading = true; this.changeDetector.markForCheck(); - const addSuccess = new Set(); - const removeSucess = new Set(); - for (const construct of this.constructs) { - const toAdd = new Set(this.selectedIds); - const toRemove = new Set(this.selectedPerConstruct[construct.id]); + const addSuccess = new Set(); + const removeSucess = new Set(); + let didChange = false; - for (const alreadAssigned of this.selectedPerConstruct[construct.id]) { - toAdd.delete(alreadAssigned); - } - for (const stillAssigned of this.selectedIds) { - toRemove.delete(stillAssigned); - } + for (const construct of this.constructs) { + const toAdd = new Set(toSelectionArray(this.selected).map(Number)); + const toRemove = new Set(toSelectionArray(this.selected, false).map(Number)); for (const nodeToAdd of toAdd) { + if (this.currentAssignment[nodeToAdd]?.has?.(construct.id)) { + continue; + } + try { - await this.handler.linkToNode(construct.id, Number(nodeToAdd)).toPromise(); + await this.handler.linkToNode(construct.id, nodeToAdd).toPromise(); addSuccess.add(nodeToAdd); + didChange = true; } catch (err) { this.notification.show({ type: 'alert', @@ -121,9 +127,14 @@ export class AssignConstructsToNodesModalComponent extends BaseModal imple } for (const nodeToRemove of toRemove) { + if (!this.currentAssignment[nodeToRemove]?.has?.(construct.id)) { + continue; + } + try { - await this.handler.unlinkFromNode(construct.id, Number(nodeToRemove)).toPromise(); + await this.handler.unlinkFromNode(construct.id, nodeToRemove).toPromise(); removeSucess.add(nodeToRemove); + didChange = true; } catch (err) { this.notification.show({ type: 'alert', @@ -182,6 +193,7 @@ export class AssignConstructsToNodesModalComponent extends BaseModal imple this.loading = false; this.changeDetector.markForCheck(); - this.closeFn(); + + return didChange; } } diff --git a/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-category-table/construct-category-table.component.html b/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-category-table/construct-category-table.component.html index 453d2e06f..43f0073a9 100644 --- a/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-category-table/construct-category-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-category-table/construct-category-table.component.html @@ -45,7 +45,7 @@
- {{ 'construct_category.info_selected_categories' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'construct_category.info_selected_categories' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-master/construct-master.component.ts b/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-master/construct-master.component.ts index e7507e529..4be716b69 100644 --- a/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-master/construct-master.component.ts +++ b/cms-ui/apps/admin-ui/src/app/features/construct/components/construct-master/construct-master.component.ts @@ -1,5 +1,5 @@ import { BO_PERMISSIONS, ConstructBO, EditableEntity, EntityTableActionClickEvent } from '@admin-ui/common'; -import { ConstructHandlerService, ConstructTableLoaderService, I18nNotificationService, I18nService } from '@admin-ui/core'; +import { ConstructHandlerService, ConstructTableLoaderService, ErrorHandler, I18nNotificationService, I18nService } from '@admin-ui/core'; import { ASSIGN_CONSTRUCT_TO_CATEGORY_ACTION, ASSIGN_CONSTRUCT_TO_NODES_ACTION, COPY_CONSTRUCT_ACTION } from '@admin-ui/shared'; import { BaseTableMasterComponent } from '@admin-ui/shared/components/base-table-master/base-table-master.component'; import { AppStateService } from '@admin-ui/state'; @@ -37,6 +37,7 @@ export class ConstructMasterComponent extends BaseTableMasterComponent 0; + res.valid = res.valid && constructs.length > 0; return res; } @@ -147,13 +148,21 @@ export class ConstructMasterComponent extends BaseTableMasterComponent { diff --git a/cms-ui/apps/admin-ui/src/app/features/content-maintenance/components/dirt-queue-item-table/dirt-queue-item-table.component.html b/cms-ui/apps/admin-ui/src/app/features/content-maintenance/components/dirt-queue-item-table/dirt-queue-item-table.component.html index 469c4f7d5..2824b104e 100644 --- a/cms-ui/apps/admin-ui/src/app/features/content-maintenance/components/dirt-queue-item-table/dirt-queue-item-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/content-maintenance/components/dirt-queue-item-table/dirt-queue-item-table.component.html @@ -32,7 +32,7 @@
- {{ 'contentmaintenance.info_selected_tasks' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'contentmaintenance.info_selected_tasks' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/content-staging/components/content-package-table/content-package-table.component.html b/cms-ui/apps/admin-ui/src/app/features/content-staging/components/content-package-table/content-package-table.component.html index ec60ac860..7e265bc4c 100644 --- a/cms-ui/apps/admin-ui/src/app/features/content-staging/components/content-package-table/content-package-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/content-staging/components/content-package-table/content-package-table.component.html @@ -32,7 +32,7 @@
- {{ 'content_staging.info_selected_content_packages' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'content_staging.info_selected_content_packages' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/data-source/components/data-source-entry-table/data-source-entry-table.component.html b/cms-ui/apps/admin-ui/src/app/features/data-source/components/data-source-entry-table/data-source-entry-table.component.html index cb38c3d5b..42d383742 100644 --- a/cms-ui/apps/admin-ui/src/app/features/data-source/components/data-source-entry-table/data-source-entry-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/data-source/components/data-source-entry-table/data-source-entry-table.component.html @@ -34,7 +34,7 @@
- {{ 'dataSourceEntry.info_selected_dataSourceentries' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'dataSourceEntry.info_selected_dataSourceentries' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/elastic-search-index/components/elastic-search-index-table/elastic-search-index-table.component.html b/cms-ui/apps/admin-ui/src/app/features/elastic-search-index/components/elastic-search-index-table/elastic-search-index-table.component.html index 83bff089c..617d2d670 100644 --- a/cms-ui/apps/admin-ui/src/app/features/elastic-search-index/components/elastic-search-index-table/elastic-search-index-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/elastic-search-index/components/elastic-search-index-table/elastic-search-index-table.component.html @@ -21,7 +21,7 @@
- {{ 'elasticSearchIndex.info_selected_indices' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'elasticSearchIndex.info_selected_indices' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/logs/components/action-log-entry-table/action-log-entry-table.component.html b/cms-ui/apps/admin-ui/src/app/features/logs/components/action-log-entry-table/action-log-entry-table.component.html index be9ee4115..77723acd0 100644 --- a/cms-ui/apps/admin-ui/src/app/features/logs/components/action-log-entry-table/action-log-entry-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/logs/components/action-log-entry-table/action-log-entry-table.component.html @@ -23,7 +23,7 @@
- {{ 'logs.info_selected_logs' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'logs.info_selected_logs' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.html b/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.html index d4fce6748..0b5196ff9 100644 --- a/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.html @@ -66,9 +66,9 @@

>{{ field.value == null ? 'question_mark' : (field.value ? 'check' : 'close') }} -
+
share - {{ field.value.displayName || field.value.uuid }} + {{ field.value?.displayName || field.value?.uuid }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.ts b/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.ts index 4a4658762..bb1215ae2 100644 --- a/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.ts +++ b/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-editor/mesh-browser-editor.component.ts @@ -71,6 +71,10 @@ export class MeshBrowserEditorComponent implements OnChanges { } public loadNode(nodeUuid: string): void { + if (nodeUuid == null) { + return; + } + this.navigator.navigateToDetails(this.route, { project: this.project, branch: this.branch, diff --git a/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-repository-table/mesh-browser-repository-table.component.html b/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-repository-table/mesh-browser-repository-table.component.html index 19c98b3d3..50d370120 100644 --- a/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-repository-table/mesh-browser-repository-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/mesh-browser/components/mesh-browser-repository-table/mesh-browser-repository-table.component.html @@ -10,7 +10,7 @@ -->
- {{ 'contentRepository.info_selected_contentrepositories' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'contentRepository.info_selected_contentrepositories' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/object-property/components/object-property-category-table/object-property-category-table.component.html b/cms-ui/apps/admin-ui/src/app/features/object-property/components/object-property-category-table/object-property-category-table.component.html index 4c7449899..e8badd3e2 100644 --- a/cms-ui/apps/admin-ui/src/app/features/object-property/components/object-property-category-table/object-property-category-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/object-property/components/object-property-category-table/object-property-category-table.component.html @@ -33,7 +33,7 @@
- {{ 'objectProperty.info_selected_objectPropertycategories' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'objectProperty.info_selected_objectPropertycategories' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/role/components/role-table/role-table.component.html b/cms-ui/apps/admin-ui/src/app/features/role/components/role-table/role-table.component.html index 3f342adbd..bf34c8bda 100644 --- a/cms-ui/apps/admin-ui/src/app/features/role/components/role-table/role-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/role/components/role-table/role-table.component.html @@ -33,7 +33,7 @@
- {{ 'role.info_selected_roles' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'role.info_selected_roles' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-executions-table/schedule-executions-table.component.html b/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-executions-table/schedule-executions-table.component.html index cefb4edba..4fa086068 100644 --- a/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-executions-table/schedule-executions-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-executions-table/schedule-executions-table.component.html @@ -10,7 +10,7 @@
- {{ 'scheduler.info_selected_schedules' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'scheduler.info_selected_schedules' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-table/schedule-table.component.html b/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-table/schedule-table.component.html index 67cf69d7b..f483afe28 100644 --- a/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-table/schedule-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-table/schedule-table.component.html @@ -55,7 +55,7 @@
- {{ 'scheduler.info_selected_schedules' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'scheduler.info_selected_schedules' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-task-table/schedule-task-table.component.html b/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-task-table/schedule-task-table.component.html index c17255974..0b823fa46 100644 --- a/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-task-table/schedule-task-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/scheduler/components/schedule-task-table/schedule-task-table.component.html @@ -33,7 +33,7 @@
- {{ 'scheduler.info_selected_schedules' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'scheduler.info_selected_schedules' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.html b/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.html index a93dc93db..ce57c5620 100644 --- a/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.html @@ -10,8 +10,8 @@

{{ 'modal.manage_templates_assignments_to_nodes_title' | i18n }}
class="modal-table" [showSearch]="true" [hideActions]="true" - [selected]="selectedIds" - (selectedChange)="selectionChange($event)" + [useSelectionMap]="true" + [(selected)]="selected" > @@ -25,7 +25,7 @@
{{ 'modal.manage_templates_assignments_to_nodes_title' | i18n }}
{{ 'common.close_button' | i18n }} diff --git a/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.ts b/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.ts index f7df86ecb..07a8ec874 100644 --- a/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.ts +++ b/cms-ui/apps/admin-ui/src/app/features/template/components/assign-templates-to-nodes-modal/assign-templates-to-nodes-modal.component.ts @@ -1,9 +1,9 @@ import { TemplateBO } from '@admin-ui/common'; -import { I18nNotificationService, NodeOperations, NodeTableLoaderService, TemplateOperations } from '@admin-ui/core'; +import { I18nNotificationService, NodeOperations, TemplateOperations } from '@admin-ui/core'; import { NodeDataService } from '@admin-ui/shared'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { EntityIdType, IndexById, Node, Raw } from '@gentics/cms-models'; -import { BaseModal } from '@gentics/ui-core'; +import { IndexById, Node, Raw } from '@gentics/cms-models'; +import { BaseModal, CHECKBOX_STATE_INDETERMINATE, TableSelection, toSelectionArray } from '@gentics/ui-core'; import { combineLatest, forkJoin, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -13,23 +13,25 @@ import { map } from 'rxjs/operators'; styleUrls: ['./assign-templates-to-nodes-modal.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class AssignTemplatesToNodesModalComponent extends BaseModal implements OnInit, OnDestroy { +export class AssignTemplatesToNodesModalComponent extends BaseModal implements OnInit, OnDestroy { @Input() public templates: TemplateBO[] = []; public loading = false; - public selectedIds: string[] = []; + public selected: TableSelection = {}; protected nodes: IndexById> = {}; - protected selectedPerTemplate: { [templateId: EntityIdType]: number[] } = {}; + /** + * @key nodeId + */ + protected currentAssignment: Record> = {}; protected subscriptions: Subscription[] = []; constructor( protected changeDetector: ChangeDetectorRef, protected nodeData: NodeDataService, protected nodeOperations: NodeOperations, - protected nodeTableLoader: NodeTableLoaderService, protected notification: I18nNotificationService, protected templateOperations: TemplateOperations, ) { @@ -40,51 +42,52 @@ export class AssignTemplatesToNodesModalComponent extends BaseModal implem this.loading = true; this.changeDetector.markForCheck(); - this.subscriptions.push(combineLatest([this.nodeData.watchAllEntities(), forkJoin(this.templates.map(template => { - // for every template, get the list of nodes to which the template is assigned - return this.templateOperations.getLinkedNodes(template.id).pipe( - map(linkedNodes => [template, linkedNodes]), - ); - }))], - ).subscribe(([nodes, templateData]: [Node[], [template: TemplateBO, linkedNodes: Node[]][]]) => { - const nodeIds: number[] = []; + this.subscriptions.push(combineLatest([ + this.nodeData.watchAllEntities(), + forkJoin(this.templates.map(template => { + // for every template, get the list of nodes to which the template is assigned + return this.templateOperations.getLinkedNodes(template.id).pipe( + map(linkedNodes => [template, linkedNodes]), + ); + })), + ]).subscribe(([allNodes, templateData]: [Node[], [template: TemplateBO, linkedNodes: Node[]][]]) => { + const assignment: Record> = {}; + const newSelection: TableSelection = {}; this.nodes = {}; - nodes.forEach(node => { - this.nodes[node.id] = node; - nodeIds.push(node.id); - }); - - const newSelection = new Set(); - const templateIds = this.templates.map(t => Number(t.id)); - - // for every template, collect the node IDs to which the template is assigned - this.selectedPerTemplate = {}; - templateData.forEach(([template, linkedNodes]) => { - linkedNodes.forEach(node => { - const templateId = Number(template.id); - const nodeId = Number(node.id); - this.selectedPerTemplate[templateId] = this.selectedPerTemplate[templateId] ?? []; - this.selectedPerTemplate[templateId].push(nodeId); - }); - }); - - // for every node, check whether all given templates are assigned - nodeIds.forEach(nodeId => { - let nodeHasAllTemplates = true; - for (const id of templateIds) { - if (!this.selectedPerTemplate[id] || !this.selectedPerTemplate[id].includes(nodeId)) { - nodeHasAllTemplates = false; - break; + + // Create a reverse mapping + for (const [template, linkedNodes] of templateData) { + for (const node of linkedNodes) { + if (!assignment[node.id]) { + assignment[node.id] = new Set(); } + assignment[node.id].add(template.id); } + } + + // Check each nodes selection state + for (const node of allNodes) { + this.nodes[node.id] = node; + const templateCount = assignment[node.id]?.size ?? 0; - // If a node contains all templates, then it should be marked as selected in the list - if (nodeHasAllTemplates) { - newSelection.add(nodeId.toString()); + switch (templateCount) { + case 0: + newSelection[node.id] = false; + break; + + case this.templates.length: + newSelection[node.id] = true; + break; + + default: + newSelection[node.id] = CHECKBOX_STATE_INDETERMINATE; + break; } - }); + } + + this.selected = newSelection; + this.currentAssignment = assignment; - this.selectedIds = Array.from(newSelection); this.loading = false; this.changeDetector.markForCheck(); })); @@ -94,32 +97,31 @@ export class AssignTemplatesToNodesModalComponent extends BaseModal implem this.subscriptions.forEach(s => s.unsubscribe()); } - selectionChange(newSelection: string[]): void { - this.selectedIds = newSelection; + async okButtonClicked(): Promise { + this.closeFn(await this.applySelection()); } - async okButtonClicked(): Promise { + async applySelection(): Promise { this.loading = true; this.changeDetector.markForCheck(); - const addSuccess = new Set(); - const removeSucess = new Set(); - for (const template of this.templates) { - const toAdd = new Set(this.selectedIds); - const nodeIds = this.selectedPerTemplate[template.id].map(id => id.toString()) - const toRemove = new Set(nodeIds); + const addSuccess = new Set(); + const removeSucess = new Set(); + let didChange = false; - for (const alreadAssigned of nodeIds) { - toAdd.delete(alreadAssigned); - } - for (const stillAssigned of this.selectedIds) { - toRemove.delete(stillAssigned); - } + for (const template of this.templates) { + const toAdd = new Set(toSelectionArray(this.selected).map(Number)); + const toRemove = new Set(toSelectionArray(this.selected, false).map(Number)); for (const nodeToAdd of toAdd) { + if (this.currentAssignment[nodeToAdd]?.has?.(template.id)) { + continue; + } + try { await this.nodeOperations.linkTemplate(nodeToAdd, template.id).toPromise(); addSuccess.add(nodeToAdd); + didChange = true; } catch (err) { this.notification.show({ type: 'alert', @@ -135,9 +137,14 @@ export class AssignTemplatesToNodesModalComponent extends BaseModal implem } for (const nodeToRemove of toRemove) { + if (!this.currentAssignment[nodeToRemove]?.has?.(template.id)) { + continue; + } + try { await this.nodeOperations.unlinkTemplate(nodeToRemove, template.id).toPromise(); removeSucess.add(nodeToRemove); + didChange = true; } catch (err) { this.notification.show({ type: 'alert', @@ -195,9 +202,9 @@ export class AssignTemplatesToNodesModalComponent extends BaseModal implem } } - this.nodeTableLoader.reload(); this.loading = false; this.changeDetector.markForCheck(); - this.closeFn(); + + return didChange; } } diff --git a/cms-ui/apps/admin-ui/src/app/features/template/components/template-master/template-master.component.ts b/cms-ui/apps/admin-ui/src/app/features/template/components/template-master/template-master.component.ts index edda772d4..63d438f00 100644 --- a/cms-ui/apps/admin-ui/src/app/features/template/components/template-master/template-master.component.ts +++ b/cms-ui/apps/admin-ui/src/app/features/template/components/template-master/template-master.component.ts @@ -204,7 +204,11 @@ export class TemplateMasterComponent extends BaseTableMasterComponent { + if (didChange) { + this.loader.reload(); + } + }); return; case Action.LOCALIZE: @@ -257,10 +261,10 @@ export class TemplateMasterComponent extends BaseTableMasterComponent { + protected async linkTemplatesToNodes(templates: TemplateBO[]): Promise { // Can't open without selection if (templates.length === 0) { - return; + return false; } let doAbort = false; @@ -278,7 +282,7 @@ export class TemplateMasterComponent extends BaseTableMasterComponent { @@ -361,7 +365,6 @@ export class TemplateMasterComponent extends BaseTableMasterComponent this.operations.unlocalizeTemplate(templateId, options), 'template.unlocalize_success'); } - private executeTemplateOperation( templates: TemplateBO[], operation: (id: number, options: LocalizeRequest | UnlocalizeRequest) => Observable, @@ -393,7 +396,6 @@ export class TemplateMasterComponent extends BaseTableMasterComponent
- {{ 'templateTag.info_selected_tags' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'templateTag.info_selected_tags' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/features/template/components/template-tag-table/template-tag-table.component.html b/cms-ui/apps/admin-ui/src/app/features/template/components/template-tag-table/template-tag-table.component.html index 231300322..d571530dc 100644 --- a/cms-ui/apps/admin-ui/src/app/features/template/components/template-tag-table/template-tag-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/features/template/components/template-tag-table/template-tag-table.component.html @@ -32,7 +32,7 @@
- {{ 'templateTag.info_selected_tags' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'templateTag.info_selected_tags' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-group-table/mesh-group-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-group-table/mesh-group-table.component.html index ed91d5380..9772b8cfc 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-group-table/mesh-group-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-group-table/mesh-group-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_groups' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_groups' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-role-table/mesh-role-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-role-table/mesh-role-table.component.html index 0beb33c91..2d2682ba6 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-role-table/mesh-role-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-role-table/mesh-role-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_roles' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_roles' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-user-table/mesh-user-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-user-table/mesh-user-table.component.html index 88bebc14c..43599ac6c 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-user-table/mesh-user-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/mesh-user-table/mesh-user-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_users' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_users' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/microschema-table/microschema-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/microschema-table/microschema-table.component.html index 74701b2db..dbad30ca3 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/microschema-table/microschema-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/microschema-table/microschema-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_microschemas' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_microschemas' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/project-table/project-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/project-table/project-table.component.html index 3699b311b..020640590 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/project-table/project-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/project-table/project-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_projects' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_projects' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/schema-table/schema-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/schema-table/schema-table.component.html index 0fcceec44..b20773631 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/schema-table/schema-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/schema-table/schema-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_schemas' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_schemas' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/tag-family-table/tag-family-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/tag-family-table/tag-family-table.component.html index aa8acf467..2651bebcb 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/tag-family-table/tag-family-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/tag-family-table/tag-family-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_tag_families' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_tag_families' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/mesh/components/tag-table/tag-table.component.html b/cms-ui/apps/admin-ui/src/app/mesh/components/tag-table/tag-table.component.html index 6c10d86e7..a41568f48 100644 --- a/cms-ui/apps/admin-ui/src/app/mesh/components/tag-table/tag-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/mesh/components/tag-table/tag-table.component.html @@ -32,7 +32,7 @@
- {{ 'mesh.info_selected_tags' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'mesh.info_selected_tags' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.html index eaa5b621e..325154185 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.html @@ -1,27 +1,26 @@ -
- + - + - diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.ts b/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.ts index 6f74c6018..f50526ee6 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.ts +++ b/cms-ui/apps/admin-ui/src/app/shared/components/assign-node-restriction-to-object-properties-modal/assign-node-restriction-to-object-properties-modal.component.ts @@ -1,54 +1,141 @@ -import { ObjectPropertyBO } from '@admin-ui/common'; -import { ObjectPropertyHandlerService } from '@admin-ui/core'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { EntityIdType, Node, Raw } from '@gentics/cms-models'; -import { BaseModal } from '@gentics/ui-core'; -import { BehaviorSubject } from 'rxjs'; -import { delay } from 'rxjs/operators'; +import { ErrorHandler, NodeOperations, ObjectPropertyHandlerService } from '@admin-ui/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { IndexById, Node, Raw } from '@gentics/cms-models'; +import { BaseModal, CHECKBOX_STATE_INDETERMINATE, TableSelection, toSelectionArray } from '@gentics/ui-core'; +import { forkJoin, Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; @Component({ selector: 'gtx-assign-node-restriction-to-object-properties-modal', templateUrl: './assign-node-restriction-to-object-properties-modal.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class AssignNodeRestrictionsToObjectPropertiesModalComponent extends BaseModal implements OnInit { +export class AssignNodeRestrictionsToObjectPropertiesModalComponent extends BaseModal implements OnInit, OnDestroy { /** IDs of objectproperties to be (un)assigned to/from groups */ - objectProperty: ObjectPropertyBO; + @Input() + public objectProperties: number[] = []; - /** IDs of nodes to be (un)assigned to/from groups */ - nodeIdsInitial: EntityIdType[]; - nodeIdsSelected: EntityIdType[]; + public loading = false; + public selected: TableSelection = {}; - /** Is TRUE if a logged-in user examines Node restrictions of a user whose restricted Nodes they're not have permission to read. */ - hiddenNodeIdsExist$ = new BehaviorSubject(false); + protected nodes: IndexById> = {}; + /** + * @key nodeId + */ + protected currentAssignment: Record> = null; + + private subscriptions: Subscription[] = []; constructor( protected changeDetector: ChangeDetectorRef, private handler: ObjectPropertyHandlerService, + private nodeOps: NodeOperations, + private errorHandler: ErrorHandler, ) { super(); } ngOnInit(): void { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - this.handler.getLinkedNodes(this.objectProperty.globalId).pipe( - delay(0), - ).subscribe((res: Node[]) => { - this.nodeIdsSelected = res.map(n => n.id); - this.nodeIdsInitial = res.map(n => n.id); + this.subscriptions.push(forkJoin([ + this.nodeOps.getAll(), + forkJoin(this.objectProperties.map(op => this.handler.getLinkedNodes(op).pipe( + map(list => [op, list]), + ))), + ]).subscribe(([loadedNodes, links]: [Node[], [number, Node[]][]]) => { + const assignment: Record> = {}; + const newSelection: TableSelection = {}; + + // Create a reverse mapping + for (const [opId, linkedNodes] of links) { + for (const linkedNode of linkedNodes) { + if (!assignment[linkedNode.id]) { + assignment[linkedNode.id] = new Set(); + } + assignment[linkedNode.id].add(opId); + } + } + + // Check each selection state + for (const node of loadedNodes) { + this.nodes[node.id] = node; + const assignCount = assignment[node.id]?.size ?? 0; + + switch (assignCount) { + case 0: + newSelection[node.id] = false; + break; + + case this.objectProperties.length: + newSelection[node.id] = true; + break; + + default: + newSelection[node.id] = CHECKBOX_STATE_INDETERMINATE; + break; + } + } + + // Apply new values + this.selected = newSelection; + this.currentAssignment = assignment; this.changeDetector.markForCheck(); - }); + })); + } + + ngOnDestroy(): void { + this.subscriptions.forEach(s => s.unsubscribe()); } /** * If user clicks "assign" */ - buttonAssignNodeRestrictonsClicked(): void { - this.handler.changeNodeRestrictions(this.objectProperty.globalId, this.nodeIdsSelected, this.nodeIdsInitial) - .toPromise() - .then(() => { - this.closeFn(); - }); + async buttonAssignNodeRestrictonsClicked(): Promise { + this.closeFn(await this.assignSelection()); + } + + private async assignSelection(): Promise { + this.loading = true; + this.changeDetector.markForCheck(); + let didChange = false; + + for (const opId of this.objectProperties) { + const toAdd = new Set(toSelectionArray(this.selected).map(Number)); + const toRemove = new Set(toSelectionArray(this.selected, false).map(Number)); + + for (const nodeToAdd of toAdd) { + if (this.currentAssignment[nodeToAdd]?.has?.(opId)) { + toAdd.delete(nodeToAdd); + } + } + + if (toAdd.size > 0) { + try { + await this.handler.addNodeRestriction([opId], Array.from(toAdd)).toPromise(); + } catch (err) { + this.errorHandler.catch(err); + } + } + + for (const nodeToRemove of toRemove) { + if (!this.currentAssignment[nodeToRemove]?.has?.(opId)) { + toRemove.delete(nodeToRemove); + } + } + + if (toRemove.size > 0) { + try { + await this.handler.removeNodeRestriction([opId], Array.from(toRemove)).toPromise(); + didChange = true; + } catch (err) { + this.errorHandler.catch(err); + } + } + } + + this.loading = false; + this.changeDetector.markForCheck(); + + return didChange; } } diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/assign-user-to-groups-modal/assign-user-to-groups-modal.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/assign-user-to-groups-modal/assign-user-to-groups-modal.component.html index e78730a35..6f9ef8d59 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/assign-user-to-groups-modal/assign-user-to-groups-modal.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/assign-user-to-groups-modal/assign-user-to-groups-modal.component.html @@ -1,8 +1,5 @@
- {{ 'construct.info_selected_constructs' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'construct.info_selected_constructs' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/content-repository-table/content-repository-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/content-repository-table/content-repository-table.component.html index 96fe74c0e..9915419d7 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/content-repository-table/content-repository-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/content-repository-table/content-repository-table.component.html @@ -48,7 +48,7 @@
- {{ 'contentRepository.info_selected_contentrepositories' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'contentRepository.info_selected_contentrepositories' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/cr-fragment-table/cr-fragment-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/cr-fragment-table/cr-fragment-table.component.html index ee24429c3..bb5e5704b 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/cr-fragment-table/cr-fragment-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/cr-fragment-table/cr-fragment-table.component.html @@ -48,7 +48,7 @@
- {{ 'contentRepositoryFragment.info_selected_contentRepositoryFragment' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'contentRepositoryFragment.info_selected_contentRepositoryFragment' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/data-source-table/data-source-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/data-source-table/data-source-table.component.html index 1b3ed345d..204e9abc4 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/data-source-table/data-source-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/data-source-table/data-source-table.component.html @@ -48,7 +48,7 @@
- {{ 'dataSource.info_selected_dataSources' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'dataSource.info_selected_dataSources' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/dev-tool-package-table/dev-tool-package-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/dev-tool-package-table/dev-tool-package-table.component.html index 911aea56f..dd6490b4c 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/dev-tool-package-table/dev-tool-package-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/dev-tool-package-table/dev-tool-package-table.component.html @@ -61,7 +61,7 @@
- {{ 'package.info_selected_packages' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'package.info_selected_packages' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.html index 2e2d81c36..8ccca70ae 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.html @@ -34,7 +34,7 @@
- {{ 'shared.info_selected_groups' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'shared.info_selected_groups' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
@@ -51,6 +51,7 @@ [rows]="rows" [actions]="actions" [selected]="selected" + [useSelectionMap]="useSelectionMap" [active]="activeEntity" [totalCount]="totalCount" diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.ts b/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.ts index 27f0017f5..8a6d318bd 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.ts +++ b/cms-ui/apps/admin-ui/src/app/shared/components/group-table/group-table.component.ts @@ -140,7 +140,7 @@ export class GroupTableComponent extends BaseEntityTableComponent, Gr return; case MOVE_MULTIPLE_GROUPS_ACTION: - this.moveGroups(this.selected.map(id => Number(id))); + this.moveGroups(this.getAffectedEntityIds(event)); return; case MOVE_SINGLE_GROUP_ACTION: @@ -177,7 +177,7 @@ export class GroupTableComponent extends BaseEntityTableComponent, Gr } } - protected async moveGroups(entityIds: number[]): Promise { + protected async moveGroups(entityIds: (string | number)[]): Promise { // if no row is selected, display modal if (!entityIds || entityIds.length < 1) { // this.notificationNoneSelected(); diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/language-table/language-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/language-table/language-table.component.html index d6f4d689a..1ccb13c96 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/language-table/language-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/language-table/language-table.component.html @@ -47,7 +47,7 @@
- {{ 'shared.info_active_languages' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'shared.info_active_languages' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/move-groups-modal/move-groups-modal.component.ts b/cms-ui/apps/admin-ui/src/app/shared/components/move-groups-modal/move-groups-modal.component.ts index 63e5ee05e..1ed62cdb1 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/move-groups-modal/move-groups-modal.component.ts +++ b/cms-ui/apps/admin-ui/src/app/shared/components/move-groups-modal/move-groups-modal.component.ts @@ -14,7 +14,7 @@ import { mergeMap } from 'rxjs/operators'; export class MoveGroupsModalComponent extends BaseModal[] | boolean> { /** IDs of groups to be moved */ - sourceGroupIds: number[] = []; + sourceGroupIds: (string | number)[] = []; /** IDs of groups the source groups shall be moved to */ targetGroupId: number; diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/node-table/node-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/node-table/node-table.component.html index 2b163bca5..86d6f5965 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/node-table/node-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/node-table/node-table.component.html @@ -33,7 +33,7 @@
- {{ 'shared.info_selected_nodes' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'shared.info_selected_nodes' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
@@ -50,6 +50,7 @@ [rows]="rows" [actions]="actions" [selected]="selected" + [useSelectionMap]="useSelectionMap" [active]="activeEntity" [totalCount]="totalCount" diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.html index 09b5a9de3..ba7ff1dd3 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.html @@ -48,7 +48,7 @@
- {{ 'objectProperty.info_selected_objectproperties' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'objectProperty.info_selected_objectproperties' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.ts b/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.ts index 2344503e4..a4b769325 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.ts +++ b/cms-ui/apps/admin-ui/src/app/shared/components/object-property-table/object-property-table.component.ts @@ -1,6 +1,7 @@ import { AdminUIEntityDetailRoutes, EditableEntity, ObjectPropertyBO } from '@admin-ui/common'; import { DevToolPackageTableLoaderService, + ErrorHandler, I18nService, ObjectPropertyTableLoaderOptions, ObjectPropertyTableLoaderService, @@ -79,6 +80,7 @@ export class ObjectPropertyTableComponent contextMenu: ContextMenuService, packageTableLoader: DevToolPackageTableLoaderService, protected permissions: PermissionsService, + protected errorHandler: ErrorHandler, ) { super( changeDetector, @@ -125,6 +127,7 @@ export class ObjectPropertyTableComponent type: 'primary', enabled: canDeleteAndEdit, single: true, + multiple: true, }, { id: DELETE_ACTION, @@ -175,19 +178,31 @@ export class ObjectPropertyTableComponent public override handleAction(event: TableActionClickEvent): void { switch (event.actionId) { case ASSIGN_TO_NODES_ACTION: - this.setObjectpropertyNodeRestrictions(event.item); + this.setObjectpropertyNodeRestrictions(this.getAffectedEntityIds(event).map(Number)); return; } super.handleAction(event); } - protected async setObjectpropertyNodeRestrictions(objectProperty: ObjectPropertyBO): Promise { - const dialog = await this.modalService.fromComponent( - AssignNodeRestrictionsToObjectPropertiesModalComponent, - { closeOnOverlayClick: false, width: '75%' }, - { objectProperty }, - ); - await dialog.open(); + protected async setObjectpropertyNodeRestrictions(ids: number[]): Promise { + if (ids == null || ids.length === 0) { + return; + } + + try { + const dialog = await this.modalService.fromComponent( + AssignNodeRestrictionsToObjectPropertiesModalComponent, + { closeOnOverlayClick: false, width: '75%' }, + { objectProperties: ids }, + ); + const didChange = await dialog.open(); + + if (didChange) { + this.reload(); + } + } catch (err) { + this.errorHandler.catch(err); + } } } diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/tag-map-entry-table/tag-map-entry-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/tag-map-entry-table/tag-map-entry-table.component.html index e01200fab..dfd77ebbd 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/tag-map-entry-table/tag-map-entry-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/tag-map-entry-table/tag-map-entry-table.component.html @@ -32,7 +32,7 @@
- {{ 'tagmapEntry.info_selected_tagmapEntry' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'tagmapEntry.info_selected_tagmapEntry' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/template-table/template-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/template-table/template-table.component.html index 8ea5b2fc9..89bf82154 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/template-table/template-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/template-table/template-table.component.html @@ -48,7 +48,7 @@
- {{ 'template.info_selected_templates' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'template.info_selected_templates' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.html b/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.html index 99a4aac49..9fcc22b50 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.html +++ b/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.html @@ -46,7 +46,7 @@
- {{ 'shared.info_selected_users' | i18n:{ amountSelected: selected?.length, amountTotal: totalCount } }} + {{ 'shared.info_selected_users' | i18n:{ amountSelected: selectedCount, amountTotal: totalCount } }}
diff --git a/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.ts b/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.ts index 4341ef479..b1bfcb881 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.ts +++ b/cms-ui/apps/admin-ui/src/app/shared/components/user-table/user-table.component.ts @@ -165,10 +165,13 @@ export class UserTableComponent extends BaseEntityTableComponent, User switch (event.actionId) { case ASSIGN_TO_GROUP_ACTION: this.changeUserGroups(this.getAffectedEntityIds(event).map(id => Number(id))) - .then(() => { + .then(didChange => { + if (!didChange) { + return; + } + if (event.selection) { - this.selected = []; - this.selectedChange.emit([]); + this.updateSelection([]); } this.loader.reload(); }); diff --git a/cms-ui/apps/admin-ui/src/app/shared/providers/context-menu/context-menu.service.ts b/cms-ui/apps/admin-ui/src/app/shared/providers/context-menu/context-menu.service.ts index 6e9c43ef0..aba50f6e6 100644 --- a/cms-ui/apps/admin-ui/src/app/shared/providers/context-menu/context-menu.service.ts +++ b/cms-ui/apps/admin-ui/src/app/shared/providers/context-menu/context-menu.service.ts @@ -1,6 +1,6 @@ -import { AppStateService } from '@admin-ui/state'; import { Injectable } from '@angular/core'; -import { Group, NormalizableEntityType, Normalized, User } from '@gentics/cms-models'; +import { wasClosedByUser } from '@gentics/cms-integration-api-models'; +import { NormalizableEntityType } from '@gentics/cms-models'; import { ModalService } from '@gentics/ui-core'; import { AssignEntityToPackageModalComponent } from '../../components/assign-entity-to-package-modal/assign-entity-to-package-modal.component'; import { AssignPackagesToNodeModalComponent } from '../../components/assign-packages-to-node-modal/assign-packages-to-node-modal.component'; @@ -11,33 +11,30 @@ import { NotificationService } from '../notification/notification.service'; export class ContextMenuService { constructor( - protected state: AppStateService, protected modalService: ModalService, protected notificationTools: NotificationService, ) { } - changeGroupsOfUsersModalOpen(userIds: number[]): Promise { + changeGroupsOfUsersModalOpen(userIds: number[]): Promise { // if no row is selected, display modal if (!userIds || userIds.length < 1) { this.notificationTools.notificationNoneSelected(); return; } - // if only one user, preselect groups - let userGroupIds: number[] = []; - let user: User; - if (userIds && userIds.length === 1) { - user = this.state.now.entity.user[userIds[0]]; - userGroupIds = [...user.groups]; - } - // open modal return this.modalService.fromComponent( AssignUserToGroupsModal, { closeOnOverlayClick: false, width: '50%' }, - { userIds, userGroupIds, user }, + { userIds }, ) - .then(modal => modal.open()); + .then(modal => modal.open()) + .catch(err => { + if (wasClosedByUser(err)) { + return false; + } + throw err; + }); } assignEntityToPackageModalOpen(packageId: string, entityIdentifier: NormalizableEntityType): Promise { diff --git a/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-button-renderer/aloha-toggle-button-renderer.component.ts b/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-button-renderer/aloha-toggle-button-renderer.component.ts index c584bf0e0..7d3b2b355 100644 --- a/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-button-renderer/aloha-toggle-button-renderer.component.ts +++ b/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-button-renderer/aloha-toggle-button-renderer.component.ts @@ -63,7 +63,7 @@ export class AlohaToggleButtonRendererComponent extends BaseAlohaRendererCompone this.aloha.restoreSelection(); } - protected getFinalValue(): boolean { + protected override getFinalValue(): boolean { return this.settings.active; } diff --git a/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-split-button-renderer/aloha-toggle-split-button-renderer.component.ts b/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-split-button-renderer/aloha-toggle-split-button-renderer.component.ts index 5eaf95b5a..ee2adcf60 100644 --- a/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-split-button-renderer/aloha-toggle-split-button-renderer.component.ts +++ b/cms-ui/apps/editor-ui/src/app/content-frame/components/aloha-toggle-split-button-renderer/aloha-toggle-split-button-renderer.component.ts @@ -76,7 +76,7 @@ export class AlohaToggleSplitButtonRendererComponent extends BaseAlohaRendererCo this.aloha.restoreSelection(); } - protected getFinalValue(): boolean { + protected override getFinalValue(): boolean { return this.settings.active; } diff --git a/cms-ui/libs/cms-models/src/lib/models/request.ts b/cms-ui/libs/cms-models/src/lib/models/request.ts index 4ef944b4c..fc1dac521 100644 --- a/cms-ui/libs/cms-models/src/lib/models/request.ts +++ b/cms-ui/libs/cms-models/src/lib/models/request.ts @@ -869,9 +869,16 @@ export interface TemplateListRequest extends BaseListOptionsWithPaging