@valtimo/access-control-management 13.31.0 → 13.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/valtimo-access-control-management.mjs +668 -26
- package/fesm2022/valtimo-access-control-management.mjs.map +1 -1
- package/lib/access-control-management.module.d.ts +3 -1
- package/lib/components/access-control-json-editor-tab/access-control-json-editor-tab.component.d.ts +49 -0
- package/lib/components/access-control-overview-tab/access-control-overview-tab.component.d.ts +56 -0
- package/lib/components/editor/access-control-editor.component.d.ts +8 -4
- package/lib/constants/access-control-labels.d.ts +4 -0
- package/lib/constants/index.d.ts +1 -0
- package/lib/models/access-control-editor-tab.model.d.ts +9 -0
- package/lib/models/index.d.ts +2 -0
- package/lib/models/permission-schema.model.d.ts +46 -1
- package/lib/models/permission.model.d.ts +35 -0
- package/lib/pipes/index.d.ts +1 -0
- package/lib/pipes/resource-type-label.pipe.d.ts +10 -0
- package/lib/services/access-control.service.d.ts +2 -2
- package/lib/services/index.d.ts +1 -0
- package/lib/services/permission-schema-metadata.service.d.ts +20 -0
- package/lib/utils/format-condition.d.ts +8 -0
- package/lib/utils/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,22 +1,60 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, EventEmitter, Output, Input, ChangeDetectionStrategy, Component, ViewChild, NgModule } from '@angular/core';
|
|
3
|
-
import { BehaviorSubject, tap, switchMap, take, catchError, of,
|
|
2
|
+
import { Injectable, EventEmitter, Output, Input, ChangeDetectionStrategy, Component, ViewChild, Pipe, signal, NgModule } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject, tap, switchMap, take, catchError, of, shareReplay, map, combineLatest, Subject, finalize, delay, Subscription, skip, filter } from 'rxjs';
|
|
4
4
|
import * as i1 from '@valtimo/shared';
|
|
5
5
|
import { ROLE_ADMIN } from '@valtimo/shared';
|
|
6
6
|
import * as i2 from '@angular/common/http';
|
|
7
7
|
import * as i4 from '@angular/common';
|
|
8
8
|
import { CommonModule } from '@angular/common';
|
|
9
|
-
import * as
|
|
9
|
+
import * as i4$1 from '@ngx-translate/core';
|
|
10
10
|
import { TranslateModule } from '@ngx-translate/core';
|
|
11
|
-
import * as i3
|
|
12
|
-
import { CARBON_CONSTANTS, ViewType, CarbonListComponent,
|
|
13
|
-
import * as
|
|
11
|
+
import * as i3 from '@valtimo/components';
|
|
12
|
+
import { CARBON_CONSTANTS, ViewType, CarbonListComponent, EditorModule, OverflowMenuComponent, ConfirmationModalModule, RenderInPageHeaderDirective, OverflowMenuOptionComponent, OverflowMenuTriggerComponent, CarbonListModule } from '@valtimo/components';
|
|
13
|
+
import * as i1$2 from '@angular/router';
|
|
14
14
|
import { RouterModule } from '@angular/router';
|
|
15
15
|
import { AuthGuardService } from '@valtimo/security';
|
|
16
|
-
import * as
|
|
17
|
-
import { ButtonModule, ModalModule, InputModule,
|
|
16
|
+
import * as i2$1 from 'carbon-components-angular';
|
|
17
|
+
import { ButtonModule, DropdownModule, IconModule, ModalModule, InputModule, LoadingModule, NotificationModule, TabsModule } from 'carbon-components-angular';
|
|
18
18
|
import * as i1$1 from '@angular/forms';
|
|
19
19
|
import { Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
20
|
+
import { Filter16, TrashCan16 } from '@carbon/icons';
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
24
|
+
*
|
|
25
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
26
|
+
* you may not use this file except in compliance with the License.
|
|
27
|
+
* You may obtain a copy of the License at
|
|
28
|
+
*
|
|
29
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
30
|
+
*
|
|
31
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
32
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
33
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
34
|
+
* See the License for the specific language governing permissions and
|
|
35
|
+
* limitations under the License.
|
|
36
|
+
*/
|
|
37
|
+
var AccessControlEditorTab;
|
|
38
|
+
(function (AccessControlEditorTab) {
|
|
39
|
+
AccessControlEditorTab["SUMMARY"] = "summary";
|
|
40
|
+
AccessControlEditorTab["JSON_EDITOR"] = "jsonEditor";
|
|
41
|
+
})(AccessControlEditorTab || (AccessControlEditorTab = {}));
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
45
|
+
*
|
|
46
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
47
|
+
* you may not use this file except in compliance with the License.
|
|
48
|
+
* You may obtain a copy of the License at
|
|
49
|
+
*
|
|
50
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
51
|
+
*
|
|
52
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
53
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
54
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
55
|
+
* See the License for the specific language governing permissions and
|
|
56
|
+
* limitations under the License.
|
|
57
|
+
*/
|
|
20
58
|
|
|
21
59
|
/*
|
|
22
60
|
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
@@ -136,6 +174,88 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
136
174
|
args: [{ providedIn: 'root' }]
|
|
137
175
|
}], ctorParameters: () => [{ type: i1.ConfigService }, { type: i2.HttpClient }] });
|
|
138
176
|
|
|
177
|
+
/*
|
|
178
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
179
|
+
*
|
|
180
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
181
|
+
* you may not use this file except in compliance with the License.
|
|
182
|
+
* You may obtain a copy of the License at
|
|
183
|
+
*
|
|
184
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
185
|
+
*
|
|
186
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
187
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
188
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
189
|
+
* See the License for the specific language governing permissions and
|
|
190
|
+
* limitations under the License.
|
|
191
|
+
*/
|
|
192
|
+
class PermissionSchemaMetadataService {
|
|
193
|
+
constructor(accessControlService) {
|
|
194
|
+
this.accessControlService = accessControlService;
|
|
195
|
+
this._knownResourceTypes$ = new BehaviorSubject(new Set());
|
|
196
|
+
this._fieldsByResourceType$ = new BehaviorSubject({});
|
|
197
|
+
this.schema$ = this.accessControlService
|
|
198
|
+
.getPermissionSchema()
|
|
199
|
+
.pipe(tap(schema => {
|
|
200
|
+
this._knownResourceTypes$.next(this.extractKnownResourceTypes(schema));
|
|
201
|
+
this._fieldsByResourceType$.next(this.extractFieldsByResourceType(schema));
|
|
202
|
+
}), shareReplay({ bufferSize: 1, refCount: false }));
|
|
203
|
+
this.actionsByResourceType$ = this.schema$.pipe(map(schema => this.extractActionsByResourceType(schema)));
|
|
204
|
+
this.allResourceTypes$ = this.actionsByResourceType$.pipe(map(actions => Object.keys(actions)));
|
|
205
|
+
}
|
|
206
|
+
isResourceTypeKnown(fqn) {
|
|
207
|
+
return this._knownResourceTypes$.value.has(fqn);
|
|
208
|
+
}
|
|
209
|
+
isFieldKnown(resourceType, field) {
|
|
210
|
+
return this._fieldsByResourceType$.value[resourceType]?.has(field) ?? false;
|
|
211
|
+
}
|
|
212
|
+
extractActionsByResourceType(schema) {
|
|
213
|
+
const branches = schema?.items?.allOf ?? [];
|
|
214
|
+
const result = {};
|
|
215
|
+
for (const branch of branches) {
|
|
216
|
+
const resourceType = branch?.if?.properties?.resourceType?.const;
|
|
217
|
+
const actions = branch?.then?.properties?.action?.enum;
|
|
218
|
+
if (resourceType && Array.isArray(actions)) {
|
|
219
|
+
result[resourceType] = [...actions];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
extractKnownResourceTypes(schema) {
|
|
225
|
+
const entries = schema?.items?.properties?.resourceType?.oneOf ?? [];
|
|
226
|
+
const result = new Set();
|
|
227
|
+
for (const entry of entries) {
|
|
228
|
+
if (entry?.const)
|
|
229
|
+
result.add(entry.const);
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
extractFieldsByResourceType(schema) {
|
|
234
|
+
const definitions = schema?.definitions ?? {};
|
|
235
|
+
const result = {};
|
|
236
|
+
for (const [key, def] of Object.entries(definitions)) {
|
|
237
|
+
if (!key.startsWith('condList.'))
|
|
238
|
+
continue;
|
|
239
|
+
const resourceType = key.substring('condList.'.length);
|
|
240
|
+
const fields = new Set();
|
|
241
|
+
for (const variant of def?.items?.oneOf ?? []) {
|
|
242
|
+
for (const part of variant?.allOf ?? []) {
|
|
243
|
+
for (const f of part?.properties?.field?.enum ?? [])
|
|
244
|
+
fields.add(f);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
result[resourceType] = fields;
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PermissionSchemaMetadataService, deps: [{ token: AccessControlService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
252
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PermissionSchemaMetadataService, providedIn: 'root' }); }
|
|
253
|
+
}
|
|
254
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: PermissionSchemaMetadataService, decorators: [{
|
|
255
|
+
type: Injectable,
|
|
256
|
+
args: [{ providedIn: 'root' }]
|
|
257
|
+
}], ctorParameters: () => [{ type: AccessControlService }] });
|
|
258
|
+
|
|
139
259
|
/*
|
|
140
260
|
* Copyright 2015-2025 Ritense BV, the Netherlands.
|
|
141
261
|
*
|
|
@@ -256,7 +376,7 @@ class RoleMetadataModalComponent {
|
|
|
256
376
|
}, CARBON_CONSTANTS.modalAnimationMs);
|
|
257
377
|
}
|
|
258
378
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: RoleMetadataModalComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
259
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: RoleMetadataModalComponent, isStandalone: false, selector: "valtimo-role-metadata-modal", inputs: { open: "open", type: "type", defaultKeyValue: "defaultKeyValue" }, outputs: { closeEvent: "closeEvent" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal\n *ngIf=\"{\n isAdd: type === 'add',\n } as vars\"\n [open]=\"open\"\n showFooter=\"true\"\n [title]=\"vars.title\"\n valtimoCdsModal\n (close)=\"onCancel()\"\n>\n <cds-modal-header [showCloseButton]=\"true\" (closeSelect)=\"onCancel()\">\n <h3 cdsModalHeaderHeading>\n {{\n vars.isAdd\n ? ('accessControl.roles.add' | translate)\n : ('accessControl.roles.editRole' | translate)\n }}\n </h3>\n </cds-modal-header>\n\n <section cdsModalContent>\n <form [formGroup]=\"form\">\n <cds-label [invalid]=\"key.dirty && key.invalid\">\n {{ 'accessControl.roles.name' | translate }}\n\n <input\n formControlName=\"key\"\n cdsText\n placeholder=\"{{ 'accessControl.roles.name' | translate }}\"\n [attr.modal-primary-focus]=\"true\"\n [invalid]=\"key.dirty && key.invalid\"\n />\n </cds-label>\n </form>\n </section>\n\n <cds-modal-footer>\n <button cdsButton=\"secondary\" (click)=\"onCancel()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button [disabled]=\"this.form.invalid\" (click)=\"onConfirm()\" cdsButton=\"primary\">\n {{ vars.isAdd ? ('interface.create' | translate) : ('interface.save' | translate) }}\n </button>\n </cds-modal-footer>\n</cds-modal>\n", dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type:
|
|
379
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: RoleMetadataModalComponent, isStandalone: false, selector: "valtimo-role-metadata-modal", inputs: { open: "open", type: "type", defaultKeyValue: "defaultKeyValue" }, outputs: { closeEvent: "closeEvent" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal\n *ngIf=\"{\n isAdd: type === 'add',\n } as vars\"\n [open]=\"open\"\n showFooter=\"true\"\n [title]=\"vars.title\"\n valtimoCdsModal\n (close)=\"onCancel()\"\n>\n <cds-modal-header [showCloseButton]=\"true\" (closeSelect)=\"onCancel()\">\n <h3 cdsModalHeaderHeading>\n {{\n vars.isAdd\n ? ('accessControl.roles.add' | translate)\n : ('accessControl.roles.editRole' | translate)\n }}\n </h3>\n </cds-modal-header>\n\n <section cdsModalContent>\n <form [formGroup]=\"form\">\n <cds-label [invalid]=\"key.dirty && key.invalid\">\n {{ 'accessControl.roles.name' | translate }}\n\n <input\n formControlName=\"key\"\n cdsText\n placeholder=\"{{ 'accessControl.roles.name' | translate }}\"\n [attr.modal-primary-focus]=\"true\"\n [invalid]=\"key.dirty && key.invalid\"\n />\n </cds-label>\n </form>\n </section>\n\n <cds-modal-footer>\n <button cdsButton=\"secondary\" (click)=\"onCancel()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button [disabled]=\"this.form.invalid\" (click)=\"onConfirm()\" cdsButton=\"primary\">\n {{ vars.isAdd ? ('interface.create' | translate) : ('interface.save' | translate) }}\n </button>\n </cds-modal-footer>\n</cds-modal>\n", dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i2$1.Modal, selector: "cds-modal, ibm-modal", inputs: ["size", "theme", "ariaLabel", "open", "trigger", "hasScrollingContent"], outputs: ["overlaySelected", "close"] }, { kind: "component", type: i2$1.ModalHeader, selector: "cds-modal-header, ibm-modal-header", inputs: ["theme", "closeLabel", "showCloseButton"], outputs: ["closeSelect"] }, { kind: "component", type: i2$1.ModalFooter, selector: "cds-modal-footer, ibm-modal-footer" }, { kind: "directive", type: i2$1.ModalContent, selector: "[cdsModalContent], [ibmModalContent]", inputs: ["hasForm"] }, { kind: "directive", type: i2$1.ModalHeaderHeading, selector: "[cdsModalHeaderHeading], [ibmModalHeaderHeading]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2$1.Label, selector: "cds-label, ibm-label", inputs: ["labelInputID", "disabled", "skeleton", "helperText", "invalidText", "invalid", "warn", "warnText", "ariaLabel"] }, { kind: "directive", type: i2$1.TextInput, selector: "[cdsText], [ibmText]", inputs: ["theme", "size", "invalid", "warn", "skeleton"] }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
260
380
|
}
|
|
261
381
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: RoleMetadataModalComponent, decorators: [{
|
|
262
382
|
type: Component,
|
|
@@ -294,7 +414,7 @@ class DeleteRoleModalComponent {
|
|
|
294
414
|
this.deleteEvent.emit(roles);
|
|
295
415
|
}
|
|
296
416
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DeleteRoleModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
297
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: DeleteRoleModalComponent, isStandalone: false, selector: "valtimo-delete-role-modal", inputs: { deleteRowKeys: "deleteRowKeys", showDeleteModal$: "showDeleteModal$" }, outputs: { deleteEvent: "deleteEvent" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"interface.delete\"\n confirmButtonType=\"danger\"\n contentTranslationKey=\"accessControl.roles.deleteModalContent\"\n [outputOnConfirm]=\"deleteRowKeys\"\n [showModalSubject$]=\"showDeleteModal$\"\n titleTranslationKey=\"interface.delete\"\n (confirmEvent)=\"onDelete($event)\"\n></valtimo-confirmation-modal>\n", dependencies: [{ kind: "component", type: i3
|
|
417
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: DeleteRoleModalComponent, isStandalone: false, selector: "valtimo-delete-role-modal", inputs: { deleteRowKeys: "deleteRowKeys", showDeleteModal$: "showDeleteModal$" }, outputs: { deleteEvent: "deleteEvent" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<valtimo-confirmation-modal\n confirmButtonTextTranslationKey=\"interface.delete\"\n confirmButtonType=\"danger\"\n contentTranslationKey=\"accessControl.roles.deleteModalContent\"\n [outputOnConfirm]=\"deleteRowKeys\"\n [showModalSubject$]=\"showDeleteModal$\"\n titleTranslationKey=\"interface.delete\"\n (confirmEvent)=\"onDelete($event)\"\n></valtimo-confirmation-modal>\n", dependencies: [{ kind: "component", type: i3.ConfirmationModalComponent, selector: "valtimo-confirmation-modal", inputs: ["titleTranslationKey", "title", "content", "contentTranslationKey", "confirmButtonText", "confirmButtonTextTranslationKey", "confirmButtonType", "showOptionalButton", "optionalButtonText", "optionalButtonTextTranslationKey", "optionalButtonType", "cancelButtonText", "cancelButtonTextTranslationKey", "cancelButtonType", "showModalSubject$", "outputOnConfirm", "outputOnOptional", "spacerAfterCancelButton"], outputs: ["confirmEvent", "optionalEvent", "cancelEvent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
298
418
|
}
|
|
299
419
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DeleteRoleModalComponent, decorators: [{
|
|
300
420
|
type: Component,
|
|
@@ -359,7 +479,7 @@ class ExportRoleModalComponent {
|
|
|
359
479
|
});
|
|
360
480
|
}
|
|
361
481
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ExportRoleModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
362
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: ExportRoleModalComponent, isStandalone: false, selector: "valtimo-export-role-modal", inputs: { open: "open", exportRowKeys: "exportRowKeys", reset$: "reset$", disabled: "disabled" }, outputs: { exportEvent: "exportEvent", closeEvent: "closeEvent" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal\n *ngIf=\"{title: ('interface.export' | translate), selectedType: selectedType$ | async} as vars\"\n valtimoCdsModal\n [open]=\"open\"\n size=\"sm\"\n showFooter=\"true\"\n [title]=\"vars.title\"\n (close)=\"onCancel()\"\n>\n <cds-modal-header [showCloseButton]=\"true\" (closeSelect)=\"onCancel()\">\n <h3 cdsModalHeaderHeading>\n {{ vars.title }}\n </h3>\n </cds-modal-header>\n\n <section cdsModalContent>\n <div class=\"export-buttons\">\n <button [disabled]=\"disabled\" cdsButton=\"secondary\" (click)=\"selectType('unified')\">\n {{ 'accessControl.roles.singleExport' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"document\" size=\"16\"></svg>\n </button>\n\n <button [disabled]=\"disabled\" cdsButton=\"secondary\" (click)=\"selectType('separate')\">\n {{ 'accessControl.roles.multipleExport' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"copy--file\" size=\"16\"></svg>\n </button>\n </div>\n </section>\n\n <cds-modal-footer>\n <button [disabled]=\"disabled\" cdsButton=\"secondary\" (click)=\"onCancel()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button\n [disabled]=\"!vars.selectedType || disabled\"\n cdsButton=\"primary\"\n (click)=\"onConfirm(vars.selectedType)\"\n >\n {{ vars.title }}\n </button>\n </cds-modal-footer>\n</cds-modal>\n", styles: [".export-buttons{display:grid;width:100%;grid-template-columns:1fr 1fr;column-gap:16px}.export-buttons button{width:100%}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type:
|
|
482
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: ExportRoleModalComponent, isStandalone: false, selector: "valtimo-export-role-modal", inputs: { open: "open", exportRowKeys: "exportRowKeys", reset$: "reset$", disabled: "disabled" }, outputs: { exportEvent: "exportEvent", closeEvent: "closeEvent" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<cds-modal\n *ngIf=\"{title: ('interface.export' | translate), selectedType: selectedType$ | async} as vars\"\n valtimoCdsModal\n [open]=\"open\"\n size=\"sm\"\n showFooter=\"true\"\n [title]=\"vars.title\"\n (close)=\"onCancel()\"\n>\n <cds-modal-header [showCloseButton]=\"true\" (closeSelect)=\"onCancel()\">\n <h3 cdsModalHeaderHeading>\n {{ vars.title }}\n </h3>\n </cds-modal-header>\n\n <section cdsModalContent>\n <div class=\"export-buttons\">\n <button [disabled]=\"disabled\" cdsButton=\"secondary\" (click)=\"selectType('unified')\">\n {{ 'accessControl.roles.singleExport' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"document\" size=\"16\"></svg>\n </button>\n\n <button [disabled]=\"disabled\" cdsButton=\"secondary\" (click)=\"selectType('separate')\">\n {{ 'accessControl.roles.multipleExport' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"copy--file\" size=\"16\"></svg>\n </button>\n </div>\n </section>\n\n <cds-modal-footer>\n <button [disabled]=\"disabled\" cdsButton=\"secondary\" (click)=\"onCancel()\">\n {{ 'interface.cancel' | translate }}\n </button>\n\n <button\n [disabled]=\"!vars.selectedType || disabled\"\n cdsButton=\"primary\"\n (click)=\"onConfirm(vars.selectedType)\"\n >\n {{ vars.title }}\n </button>\n </cds-modal-footer>\n</cds-modal>\n", styles: [".export-buttons{display:grid;width:100%;grid-template-columns:1fr 1fr;column-gap:16px}.export-buttons button{width:100%}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "component", type: i2$1.Modal, selector: "cds-modal, ibm-modal", inputs: ["size", "theme", "ariaLabel", "open", "trigger", "hasScrollingContent"], outputs: ["overlaySelected", "close"] }, { kind: "component", type: i2$1.ModalHeader, selector: "cds-modal-header, ibm-modal-header", inputs: ["theme", "closeLabel", "showCloseButton"], outputs: ["closeSelect"] }, { kind: "component", type: i2$1.ModalFooter, selector: "cds-modal-footer, ibm-modal-footer" }, { kind: "directive", type: i2$1.ModalContent, selector: "[cdsModalContent], [ibmModalContent]", inputs: ["hasForm"] }, { kind: "directive", type: i2$1.ModalHeaderHeading, selector: "[cdsModalHeaderHeading], [ibmModalHeaderHeading]" }, { kind: "directive", type: i2$1.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
363
483
|
}
|
|
364
484
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ExportRoleModalComponent, decorators: [{
|
|
365
485
|
type: Component,
|
|
@@ -470,17 +590,494 @@ class AccessControlOverviewComponent {
|
|
|
470
590
|
setSelectedRoleKeys() {
|
|
471
591
|
this.selectedRowKeys$.next(this.carbonList.selectedItems.map((role) => role.roleKey));
|
|
472
592
|
}
|
|
473
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlOverviewComponent, deps: [{ token: AccessControlService }, { token: AccessControlExportService }, { token:
|
|
474
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: AccessControlOverviewComponent, isStandalone: false, selector: "ng-component", viewQueries: [{ propertyName: "carbonList", first: true, predicate: CarbonListComponent, descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<valtimo-carbon-list\n [header]=\"false\"\n [items]=\"roles$ | async\"\n [fields]=\"fields\"\n [loading]=\"loading$ | async\"\n [showSelectionColumn]=\"true\"\n (rowClicked)=\"onRowClick($event)\"\n>\n <ng-container header> {{ 'accessControl.roles.title' | translate }} </ng-container>\n\n <div carbonToolbarContent>\n <ng-container [ngTemplateOutlet]=\"addRoleButton\"></ng-container>\n </div>\n\n <ng-container carbonToolbarActions>\n <button cdsButton=\"primary\" (click)=\"showDeleteModal()\">\n {{ 'interface.delete' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"trash-can\" size=\"16\"></svg>\n </button>\n\n <button cdsButton=\"primary\" (click)=\"showExportModal()\">\n {{ 'interface.export' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"download\" size=\"16\"></svg>\n </button>\n </ng-container>\n\n <valtimo-no-results\n [action]=\"addRoleButton\"\n description=\"{{ 'accessControl.roles.noResults.description' | translate }}\"\n title=\"{{ 'accessControl.roles.noResults.title' | translate }}\"\n ></valtimo-no-results>\n</valtimo-carbon-list>\n\n<valtimo-role-metadata-modal\n [open]=\"showAddModal$ | async\"\n (closeEvent)=\"onAdd($event)\"\n></valtimo-role-metadata-modal>\n\n<ng-container *ngIf=\"{selectedRowKeys: selectedRowKeys$ | async} as obs\">\n <valtimo-delete-role-modal\n [deleteRowKeys]=\"obs.selectedRowKeys\"\n [showDeleteModal$]=\"showDeleteModal$\"\n (deleteEvent)=\"onDelete($event)\"\n >\n </valtimo-delete-role-modal>\n\n <valtimo-export-role-modal\n [disabled]=\"exportDisabled$ | async\"\n [exportRowKeys]=\"obs.selectedRowKeys\"\n [open]=\"showExportModal$ | async\"\n [reset$]=\"resetExportType$\"\n (exportEvent)=\"onExport($event)\"\n (closeEvent)=\"closeExportModal()\"\n >\n </valtimo-export-role-modal>\n</ng-container>\n\n<ng-template #addRoleButton>\n <button cdsButton=\"primary\" (click)=\"openAddModal()\">\n {{ 'accessControl.roles.add' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"add\" size=\"16\"></svg>\n </button>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type:
|
|
593
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlOverviewComponent, deps: [{ token: AccessControlService }, { token: AccessControlExportService }, { token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
594
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: AccessControlOverviewComponent, isStandalone: false, selector: "ng-component", viewQueries: [{ propertyName: "carbonList", first: true, predicate: CarbonListComponent, descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<valtimo-carbon-list\n [header]=\"false\"\n [items]=\"roles$ | async\"\n [fields]=\"fields\"\n [loading]=\"loading$ | async\"\n [showSelectionColumn]=\"true\"\n (rowClicked)=\"onRowClick($event)\"\n>\n <ng-container header> {{ 'accessControl.roles.title' | translate }} </ng-container>\n\n <div carbonToolbarContent>\n <ng-container [ngTemplateOutlet]=\"addRoleButton\"></ng-container>\n </div>\n\n <ng-container carbonToolbarActions>\n <button cdsButton=\"primary\" (click)=\"showDeleteModal()\">\n {{ 'interface.delete' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"trash-can\" size=\"16\"></svg>\n </button>\n\n <button cdsButton=\"primary\" (click)=\"showExportModal()\">\n {{ 'interface.export' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"download\" size=\"16\"></svg>\n </button>\n </ng-container>\n\n <valtimo-no-results\n [action]=\"addRoleButton\"\n description=\"{{ 'accessControl.roles.noResults.description' | translate }}\"\n title=\"{{ 'accessControl.roles.noResults.title' | translate }}\"\n ></valtimo-no-results>\n</valtimo-carbon-list>\n\n<valtimo-role-metadata-modal\n [open]=\"showAddModal$ | async\"\n (closeEvent)=\"onAdd($event)\"\n></valtimo-role-metadata-modal>\n\n<ng-container *ngIf=\"{selectedRowKeys: selectedRowKeys$ | async} as obs\">\n <valtimo-delete-role-modal\n [deleteRowKeys]=\"obs.selectedRowKeys\"\n [showDeleteModal$]=\"showDeleteModal$\"\n (deleteEvent)=\"onDelete($event)\"\n >\n </valtimo-delete-role-modal>\n\n <valtimo-export-role-modal\n [disabled]=\"exportDisabled$ | async\"\n [exportRowKeys]=\"obs.selectedRowKeys\"\n [open]=\"showExportModal$ | async\"\n [reset$]=\"resetExportType$\"\n (exportEvent)=\"onExport($event)\"\n (closeEvent)=\"closeExportModal()\"\n >\n </valtimo-export-role-modal>\n</ng-container>\n\n<ng-template #addRoleButton>\n <button cdsButton=\"primary\" (click)=\"openAddModal()\">\n {{ 'accessControl.roles.add' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"add\" size=\"16\"></svg>\n </button>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2$1.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "directive", type: i2$1.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: i3.CarbonListComponent, selector: "valtimo-carbon-list", inputs: ["items", "fields", "tableTranslations", "paginatorConfig", "pagination", "loading", "skeletonRowCount", "actions", "actionItems", "showActionItems", "header", "hideColumnHeader", "initialSortState", "sortState", "isSearchable", "enableSingleSelection", "lastColumnTemplate", "paginationIdentifier", "showSelectionColumn", "striped", "hideToolbar", "lockedTooltipTranslationKey", "movingRowsEnabled", "dragAndDrop", "dragAndDropDisabled"], outputs: ["rowClicked", "paginationClicked", "paginationSet", "search", "sortChanged", "moveRow", "itemsReordered"] }, { kind: "component", type: i3.CarbonNoResultsComponent, selector: "valtimo-no-results", inputs: ["action", "description", "illustration", "title", "smallPadding", "collapseVertically", "alwaysRenderVertically"] }, { kind: "component", type: RoleMetadataModalComponent, selector: "valtimo-role-metadata-modal", inputs: ["open", "type", "defaultKeyValue"], outputs: ["closeEvent"] }, { kind: "component", type: DeleteRoleModalComponent, selector: "valtimo-delete-role-modal", inputs: ["deleteRowKeys", "showDeleteModal$"], outputs: ["deleteEvent"] }, { kind: "component", type: ExportRoleModalComponent, selector: "valtimo-export-role-modal", inputs: ["open", "exportRowKeys", "reset$", "disabled"], outputs: ["exportEvent", "closeEvent"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
475
595
|
}
|
|
476
596
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlOverviewComponent, decorators: [{
|
|
477
597
|
type: Component,
|
|
478
598
|
args: [{ standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<valtimo-carbon-list\n [header]=\"false\"\n [items]=\"roles$ | async\"\n [fields]=\"fields\"\n [loading]=\"loading$ | async\"\n [showSelectionColumn]=\"true\"\n (rowClicked)=\"onRowClick($event)\"\n>\n <ng-container header> {{ 'accessControl.roles.title' | translate }} </ng-container>\n\n <div carbonToolbarContent>\n <ng-container [ngTemplateOutlet]=\"addRoleButton\"></ng-container>\n </div>\n\n <ng-container carbonToolbarActions>\n <button cdsButton=\"primary\" (click)=\"showDeleteModal()\">\n {{ 'interface.delete' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"trash-can\" size=\"16\"></svg>\n </button>\n\n <button cdsButton=\"primary\" (click)=\"showExportModal()\">\n {{ 'interface.export' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"download\" size=\"16\"></svg>\n </button>\n </ng-container>\n\n <valtimo-no-results\n [action]=\"addRoleButton\"\n description=\"{{ 'accessControl.roles.noResults.description' | translate }}\"\n title=\"{{ 'accessControl.roles.noResults.title' | translate }}\"\n ></valtimo-no-results>\n</valtimo-carbon-list>\n\n<valtimo-role-metadata-modal\n [open]=\"showAddModal$ | async\"\n (closeEvent)=\"onAdd($event)\"\n></valtimo-role-metadata-modal>\n\n<ng-container *ngIf=\"{selectedRowKeys: selectedRowKeys$ | async} as obs\">\n <valtimo-delete-role-modal\n [deleteRowKeys]=\"obs.selectedRowKeys\"\n [showDeleteModal$]=\"showDeleteModal$\"\n (deleteEvent)=\"onDelete($event)\"\n >\n </valtimo-delete-role-modal>\n\n <valtimo-export-role-modal\n [disabled]=\"exportDisabled$ | async\"\n [exportRowKeys]=\"obs.selectedRowKeys\"\n [open]=\"showExportModal$ | async\"\n [reset$]=\"resetExportType$\"\n (exportEvent)=\"onExport($event)\"\n (closeEvent)=\"closeExportModal()\"\n >\n </valtimo-export-role-modal>\n</ng-container>\n\n<ng-template #addRoleButton>\n <button cdsButton=\"primary\" (click)=\"openAddModal()\">\n {{ 'accessControl.roles.add' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"add\" size=\"16\"></svg>\n </button>\n</ng-template>\n" }]
|
|
479
|
-
}], ctorParameters: () => [{ type: AccessControlService }, { type: AccessControlExportService }, { type:
|
|
599
|
+
}], ctorParameters: () => [{ type: AccessControlService }, { type: AccessControlExportService }, { type: i1$2.Router }], propDecorators: { carbonList: [{
|
|
480
600
|
type: ViewChild,
|
|
481
601
|
args: [CarbonListComponent]
|
|
482
602
|
}] } });
|
|
483
603
|
|
|
604
|
+
/*
|
|
605
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
606
|
+
*
|
|
607
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
608
|
+
* you may not use this file except in compliance with the License.
|
|
609
|
+
* You may obtain a copy of the License at
|
|
610
|
+
*
|
|
611
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
612
|
+
*
|
|
613
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
614
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
615
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
616
|
+
* See the License for the specific language governing permissions and
|
|
617
|
+
* limitations under the License.
|
|
618
|
+
*/
|
|
619
|
+
const OPERATOR_LABEL = {
|
|
620
|
+
'==': 'accessControl.overview.operators.eq',
|
|
621
|
+
'!=': 'accessControl.overview.operators.neq',
|
|
622
|
+
'>': 'accessControl.overview.operators.gt',
|
|
623
|
+
'>=': 'accessControl.overview.operators.gte',
|
|
624
|
+
'<': 'accessControl.overview.operators.lt',
|
|
625
|
+
'<=': 'accessControl.overview.operators.lte',
|
|
626
|
+
in: 'accessControl.overview.operators.in',
|
|
627
|
+
list_contains: 'accessControl.overview.operators.list_contains',
|
|
628
|
+
};
|
|
629
|
+
const NO_CONTEXT_RESOURCE_TYPE = 'com.ritense.authorization.NoContext';
|
|
630
|
+
|
|
631
|
+
/*
|
|
632
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
633
|
+
*
|
|
634
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
635
|
+
* you may not use this file except in compliance with the License.
|
|
636
|
+
* You may obtain a copy of the License at
|
|
637
|
+
*
|
|
638
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
639
|
+
*
|
|
640
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
641
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
642
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
643
|
+
* See the License for the specific language governing permissions and
|
|
644
|
+
* limitations under the License.
|
|
645
|
+
*/
|
|
646
|
+
|
|
647
|
+
/*
|
|
648
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
649
|
+
*
|
|
650
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
651
|
+
* you may not use this file except in compliance with the License.
|
|
652
|
+
* You may obtain a copy of the License at
|
|
653
|
+
*
|
|
654
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
655
|
+
*
|
|
656
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
657
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
658
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
659
|
+
* See the License for the specific language governing permissions and
|
|
660
|
+
* limitations under the License.
|
|
661
|
+
*/
|
|
662
|
+
const SPECIAL_VALUE_PATTERN = /^\$\{([A-Za-z_$][A-Za-z0-9_$]*)\}$/;
|
|
663
|
+
function lowerFirst(s) {
|
|
664
|
+
return s.charAt(0).toLowerCase() + s.slice(1);
|
|
665
|
+
}
|
|
666
|
+
function upperFirst(s) {
|
|
667
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
668
|
+
}
|
|
669
|
+
function resourceTypeI18nKey(fqn) {
|
|
670
|
+
const lastSegment = fqn.split('.').pop();
|
|
671
|
+
if (!lastSegment)
|
|
672
|
+
return null;
|
|
673
|
+
return `accessControl.resourceTypes.${lowerFirst(lastSegment)}`;
|
|
674
|
+
}
|
|
675
|
+
function fieldI18nKey(resourceType, field) {
|
|
676
|
+
const resourceSegment = resourceType.split('.').pop();
|
|
677
|
+
if (!resourceSegment || !field)
|
|
678
|
+
return null;
|
|
679
|
+
const fieldSegment = field
|
|
680
|
+
.split('.')
|
|
681
|
+
.map((part, i) => (i === 0 ? part : upperFirst(part)))
|
|
682
|
+
.join('');
|
|
683
|
+
return `accessControl.overview.fields.${lowerFirst(resourceSegment)}.${fieldSegment}`;
|
|
684
|
+
}
|
|
685
|
+
function tryTranslate(translate, key) {
|
|
686
|
+
const translated = translate.instant(key);
|
|
687
|
+
return translated === key ? null : translated;
|
|
688
|
+
}
|
|
689
|
+
function formatResourceType(translate, fqn) {
|
|
690
|
+
const key = resourceTypeI18nKey(fqn);
|
|
691
|
+
const translated = key ? tryTranslate(translate, key) : null;
|
|
692
|
+
if (translated !== null)
|
|
693
|
+
return translated;
|
|
694
|
+
const segments = fqn.split('.');
|
|
695
|
+
return segments[segments.length - 1] || fqn;
|
|
696
|
+
}
|
|
697
|
+
function formatField(translate, resourceType, field) {
|
|
698
|
+
const key = fieldI18nKey(resourceType, field);
|
|
699
|
+
const translated = key ? tryTranslate(translate, key) : null;
|
|
700
|
+
if (translated !== null)
|
|
701
|
+
return translated;
|
|
702
|
+
return humanizeFieldPath(field);
|
|
703
|
+
}
|
|
704
|
+
function formatOperator(translate, operator) {
|
|
705
|
+
const key = OPERATOR_LABEL[operator];
|
|
706
|
+
return key ? translate.instant(key) : operator;
|
|
707
|
+
}
|
|
708
|
+
function formatValue(translate, value) {
|
|
709
|
+
if (value === null) {
|
|
710
|
+
return translate.instant('accessControl.overview.specialValues.null');
|
|
711
|
+
}
|
|
712
|
+
if (typeof value === 'string') {
|
|
713
|
+
if (value === '')
|
|
714
|
+
return translate.instant('accessControl.overview.specialValues.empty');
|
|
715
|
+
const match = SPECIAL_VALUE_PATTERN.exec(value);
|
|
716
|
+
if (match) {
|
|
717
|
+
const key = `accessControl.overview.specialValues.${match[1]}`;
|
|
718
|
+
const translated = tryTranslate(translate, key);
|
|
719
|
+
if (translated !== null)
|
|
720
|
+
return translated;
|
|
721
|
+
}
|
|
722
|
+
return value;
|
|
723
|
+
}
|
|
724
|
+
if (Array.isArray(value)) {
|
|
725
|
+
return value.map(item => formatValue(translate, item)).join(', ');
|
|
726
|
+
}
|
|
727
|
+
return String(value);
|
|
728
|
+
}
|
|
729
|
+
function humanizeFieldPath(field) {
|
|
730
|
+
return field
|
|
731
|
+
.split('.')
|
|
732
|
+
.map(part => part.replace(/([a-z0-9])([A-Z])/g, '$1 $2').toLowerCase())
|
|
733
|
+
.join(' ');
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/*
|
|
737
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
738
|
+
*
|
|
739
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
740
|
+
* you may not use this file except in compliance with the License.
|
|
741
|
+
* You may obtain a copy of the License at
|
|
742
|
+
*
|
|
743
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
744
|
+
*
|
|
745
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
746
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
747
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
748
|
+
* See the License for the specific language governing permissions and
|
|
749
|
+
* limitations under the License.
|
|
750
|
+
*/
|
|
751
|
+
|
|
752
|
+
/*
|
|
753
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
754
|
+
*
|
|
755
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
756
|
+
* you may not use this file except in compliance with the License.
|
|
757
|
+
* You may obtain a copy of the License at
|
|
758
|
+
*
|
|
759
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
760
|
+
*
|
|
761
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
762
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
763
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
764
|
+
* See the License for the specific language governing permissions and
|
|
765
|
+
* limitations under the License.
|
|
766
|
+
*/
|
|
767
|
+
class AccessControlJsonEditorTabComponent {
|
|
768
|
+
constructor(activatedRoute, iconService, metadataService, router, translateService) {
|
|
769
|
+
this.activatedRoute = activatedRoute;
|
|
770
|
+
this.iconService = iconService;
|
|
771
|
+
this.metadataService = metadataService;
|
|
772
|
+
this.router = router;
|
|
773
|
+
this.translateService = translateService;
|
|
774
|
+
this.disabled = false;
|
|
775
|
+
this.validEvent = new EventEmitter();
|
|
776
|
+
this.valueChangeEvent = new EventEmitter();
|
|
777
|
+
this._sourceModel$ = new BehaviorSubject(null);
|
|
778
|
+
this._filter$ = new BehaviorSubject({
|
|
779
|
+
resourceType: null,
|
|
780
|
+
action: null,
|
|
781
|
+
});
|
|
782
|
+
this._subscriptions = new Subscription();
|
|
783
|
+
this.isFilterActive$ = this._filter$.pipe(map(({ resourceType, action }) => !!resourceType || !!action));
|
|
784
|
+
this.resourceTypeItems$ = combineLatest([
|
|
785
|
+
this._sourceModel$,
|
|
786
|
+
this._filter$,
|
|
787
|
+
]).pipe(map(([sourceModel, currentFilter]) => {
|
|
788
|
+
const permissions = this.parsePermissions(sourceModel);
|
|
789
|
+
const resourceTypes = Array.from(new Set(permissions.map(p => p.resourceType).filter(Boolean))).sort();
|
|
790
|
+
return resourceTypes.map(resourceType => ({
|
|
791
|
+
content: formatResourceType(this.translateService, resourceType),
|
|
792
|
+
resourceType,
|
|
793
|
+
selected: currentFilter.resourceType === resourceType,
|
|
794
|
+
}));
|
|
795
|
+
}));
|
|
796
|
+
this.actionItems$ = combineLatest([
|
|
797
|
+
this._sourceModel$,
|
|
798
|
+
this._filter$,
|
|
799
|
+
]).pipe(map(([sourceModel, currentFilter]) => {
|
|
800
|
+
const permissions = this.parsePermissions(sourceModel);
|
|
801
|
+
const scoped = currentFilter.resourceType
|
|
802
|
+
? permissions.filter(p => p.resourceType === currentFilter.resourceType)
|
|
803
|
+
: permissions;
|
|
804
|
+
const actions = Array.from(new Set(scoped.flatMap(p => [...(p.actions ?? []), ...(p.action ? [p.action] : [])]))).sort();
|
|
805
|
+
return actions.map(action => ({
|
|
806
|
+
content: this.translateService.instant(`accessControl.actions.${action}`),
|
|
807
|
+
action,
|
|
808
|
+
selected: currentFilter.action === action,
|
|
809
|
+
}));
|
|
810
|
+
}));
|
|
811
|
+
this.filteredModel$ = combineLatest([
|
|
812
|
+
this._sourceModel$,
|
|
813
|
+
this._filter$,
|
|
814
|
+
]).pipe(map(([sourceModel, currentFilter]) => {
|
|
815
|
+
if (!sourceModel)
|
|
816
|
+
return null;
|
|
817
|
+
if (!currentFilter.resourceType && !currentFilter.action)
|
|
818
|
+
return sourceModel;
|
|
819
|
+
const permissions = this.parsePermissions(sourceModel);
|
|
820
|
+
const filtered = permissions.filter(permission => {
|
|
821
|
+
const resourceMatch = !currentFilter.resourceType || permission.resourceType === currentFilter.resourceType;
|
|
822
|
+
const actionMatch = !currentFilter.action ||
|
|
823
|
+
(permission.actions ?? []).includes(currentFilter.action) ||
|
|
824
|
+
permission.action === currentFilter.action;
|
|
825
|
+
return resourceMatch && actionMatch;
|
|
826
|
+
});
|
|
827
|
+
return {
|
|
828
|
+
...sourceModel,
|
|
829
|
+
value: JSON.stringify(filtered, null, 2),
|
|
830
|
+
};
|
|
831
|
+
}));
|
|
832
|
+
this.editorDisabled$ = this._filter$.pipe(map(({ resourceType, action }) => !!resourceType || !!action));
|
|
833
|
+
this.permissionSchema$ = this.metadataService.schema$;
|
|
834
|
+
this.iconService.registerAll([Filter16, TrashCan16]);
|
|
835
|
+
}
|
|
836
|
+
ngOnInit() {
|
|
837
|
+
this.activatedRoute.queryParamMap.pipe(take(1)).subscribe(params => {
|
|
838
|
+
this._filter$.next({
|
|
839
|
+
resourceType: params.get('filterResourceType'),
|
|
840
|
+
action: params.get('filterAction'),
|
|
841
|
+
});
|
|
842
|
+
});
|
|
843
|
+
this._subscriptions.add(this._filter$.pipe(skip(1)).subscribe(currentFilter => {
|
|
844
|
+
this.router.navigate([], {
|
|
845
|
+
relativeTo: this.activatedRoute,
|
|
846
|
+
queryParams: {
|
|
847
|
+
filterResourceType: currentFilter.resourceType ?? null,
|
|
848
|
+
filterAction: currentFilter.action ?? null,
|
|
849
|
+
},
|
|
850
|
+
queryParamsHandling: 'merge',
|
|
851
|
+
replaceUrl: true,
|
|
852
|
+
});
|
|
853
|
+
}));
|
|
854
|
+
}
|
|
855
|
+
ngOnChanges(changes) {
|
|
856
|
+
if (changes['model']) {
|
|
857
|
+
this._sourceModel$.next(this.model);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
ngOnDestroy() {
|
|
861
|
+
this._subscriptions.unsubscribe();
|
|
862
|
+
}
|
|
863
|
+
onValid(valid) {
|
|
864
|
+
this.validEvent.emit(valid);
|
|
865
|
+
}
|
|
866
|
+
onValueChange(value) {
|
|
867
|
+
if (this._filter$.getValue().resourceType || this._filter$.getValue().action)
|
|
868
|
+
return;
|
|
869
|
+
this.valueChangeEvent.emit(value);
|
|
870
|
+
}
|
|
871
|
+
onResourceTypeSelected(event) {
|
|
872
|
+
const resourceType = event.item?.resourceType ?? null;
|
|
873
|
+
this._filter$.next({ ...this._filter$.getValue(), resourceType, action: null });
|
|
874
|
+
}
|
|
875
|
+
onActionSelected(event) {
|
|
876
|
+
const action = event.item?.action ?? null;
|
|
877
|
+
this._filter$.next({ ...this._filter$.getValue(), action });
|
|
878
|
+
}
|
|
879
|
+
onClearFilter() {
|
|
880
|
+
this._filter$.next({ resourceType: null, action: null });
|
|
881
|
+
}
|
|
882
|
+
parsePermissions(model) {
|
|
883
|
+
if (!model?.value)
|
|
884
|
+
return [];
|
|
885
|
+
try {
|
|
886
|
+
const parsed = JSON.parse(model.value);
|
|
887
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
888
|
+
}
|
|
889
|
+
catch {
|
|
890
|
+
return [];
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlJsonEditorTabComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2$1.IconService }, { token: PermissionSchemaMetadataService }, { token: i1$2.Router }, { token: i4$1.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
894
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: AccessControlJsonEditorTabComponent, isStandalone: true, selector: "valtimo-access-control-json-editor-tab", inputs: { disabled: "disabled", model: "model" }, outputs: { validEvent: "validEvent", valueChangeEvent: "valueChangeEvent" }, usesOnChanges: true, ngImport: i0, template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n *ngIf=\"{\n filteredModel: filteredModel$ | async,\n editorDisabled: editorDisabled$ | async,\n permissionSchema: permissionSchema$ | async,\n } as obs\"\n class=\"json-editor-tab\"\n>\n <div class=\"json-editor-tab__toolbar\">\n <v-overflow-menu placement=\"bottom-end\" [closeOnSelect]=\"false\">\n <button\n overflowTrigger\n cdsButton=\"ghost\"\n class=\"json-editor-tab__filter-trigger\"\n [class.json-editor-tab__filter-trigger--active]=\"isFilterActive$ | async\"\n [iconOnly]=\"true\"\n >\n <svg cdsIcon=\"filter\" size=\"16\"></svg>\n </button>\n\n <div overflowPane>\n <ng-container *ngTemplateOutlet=\"filterPane\"></ng-container>\n </div>\n </v-overflow-menu>\n </div>\n\n <valtimo-editor\n *ngIf=\"obs.permissionSchema\"\n [disabled]=\"obs.editorDisabled || disabled\"\n [fitPage]=\"true\"\n [jsonSchema]=\"obs.permissionSchema\"\n [model]=\"obs.filteredModel\"\n (validEvent)=\"onValid($event)\"\n (valueChangeEvent)=\"onValueChange($event)\"\n ></valtimo-editor>\n</div>\n\n<ng-template #filterPane>\n <form class=\"json-editor-tab__filter\" (click)=\"$event.stopImmediatePropagation()\">\n <cds-dropdown\n [appendInline]=\"true\"\n [label]=\"'accessControl.filter.resourceType' | translate\"\n [placeholder]=\"'accessControl.filter.allResourceTypes' | translate\"\n (selected)=\"onResourceTypeSelected($event)\"\n >\n <cds-dropdown-list [items]=\"resourceTypeItems$ | async\"></cds-dropdown-list>\n </cds-dropdown>\n\n <cds-dropdown\n [appendInline]=\"true\"\n [label]=\"'accessControl.filter.action' | translate\"\n [placeholder]=\"'accessControl.filter.allActions' | translate\"\n (selected)=\"onActionSelected($event)\"\n >\n <cds-dropdown-list [items]=\"actionItems$ | async\"></cds-dropdown-list>\n </cds-dropdown>\n\n <button cdsButton=\"tertiary\" type=\"button\" (click)=\"onClearFilter()\">\n {{ 'interface.clear' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"trash-can\" size=\"16\"></svg>\n </button>\n </form>\n</ng-template>\n", styles: [":host{display:block;height:100%}.json-editor-tab{display:flex;flex-direction:column;height:100%}.json-editor-tab__toolbar{display:flex;justify-content:flex-end;padding:.25rem 0}.json-editor-tab__filter-trigger{position:relative}.json-editor-tab__filter-trigger--active:after{content:\"\";position:absolute;top:.375rem;right:.375rem;width:.5rem;height:.5rem;border-radius:50%;background-color:var(--cds-support-info, #0f62fe)}.json-editor-tab__filter{display:flex;flex-direction:column;gap:1rem;padding:1rem;min-width:16rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i2$1.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i2$1.Dropdown, selector: "cds-dropdown, ibm-dropdown", inputs: ["id", "label", "hideLabel", "helperText", "placeholder", "displayValue", "clearText", "size", "type", "theme", "disabled", "readonly", "skeleton", "inline", "disableArrowKeys", "invalid", "invalidText", "warn", "warnText", "appendInline", "scrollableContainer", "itemValueKey", "selectionFeedback", "menuButtonLabel", "selectedLabel", "dropUp", "fluid"], outputs: ["selected", "onClose", "close"] }, { kind: "component", type: i2$1.DropdownList, selector: "cds-dropdown-list, ibm-dropdown-list", inputs: ["ariaLabel", "items", "listTpl", "type", "showTitles"], outputs: ["select", "scroll", "blurIntent"] }, { kind: "ngmodule", type: EditorModule }, { kind: "component", type: i3.EditorComponent, selector: "valtimo-editor", inputs: ["editorOptions", "model", "disabled", "formatOnLoad", "widthPx", "heightPx", "heightStyle", "jsonSchema", "fitPage", "fitPageSpaceAdjustment"], outputs: ["validEvent", "valueChangeEvent"] }, { kind: "ngmodule", type: IconModule }, { kind: "directive", type: i2$1.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: OverflowMenuComponent, selector: "v-overflow-menu", inputs: ["open", "placement", "menuWidth", "offsetX", "offsetY", "closeOnSelect", "useHostAsReference", "portalToBody"], outputs: ["openChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
895
|
+
}
|
|
896
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlJsonEditorTabComponent, decorators: [{
|
|
897
|
+
type: Component,
|
|
898
|
+
args: [{ standalone: true, selector: 'valtimo-access-control-json-editor-tab', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
899
|
+
CommonModule,
|
|
900
|
+
TranslateModule,
|
|
901
|
+
ButtonModule,
|
|
902
|
+
DropdownModule,
|
|
903
|
+
EditorModule,
|
|
904
|
+
IconModule,
|
|
905
|
+
OverflowMenuComponent,
|
|
906
|
+
], template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div\n *ngIf=\"{\n filteredModel: filteredModel$ | async,\n editorDisabled: editorDisabled$ | async,\n permissionSchema: permissionSchema$ | async,\n } as obs\"\n class=\"json-editor-tab\"\n>\n <div class=\"json-editor-tab__toolbar\">\n <v-overflow-menu placement=\"bottom-end\" [closeOnSelect]=\"false\">\n <button\n overflowTrigger\n cdsButton=\"ghost\"\n class=\"json-editor-tab__filter-trigger\"\n [class.json-editor-tab__filter-trigger--active]=\"isFilterActive$ | async\"\n [iconOnly]=\"true\"\n >\n <svg cdsIcon=\"filter\" size=\"16\"></svg>\n </button>\n\n <div overflowPane>\n <ng-container *ngTemplateOutlet=\"filterPane\"></ng-container>\n </div>\n </v-overflow-menu>\n </div>\n\n <valtimo-editor\n *ngIf=\"obs.permissionSchema\"\n [disabled]=\"obs.editorDisabled || disabled\"\n [fitPage]=\"true\"\n [jsonSchema]=\"obs.permissionSchema\"\n [model]=\"obs.filteredModel\"\n (validEvent)=\"onValid($event)\"\n (valueChangeEvent)=\"onValueChange($event)\"\n ></valtimo-editor>\n</div>\n\n<ng-template #filterPane>\n <form class=\"json-editor-tab__filter\" (click)=\"$event.stopImmediatePropagation()\">\n <cds-dropdown\n [appendInline]=\"true\"\n [label]=\"'accessControl.filter.resourceType' | translate\"\n [placeholder]=\"'accessControl.filter.allResourceTypes' | translate\"\n (selected)=\"onResourceTypeSelected($event)\"\n >\n <cds-dropdown-list [items]=\"resourceTypeItems$ | async\"></cds-dropdown-list>\n </cds-dropdown>\n\n <cds-dropdown\n [appendInline]=\"true\"\n [label]=\"'accessControl.filter.action' | translate\"\n [placeholder]=\"'accessControl.filter.allActions' | translate\"\n (selected)=\"onActionSelected($event)\"\n >\n <cds-dropdown-list [items]=\"actionItems$ | async\"></cds-dropdown-list>\n </cds-dropdown>\n\n <button cdsButton=\"tertiary\" type=\"button\" (click)=\"onClearFilter()\">\n {{ 'interface.clear' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"trash-can\" size=\"16\"></svg>\n </button>\n </form>\n</ng-template>\n", styles: [":host{display:block;height:100%}.json-editor-tab{display:flex;flex-direction:column;height:100%}.json-editor-tab__toolbar{display:flex;justify-content:flex-end;padding:.25rem 0}.json-editor-tab__filter-trigger{position:relative}.json-editor-tab__filter-trigger--active:after{content:\"\";position:absolute;top:.375rem;right:.375rem;width:.5rem;height:.5rem;border-radius:50%;background-color:var(--cds-support-info, #0f62fe)}.json-editor-tab__filter{display:flex;flex-direction:column;gap:1rem;padding:1rem;min-width:16rem}\n"] }]
|
|
907
|
+
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2$1.IconService }, { type: PermissionSchemaMetadataService }, { type: i1$2.Router }, { type: i4$1.TranslateService }], propDecorators: { disabled: [{
|
|
908
|
+
type: Input
|
|
909
|
+
}], model: [{
|
|
910
|
+
type: Input
|
|
911
|
+
}], validEvent: [{
|
|
912
|
+
type: Output
|
|
913
|
+
}], valueChangeEvent: [{
|
|
914
|
+
type: Output
|
|
915
|
+
}] } });
|
|
916
|
+
|
|
917
|
+
/*
|
|
918
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
919
|
+
*
|
|
920
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
921
|
+
* you may not use this file except in compliance with the License.
|
|
922
|
+
* You may obtain a copy of the License at
|
|
923
|
+
*
|
|
924
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
925
|
+
*
|
|
926
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
927
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
928
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
929
|
+
* See the License for the specific language governing permissions and
|
|
930
|
+
* limitations under the License.
|
|
931
|
+
*/
|
|
932
|
+
class ResourceTypeLabelPipe {
|
|
933
|
+
constructor(translateService) {
|
|
934
|
+
this.translateService = translateService;
|
|
935
|
+
}
|
|
936
|
+
transform(fqn) {
|
|
937
|
+
if (!fqn)
|
|
938
|
+
return '';
|
|
939
|
+
return formatResourceType(this.translateService, fqn);
|
|
940
|
+
}
|
|
941
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ResourceTypeLabelPipe, deps: [{ token: i4$1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
942
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: ResourceTypeLabelPipe, isStandalone: true, name: "resourceTypeLabel" }); }
|
|
943
|
+
}
|
|
944
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ResourceTypeLabelPipe, decorators: [{
|
|
945
|
+
type: Pipe,
|
|
946
|
+
args: [{
|
|
947
|
+
standalone: true,
|
|
948
|
+
name: 'resourceTypeLabel',
|
|
949
|
+
}]
|
|
950
|
+
}], ctorParameters: () => [{ type: i4$1.TranslateService }] });
|
|
951
|
+
|
|
952
|
+
/*
|
|
953
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
954
|
+
*
|
|
955
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
956
|
+
* you may not use this file except in compliance with the License.
|
|
957
|
+
* You may obtain a copy of the License at
|
|
958
|
+
*
|
|
959
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
960
|
+
*
|
|
961
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
962
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
963
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
964
|
+
* See the License for the specific language governing permissions and
|
|
965
|
+
* limitations under the License.
|
|
966
|
+
*/
|
|
967
|
+
|
|
968
|
+
/*
|
|
969
|
+
* Copyright 2015-2026 Ritense BV, the Netherlands.
|
|
970
|
+
*
|
|
971
|
+
* Licensed under EUPL, Version 1.2 (the "License");
|
|
972
|
+
* you may not use this file except in compliance with the License.
|
|
973
|
+
* You may obtain a copy of the License at
|
|
974
|
+
*
|
|
975
|
+
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
|
976
|
+
*
|
|
977
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
978
|
+
* distributed under the License is distributed on an "AS IS" basis,
|
|
979
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
980
|
+
* See the License for the specific language governing permissions and
|
|
981
|
+
* limitations under the License.
|
|
982
|
+
*/
|
|
983
|
+
class AccessControlOverviewTabComponent {
|
|
984
|
+
set permissions(value) {
|
|
985
|
+
this._permissions$.next(value ?? []);
|
|
986
|
+
}
|
|
987
|
+
constructor(metadataService, translateService) {
|
|
988
|
+
this.metadataService = metadataService;
|
|
989
|
+
this.translateService = translateService;
|
|
990
|
+
this.roleKey = null;
|
|
991
|
+
this._permissions$ = new BehaviorSubject([]);
|
|
992
|
+
this.overview$ = combineLatest([
|
|
993
|
+
this._permissions$,
|
|
994
|
+
this.metadataService.allResourceTypes$,
|
|
995
|
+
this.metadataService.actionsByResourceType$,
|
|
996
|
+
]).pipe(map(([permissions, allResourceTypes, actionsByResourceType]) => this.buildOverview(permissions, allResourceTypes, actionsByResourceType)));
|
|
997
|
+
}
|
|
998
|
+
formatConditions(conditions, resourceType) {
|
|
999
|
+
return (conditions ?? []).map(condition => this.formatCondition(condition, resourceType));
|
|
1000
|
+
}
|
|
1001
|
+
isNoContext(contextResourceType) {
|
|
1002
|
+
return contextResourceType === NO_CONTEXT_RESOURCE_TYPE;
|
|
1003
|
+
}
|
|
1004
|
+
buildOverview(permissions, allResourceTypes, actionsByResourceType) {
|
|
1005
|
+
const knownResourceTypes = new Set(allResourceTypes);
|
|
1006
|
+
const extraResourceTypes = permissions
|
|
1007
|
+
.map(p => p.resourceType)
|
|
1008
|
+
.filter(rt => !!rt && !knownResourceTypes.has(rt));
|
|
1009
|
+
const resourceTypes = [...allResourceTypes, ...Array.from(new Set(extraResourceTypes))];
|
|
1010
|
+
return resourceTypes.map(resourceType => {
|
|
1011
|
+
const forResource = permissions.filter(p => p.resourceType === resourceType);
|
|
1012
|
+
const allowedActions = actionsByResourceType[resourceType] ?? [];
|
|
1013
|
+
const allowedSet = new Set(allowedActions);
|
|
1014
|
+
const extraActions = forResource
|
|
1015
|
+
.flatMap(p => [...(p.actions ?? []), ...(p.action ? [p.action] : [])])
|
|
1016
|
+
.filter(a => !!a && !allowedSet.has(a));
|
|
1017
|
+
const actions = [...allowedActions, ...Array.from(new Set(extraActions))];
|
|
1018
|
+
return {
|
|
1019
|
+
resourceType,
|
|
1020
|
+
actions: actions.map(action => ({
|
|
1021
|
+
action,
|
|
1022
|
+
grants: forResource.filter(p => this.permissionGrants(p, action)),
|
|
1023
|
+
})),
|
|
1024
|
+
};
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
permissionGrants(permission, action) {
|
|
1028
|
+
if (permission.action === action)
|
|
1029
|
+
return true;
|
|
1030
|
+
return (permission.actions ?? []).includes(action);
|
|
1031
|
+
}
|
|
1032
|
+
formatCondition(condition, resourceType) {
|
|
1033
|
+
if (condition.type === 'container') {
|
|
1034
|
+
return this.formatContainer(condition);
|
|
1035
|
+
}
|
|
1036
|
+
if (condition.type === 'expression') {
|
|
1037
|
+
return this.formatExpression(condition, resourceType);
|
|
1038
|
+
}
|
|
1039
|
+
return this.formatField(condition, resourceType);
|
|
1040
|
+
}
|
|
1041
|
+
formatField(condition, resourceType) {
|
|
1042
|
+
return {
|
|
1043
|
+
kind: 'field',
|
|
1044
|
+
field: formatField(this.translateService, resourceType, condition.field),
|
|
1045
|
+
operator: formatOperator(this.translateService, condition.operator),
|
|
1046
|
+
value: formatValue(this.translateService, condition.value),
|
|
1047
|
+
customField: !this.metadataService.isFieldKnown(resourceType, condition.field),
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
formatExpression(condition, resourceType) {
|
|
1051
|
+
return {
|
|
1052
|
+
kind: 'expression',
|
|
1053
|
+
field: formatField(this.translateService, resourceType, condition.field),
|
|
1054
|
+
path: condition.path,
|
|
1055
|
+
operator: formatOperator(this.translateService, condition.operator),
|
|
1056
|
+
value: formatValue(this.translateService, condition.value),
|
|
1057
|
+
clazz: condition.clazz,
|
|
1058
|
+
customField: !this.metadataService.isFieldKnown(resourceType, condition.field),
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
formatContainer(condition) {
|
|
1062
|
+
return {
|
|
1063
|
+
kind: 'container',
|
|
1064
|
+
resourceType: condition.resourceType,
|
|
1065
|
+
conditions: condition.conditions ?? [],
|
|
1066
|
+
customResource: !this.metadataService.isResourceTypeKnown(condition.resourceType),
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlOverviewTabComponent, deps: [{ token: PermissionSchemaMetadataService }, { token: i4$1.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1070
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: AccessControlOverviewTabComponent, isStandalone: true, selector: "valtimo-access-control-overview-tab", inputs: { roleKey: "roleKey", permissions: "permissions" }, ngImport: i0, template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div *ngIf=\"overview$ | async as overview\" class=\"ac\">\n @for (resource of overview; track resource.resourceType) {\n <section class=\"ac__group\">\n <h4 class=\"ac__heading\">\n @if (roleKey) {\n <a\n class=\"ac__heading-link\"\n [routerLink]=\"['/access-control', roleKey, 'json-editor']\"\n [queryParams]=\"{filterResourceType: resource.resourceType}\"\n >\n {{ resource.resourceType | resourceTypeLabel }}\n <span class=\"ac__fqn\">({{ resource.resourceType }})</span>\n </a>\n } @else {\n {{ resource.resourceType | resourceTypeLabel }}\n <span class=\"ac__fqn\">({{ resource.resourceType }})</span>\n }\n </h4>\n\n @for (entry of resource.actions; track entry.action) {\n <div class=\"ac__action\">\n @if (entry.grants.length) {\n <span class=\"ac__connective\">{{ 'accessControl.overview.can' | translate }}</span>\n @if (roleKey) {\n <a\n class=\"ac__action-link\"\n [routerLink]=\"['/access-control', roleKey, 'json-editor']\"\n [queryParams]=\"{\n filterResourceType: resource.resourceType,\n filterAction: entry.action,\n }\"\n >\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n </a>\n } @else {\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n }\n\n @for (perm of entry.grants; track $index; let isFirst = $first) {\n @if (!isFirst) {\n <div class=\"ac__or ac__connective\">{{\n 'accessControl.overview.or' | translate\n }}</div>\n }\n <div class=\"ac__grant\">\n @if (perm.conditions?.length) {\n <div class=\"ac__connective\">{{\n 'accessControl.overview.when' | translate\n }}</div>\n <ng-container\n *ngTemplateOutlet=\"\n conditionsTpl;\n context: {\n conditions: perm.conditions,\n resourceType: perm.resourceType,\n }\n \"\n ></ng-container>\n } @else if (!perm.contextResourceType) {\n <div class=\"ac__connective\">{{\n 'accessControl.overview.unconditional' | translate\n }}</div>\n }\n\n @if (perm.contextResourceType) {\n @if (isNoContext(perm.contextResourceType)) {\n <div class=\"ac__connective\">{{\n 'accessControl.overview.noContext' | translate\n }}</div>\n } @else {\n <div>\n <span class=\"ac__connective\">{{\n 'accessControl.overview.inContextOf' | translate\n }}</span>\n <span class=\"ac__resource-type\">{{\n perm.contextResourceType | resourceTypeLabel\n }}</span>\n @if (perm.contextConditions?.length) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.where' | translate\n }}</span>\n }\n </div>\n @if (perm.contextConditions?.length) {\n <ng-container\n *ngTemplateOutlet=\"\n conditionsTpl;\n context: {\n conditions: perm.contextConditions,\n resourceType: perm.contextResourceType,\n }\n \"\n ></ng-container>\n }\n }\n }\n </div>\n }\n } @else {\n <span class=\"ac__no-access\">{{\n 'accessControl.overview.cannot' | translate\n }}</span>\n @if (roleKey) {\n <a\n class=\"ac__action-link\"\n [routerLink]=\"['/access-control', roleKey, 'json-editor']\"\n [queryParams]=\"{\n filterResourceType: resource.resourceType,\n filterAction: entry.action,\n }\"\n >\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n </a>\n } @else {\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n }\n }\n </div>\n }\n </section>\n }\n</div>\n\n<ng-template #conditionsTpl let-conditions=\"conditions\" let-resourceType=\"resourceType\">\n <div class=\"ac__conditions\">\n @for (\n condition of formatConditions(conditions, resourceType);\n track $index;\n let isFirst = $first\n ) {\n <div class=\"ac__condition\">\n @if (!isFirst) {\n <span class=\"ac__connective\">{{ 'accessControl.overview.and' | translate }}</span>\n }\n @switch (condition.kind) {\n @case ('field') {\n <span>{{ condition.field }}</span>\n @if (condition.customField) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.customField' | translate\n }}</span>\n }\n <span class=\"ac__operator\">{{ condition.operator }}</span>\n <span>{{ condition.value }}</span>\n }\n\n @case ('expression') {\n <span>{{ condition.field }}</span>\n @if (condition.customField) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.customField' | translate\n }}</span>\n }\n <span class=\"ac__connective\">{{\n 'accessControl.overview.atJsonPath' | translate\n }}</span>\n <code class=\"ac__path\" [title]=\"condition.clazz\">{{ condition.path }}</code>\n <span class=\"ac__operator\">{{ condition.operator }}</span>\n <span>{{ condition.value }}</span>\n }\n\n @case ('container') {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.relatedResource' | translate\n }}</span>\n <span class=\"ac__resource-type\">{{\n condition.resourceType | resourceTypeLabel\n }}</span>\n @if (condition.customResource) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.customResource' | translate\n }}</span>\n }\n <span class=\"ac__connective\">{{\n 'accessControl.overview.where' | translate\n }}</span>\n <ng-container\n *ngTemplateOutlet=\"\n conditionsTpl;\n context: {\n conditions: condition.conditions,\n resourceType: condition.resourceType,\n }\n \"\n ></ng-container>\n }\n }\n </div>\n }\n </div>\n</ng-template>\n", styles: [".ac{display:flex;flex-direction:column;gap:2rem;padding:1rem}.ac__group{display:flex;flex-direction:column;gap:.75rem}.ac__heading{border-bottom:1px solid var(--cds-border-subtle, #c6c6c6);margin:0 0 .5rem;padding-bottom:.25rem}.ac__heading-link{color:inherit;text-decoration:none}.ac__heading-link:hover,.ac__heading-link:focus-visible{text-decoration:underline}.ac__action-link{color:inherit;text-decoration:none}.ac__action-link:hover,.ac__action-link:focus-visible{text-decoration:underline}.ac__fqn{color:var(--cds-text-secondary, #525252);font-family:var(--cds-code-01-font-family, monospace);font-size:.875rem;font-weight:400;margin-left:.5rem}.ac__action{line-height:1.6}.ac__action-name,.ac__resource-type{font-weight:600}.ac__operator{font-style:italic}.ac__connective{color:var(--cds-text-secondary, #525252);font-style:italic}.ac__no-access{color:var(--cds-text-error, #da1e28);font-style:italic}.ac__grant,.ac__or,.ac__conditions{padding-left:1.5rem}.ac__path{background-color:var(--cds-layer-accent, #e0e0e0);border-radius:2px;font-family:var(--cds-code-01-font-family, monospace);padding:0 .25rem}\n/*!\n * Copyright 2015-2026 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: ResourceTypeLabelPipe, name: "resourceTypeLabel" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
|
|
1071
|
+
}
|
|
1072
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlOverviewTabComponent, decorators: [{
|
|
1073
|
+
type: Component,
|
|
1074
|
+
args: [{ standalone: true, selector: 'valtimo-access-control-overview-tab', changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: true, imports: [CommonModule, RouterModule, TranslateModule, ResourceTypeLabelPipe], template: "<!--\n ~ Copyright 2015-2026 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<div *ngIf=\"overview$ | async as overview\" class=\"ac\">\n @for (resource of overview; track resource.resourceType) {\n <section class=\"ac__group\">\n <h4 class=\"ac__heading\">\n @if (roleKey) {\n <a\n class=\"ac__heading-link\"\n [routerLink]=\"['/access-control', roleKey, 'json-editor']\"\n [queryParams]=\"{filterResourceType: resource.resourceType}\"\n >\n {{ resource.resourceType | resourceTypeLabel }}\n <span class=\"ac__fqn\">({{ resource.resourceType }})</span>\n </a>\n } @else {\n {{ resource.resourceType | resourceTypeLabel }}\n <span class=\"ac__fqn\">({{ resource.resourceType }})</span>\n }\n </h4>\n\n @for (entry of resource.actions; track entry.action) {\n <div class=\"ac__action\">\n @if (entry.grants.length) {\n <span class=\"ac__connective\">{{ 'accessControl.overview.can' | translate }}</span>\n @if (roleKey) {\n <a\n class=\"ac__action-link\"\n [routerLink]=\"['/access-control', roleKey, 'json-editor']\"\n [queryParams]=\"{\n filterResourceType: resource.resourceType,\n filterAction: entry.action,\n }\"\n >\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n </a>\n } @else {\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n }\n\n @for (perm of entry.grants; track $index; let isFirst = $first) {\n @if (!isFirst) {\n <div class=\"ac__or ac__connective\">{{\n 'accessControl.overview.or' | translate\n }}</div>\n }\n <div class=\"ac__grant\">\n @if (perm.conditions?.length) {\n <div class=\"ac__connective\">{{\n 'accessControl.overview.when' | translate\n }}</div>\n <ng-container\n *ngTemplateOutlet=\"\n conditionsTpl;\n context: {\n conditions: perm.conditions,\n resourceType: perm.resourceType,\n }\n \"\n ></ng-container>\n } @else if (!perm.contextResourceType) {\n <div class=\"ac__connective\">{{\n 'accessControl.overview.unconditional' | translate\n }}</div>\n }\n\n @if (perm.contextResourceType) {\n @if (isNoContext(perm.contextResourceType)) {\n <div class=\"ac__connective\">{{\n 'accessControl.overview.noContext' | translate\n }}</div>\n } @else {\n <div>\n <span class=\"ac__connective\">{{\n 'accessControl.overview.inContextOf' | translate\n }}</span>\n <span class=\"ac__resource-type\">{{\n perm.contextResourceType | resourceTypeLabel\n }}</span>\n @if (perm.contextConditions?.length) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.where' | translate\n }}</span>\n }\n </div>\n @if (perm.contextConditions?.length) {\n <ng-container\n *ngTemplateOutlet=\"\n conditionsTpl;\n context: {\n conditions: perm.contextConditions,\n resourceType: perm.contextResourceType,\n }\n \"\n ></ng-container>\n }\n }\n }\n </div>\n }\n } @else {\n <span class=\"ac__no-access\">{{\n 'accessControl.overview.cannot' | translate\n }}</span>\n @if (roleKey) {\n <a\n class=\"ac__action-link\"\n [routerLink]=\"['/access-control', roleKey, 'json-editor']\"\n [queryParams]=\"{\n filterResourceType: resource.resourceType,\n filterAction: entry.action,\n }\"\n >\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n </a>\n } @else {\n <span class=\"ac__action-name\">{{\n 'accessControl.actions.' + entry.action | translate\n }}</span>\n }\n }\n </div>\n }\n </section>\n }\n</div>\n\n<ng-template #conditionsTpl let-conditions=\"conditions\" let-resourceType=\"resourceType\">\n <div class=\"ac__conditions\">\n @for (\n condition of formatConditions(conditions, resourceType);\n track $index;\n let isFirst = $first\n ) {\n <div class=\"ac__condition\">\n @if (!isFirst) {\n <span class=\"ac__connective\">{{ 'accessControl.overview.and' | translate }}</span>\n }\n @switch (condition.kind) {\n @case ('field') {\n <span>{{ condition.field }}</span>\n @if (condition.customField) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.customField' | translate\n }}</span>\n }\n <span class=\"ac__operator\">{{ condition.operator }}</span>\n <span>{{ condition.value }}</span>\n }\n\n @case ('expression') {\n <span>{{ condition.field }}</span>\n @if (condition.customField) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.customField' | translate\n }}</span>\n }\n <span class=\"ac__connective\">{{\n 'accessControl.overview.atJsonPath' | translate\n }}</span>\n <code class=\"ac__path\" [title]=\"condition.clazz\">{{ condition.path }}</code>\n <span class=\"ac__operator\">{{ condition.operator }}</span>\n <span>{{ condition.value }}</span>\n }\n\n @case ('container') {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.relatedResource' | translate\n }}</span>\n <span class=\"ac__resource-type\">{{\n condition.resourceType | resourceTypeLabel\n }}</span>\n @if (condition.customResource) {\n <span class=\"ac__connective\">{{\n 'accessControl.overview.customResource' | translate\n }}</span>\n }\n <span class=\"ac__connective\">{{\n 'accessControl.overview.where' | translate\n }}</span>\n <ng-container\n *ngTemplateOutlet=\"\n conditionsTpl;\n context: {\n conditions: condition.conditions,\n resourceType: condition.resourceType,\n }\n \"\n ></ng-container>\n }\n }\n </div>\n }\n </div>\n</ng-template>\n", styles: [".ac{display:flex;flex-direction:column;gap:2rem;padding:1rem}.ac__group{display:flex;flex-direction:column;gap:.75rem}.ac__heading{border-bottom:1px solid var(--cds-border-subtle, #c6c6c6);margin:0 0 .5rem;padding-bottom:.25rem}.ac__heading-link{color:inherit;text-decoration:none}.ac__heading-link:hover,.ac__heading-link:focus-visible{text-decoration:underline}.ac__action-link{color:inherit;text-decoration:none}.ac__action-link:hover,.ac__action-link:focus-visible{text-decoration:underline}.ac__fqn{color:var(--cds-text-secondary, #525252);font-family:var(--cds-code-01-font-family, monospace);font-size:.875rem;font-weight:400;margin-left:.5rem}.ac__action{line-height:1.6}.ac__action-name,.ac__resource-type{font-weight:600}.ac__operator{font-style:italic}.ac__connective{color:var(--cds-text-secondary, #525252);font-style:italic}.ac__no-access{color:var(--cds-text-error, #da1e28);font-style:italic}.ac__grant,.ac__or,.ac__conditions{padding-left:1.5rem}.ac__path{background-color:var(--cds-layer-accent, #e0e0e0);border-radius:2px;font-family:var(--cds-code-01-font-family, monospace);padding:0 .25rem}\n/*!\n * Copyright 2015-2026 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"] }]
|
|
1075
|
+
}], ctorParameters: () => [{ type: PermissionSchemaMetadataService }, { type: i4$1.TranslateService }], propDecorators: { roleKey: [{
|
|
1076
|
+
type: Input
|
|
1077
|
+
}], permissions: [{
|
|
1078
|
+
type: Input
|
|
1079
|
+
}] } });
|
|
1080
|
+
|
|
484
1081
|
/*
|
|
485
1082
|
* Copyright 2015-2025 Ritense BV, the Netherlands.
|
|
486
1083
|
*
|
|
@@ -507,6 +1104,7 @@ class AccessControlEditorComponent {
|
|
|
507
1104
|
this.accessControlExportService = accessControlExportService;
|
|
508
1105
|
this.pageHeaderService = pageHeaderService;
|
|
509
1106
|
this.model$ = new BehaviorSubject(null);
|
|
1107
|
+
this.permissions$ = new BehaviorSubject(null);
|
|
510
1108
|
this.roleKey$ = new BehaviorSubject(null);
|
|
511
1109
|
this.saveDisabled$ = new BehaviorSubject(true);
|
|
512
1110
|
this.editorDisabled$ = new BehaviorSubject(false);
|
|
@@ -515,10 +1113,12 @@ class AccessControlEditorComponent {
|
|
|
515
1113
|
this.showEditModal$ = new BehaviorSubject(false);
|
|
516
1114
|
this.selectedRowKeys$ = new BehaviorSubject(null);
|
|
517
1115
|
this.compactMode$ = this.pageHeaderService.compactMode$;
|
|
518
|
-
this
|
|
1116
|
+
this.$activeTab = signal(AccessControlEditorTab.SUMMARY);
|
|
1117
|
+
this.AccessControlEditorTab = AccessControlEditorTab;
|
|
519
1118
|
this._updatedModelValue$ = new BehaviorSubject('');
|
|
520
1119
|
}
|
|
521
1120
|
ngOnInit() {
|
|
1121
|
+
this.restoreActiveTabFromUrl();
|
|
522
1122
|
this.getPermissions();
|
|
523
1123
|
this.openRoleKeySubscription();
|
|
524
1124
|
}
|
|
@@ -580,6 +1180,31 @@ class AccessControlEditorComponent {
|
|
|
580
1180
|
this.showSuccessMessage(data.roleKey);
|
|
581
1181
|
});
|
|
582
1182
|
}
|
|
1183
|
+
setActiveTab(tab) {
|
|
1184
|
+
if (this.$activeTab() === tab)
|
|
1185
|
+
return;
|
|
1186
|
+
const roleKey = this.route.snapshot.paramMap.get('id');
|
|
1187
|
+
if (!roleKey) {
|
|
1188
|
+
this.$activeTab.set(tab);
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
const segments = tab === AccessControlEditorTab.JSON_EDITOR
|
|
1192
|
+
? ['/access-control', roleKey, 'json-editor']
|
|
1193
|
+
: ['/access-control', roleKey];
|
|
1194
|
+
this.router.navigate(segments);
|
|
1195
|
+
}
|
|
1196
|
+
restoreActiveTabFromUrl() {
|
|
1197
|
+
const url = this.route.snapshot.url;
|
|
1198
|
+
const lastSegment = url[url.length - 1]?.path;
|
|
1199
|
+
if (lastSegment === 'json-editor') {
|
|
1200
|
+
this.$activeTab.set(AccessControlEditorTab.JSON_EDITOR);
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
const params = this.route.snapshot.queryParamMap;
|
|
1204
|
+
if (params.get('filterResourceType') || params.get('filterAction')) {
|
|
1205
|
+
this.$activeTab.set(AccessControlEditorTab.JSON_EDITOR);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
583
1208
|
exportPermissions() {
|
|
584
1209
|
this.accessControlExportService
|
|
585
1210
|
.exportRoles({ type: 'separate', roleKeys: [this._roleKey] })
|
|
@@ -621,6 +1246,7 @@ class AccessControlEditorComponent {
|
|
|
621
1246
|
language: 'json',
|
|
622
1247
|
uri: `inmemory://access-control/role-${roleKey}.access-control-permissions.json`,
|
|
623
1248
|
});
|
|
1249
|
+
this.permissions$.next(Array.isArray(permissions) ? permissions : null);
|
|
624
1250
|
}
|
|
625
1251
|
disableMore() {
|
|
626
1252
|
this.moreDisabled$.next(true);
|
|
@@ -649,13 +1275,13 @@ class AccessControlEditorComponent {
|
|
|
649
1275
|
type: 'success',
|
|
650
1276
|
});
|
|
651
1277
|
}
|
|
652
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlEditorComponent, deps: [{ token: AccessControlService }, { token:
|
|
653
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
1278
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlEditorComponent, deps: [{ token: AccessControlService }, { token: i1$2.ActivatedRoute }, { token: i3.PageTitleService }, { token: i1$2.Router }, { token: i1.GlobalNotificationService }, { token: i4$1.TranslateService }, { token: AccessControlExportService }, { token: i3.PageHeaderService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1279
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: AccessControlEditorComponent, isStandalone: false, selector: "ng-component", ngImport: i0, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<ng-container *ngIf=\"model$ | async as model; else loading\">\n <cds-tabs type=\"contained\">\n <cds-tab\n [active]=\"$activeTab() === AccessControlEditorTab.SUMMARY\"\n [heading]=\"'accessControl.roles.tabs.summary' | translate\"\n (selected)=\"setActiveTab(AccessControlEditorTab.SUMMARY)\"\n >\n <valtimo-access-control-overview-tab\n *ngIf=\"$activeTab() === AccessControlEditorTab.SUMMARY\"\n [permissions]=\"permissions$ | async\"\n [roleKey]=\"roleKey$ | async\"\n ></valtimo-access-control-overview-tab>\n </cds-tab>\n\n <cds-tab\n [active]=\"$activeTab() === AccessControlEditorTab.JSON_EDITOR\"\n [heading]=\"'accessControl.roles.tabs.jsonEditor' | translate\"\n (selected)=\"setActiveTab(AccessControlEditorTab.JSON_EDITOR)\"\n >\n <valtimo-access-control-json-editor-tab\n *ngIf=\"$activeTab() === AccessControlEditorTab.JSON_EDITOR\"\n [disabled]=\"editorDisabled$ | async\"\n [model]=\"model\"\n (validEvent)=\"onValid($event)\"\n (valueChangeEvent)=\"onValueChange($event)\"\n ></valtimo-access-control-json-editor-tab>\n </cds-tab>\n </cds-tabs>\n</ng-container>\n\n<ng-container renderInPageHeader>\n <ng-template>\n <div\n *ngIf=\"{\n model: model$ | async,\n moreDisabled: moreDisabled$ | async,\n compactMode: compactMode$ | async,\n } as obs\"\n class=\"buttons-container\"\n >\n <v-overflow-menu class=\"overflow-button\" placement=\"bottom-end\">\n <v-overflow-menu-trigger overflowTrigger></v-overflow-menu-trigger>\n <v-overflow-menu-option [disabled]=\"obs.moreDisabled\" (selected)=\"showEditModal()\">{{\n 'accessControl.roles.editMetadata' | translate\n }}</v-overflow-menu-option>\n\n <v-overflow-menu-option [disabled]=\"obs.moreDisabled\" (selected)=\"exportPermissions()\">{{\n 'interface.export' | translate\n }}</v-overflow-menu-option>\n\n <v-overflow-menu-option\n [disabled]=\"obs.moreDisabled\"\n type=\"danger\"\n (selected)=\"showDeleteModal()\"\n >{{ 'interface.delete' | translate }}</v-overflow-menu-option\n >\n </v-overflow-menu>\n\n <button\n [disabled]=\"saveDisabled$ | async\"\n cdsButton=\"primary\"\n [size]=\"obs.compactMode ? 'sm' : 'md'\"\n (click)=\"updatePermissions()\"\n >\n {{ 'interface.save' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"save\" size=\"16\"></svg>\n </button>\n </div>\n </ng-template>\n</ng-container>\n\n<ng-container *ngIf=\"{selectedRowKeys: selectedRowKeys$ | async} as obs\">\n <valtimo-delete-role-modal\n [deleteRowKeys]=\"obs.selectedRowKeys\"\n [showDeleteModal$]=\"showDeleteModal$\"\n (deleteEvent)=\"onDelete($event)\"\n >\n </valtimo-delete-role-modal>\n\n <valtimo-role-metadata-modal\n [defaultKeyValue]=\"obs.selectedRowKeys[0]\"\n [open]=\"showEditModal$ | async\"\n type=\"edit\"\n (closeEvent)=\"onEdit(obs.selectedRowKeys[0], $event)\"\n ></valtimo-role-metadata-modal>\n</ng-container>\n\n<ng-template #loading>\n <div class=\"loading-container\">\n <cds-loading></cds-loading>\n </div>\n</ng-template>\n", styles: [".loading-container{display:flex;width:100%;justify-content:center}.overflow-button{margin-right:16px}.buttons-container{display:flex;flex-direction:row;align-items:center}.buttons-container button{height:min-content}:host ::ng-deep .cds--tab-content{background-color:#fff}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "directive", type: i2$1.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "directive", type: i3.RenderInPageHeaderDirective, selector: "[renderInPageHeader]", inputs: ["fullWidth"] }, { kind: "component", type: i2$1.Loading, selector: "cds-loading, ibm-loading", inputs: ["title", "isActive", "size", "overlay"] }, { kind: "component", type: i3.OverflowMenuComponent, selector: "v-overflow-menu", inputs: ["open", "placement", "menuWidth", "offsetX", "offsetY", "closeOnSelect", "useHostAsReference", "portalToBody"], outputs: ["openChange"] }, { kind: "component", type: i3.OverflowMenuOptionComponent, selector: "v-overflow-menu-option", inputs: ["disabled", "type", "testId", "optionId"], outputs: ["selected"] }, { kind: "component", type: i3.OverflowMenuTriggerComponent, selector: "v-overflow-menu-trigger", inputs: ["compact"] }, { kind: "component", type: i2$1.Tabs, selector: "cds-tabs, ibm-tabs", inputs: ["position", "cacheActive", "followFocus", "isNavigation", "ariaLabel", "ariaLabelledby", "type", "theme", "skeleton"] }, { kind: "component", type: i2$1.Tab, selector: "cds-tab, ibm-tab", inputs: ["heading", "title", "context", "active", "disabled", "tabIndex", "id", "cacheActive", "tabContent", "templateContext"], outputs: ["selected"] }, { kind: "component", type: AccessControlJsonEditorTabComponent, selector: "valtimo-access-control-json-editor-tab", inputs: ["disabled", "model"], outputs: ["validEvent", "valueChangeEvent"] }, { kind: "component", type: AccessControlOverviewTabComponent, selector: "valtimo-access-control-overview-tab", inputs: ["roleKey", "permissions"] }, { kind: "component", type: RoleMetadataModalComponent, selector: "valtimo-role-metadata-modal", inputs: ["open", "type", "defaultKeyValue"], outputs: ["closeEvent"] }, { kind: "component", type: DeleteRoleModalComponent, selector: "valtimo-delete-role-modal", inputs: ["deleteRowKeys", "showDeleteModal$"], outputs: ["deleteEvent"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
654
1280
|
}
|
|
655
1281
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlEditorComponent, decorators: [{
|
|
656
1282
|
type: Component,
|
|
657
|
-
args: [{ standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n
|
|
658
|
-
}], ctorParameters: () => [{ type: AccessControlService }, { type:
|
|
1283
|
+
args: [{ standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n ~ Copyright 2015-2025 Ritense BV, the Netherlands.\n ~\n ~ Licensed under EUPL, Version 1.2 (the \"License\");\n ~ you may not use this file except in compliance with the License.\n ~ You may obtain a copy of the License at\n ~\n ~ https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n ~\n ~ Unless required by applicable law or agreed to in writing, software\n ~ distributed under the License is distributed on an \"AS IS\" basis,\n ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n ~ See the License for the specific language governing permissions and\n ~ limitations under the License.\n -->\n\n<ng-container *ngIf=\"model$ | async as model; else loading\">\n <cds-tabs type=\"contained\">\n <cds-tab\n [active]=\"$activeTab() === AccessControlEditorTab.SUMMARY\"\n [heading]=\"'accessControl.roles.tabs.summary' | translate\"\n (selected)=\"setActiveTab(AccessControlEditorTab.SUMMARY)\"\n >\n <valtimo-access-control-overview-tab\n *ngIf=\"$activeTab() === AccessControlEditorTab.SUMMARY\"\n [permissions]=\"permissions$ | async\"\n [roleKey]=\"roleKey$ | async\"\n ></valtimo-access-control-overview-tab>\n </cds-tab>\n\n <cds-tab\n [active]=\"$activeTab() === AccessControlEditorTab.JSON_EDITOR\"\n [heading]=\"'accessControl.roles.tabs.jsonEditor' | translate\"\n (selected)=\"setActiveTab(AccessControlEditorTab.JSON_EDITOR)\"\n >\n <valtimo-access-control-json-editor-tab\n *ngIf=\"$activeTab() === AccessControlEditorTab.JSON_EDITOR\"\n [disabled]=\"editorDisabled$ | async\"\n [model]=\"model\"\n (validEvent)=\"onValid($event)\"\n (valueChangeEvent)=\"onValueChange($event)\"\n ></valtimo-access-control-json-editor-tab>\n </cds-tab>\n </cds-tabs>\n</ng-container>\n\n<ng-container renderInPageHeader>\n <ng-template>\n <div\n *ngIf=\"{\n model: model$ | async,\n moreDisabled: moreDisabled$ | async,\n compactMode: compactMode$ | async,\n } as obs\"\n class=\"buttons-container\"\n >\n <v-overflow-menu class=\"overflow-button\" placement=\"bottom-end\">\n <v-overflow-menu-trigger overflowTrigger></v-overflow-menu-trigger>\n <v-overflow-menu-option [disabled]=\"obs.moreDisabled\" (selected)=\"showEditModal()\">{{\n 'accessControl.roles.editMetadata' | translate\n }}</v-overflow-menu-option>\n\n <v-overflow-menu-option [disabled]=\"obs.moreDisabled\" (selected)=\"exportPermissions()\">{{\n 'interface.export' | translate\n }}</v-overflow-menu-option>\n\n <v-overflow-menu-option\n [disabled]=\"obs.moreDisabled\"\n type=\"danger\"\n (selected)=\"showDeleteModal()\"\n >{{ 'interface.delete' | translate }}</v-overflow-menu-option\n >\n </v-overflow-menu>\n\n <button\n [disabled]=\"saveDisabled$ | async\"\n cdsButton=\"primary\"\n [size]=\"obs.compactMode ? 'sm' : 'md'\"\n (click)=\"updatePermissions()\"\n >\n {{ 'interface.save' | translate }}\n\n <svg class=\"cds--btn__icon\" cdsIcon=\"save\" size=\"16\"></svg>\n </button>\n </div>\n </ng-template>\n</ng-container>\n\n<ng-container *ngIf=\"{selectedRowKeys: selectedRowKeys$ | async} as obs\">\n <valtimo-delete-role-modal\n [deleteRowKeys]=\"obs.selectedRowKeys\"\n [showDeleteModal$]=\"showDeleteModal$\"\n (deleteEvent)=\"onDelete($event)\"\n >\n </valtimo-delete-role-modal>\n\n <valtimo-role-metadata-modal\n [defaultKeyValue]=\"obs.selectedRowKeys[0]\"\n [open]=\"showEditModal$ | async\"\n type=\"edit\"\n (closeEvent)=\"onEdit(obs.selectedRowKeys[0], $event)\"\n ></valtimo-role-metadata-modal>\n</ng-container>\n\n<ng-template #loading>\n <div class=\"loading-container\">\n <cds-loading></cds-loading>\n </div>\n</ng-template>\n", styles: [".loading-container{display:flex;width:100%;justify-content:center}.overflow-button{margin-right:16px}.buttons-container{display:flex;flex-direction:row;align-items:center}.buttons-container button{height:min-content}:host ::ng-deep .cds--tab-content{background-color:#fff}\n/*!\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"] }]
|
|
1284
|
+
}], ctorParameters: () => [{ type: AccessControlService }, { type: i1$2.ActivatedRoute }, { type: i3.PageTitleService }, { type: i1$2.Router }, { type: i1.GlobalNotificationService }, { type: i4$1.TranslateService }, { type: AccessControlExportService }, { type: i3.PageHeaderService }] });
|
|
659
1285
|
|
|
660
1286
|
/*
|
|
661
1287
|
* Copyright 2015-2025 Ritense BV, the Netherlands.
|
|
@@ -689,10 +1315,20 @@ const routes = [
|
|
|
689
1315
|
customPageTitle: true,
|
|
690
1316
|
},
|
|
691
1317
|
},
|
|
1318
|
+
{
|
|
1319
|
+
path: 'access-control/:id/json-editor',
|
|
1320
|
+
component: AccessControlEditorComponent,
|
|
1321
|
+
canActivate: [AuthGuardService],
|
|
1322
|
+
data: {
|
|
1323
|
+
title: 'Role details',
|
|
1324
|
+
roles: [ROLE_ADMIN],
|
|
1325
|
+
customPageTitle: true,
|
|
1326
|
+
},
|
|
1327
|
+
},
|
|
692
1328
|
];
|
|
693
1329
|
class AccessControlManagementRoutingModule {
|
|
694
1330
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlManagementRoutingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
695
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: AccessControlManagementRoutingModule, imports: [CommonModule,
|
|
1331
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: AccessControlManagementRoutingModule, imports: [CommonModule, i1$2.RouterModule], exports: [RouterModule] }); }
|
|
696
1332
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlManagementRoutingModule, imports: [CommonModule, RouterModule.forChild(routes), RouterModule] }); }
|
|
697
1333
|
}
|
|
698
1334
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlManagementRoutingModule, decorators: [{
|
|
@@ -734,7 +1370,6 @@ class AccessControlManagementModule {
|
|
|
734
1370
|
InputModule,
|
|
735
1371
|
IconModule,
|
|
736
1372
|
ConfirmationModalModule,
|
|
737
|
-
EditorModule,
|
|
738
1373
|
RenderInPageHeaderDirective,
|
|
739
1374
|
LoadingModule,
|
|
740
1375
|
IconModule,
|
|
@@ -742,7 +1377,10 @@ class AccessControlManagementModule {
|
|
|
742
1377
|
OverflowMenuOptionComponent,
|
|
743
1378
|
OverflowMenuTriggerComponent,
|
|
744
1379
|
NotificationModule,
|
|
745
|
-
CarbonListModule
|
|
1380
|
+
CarbonListModule,
|
|
1381
|
+
TabsModule,
|
|
1382
|
+
AccessControlJsonEditorTabComponent,
|
|
1383
|
+
AccessControlOverviewTabComponent] }); }
|
|
746
1384
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlManagementModule, imports: [CommonModule,
|
|
747
1385
|
AccessControlManagementRoutingModule,
|
|
748
1386
|
ButtonModule,
|
|
@@ -753,14 +1391,16 @@ class AccessControlManagementModule {
|
|
|
753
1391
|
InputModule,
|
|
754
1392
|
IconModule,
|
|
755
1393
|
ConfirmationModalModule,
|
|
756
|
-
EditorModule,
|
|
757
1394
|
LoadingModule,
|
|
758
1395
|
IconModule,
|
|
759
1396
|
OverflowMenuComponent,
|
|
760
1397
|
OverflowMenuOptionComponent,
|
|
761
1398
|
OverflowMenuTriggerComponent,
|
|
762
1399
|
NotificationModule,
|
|
763
|
-
CarbonListModule
|
|
1400
|
+
CarbonListModule,
|
|
1401
|
+
TabsModule,
|
|
1402
|
+
AccessControlJsonEditorTabComponent,
|
|
1403
|
+
AccessControlOverviewTabComponent] }); }
|
|
764
1404
|
}
|
|
765
1405
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccessControlManagementModule, decorators: [{
|
|
766
1406
|
type: NgModule,
|
|
@@ -783,7 +1423,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
783
1423
|
InputModule,
|
|
784
1424
|
IconModule,
|
|
785
1425
|
ConfirmationModalModule,
|
|
786
|
-
EditorModule,
|
|
787
1426
|
RenderInPageHeaderDirective,
|
|
788
1427
|
LoadingModule,
|
|
789
1428
|
IconModule,
|
|
@@ -792,6 +1431,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
792
1431
|
OverflowMenuTriggerComponent,
|
|
793
1432
|
NotificationModule,
|
|
794
1433
|
CarbonListModule,
|
|
1434
|
+
TabsModule,
|
|
1435
|
+
AccessControlJsonEditorTabComponent,
|
|
1436
|
+
AccessControlOverviewTabComponent,
|
|
795
1437
|
],
|
|
796
1438
|
}]
|
|
797
1439
|
}] });
|
|
@@ -819,5 +1461,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
|
|
|
819
1461
|
* Generated bundle index. Do not edit.
|
|
820
1462
|
*/
|
|
821
1463
|
|
|
822
|
-
export { AccessControlManagementModule, AccessControlService };
|
|
1464
|
+
export { AccessControlEditorTab, AccessControlManagementModule, AccessControlService, PermissionSchemaMetadataService };
|
|
823
1465
|
//# sourceMappingURL=valtimo-access-control-management.mjs.map
|