@firestitch/app-acl 18.0.11 → 18.0.13

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.
@@ -1,41 +1,41 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, Pipe, ChangeDetectorRef, Component, ChangeDetectionStrategy, ViewChild, Input, QueryList, ViewChildren, EventEmitter, Output } from '@angular/core';
3
- import { MAT_DIALOG_DATA, MatDialogRef, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose, MatDialog } from '@angular/material/dialog';
4
- import { list } from '@firestitch/common';
5
- import { ItemType } from '@firestitch/filter';
6
- import * as i1$1 from '@firestitch/list';
2
+ import { InjectionToken, inject, Injectable, EventEmitter, Component, Input, Output, ChangeDetectorRef, ViewChild, Pipe, ChangeDetectionStrategy, QueryList, ViewChildren, NgModule } from '@angular/core';
3
+ import { MatDialogRef, MAT_DIALOG_DATA, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose, MatDialog } from '@angular/material/dialog';
4
+ import { shareReplay, map, tap, takeUntil, filter } from 'rxjs/operators';
5
+ import { forkJoin, Subject, Observable, of } from 'rxjs';
6
+ import { groupBy, sortBy } from 'lodash-es';
7
+ import * as i1$3 from '@firestitch/list';
7
8
  import { FsListComponent, FsListModule } from '@firestitch/list';
8
- import { Subject, forkJoin, of, Observable } from 'rxjs';
9
- import { shareReplay, map, takeUntil, tap, filter } from 'rxjs/operators';
10
- import { MatButton } from '@angular/material/button';
11
- import { FsMessage } from '@firestitch/message';
12
- import * as i1 from '@angular/forms';
9
+ import { FsPrompt } from '@firestitch/prompt';
10
+ import * as i2$1 from '@firestitch/badge';
11
+ import { FsBadgeModule } from '@firestitch/badge';
12
+ import { list } from '@firestitch/common';
13
+ import * as i1$1 from '@angular/forms';
13
14
  import { FormsModule, ControlContainer, NgForm } from '@angular/forms';
14
- import * as i2 from '@firestitch/form';
15
- import { FsFormModule } from '@firestitch/form';
15
+ import { CdkScrollable } from '@angular/cdk/scrolling';
16
+ import { MatButton } from '@angular/material/button';
16
17
  import * as i3 from '@firestitch/dialog';
17
18
  import { FsDialogModule } from '@firestitch/dialog';
18
- import { CdkScrollable } from '@angular/cdk/scrolling';
19
- import { MatFormField, MatLabel, MatHint } from '@angular/material/form-field';
20
- import { MatInput } from '@angular/material/input';
19
+ import * as i2 from '@firestitch/form';
20
+ import { FsFormModule } from '@firestitch/form';
21
21
  import * as i4 from '@firestitch/label';
22
22
  import { FsLabelModule } from '@firestitch/label';
23
- import * as i5 from '@firestitch/radiogroup';
24
- import { FsRadioGroupModule } from '@firestitch/radiogroup';
25
- import { MatRadioButton } from '@angular/material/radio';
23
+ import { FsMessage } from '@firestitch/message';
26
24
  import { MatCheckbox } from '@angular/material/checkbox';
27
- import { MatSelect } from '@angular/material/select';
28
25
  import { MatOption } from '@angular/material/core';
29
- import * as i7 from '@firestitch/menu';
30
- import { FsMenuModule } from '@firestitch/menu';
26
+ import { MatFormField, MatLabel, MatHint } from '@angular/material/form-field';
27
+ import { MatSelect } from '@angular/material/select';
28
+ import * as i1 from '@firestitch/checkboxgroup';
29
+ import { FsCheckboxGroupModule } from '@firestitch/checkboxgroup';
31
30
  import * as i1$2 from '@firestitch/popover';
32
31
  import { FsPopoverModule } from '@firestitch/popover';
33
- import { groupBy, sortBy } from 'lodash-es';
34
- import { FsPrompt } from '@firestitch/prompt';
35
- import * as i2$1 from '@firestitch/badge';
36
- import { FsBadgeModule } from '@firestitch/badge';
37
- import * as i1$3 from '@firestitch/checkboxgroup';
38
- import { FsCheckboxGroupModule } from '@firestitch/checkboxgroup';
32
+ import { MatInput } from '@angular/material/input';
33
+ import { MatRadioButton } from '@angular/material/radio';
34
+ import * as i7 from '@firestitch/menu';
35
+ import { FsMenuModule } from '@firestitch/menu';
36
+ import * as i5 from '@firestitch/radiogroup';
37
+ import { FsRadioGroupModule } from '@firestitch/radiogroup';
38
+ import { ItemType } from '@firestitch/filter';
39
39
 
40
40
  const FS_APP_ACL_CONFIG = new InjectionToken('fs-app-acl-config');
41
41
 
@@ -71,823 +71,870 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImpor
71
71
  }]
72
72
  }] });
73
73
 
74
- var AclRoleAccess;
75
- (function (AclRoleAccess) {
76
- AclRoleAccess[AclRoleAccess["None"] = 0] = "None";
77
- AclRoleAccess[AclRoleAccess["Read"] = 5] = "Read";
78
- AclRoleAccess[AclRoleAccess["Write"] = 10] = "Write";
79
- AclRoleAccess[AclRoleAccess["Full"] = 15] = "Full";
80
- })(AclRoleAccess || (AclRoleAccess = {}));
81
-
82
- const AclRoleAccesses = [
83
- { name: 'None', value: AclRoleAccess.None },
84
- { name: 'Read', value: AclRoleAccess.Read },
85
- { name: 'Write', value: AclRoleAccess.Write },
86
- { name: 'Full', value: AclRoleAccess.Full }
87
- ];
88
-
89
- class BulkOptionsFilterPipe {
90
- transform(rolesList, children) {
91
- const accessLevels = this._uniqListOfAccessLevels(children);
92
- return rolesList.filter((permission) => {
93
- return permission.value === 0 || accessLevels.has(permission.value);
94
- });
95
- }
96
- _uniqListOfAccessLevels(children) {
97
- return children.reduce((acc, value) => {
98
- value.accesses.forEach((access) => {
99
- acc.add(access);
100
- });
101
- return acc;
102
- }, (new Set));
103
- }
104
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: BulkOptionsFilterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
105
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: BulkOptionsFilterPipe, isStandalone: true, name: "builkOptionsFilter" });
106
- }
107
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: BulkOptionsFilterPipe, decorators: [{
108
- type: Pipe,
109
- args: [{
110
- name: 'builkOptionsFilter',
111
- standalone: true
112
- }]
113
- }] });
114
-
115
- class AclRolePermissionAvailablePipe {
116
- transform(permission, aclRolePermissions) {
117
- if (permission.requires && permission.requires.length) {
118
- const exists = permission.requires
119
- .every((item) => aclRolePermissions[item]);
120
- return exists;
121
- }
122
- return true;
74
+ class FsAclObjectRolesComponent {
75
+ aclRoles = [];
76
+ required = false;
77
+ multiple = false;
78
+ disabled = false;
79
+ aclObjectRoles = [];
80
+ rolesLabel = 'Roles';
81
+ levelLabel = '';
82
+ change = new EventEmitter();
83
+ compareAclRole = (o1, o2) => {
84
+ return o1 && o2 && o1.id === o2.id;
85
+ };
86
+ changed() {
87
+ this.change.emit(this.aclObjectRoles);
123
88
  }
124
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: AclRolePermissionAvailablePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
125
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: AclRolePermissionAvailablePipe, isStandalone: true, name: "aclRolePermissionAvailable" });
89
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclObjectRolesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
90
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclObjectRolesComponent, isStandalone: true, selector: "fs-acl-object-roles", inputs: { aclRoles: "aclRoles", required: "required", multiple: "multiple", disabled: "disabled", aclObjectRoles: "aclObjectRoles", rolesLabel: "rolesLabel", levelLabel: "levelLabel" }, outputs: { change: "change" }, ngImport: i0, template: "@if (!multiple) {\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole.object?.id) {\n <fs-checkbox-group\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n (ngModelChange)=\"changed()\"\n name=\"roles\"\n [compareWith]=\"compareAclRole\"\n [disabled]=\"disabled\"\n [label]=\"rolesLabel\"\n [fsFormRequired]=\"required\"\n orientation=\"vertical\">\n @for (aclRole of aclRoles; track aclRole.id) {\n <mat-checkbox [disabled]=\"disabled\" [value]=\"$any(aclRole)\">\n {{ aclRole.name }}\n </mat-checkbox>\n }\n </fs-checkbox-group>\n }\n}\n\n@if (multiple) {\n <table>\n <tr>\n <td>\n <small>{{levelLabel}}</small>\n </td>\n <td>\n <small>{{rolesLabel}}</small>\n </td>\n </tr>\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole.object?.id) {\n <tr>\n <td>{{aclObjectRole.object.name}}</td>\n <td>\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n multiple=\"true\"\n [disabled]=\"disabled\"\n [compareWith]=\"compareAclRole\"\n (ngModelChange)=\"changed()\"\n name=\"aclRole_{{ aclObjectRole.object.id }}\">\n @for (aclRole of aclRoles; track aclRole.id) {\n <mat-option [value]=\"aclRole\">\n {{ aclRole.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </td>\n </tr>\n }\n </table>\n}\n", styles: ["table tr td:first-child{padding-right:15px}\n"], dependencies: [{ kind: "ngmodule", type: FsCheckboxGroupModule }, { kind: "component", type: i1.FsCheckboxGroupComponent, selector: "fs-checkbox-group", inputs: ["orientation", "position", "label", "disabled", "compareWith"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormRequiredDirective, selector: "[fsFormRequired],[ngModel][required]", inputs: ["fsFormRequired", "required", "fsFormRequiredMessage"] }, { kind: "directive", type: i2.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] });
126
91
  }
127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: AclRolePermissionAvailablePipe, decorators: [{
128
- type: Pipe,
129
- args: [{
130
- name: 'aclRolePermissionAvailable',
131
- standalone: true
132
- }]
133
- }] });
92
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclObjectRolesComponent, decorators: [{
93
+ type: Component,
94
+ args: [{ selector: 'fs-acl-object-roles', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], standalone: true, imports: [FsCheckboxGroupModule, FormsModule, FsFormModule, MatCheckbox, MatFormField, MatSelect, MatOption], template: "@if (!multiple) {\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole.object?.id) {\n <fs-checkbox-group\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n (ngModelChange)=\"changed()\"\n name=\"roles\"\n [compareWith]=\"compareAclRole\"\n [disabled]=\"disabled\"\n [label]=\"rolesLabel\"\n [fsFormRequired]=\"required\"\n orientation=\"vertical\">\n @for (aclRole of aclRoles; track aclRole.id) {\n <mat-checkbox [disabled]=\"disabled\" [value]=\"$any(aclRole)\">\n {{ aclRole.name }}\n </mat-checkbox>\n }\n </fs-checkbox-group>\n }\n}\n\n@if (multiple) {\n <table>\n <tr>\n <td>\n <small>{{levelLabel}}</small>\n </td>\n <td>\n <small>{{rolesLabel}}</small>\n </td>\n </tr>\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole.object?.id) {\n <tr>\n <td>{{aclObjectRole.object.name}}</td>\n <td>\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n multiple=\"true\"\n [disabled]=\"disabled\"\n [compareWith]=\"compareAclRole\"\n (ngModelChange)=\"changed()\"\n name=\"aclRole_{{ aclObjectRole.object.id }}\">\n @for (aclRole of aclRoles; track aclRole.id) {\n <mat-option [value]=\"aclRole\">\n {{ aclRole.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </td>\n </tr>\n }\n </table>\n}\n", styles: ["table tr td:first-child{padding-right:15px}\n"] }]
95
+ }], propDecorators: { aclRoles: [{
96
+ type: Input
97
+ }], required: [{
98
+ type: Input
99
+ }], multiple: [{
100
+ type: Input
101
+ }], disabled: [{
102
+ type: Input
103
+ }], aclObjectRoles: [{
104
+ type: Input
105
+ }], rolesLabel: [{
106
+ type: Input
107
+ }], levelLabel: [{
108
+ type: Input
109
+ }], change: [{
110
+ type: Output
111
+ }] } });
134
112
 
135
- class FsAclRoleComponent {
136
- _data = inject(MAT_DIALOG_DATA);
113
+ class FsAclEntryComponent {
114
+ aclRoles = [];
115
+ aclObjectEntry;
116
+ aclObjectRole;
117
+ aclEntries = [];
118
+ indexedAclRoleLevels = {};
119
+ titleEdit = 'Edit Roles';
120
+ titleAdd = 'Assign Roles';
121
+ required = true;
137
122
  _appAclService = inject(FsAppAclService);
138
123
  _dialogRef = inject(MatDialogRef);
139
124
  _message = inject(FsMessage);
125
+ _data = inject(MAT_DIALOG_DATA);
140
126
  _cdRef = inject(ChangeDetectorRef);
141
- list;
142
- submitButton;
143
- aclRole = null;
144
- environment;
145
- permissions = [];
146
- listConfig;
147
- levelPermissions = [];
148
- AclRoleAccesses = AclRoleAccesses;
149
- indexedAccesses = {};
150
- aclLevels = [];
151
- indexedAclLevels = {};
152
- onlyFullAccess = false;
153
- AclLevels = {};
154
- roleConfigs = [];
155
- aclRoleConfigValues = {};
156
- aclRolePermissions = {};
157
- loadRoleConfigs;
158
- disabled;
159
- _destroy$ = new Subject();
127
+ constructor() {
128
+ const _data = this._data;
129
+ this.aclObjectEntry = { ..._data.aclObjectEntry };
130
+ this.required = _data.required ?? true;
131
+ if (_data.titleEdit) {
132
+ this.titleEdit = _data.titleEdit;
133
+ }
134
+ if (_data.titleAdd) {
135
+ this.titleAdd = _data.titleAdd;
136
+ }
137
+ }
160
138
  ngOnInit() {
161
- forkJoin(this.getRole(), this._appAclService.getPermissions())
162
- .pipe(takeUntil(this._destroy$))
163
- .subscribe(([aclRole, aclPermissions,]) => {
164
- this.permissions = aclPermissions;
165
- this.aclLevels = this._data.aclLevels;
166
- this.disabled = this._data.disabled;
167
- this.indexedAclLevels = list(this.aclLevels, 'name', 'value');
168
- this.indexedAccesses = list(AclRoleAccesses, 'name', 'value');
169
- this.aclRole = {
170
- ...{
171
- aclPermissions: [],
172
- allPermissions: true,
173
- aclRoleConfigs: [],
174
- permissions: {},
175
- level: this.aclLevels[0].value,
176
- },
177
- ...aclRole,
139
+ forkJoin([
140
+ this._data.loadAclRoles({
141
+ level: this.aclObjectEntry.level,
142
+ environmentId: this.aclObjectEntry.environmentId || null,
143
+ }),
144
+ this._appAclService.getIndexedLevels(),
145
+ ])
146
+ .subscribe(([aclRoles, levels]) => {
147
+ this.aclRoles = aclRoles;
148
+ this.indexedAclRoleLevels = levels;
149
+ this.aclObjectRole = {
150
+ object: this.aclObjectEntry.object,
151
+ aclRoles: this.aclObjectEntry.aclEntries
152
+ .map((aclEntry) => {
153
+ return aclEntry.aclRole;
154
+ }),
178
155
  };
179
- this.aclRoleConfigValues = (aclRole.aclRoleConfigs || [])
180
- .reduce((accum, aclRoleConfig) => {
181
- return {
182
- ...accum,
183
- [aclRoleConfig.name]: aclRoleConfig.value,
184
- };
185
- }, {});
186
- if (this.aclRole.id) {
187
- this.permissions.forEach((permission) => {
188
- let access = 0;
189
- const aclPermission = this.aclRole.aclPermissions.find((item) => {
190
- return item.permission === permission.value;
191
- });
192
- if (aclPermission) {
193
- access = aclPermission.access;
194
- }
195
- this.aclRolePermissions[permission.value] = access;
196
- });
197
- }
198
- if (this.aclRole.allPermissions) {
199
- this._applyMaxPermissionAccess();
200
- }
201
- this._updatePermissions();
202
- this._updateRoleConfigs();
203
156
  this._cdRef.markForCheck();
204
157
  });
205
- this.listConfig = {
206
- status: false,
207
- paging: false,
208
- rowHoverHighlight: false,
209
- noResults: {
210
- message: '',
211
- },
212
- group: {
213
- initialExpand: true,
214
- groupBy: (data) => {
215
- return data;
216
- },
217
- compareBy: (data) => {
218
- return data.category || 'General';
219
- },
220
- },
221
- fetch: () => {
222
- return of({
223
- data: this.levelPermissions.sort((a, b) => {
224
- a = a.name.toUpperCase();
225
- b = b.name.toUpperCase();
226
- if (a < b) {
227
- return -1;
228
- }
229
- else if (a > b) {
230
- return 1;
231
- }
232
- return 0;
233
- }),
234
- });
235
- },
236
- };
237
- }
238
- bulkChange(value, groupChildren, group) {
239
- groupChildren
240
- .forEach((permission) => {
241
- const access = permission.accesses
242
- .find((access) => value === access);
243
- if (access || !value) {
244
- this.aclRolePermissions[permission.value] = value;
245
- }
246
- });
247
- setTimeout(() => {
248
- this.submitButton.disabled = false;
249
- this.permissionChange();
250
- });
251
- }
252
- permissionChange() {
253
- this.aclRolePermissions = {
254
- ...this.aclRolePermissions,
255
- };
256
- this._cdRef.markForCheck();
257
- }
258
- levelChange() {
259
- this._updatePermissions();
260
- this._updateRoleConfigs();
261
- this.list.reload();
262
158
  }
263
- getRole() {
264
- if (!this._data.aclRole.id) {
265
- return of(this._data.aclRole);
266
- }
267
- const query = {
268
- aclPermissions: true,
269
- aclRoleConfigs: true,
270
- };
271
- if (!this.environment) {
272
- query.environmentId = null;
273
- }
274
- return this._data.loadAclRole(this._data.aclRole, query);
159
+ aclObjectRoleChange(aclObjectRoles) {
160
+ this.aclEntries = aclObjectRoles.reduce((aclEntries, aclObjectRole) => {
161
+ aclObjectRole.aclRoles.forEach((aclRole) => {
162
+ aclEntries.push({
163
+ aclRoleId: aclRole.id,
164
+ aclRole: aclRole,
165
+ objectId: aclObjectRole.object ? aclObjectRole.object.id : null,
166
+ object: aclObjectRole.object || null,
167
+ });
168
+ });
169
+ return aclEntries;
170
+ }, []);
275
171
  }
276
172
  save = () => {
277
- const aclRoleConfigs = this.roleConfigs
278
- .map((roleConfig) => {
279
- return {
280
- name: roleConfig.name,
281
- value: this.aclRoleConfigValues[roleConfig.name],
282
- };
283
- });
284
- const aclRole = {
285
- ...this.aclRole,
286
- permissions: this.levelPermissions.map((permission) => {
287
- return {
288
- value: permission.value,
289
- access: this.aclRolePermissions[permission.value] || 0,
290
- };
291
- }),
292
- aclRoleConfigs,
173
+ const aclObjectEntry = {
174
+ ...this.aclObjectEntry,
175
+ aclEntries: this.aclEntries,
293
176
  };
294
- return this._data.saveAclRole(aclRole)
295
- .pipe(tap((response) => {
177
+ return this._data.saveAclObjectEntry(aclObjectEntry)
178
+ .pipe(tap((data) => {
296
179
  this._message.success('Saved Changes');
297
- this.close(response);
180
+ this.close(data);
298
181
  }));
299
182
  };
300
183
  close(data = null) {
301
184
  this._dialogRef.close(data);
302
185
  }
303
- allPermissionsChange(all) {
304
- this._updatePermissions();
305
- if (all) {
306
- this._applyMaxPermissionAccess();
307
- }
308
- else {
309
- this._applyNonePermissionAccess();
310
- }
311
- }
312
- ngOnDestroy() {
313
- this._destroy$.next(null);
314
- this._destroy$.complete();
315
- }
316
- _updatePermissions() {
317
- this.levelPermissions = this.permissions
318
- .filter((permission) => {
319
- return permission.levels.some((item) => {
320
- return item === this.aclRole.level;
321
- });
322
- });
323
- }
324
- _updateRoleConfigs() {
325
- if (this._data.loadRoleConfigs) {
326
- this._data.loadRoleConfigs()
327
- .subscribe((roleConfigs) => {
328
- this.roleConfigs = roleConfigs
329
- .filter((roleConfig) => roleConfig.level === this.aclRole.level);
330
- this._cdRef.markForCheck();
331
- });
332
- }
333
- }
334
- _applyMaxPermissionAccess() {
335
- this.permissions.forEach((permission) => {
336
- this.aclRolePermissions[permission.value] = Math.max(...permission.accesses);
337
- });
338
- }
339
- _applyNonePermissionAccess() {
340
- this.permissions.forEach((permission) => {
341
- this.aclRolePermissions[permission.value] = AclRoleAccess.None;
342
- });
343
- }
344
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRoleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
345
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclRoleComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "list", first: true, predicate: FsListComponent, descendants: true }, { propertyName: "submitButton", first: true, predicate: ["submit"], descendants: true }], ngImport: i0, template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n @if (aclRole) {\n <div mat-dialog-title>\n @if (!disabled) {\n {{ aclRole.id ? 'Edit' : 'Create' }}\n }\n @if (disabled) {\n View\n }\n role\n </div>\n <mat-dialog-content>\n <div class=\"fs-row.gap-lg.align-start\">\n <div class=\"fs-column left-column\">\n <mat-form-field>\n <mat-label>\n Name\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.name\"\n [disabled]=\"disabled\"\n name=\"name\"\n fsFormRequired>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Description\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.description\"\n [disabled]=\"disabled\"\n name=\"description\">\n </mat-form-field>\n @if (aclRole.id || aclLevels.length === 1) {\n <fs-label-field>\n <fs-label>\n Level\n </fs-label>\n {{ indexedAclLevels[aclRole.level] }}\n </fs-label-field>\n } @else {\n <div class=\"level\">\n <fs-radio-group\n [(ngModel)]=\"aclRole.level\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"levelChange()\"\n fsFormRequired\n label=\"Level\"\n orientation=\"vertical\"\n name=\"level\">\n @for (item of aclLevels; track item) {\n <mat-radio-button\n [value]=\"item.value\"\n [disabled]=\"!!aclRole.protected\">\n {{ item.name }}\n </mat-radio-button>\n }\n </fs-radio-group>\n </div>\n }\n @if (levelPermissions.length) {\n <fs-label-field>\n <fs-label>\n All permissions\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRole.allPermissions\"\n (ngModelChange)=\"allPermissionsChange($event)\"\n [disabled]=\"!!aclRole.protected || disabled\"\n name=\"allPermissions\">\n Enable\n </mat-checkbox>\n </fs-label-field>\n }\n @for (roleConfig of roleConfigs; track roleConfig) {\n <div\n class=\"fs-column\"\n >\n @if (roleConfig.type === 'checkbox') {\n <fs-label-field>\n <fs-label>\n {{ roleConfig.label }}\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [disabled]=\"disabled\"\n [name]=\"roleConfig.name\">\n Enable\n </mat-checkbox>\n <fs-label-message>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </fs-label-message>\n </fs-label-field>\n }\n @if (roleConfig.type === 'select') {\n <mat-form-field>\n <mat-select\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [name]=\"roleConfig.name\"\n [required]=\"roleConfig.required\"\n [disabled]=\"disabled\"\n [placeholder]=\"roleConfig.label\">\n @for (item of roleConfig.values; track item) {\n <mat-option\n [value]=\"item.value\">\n {{ item.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </mat-form-field>\n }\n </div>\n }\n </div>\n @if (aclRole.level) {\n <div\n [hidden]=\"!levelPermissions.length\"\n class=\"permissions fs-column\">\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Permissions\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n class=\"permission-group\">\n <div class=\"permission-group\">\n {{ row.category || 'General' }}\n </div>\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"permission\">\n {{ row.name }}\n </div>\n <div class=\"description small\">\n {{ row.description }}\n </div>\n </ng-template>\n </fs-list-column>\n <fs-list-column\n title=\"Access\"\n width=\"1%\"\n class=\"access\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n let-group=\"group\"\n let-groupChildren=\"groupChildren\"\n class=\"permission-group\"\n align=\"right\">\n @if (!aclRole.allPermissions && !disabled) {\n <fs-menu>\n @for (access of AclRoleAccesses | builkOptionsFilter: groupChildren; track access) {\n <ng-template\n fs-menu-item\n (click)=\"bulkChange(access.value, groupChildren, group)\">\n {{ access.name }}\n </ng-template>\n }\n </fs-menu>\n }\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"permission\"\n let-permission=\"row\">\n @if (aclRole.allPermissions || disabled) {\n <span>\n {{ indexedAccesses[aclRolePermissions[permission.value]] }}\n </span>\n } @else {\n @if (permission|aclRolePermissionAvailable:aclRolePermissions) {\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclRolePermissions[permission.value]\"\n [disabled]=\"!!aclRole.protected\"\n required\n [name]=\"'access-' + permission.value\"\n (ngModelChange)=\"permissionChange()\">\n @for (access of AclRoleAccesses; track access) {\n @if (access.value === 0 || permission.accesses.indexOf(access.value) !== -1) {\n <mat-option\n [value]=\"access.value\">\n {{ access.name }}\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n } @else {\n Unavailable\n }\n }\n </ng-template>\n </fs-list-column>\n </fs-list>\n </div>\n }\n </div>\n </mat-dialog-content>\n <mat-dialog-actions>\n @if (!disabled) {\n <button\n #submit\n mat-button\n type=\"submit\"\n color=\"primary\">\n {{ aclRole.id ? 'Save' : 'Create' }}\n </button>\n }\n <button\n mat-button\n [mat-dialog-close]=\"null\"\n type=\"button\">\n {{ disabled ? 'Done' : 'Cancel' }}\n </button>\n </mat-dialog-actions>\n }\n </fs-dialog>\n</form>", styles: [".permissions{flex:1}.permissions ::ng-deep .fs-list-row-group{background-color:#e4e4e4;font-size:112%}.permissions ::ng-deep fs-list .access{white-space:nowrap}.permissions ::ng-deep .mat-form-field{width:100px}.permissions ::ng-deep .mat-form-field .mat-form-field-wrapper{padding-bottom:0}.permissions ::ng-deep .mat-form-field .mat-form-field-infix{border-top:0}.permissions ::ng-deep .mat-form-field .mat-form-field-underline{bottom:0}.permissions ::ng-deep fs-radio-group{width:100%}.permissions ::ng-deep fs-label-field{width:100%}.permissions .level{width:100%}.left-column{width:40%;max-width:400px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormDirective, selector: "[fsForm]", inputs: ["wrapperSelector", "messageSelector", "hintSelector", "labelSelector", "autocomplete", "shortcuts", "confirm", "confirmDialog", "confirmDrawer", "confirmBrowser", "confirmTabs", "dirtySubmitButton", "submit", "successDelay", "errorDelay", "tabGroup", "deactivationGuard"], outputs: ["fsForm", "invalid", "valid", "submitted", "reseted", "cleared"], exportAs: ["fsForm"] }, { kind: "directive", type: i2.FsFormRequiredDirective, selector: "[fsFormRequired],[ngModel][required]", inputs: ["fsFormRequired", "required", "fsFormRequiredMessage"] }, { kind: "directive", type: i2.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "directive", type: i2.FsButtonDirective, selector: "[mat-raised-button]:not([fsFormButtonStandalone]),[mat-button]:not([fsFormButtonStandalone]),[mat-flat-button]:not([fsFormButtonStandalone]),[mat-stroked-button]:not([fsFormButtonStandalone])", inputs: ["name", "dirtySubmit", "form"] }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i3.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: FsLabelModule }, { kind: "component", type: i4.FsLabelComponent, selector: "fs-label" }, { kind: "component", type: i4.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["appearance", "showOutline", "disabled", "focused", "hoverable", "padless"] }, { kind: "component", type: i4.FsLabelMessageComponent, selector: "fs-label-message" }, { kind: "ngmodule", type: FsRadioGroupModule }, { kind: "component", type: i5.FsRadioGroupComponent, selector: "fs-radio-group", inputs: ["orientation", "label", "name", "disabled", "radioPosition", "compareWith", "required"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: FsListModule }, { kind: "component", type: i1$1.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines"], outputs: ["filtersReady"] }, { kind: "directive", type: i1$1.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i1$1.FsListCellDirective, selector: "[fs-list-cell]", inputs: ["colspan", "align", "class"] }, { kind: "directive", type: i1$1.FsListGroupHeaderDirective, selector: "[fs-list-group-cell],[fs-list-group-header]" }, { kind: "ngmodule", type: FsMenuModule }, { kind: "component", type: i7.FsMenuComponent, selector: "fs-menu", inputs: ["class", "buttonClass", "buttonType", "buttonColor"], outputs: ["opened", "closed"] }, { kind: "directive", type: i7.FsMenuItemDirective, selector: "fs-menu-group,[fs-menu-item]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "pipe", type: BulkOptionsFilterPipe, name: "builkOptionsFilter" }, { kind: "pipe", type: AclRolePermissionAvailablePipe, name: "aclRolePermissionAvailable" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
186
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
187
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclEntryComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "<form fsForm [submit]=\"save\">\n <fs-dialog>\n <div mat-dialog-title>{{ titleEdit? titleEdit : titleAdd }}</div>\n <mat-dialog-content>\n @if (aclObjectRole) {\n <div>\n @if (aclObjectEntry.object) {\n <fs-label-field>\n <fs-label>{{indexedAclRoleLevels[aclObjectEntry.level]}}</fs-label>\n {{aclObjectEntry.object.name}}\n </fs-label-field>\n }\n <fs-acl-object-roles\n [aclRoles]=\"aclRoles\"\n [aclObjectRoles]=\"[aclObjectRole]\"\n [required]=\"required\"\n (change)=\"aclObjectRoleChange($event)\">\n </fs-acl-object-roles>\n </div>\n }\n </mat-dialog-content>\n <mat-dialog-actions>\n <button mat-button type=\"submit\" color=\"primary\">Save</button>\n <button mat-button mat-dialog-close type=\"button\">Cancel</button>\n </mat-dialog-actions>\n </fs-dialog>\n</form>\n", styles: ["::ng-deep .account-roles-autocomplete-panel .mat-option{line-height:normal}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text{display:flex;flex-direction:row;align-items:center}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text fs-badge{margin-right:5px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormDirective, selector: "[fsForm]", inputs: ["wrapperSelector", "messageSelector", "hintSelector", "labelSelector", "autocomplete", "shortcuts", "confirm", "confirmDialog", "confirmDrawer", "confirmBrowser", "confirmTabs", "dirtySubmitButton", "submit", "successDelay", "errorDelay", "tabGroup", "deactivationGuard"], outputs: ["fsForm", "invalid", "valid", "submitted", "reseted", "cleared"], exportAs: ["fsForm"] }, { kind: "directive", type: i2.FsButtonDirective, selector: "[mat-raised-button]:not([fsFormButtonStandalone]),[mat-button]:not([fsFormButtonStandalone]),[mat-flat-button]:not([fsFormButtonStandalone]),[mat-stroked-button]:not([fsFormButtonStandalone])", inputs: ["name", "dirtySubmit", "form"] }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i3.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: FsLabelModule }, { kind: "component", type: i4.FsLabelComponent, selector: "fs-label" }, { kind: "component", type: i4.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["appearance", "showOutline", "disabled", "focused", "hoverable", "padless"] }, { kind: "component", type: FsAclObjectRolesComponent, selector: "fs-acl-object-roles", inputs: ["aclRoles", "required", "multiple", "disabled", "aclObjectRoles", "rolesLabel", "levelLabel"], outputs: ["change"] }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }] });
346
188
  }
347
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRoleComponent, decorators: [{
189
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntryComponent, decorators: [{
348
190
  type: Component,
349
- args: [{ changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
191
+ args: [{ standalone: true, imports: [
350
192
  FormsModule,
351
193
  FsFormModule,
352
194
  FsDialogModule,
353
195
  MatDialogTitle,
354
196
  CdkScrollable,
355
197
  MatDialogContent,
356
- MatFormField,
357
- MatLabel,
358
- MatInput,
359
198
  FsLabelModule,
360
- FsRadioGroupModule,
361
- MatRadioButton,
362
- MatCheckbox,
363
- MatHint,
364
- MatSelect,
365
- MatOption,
366
- FsListModule,
367
- FsMenuModule,
199
+ FsAclObjectRolesComponent,
368
200
  MatDialogActions,
369
201
  MatButton,
370
202
  MatDialogClose,
371
- BulkOptionsFilterPipe,
372
- AclRolePermissionAvailablePipe,
373
- ], template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n @if (aclRole) {\n <div mat-dialog-title>\n @if (!disabled) {\n {{ aclRole.id ? 'Edit' : 'Create' }}\n }\n @if (disabled) {\n View\n }\n role\n </div>\n <mat-dialog-content>\n <div class=\"fs-row.gap-lg.align-start\">\n <div class=\"fs-column left-column\">\n <mat-form-field>\n <mat-label>\n Name\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.name\"\n [disabled]=\"disabled\"\n name=\"name\"\n fsFormRequired>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Description\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.description\"\n [disabled]=\"disabled\"\n name=\"description\">\n </mat-form-field>\n @if (aclRole.id || aclLevels.length === 1) {\n <fs-label-field>\n <fs-label>\n Level\n </fs-label>\n {{ indexedAclLevels[aclRole.level] }}\n </fs-label-field>\n } @else {\n <div class=\"level\">\n <fs-radio-group\n [(ngModel)]=\"aclRole.level\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"levelChange()\"\n fsFormRequired\n label=\"Level\"\n orientation=\"vertical\"\n name=\"level\">\n @for (item of aclLevels; track item) {\n <mat-radio-button\n [value]=\"item.value\"\n [disabled]=\"!!aclRole.protected\">\n {{ item.name }}\n </mat-radio-button>\n }\n </fs-radio-group>\n </div>\n }\n @if (levelPermissions.length) {\n <fs-label-field>\n <fs-label>\n All permissions\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRole.allPermissions\"\n (ngModelChange)=\"allPermissionsChange($event)\"\n [disabled]=\"!!aclRole.protected || disabled\"\n name=\"allPermissions\">\n Enable\n </mat-checkbox>\n </fs-label-field>\n }\n @for (roleConfig of roleConfigs; track roleConfig) {\n <div\n class=\"fs-column\"\n >\n @if (roleConfig.type === 'checkbox') {\n <fs-label-field>\n <fs-label>\n {{ roleConfig.label }}\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [disabled]=\"disabled\"\n [name]=\"roleConfig.name\">\n Enable\n </mat-checkbox>\n <fs-label-message>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </fs-label-message>\n </fs-label-field>\n }\n @if (roleConfig.type === 'select') {\n <mat-form-field>\n <mat-select\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [name]=\"roleConfig.name\"\n [required]=\"roleConfig.required\"\n [disabled]=\"disabled\"\n [placeholder]=\"roleConfig.label\">\n @for (item of roleConfig.values; track item) {\n <mat-option\n [value]=\"item.value\">\n {{ item.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </mat-form-field>\n }\n </div>\n }\n </div>\n @if (aclRole.level) {\n <div\n [hidden]=\"!levelPermissions.length\"\n class=\"permissions fs-column\">\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Permissions\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n class=\"permission-group\">\n <div class=\"permission-group\">\n {{ row.category || 'General' }}\n </div>\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"permission\">\n {{ row.name }}\n </div>\n <div class=\"description small\">\n {{ row.description }}\n </div>\n </ng-template>\n </fs-list-column>\n <fs-list-column\n title=\"Access\"\n width=\"1%\"\n class=\"access\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n let-group=\"group\"\n let-groupChildren=\"groupChildren\"\n class=\"permission-group\"\n align=\"right\">\n @if (!aclRole.allPermissions && !disabled) {\n <fs-menu>\n @for (access of AclRoleAccesses | builkOptionsFilter: groupChildren; track access) {\n <ng-template\n fs-menu-item\n (click)=\"bulkChange(access.value, groupChildren, group)\">\n {{ access.name }}\n </ng-template>\n }\n </fs-menu>\n }\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"permission\"\n let-permission=\"row\">\n @if (aclRole.allPermissions || disabled) {\n <span>\n {{ indexedAccesses[aclRolePermissions[permission.value]] }}\n </span>\n } @else {\n @if (permission|aclRolePermissionAvailable:aclRolePermissions) {\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclRolePermissions[permission.value]\"\n [disabled]=\"!!aclRole.protected\"\n required\n [name]=\"'access-' + permission.value\"\n (ngModelChange)=\"permissionChange()\">\n @for (access of AclRoleAccesses; track access) {\n @if (access.value === 0 || permission.accesses.indexOf(access.value) !== -1) {\n <mat-option\n [value]=\"access.value\">\n {{ access.name }}\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n } @else {\n Unavailable\n }\n }\n </ng-template>\n </fs-list-column>\n </fs-list>\n </div>\n }\n </div>\n </mat-dialog-content>\n <mat-dialog-actions>\n @if (!disabled) {\n <button\n #submit\n mat-button\n type=\"submit\"\n color=\"primary\">\n {{ aclRole.id ? 'Save' : 'Create' }}\n </button>\n }\n <button\n mat-button\n [mat-dialog-close]=\"null\"\n type=\"button\">\n {{ disabled ? 'Done' : 'Cancel' }}\n </button>\n </mat-dialog-actions>\n }\n </fs-dialog>\n</form>", styles: [".permissions{flex:1}.permissions ::ng-deep .fs-list-row-group{background-color:#e4e4e4;font-size:112%}.permissions ::ng-deep fs-list .access{white-space:nowrap}.permissions ::ng-deep .mat-form-field{width:100px}.permissions ::ng-deep .mat-form-field .mat-form-field-wrapper{padding-bottom:0}.permissions ::ng-deep .mat-form-field .mat-form-field-infix{border-top:0}.permissions ::ng-deep .mat-form-field .mat-form-field-underline{bottom:0}.permissions ::ng-deep fs-radio-group{width:100%}.permissions ::ng-deep fs-label-field{width:100%}.permissions .level{width:100%}.left-column{width:40%;max-width:400px}\n"] }]
374
- }], propDecorators: { list: [{
375
- type: ViewChild,
376
- args: [FsListComponent]
377
- }], submitButton: [{
378
- type: ViewChild,
379
- args: ['submit', { static: false }]
380
- }] } });
203
+ ], template: "<form fsForm [submit]=\"save\">\n <fs-dialog>\n <div mat-dialog-title>{{ titleEdit? titleEdit : titleAdd }}</div>\n <mat-dialog-content>\n @if (aclObjectRole) {\n <div>\n @if (aclObjectEntry.object) {\n <fs-label-field>\n <fs-label>{{indexedAclRoleLevels[aclObjectEntry.level]}}</fs-label>\n {{aclObjectEntry.object.name}}\n </fs-label-field>\n }\n <fs-acl-object-roles\n [aclRoles]=\"aclRoles\"\n [aclObjectRoles]=\"[aclObjectRole]\"\n [required]=\"required\"\n (change)=\"aclObjectRoleChange($event)\">\n </fs-acl-object-roles>\n </div>\n }\n </mat-dialog-content>\n <mat-dialog-actions>\n <button mat-button type=\"submit\" color=\"primary\">Save</button>\n <button mat-button mat-dialog-close type=\"button\">Cancel</button>\n </mat-dialog-actions>\n </fs-dialog>\n</form>\n", styles: ["::ng-deep .account-roles-autocomplete-panel .mat-option{line-height:normal}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text{display:flex;flex-direction:row;align-items:center}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text fs-badge{margin-right:5px}\n"] }]
204
+ }], ctorParameters: () => [] });
381
205
 
382
- class FsAclPermissionPopoverComponent {
206
+ class FsAclRolePopoverComponent {
383
207
  _appAclService = inject(FsAppAclService);
384
- permission;
385
- description;
208
+ aclRole;
209
+ objectName;
210
+ permissions = [];
386
211
  ngOnInit() {
212
+ const aclRolePermissions = this.aclRole.permissions || [];
387
213
  this._appAclService.getPermissions()
388
- .subscribe(permissions => {
389
- this.description = permissions.filter(item => {
390
- return item.value === this.permission.value;
391
- }).map(item => {
392
- return item.description;
393
- })[0];
214
+ .subscribe((response) => {
215
+ this.permissions = response.filter(item => {
216
+ return aclRolePermissions.some(permission => {
217
+ return item.value === permission.value;
218
+ });
219
+ });
394
220
  });
395
221
  }
396
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclPermissionPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
397
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.7", type: FsAclPermissionPopoverComponent, isStandalone: true, selector: "acl-permission-popover", inputs: { permission: "permission" }, ngImport: i0, template: "\n<fs-popover [template]=\"popover\" [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n\n<ng-template #popover>\n {{permission.name}}\n <div class=\"small\">{{description}}</div>\n</ng-template>\n\n", styles: [":host{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: FsPopoverModule }, { kind: "component", type: i1$2.FsPopoverComponent, selector: "fs-popover" }] });
222
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolePopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
223
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclRolePopoverComponent, isStandalone: true, selector: "fs-acl-role-popover", inputs: { aclRole: "aclRole", objectName: "objectName" }, ngImport: i0, template: "<fs-popover\n [template]=\"popover\"\n [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n<ng-template #popover>\n <div class=\"name small\">\n {{ aclRole.name }}\n @if (objectName) {\n <span>\n : {{ objectName }}\n </span>\n }\n </div>\n @if (permissions.length) {\n @for (permission of permissions; track permission.name) {\n <div class=\"permission\">\n <div>\n {{ permission.name }}\n </div>\n <div class=\"small\">\n {{ permission.description }}\n </div>\n </div>\n }\n } @else {\n None\n }\n</ng-template>", styles: [".name{padding-bottom:10px}.permission+.permission{padding-top:5px}:host{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: FsPopoverModule }, { kind: "component", type: i1$2.FsPopoverComponent, selector: "fs-popover" }] });
398
224
  }
399
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclPermissionPopoverComponent, decorators: [{
225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolePopoverComponent, decorators: [{
400
226
  type: Component,
401
- args: [{ selector: 'acl-permission-popover', standalone: true, imports: [FsPopoverModule], template: "\n<fs-popover [template]=\"popover\" [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n\n<ng-template #popover>\n {{permission.name}}\n <div class=\"small\">{{description}}</div>\n</ng-template>\n\n", styles: [":host{cursor:pointer}\n"] }]
402
- }], propDecorators: { permission: [{
227
+ args: [{ selector: 'fs-acl-role-popover', standalone: true, imports: [FsPopoverModule], template: "<fs-popover\n [template]=\"popover\"\n [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n<ng-template #popover>\n <div class=\"name small\">\n {{ aclRole.name }}\n @if (objectName) {\n <span>\n : {{ objectName }}\n </span>\n }\n </div>\n @if (permissions.length) {\n @for (permission of permissions; track permission.name) {\n <div class=\"permission\">\n <div>\n {{ permission.name }}\n </div>\n <div class=\"small\">\n {{ permission.description }}\n </div>\n </div>\n }\n } @else {\n None\n }\n</ng-template>", styles: [".name{padding-bottom:10px}.permission+.permission{padding-top:5px}:host{cursor:pointer}\n"] }]
228
+ }], propDecorators: { aclRole: [{
229
+ type: Input
230
+ }], objectName: [{
403
231
  type: Input
404
232
  }] } });
405
233
 
406
- class FsAclRolesComponent {
234
+ class FsAclEntriesComponent {
407
235
  _appAclService = inject(FsAppAclService);
408
236
  _dialog = inject(MatDialog);
409
- deleteAclRole;
410
- restoreAclRole;
411
- saveAclRole;
237
+ _confirm = inject(FsPrompt);
238
+ loadAclEntries;
412
239
  loadAclRoles;
413
- loadAclRole;
414
- loadRoleConfigs;
415
- aclLevels = [];
416
- disabledAclRole;
417
- list = new QueryList();
418
- listConfig;
419
- permissions;
420
- indexedAclRoleLevels = {};
240
+ saveAclObjectEntry;
241
+ environmentShow = true;
242
+ environmentLabel = 'Environment';
243
+ environmentKey = 'environment';
244
+ actions = [];
245
+ aclEntriesList = null;
246
+ aclEntriesConfig = null;
247
+ permissions = [];
421
248
  _destroy$ = new Subject();
422
249
  ngOnInit() {
423
- new Observable((observer) => {
424
- if (this.aclLevels.length) {
425
- observer.next(this.aclLevels);
426
- observer.complete();
427
- }
428
- else {
429
- this._appAclService.getLevels()
430
- .subscribe((aclLevels) => {
431
- observer.next(aclLevels);
432
- observer.complete();
433
- });
434
- }
435
- })
436
- .subscribe((aclLevels) => {
437
- this.aclLevels = aclLevels;
438
- this.indexedAclRoleLevels = list(this.aclLevels, 'name', 'value');
439
- this._loadListConfig();
440
- });
441
- }
442
- openDialog(aclRole = { id: null }) {
443
- this._dialog.open(FsAclRoleComponent, {
444
- width: '70%',
445
- data: {
446
- aclRole,
447
- aclLevels: this.aclLevels,
448
- loadAclRole: this.loadAclRole,
449
- saveAclRole: this.saveAclRole,
450
- loadRoleConfigs: this.loadRoleConfigs,
451
- disabled: this.disabledAclRole
452
- ? this.disabledAclRole(aclRole)
453
- : false,
454
- },
455
- })
456
- .afterClosed()
457
- .pipe(takeUntil(this._destroy$), filter((response) => !!response))
458
- .subscribe((response) => {
459
- this.list.forEach((list) => {
460
- list.reload();
461
- });
250
+ this._appAclService.getPermissions()
251
+ .subscribe(response => {
252
+ this.permissions = response;
462
253
  });
463
- }
464
- ngOnDestroy() {
465
- this._destroy$.next(null);
466
- this._destroy$.complete();
467
- }
468
- _loadListConfig() {
469
- this.listConfig = {
470
- sort: { value: 'hierarchy' },
471
- filters: [
472
- {
473
- name: 'keyword',
474
- type: ItemType.Keyword,
475
- label: 'Search',
476
- },
477
- {
478
- name: 'level',
479
- label: 'Level',
480
- type: ItemType.Select,
481
- values: this.aclLevels,
482
- hide: this.aclLevels.length <= 1,
483
- },
484
- {
485
- name: 'state',
486
- label: 'Show deleted',
487
- type: ItemType.Checkbox,
488
- unchecked: 'active',
489
- checked: 'deleted',
490
- },
491
- ],
492
- actions: [
493
- {
494
- click: (event) => {
495
- this.openDialog();
496
- },
497
- label: 'Create',
498
- },
499
- ],
254
+ this.aclEntriesConfig = {
255
+ status: false,
256
+ paging: false,
257
+ actions: this.actions,
500
258
  rowActions: [
501
259
  {
502
- click: (data) => {
503
- return this.deleteAclRole(data);
504
- },
505
- remove: {
506
- title: 'Confirm',
507
- template: 'Are you sure you would like to delete this role?',
508
- },
509
- menu: true,
510
- label: 'Delete',
511
- show: (row) => {
512
- const hideDelete = this.disabledAclRole
513
- ? this.disabledAclRole(row)
514
- : false;
515
- return !!this.deleteAclRole
516
- && row.state !== 'deleted'
517
- && !hideDelete;
518
- },
519
- },
520
- {
521
- click: (data) => {
522
- return this.restoreAclRole(data)
523
- .pipe(tap(() => {
524
- this.list.forEach((l) => {
525
- l.reload();
260
+ label: 'Remove All Roles',
261
+ click: (aclObjectEntry) => {
262
+ this._confirm
263
+ .confirm({
264
+ title: 'Remove All Roles',
265
+ commitLabel: 'Save',
266
+ template: `Please note that removing roles may prevent users from being able to successfully login.<br>
267
+ These changes are effective immediately.<br>
268
+ Are you sure you would like to continue?`,
269
+ }).subscribe(() => {
270
+ const data = { ...aclObjectEntry, aclEntries: [] };
271
+ this.saveAclObjectEntry(data)
272
+ .subscribe(() => {
273
+ this.aclEntriesList.reload();
526
274
  });
527
- }), takeUntil(this._destroy$))
528
- .subscribe();
529
- },
530
- label: 'Restore',
531
- show: (row) => !!this.restoreAclRole && row.state === 'deleted',
532
- },
275
+ });
276
+ }
277
+ }
533
278
  ],
534
- fetch: (query) => {
535
- query.permissions = true;
536
- return this.loadAclRoles(query)
537
- .pipe(map((data) => data));
279
+ fetch: () => {
280
+ return new Observable((observer) => {
281
+ this.loadAclEntries({
282
+ aclRoles: true,
283
+ aclRolePermissions: true,
284
+ objects: true,
285
+ aclRoleState: 'active',
286
+ })
287
+ .subscribe((aclEntries) => {
288
+ const objects = aclEntries
289
+ .filter((aclEntry) => (!!aclEntry.object))
290
+ .reduce((items, item) => {
291
+ return {
292
+ ...items,
293
+ [item.object.id]: item.object,
294
+ };
295
+ }, {});
296
+ const environments = aclEntries
297
+ .filter((aclEntry) => (!!aclEntry[this.environmentKey]))
298
+ .reduce((items, item) => {
299
+ const environment = item[this.environmentKey];
300
+ return {
301
+ ...items,
302
+ [environment.id]: environment,
303
+ };
304
+ }, {});
305
+ const groupedAclEntries = groupBy(aclEntries, (item) => {
306
+ const environmentId = (item[this.environmentKey])?.id;
307
+ return [item.aclRole.level, environmentId, item.objectId];
308
+ });
309
+ let aclObjectEntries = Object.keys(groupedAclEntries)
310
+ .reduce((accum, key) => {
311
+ const parts = key.split(',');
312
+ return [
313
+ ...accum,
314
+ {
315
+ object: objects[parts[2]],
316
+ level: parts[0],
317
+ [`${this.environmentKey}Id`]: parts[1] ? parseInt(parts[1]) : null,
318
+ [this.environmentKey]: environments[parts[1]],
319
+ aclEntries: groupedAclEntries[key],
320
+ }
321
+ ];
322
+ }, []);
323
+ const hasApp = aclObjectEntries.some((item) => {
324
+ return item.aclEntries.some((entry) => {
325
+ return !entry.objectId;
326
+ });
327
+ });
328
+ if (!hasApp) {
329
+ aclObjectEntries.unshift({
330
+ object: null,
331
+ aclEntries: [],
332
+ level: 'app',
333
+ environmentId: null,
334
+ });
335
+ }
336
+ aclObjectEntries = sortBy(aclObjectEntries, (item) => {
337
+ return item.object ? item.level : '';
338
+ });
339
+ observer.next({ data: aclObjectEntries });
340
+ observer.complete();
341
+ });
342
+ });
538
343
  },
539
344
  };
540
345
  }
541
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
542
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclRolesComponent, isStandalone: true, selector: "fs-acl-roles", inputs: { deleteAclRole: "deleteAclRole", restoreAclRole: "restoreAclRole", saveAclRole: "saveAclRole", loadAclRoles: "loadAclRoles", loadAclRole: "loadAclRole", loadRoleConfigs: "loadRoleConfigs", aclLevels: "aclLevels", disabledAclRole: "disabledAclRole" }, viewQueries: [{ propertyName: "list", predicate: FsListComponent, descendants: true }], ngImport: i0, template: "@if (listConfig) {\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Name\" name=\"name\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n @if (row.state !== 'deleted') {\n <a (click)=\"openDialog(row)\">{{ row.name }}</a>\n } @else {\n {{ row.name }}\n }\n <div class=\"small\">{{row.description}}</div>\n </ng-template>\n </fs-list-column>\n <fs-list-column name=\"hierarchy\" title=\"Level\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n {{ indexedAclRoleLevels[row.level] }}\n </ng-template>\n </fs-list-column>\n <fs-list-column title=\"Permissions\">\n <ng-template fs-list-cell let-row=\"row\">\n <div class=\"permissions\">\n @for (permission of row.permissions; track permission) {\n @if (permission.access) {\n <span class=\"permission\">\n <acl-permission-popover [permission]=\"permission\">{{permission.name}}</acl-permission-popover>\n </span>\n }\n }\n </div>\n </ng-template>\n </fs-list-column>\n </fs-list>\n}\n", styles: [".permissions .permission+.permission:before{content:\", \"}\n"], dependencies: [{ kind: "ngmodule", type: FsListModule }, { kind: "component", type: i1$1.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines"], outputs: ["filtersReady"] }, { kind: "directive", type: i1$1.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i1$1.FsListCellDirective, selector: "[fs-list-cell]", inputs: ["colspan", "align", "class"] }, { kind: "component", type: FsAclPermissionPopoverComponent, selector: "acl-permission-popover", inputs: ["permission"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
346
+ update(aclObjectEntry) {
347
+ const data = {
348
+ aclObjectEntry,
349
+ required: false,
350
+ loadAclRoles: this.loadAclRoles,
351
+ saveAclObjectEntry: this.saveAclObjectEntry
352
+ };
353
+ this._dialog.open(FsAclEntryComponent, {
354
+ data: data
355
+ })
356
+ .afterClosed()
357
+ .pipe(takeUntil(this._destroy$))
358
+ .subscribe(() => {
359
+ this.aclEntriesList.reload();
360
+ });
361
+ }
362
+ ngOnDestroy() {
363
+ this._destroy$.next(null);
364
+ this._destroy$.complete();
365
+ }
366
+ reload() {
367
+ this.aclEntriesList.reload();
368
+ }
369
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntriesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
370
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclEntriesComponent, isStandalone: true, selector: "fs-acl-entries", inputs: { loadAclEntries: "loadAclEntries", loadAclRoles: "loadAclRoles", saveAclObjectEntry: "saveAclObjectEntry", environmentShow: "environmentShow", environmentLabel: "environmentLabel", environmentKey: "environmentKey", actions: "actions" }, viewQueries: [{ propertyName: "aclEntriesList", first: true, predicate: FsListComponent, descendants: true }], ngImport: i0, template: "<fs-list [config]=\"aclEntriesConfig\">\n <fs-list-column>\n <ng-template fs-list-header>\n Context\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n @if (row.object) {\n <div class=\"fs-row.gap-sm\">\n @if (row.object.imageUrl) {\n <fs-badge\n shape=\"circle\"\n [image]=\"row.object.imageUrl\">\n </fs-badge>\n }\n <span>\n <div>\n <small>\n {{ row.object.class }}\n </small>\n </div>\n <a (click)=\"update(row)\">\n {{ row.object.name }}\n </a>\n </span>\n </div>\n } @else {\n <a (click)=\"update(row)\">\n App\n </a>\n }\n </ng-template>\n </fs-list-column>\n <fs-list-column [show]=\"environmentShow\">\n <ng-template fs-list-header>\n {{ environmentLabel }}\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n {{ row.environment?.name }}\n </ng-template>\n </fs-list-column>\n <fs-list-column>\n <ng-template fs-list-header>\n Roles\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"fs-column\">\n @for (aclEntry of row.aclEntries; track aclEntry.id) {\n <div div>\n @switch (row.level) {\n @case ('app') {\n <fs-acl-role-popover\n [aclRole]=\"aclEntry.aclRole\"\n objectName=\"App\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n @default {\n @if (row.object) {\n <fs-acl-role-popover [aclRole]=\"aclEntry.aclRole\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n }\n }\n </div>\n }\n </div>\n </ng-template>\n </fs-list-column>\n</fs-list>", styles: [""], dependencies: [{ kind: "ngmodule", type: FsListModule }, { kind: "component", type: i1$3.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines"], outputs: ["filtersReady"] }, { kind: "directive", type: i1$3.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i1$3.FsListCellDirective, selector: "[fs-list-cell]", inputs: ["colspan", "align", "class"] }, { kind: "directive", type: i1$3.FsListHeaderDirective, selector: "[fs-list-header]", inputs: ["colspan", "align", "class"] }, { kind: "ngmodule", type: FsBadgeModule }, { kind: "component", type: i2$1.FsBadgeComponent, selector: "fs-badge", inputs: ["color", "text", "tooltip", "size", "shape", "image", "icon", "iconSize", "iconSizePercent", "iconColor", "backgroundSize"] }, { kind: "component", type: FsAclRolePopoverComponent, selector: "fs-acl-role-popover", inputs: ["aclRole", "objectName"] }] });
543
371
  }
544
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolesComponent, decorators: [{
372
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntriesComponent, decorators: [{
545
373
  type: Component,
546
- args: [{ selector: 'fs-acl-roles', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [FsListModule, FsAclPermissionPopoverComponent], template: "@if (listConfig) {\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Name\" name=\"name\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n @if (row.state !== 'deleted') {\n <a (click)=\"openDialog(row)\">{{ row.name }}</a>\n } @else {\n {{ row.name }}\n }\n <div class=\"small\">{{row.description}}</div>\n </ng-template>\n </fs-list-column>\n <fs-list-column name=\"hierarchy\" title=\"Level\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n {{ indexedAclRoleLevels[row.level] }}\n </ng-template>\n </fs-list-column>\n <fs-list-column title=\"Permissions\">\n <ng-template fs-list-cell let-row=\"row\">\n <div class=\"permissions\">\n @for (permission of row.permissions; track permission) {\n @if (permission.access) {\n <span class=\"permission\">\n <acl-permission-popover [permission]=\"permission\">{{permission.name}}</acl-permission-popover>\n </span>\n }\n }\n </div>\n </ng-template>\n </fs-list-column>\n </fs-list>\n}\n", styles: [".permissions .permission+.permission:before{content:\", \"}\n"] }]
547
- }], propDecorators: { deleteAclRole: [{
548
- type: Input
549
- }], restoreAclRole: [{
550
- type: Input
551
- }], saveAclRole: [{
374
+ args: [{ selector: 'fs-acl-entries', standalone: true, imports: [FsListModule, FsBadgeModule, FsAclRolePopoverComponent], template: "<fs-list [config]=\"aclEntriesConfig\">\n <fs-list-column>\n <ng-template fs-list-header>\n Context\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n @if (row.object) {\n <div class=\"fs-row.gap-sm\">\n @if (row.object.imageUrl) {\n <fs-badge\n shape=\"circle\"\n [image]=\"row.object.imageUrl\">\n </fs-badge>\n }\n <span>\n <div>\n <small>\n {{ row.object.class }}\n </small>\n </div>\n <a (click)=\"update(row)\">\n {{ row.object.name }}\n </a>\n </span>\n </div>\n } @else {\n <a (click)=\"update(row)\">\n App\n </a>\n }\n </ng-template>\n </fs-list-column>\n <fs-list-column [show]=\"environmentShow\">\n <ng-template fs-list-header>\n {{ environmentLabel }}\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n {{ row.environment?.name }}\n </ng-template>\n </fs-list-column>\n <fs-list-column>\n <ng-template fs-list-header>\n Roles\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"fs-column\">\n @for (aclEntry of row.aclEntries; track aclEntry.id) {\n <div div>\n @switch (row.level) {\n @case ('app') {\n <fs-acl-role-popover\n [aclRole]=\"aclEntry.aclRole\"\n objectName=\"App\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n @default {\n @if (row.object) {\n <fs-acl-role-popover [aclRole]=\"aclEntry.aclRole\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n }\n }\n </div>\n }\n </div>\n </ng-template>\n </fs-list-column>\n</fs-list>" }]
375
+ }], propDecorators: { loadAclEntries: [{
552
376
  type: Input
553
377
  }], loadAclRoles: [{
554
378
  type: Input
555
- }], loadAclRole: [{
379
+ }], saveAclObjectEntry: [{
556
380
  type: Input
557
- }], loadRoleConfigs: [{
381
+ }], environmentShow: [{
558
382
  type: Input
559
- }], aclLevels: [{
383
+ }], environmentLabel: [{
560
384
  type: Input
561
- }], disabledAclRole: [{
385
+ }], environmentKey: [{
562
386
  type: Input
563
- }], list: [{
564
- type: ViewChildren,
387
+ }], actions: [{
388
+ type: Input
389
+ }], aclEntriesList: [{
390
+ type: ViewChild,
565
391
  args: [FsListComponent]
566
392
  }] } });
567
393
 
568
- class FsAclObjectRolesComponent {
569
- aclRoles = [];
570
- required = false;
571
- multiple = false;
572
- disabled = false;
573
- aclObjectRoles = [];
574
- rolesLabel = 'Roles';
575
- levelLabel = '';
576
- change = new EventEmitter();
577
- compareAclRole = (o1, o2) => {
578
- return o1 && o2 && o1.id === o2.id;
579
- };
580
- changed() {
581
- this.change.emit(this.aclObjectRoles);
394
+ class FsAclPermissionPopoverComponent {
395
+ _appAclService = inject(FsAppAclService);
396
+ permission;
397
+ description;
398
+ ngOnInit() {
399
+ this._appAclService.getPermissions()
400
+ .subscribe(permissions => {
401
+ this.description = permissions.filter(item => {
402
+ return item.value === this.permission.value;
403
+ }).map(item => {
404
+ return item.description;
405
+ })[0];
406
+ });
582
407
  }
583
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclObjectRolesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
584
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclObjectRolesComponent, isStandalone: true, selector: "fs-acl-object-roles", inputs: { aclRoles: "aclRoles", required: "required", multiple: "multiple", disabled: "disabled", aclObjectRoles: "aclObjectRoles", rolesLabel: "rolesLabel", levelLabel: "levelLabel" }, outputs: { change: "change" }, ngImport: i0, template: "@if (!multiple) {\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole) {\n <fs-checkbox-group\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n (ngModelChange)=\"changed()\"\n name=\"roles\"\n [compareWith]=\"compareAclRole\"\n [disabled]=\"disabled\"\n [label]=\"rolesLabel\"\n [fsFormRequired]=\"required\"\n orientation=\"vertical\">\n @for (aclRole of aclRoles; track aclRole) {\n <mat-checkbox [disabled]=\"disabled\" [value]=\"$any(aclRole)\">\n {{ aclRole.name }}\n </mat-checkbox>\n }\n </fs-checkbox-group>\n }\n}\n\n@if (multiple) {\n <table>\n <tr>\n <td>\n <small>{{levelLabel}}</small>\n </td>\n <td>\n <small>{{rolesLabel}}</small>\n </td>\n </tr>\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole) {\n <tr>\n <td>{{aclObjectRole.object.name}}</td>\n <td>\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n multiple=\"true\"\n [disabled]=\"disabled\"\n [compareWith]=\"compareAclRole\"\n (ngModelChange)=\"changed()\"\n name=\"aclRole_{{ aclObjectRole.object.id }}\">\n @for (aclRole of aclRoles; track aclRole) {\n <mat-option [value]=\"aclRole\">\n {{ aclRole.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </td>\n </tr>\n }\n </table>\n}\n", styles: ["table tr td:first-child{padding-right:15px}\n"], dependencies: [{ kind: "ngmodule", type: FsCheckboxGroupModule }, { kind: "component", type: i1$3.FsCheckboxGroupComponent, selector: "fs-checkbox-group", inputs: ["orientation", "position", "label", "disabled", "compareWith"], outputs: ["change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormRequiredDirective, selector: "[fsFormRequired],[ngModel][required]", inputs: ["fsFormRequired", "required", "fsFormRequiredMessage"] }, { kind: "directive", type: i2.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }], viewProviders: [{ provide: ControlContainer, useExisting: NgForm }] });
408
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclPermissionPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
409
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.7", type: FsAclPermissionPopoverComponent, isStandalone: true, selector: "acl-permission-popover", inputs: { permission: "permission" }, ngImport: i0, template: "\n<fs-popover [template]=\"popover\" [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n\n<ng-template #popover>\n {{permission.name}}\n <div class=\"small\">{{description}}</div>\n</ng-template>\n\n", styles: [":host{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: FsPopoverModule }, { kind: "component", type: i1$2.FsPopoverComponent, selector: "fs-popover" }] });
585
410
  }
586
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclObjectRolesComponent, decorators: [{
411
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclPermissionPopoverComponent, decorators: [{
587
412
  type: Component,
588
- args: [{ selector: 'fs-acl-object-roles', viewProviders: [{ provide: ControlContainer, useExisting: NgForm }], standalone: true, imports: [FsCheckboxGroupModule, FormsModule, FsFormModule, MatCheckbox, MatFormField, MatSelect, MatOption], template: "@if (!multiple) {\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole) {\n <fs-checkbox-group\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n (ngModelChange)=\"changed()\"\n name=\"roles\"\n [compareWith]=\"compareAclRole\"\n [disabled]=\"disabled\"\n [label]=\"rolesLabel\"\n [fsFormRequired]=\"required\"\n orientation=\"vertical\">\n @for (aclRole of aclRoles; track aclRole) {\n <mat-checkbox [disabled]=\"disabled\" [value]=\"$any(aclRole)\">\n {{ aclRole.name }}\n </mat-checkbox>\n }\n </fs-checkbox-group>\n }\n}\n\n@if (multiple) {\n <table>\n <tr>\n <td>\n <small>{{levelLabel}}</small>\n </td>\n <td>\n <small>{{rolesLabel}}</small>\n </td>\n </tr>\n @for (aclObjectRole of aclObjectRoles; track aclObjectRole) {\n <tr>\n <td>{{aclObjectRole.object.name}}</td>\n <td>\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclObjectRole.aclRoles\"\n multiple=\"true\"\n [disabled]=\"disabled\"\n [compareWith]=\"compareAclRole\"\n (ngModelChange)=\"changed()\"\n name=\"aclRole_{{ aclObjectRole.object.id }}\">\n @for (aclRole of aclRoles; track aclRole) {\n <mat-option [value]=\"aclRole\">\n {{ aclRole.name }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n </td>\n </tr>\n }\n </table>\n}\n", styles: ["table tr td:first-child{padding-right:15px}\n"] }]
589
- }], propDecorators: { aclRoles: [{
590
- type: Input
591
- }], required: [{
592
- type: Input
593
- }], multiple: [{
594
- type: Input
595
- }], disabled: [{
596
- type: Input
597
- }], aclObjectRoles: [{
598
- type: Input
599
- }], rolesLabel: [{
600
- type: Input
601
- }], levelLabel: [{
413
+ args: [{ selector: 'acl-permission-popover', standalone: true, imports: [FsPopoverModule], template: "\n<fs-popover [template]=\"popover\" [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n\n<ng-template #popover>\n {{permission.name}}\n <div class=\"small\">{{description}}</div>\n</ng-template>\n\n", styles: [":host{cursor:pointer}\n"] }]
414
+ }], propDecorators: { permission: [{
602
415
  type: Input
603
- }], change: [{
604
- type: Output
605
416
  }] } });
606
417
 
607
- class FsAclEntryComponent {
608
- aclRoles = [];
609
- aclObjectEntry;
610
- aclObjectRole;
611
- aclEntries = [];
612
- indexedAclRoleLevels = {};
613
- titleEdit = 'Edit Roles';
614
- titleAdd = 'Assign Roles';
615
- required = true;
616
- _appAclService = inject(FsAppAclService);
617
- _dialogRef = inject(MatDialogRef);
618
- _message = inject(FsMessage);
619
- _data = inject(MAT_DIALOG_DATA);
620
- _cdRef = inject(ChangeDetectorRef);
621
- constructor() {
622
- const _data = this._data;
623
- this.aclObjectEntry = { ..._data.aclObjectEntry };
624
- this.required = _data.required ?? true;
625
- if (_data.titleEdit) {
626
- this.titleEdit = _data.titleEdit;
627
- }
628
- if (_data.titleAdd) {
629
- this.titleAdd = _data.titleAdd;
418
+ var AclRoleAccess;
419
+ (function (AclRoleAccess) {
420
+ AclRoleAccess[AclRoleAccess["None"] = 0] = "None";
421
+ AclRoleAccess[AclRoleAccess["Read"] = 5] = "Read";
422
+ AclRoleAccess[AclRoleAccess["Write"] = 10] = "Write";
423
+ AclRoleAccess[AclRoleAccess["Full"] = 15] = "Full";
424
+ })(AclRoleAccess || (AclRoleAccess = {}));
425
+
426
+ const AclRoleAccesses = [
427
+ { name: 'None', value: AclRoleAccess.None },
428
+ { name: 'Read', value: AclRoleAccess.Read },
429
+ { name: 'Write', value: AclRoleAccess.Write },
430
+ { name: 'Full', value: AclRoleAccess.Full }
431
+ ];
432
+
433
+ class AclRolePermissionAvailablePipe {
434
+ transform(permission, aclRolePermissions) {
435
+ if (permission.requires && permission.requires.length) {
436
+ const exists = permission.requires
437
+ .every((item) => aclRolePermissions[item]);
438
+ return exists;
630
439
  }
440
+ return true;
441
+ }
442
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: AclRolePermissionAvailablePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
443
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: AclRolePermissionAvailablePipe, isStandalone: true, name: "aclRolePermissionAvailable" });
444
+ }
445
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: AclRolePermissionAvailablePipe, decorators: [{
446
+ type: Pipe,
447
+ args: [{
448
+ name: 'aclRolePermissionAvailable',
449
+ standalone: true
450
+ }]
451
+ }] });
452
+
453
+ class BulkOptionsFilterPipe {
454
+ transform(rolesList, children) {
455
+ const accessLevels = this._uniqListOfAccessLevels(children);
456
+ return rolesList.filter((permission) => {
457
+ return permission.value === 0 || accessLevels.has(permission.value);
458
+ });
459
+ }
460
+ _uniqListOfAccessLevels(children) {
461
+ return children.reduce((acc, value) => {
462
+ value.accesses.forEach((access) => {
463
+ acc.add(access);
464
+ });
465
+ return acc;
466
+ }, (new Set));
631
467
  }
468
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: BulkOptionsFilterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
469
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: BulkOptionsFilterPipe, isStandalone: true, name: "builkOptionsFilter" });
470
+ }
471
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: BulkOptionsFilterPipe, decorators: [{
472
+ type: Pipe,
473
+ args: [{
474
+ name: 'builkOptionsFilter',
475
+ standalone: true
476
+ }]
477
+ }] });
478
+
479
+ class FsAclRoleComponent {
480
+ _data = inject(MAT_DIALOG_DATA);
481
+ _appAclService = inject(FsAppAclService);
482
+ _dialogRef = inject(MatDialogRef);
483
+ _message = inject(FsMessage);
484
+ _cdRef = inject(ChangeDetectorRef);
485
+ list;
486
+ submitButton;
487
+ aclRole = null;
488
+ environment;
489
+ permissions = [];
490
+ listConfig;
491
+ levelPermissions = [];
492
+ AclRoleAccesses = AclRoleAccesses;
493
+ indexedAccesses = {};
494
+ aclLevels = [];
495
+ indexedAclLevels = {};
496
+ onlyFullAccess = false;
497
+ AclLevels = {};
498
+ roleConfigs = [];
499
+ aclRoleConfigValues = {};
500
+ aclRolePermissions = {};
501
+ loadRoleConfigs;
502
+ disabled;
503
+ _destroy$ = new Subject();
632
504
  ngOnInit() {
633
- forkJoin([
634
- this._data.loadAclRoles({
635
- level: this.aclObjectEntry.level,
636
- environmentId: this.aclObjectEntry.environmentId || null,
637
- }),
638
- this._appAclService.getIndexedLevels(),
639
- ])
640
- .subscribe(([aclRoles, levels]) => {
641
- this.aclRoles = aclRoles;
642
- this.indexedAclRoleLevels = levels;
643
- this.aclObjectRole = {
644
- object: this.aclObjectEntry.object,
645
- aclRoles: this.aclObjectEntry.aclEntries
646
- .map((aclEntry) => {
647
- return aclEntry.aclRole;
648
- }),
505
+ forkJoin(this.getRole(), this._appAclService.getPermissions())
506
+ .pipe(takeUntil(this._destroy$))
507
+ .subscribe(([aclRole, aclPermissions,]) => {
508
+ this.permissions = aclPermissions;
509
+ this.aclLevels = this._data.aclLevels;
510
+ this.disabled = this._data.disabled;
511
+ this.indexedAclLevels = list(this.aclLevels, 'name', 'value');
512
+ this.indexedAccesses = list(AclRoleAccesses, 'name', 'value');
513
+ this.aclRole = {
514
+ ...{
515
+ aclPermissions: [],
516
+ allPermissions: true,
517
+ aclRoleConfigs: [],
518
+ permissions: {},
519
+ level: this.aclLevels[0].value,
520
+ },
521
+ ...aclRole,
649
522
  };
523
+ this.aclRoleConfigValues = (aclRole.aclRoleConfigs || [])
524
+ .reduce((accum, aclRoleConfig) => {
525
+ return {
526
+ ...accum,
527
+ [aclRoleConfig.name]: aclRoleConfig.value,
528
+ };
529
+ }, {});
530
+ if (this.aclRole.id) {
531
+ this.permissions.forEach((permission) => {
532
+ let access = 0;
533
+ const aclPermission = this.aclRole.aclPermissions.find((item) => {
534
+ return item.permission === permission.value;
535
+ });
536
+ if (aclPermission) {
537
+ access = aclPermission.access;
538
+ }
539
+ this.aclRolePermissions[permission.value] = access;
540
+ });
541
+ }
542
+ if (this.aclRole.allPermissions) {
543
+ this._applyMaxPermissionAccess();
544
+ }
545
+ this._updatePermissions();
546
+ this._updateRoleConfigs();
650
547
  this._cdRef.markForCheck();
651
548
  });
652
- }
653
- aclObjectRoleChange(aclObjectRoles) {
654
- this.aclEntries = aclObjectRoles.reduce((aclEntries, aclObjectRole) => {
655
- aclObjectRole.aclRoles.forEach((aclRole) => {
656
- aclEntries.push({
657
- aclRoleId: aclRole.id,
658
- aclRole: aclRole,
659
- objectId: aclObjectRole.object ? aclObjectRole.object.id : null,
660
- object: aclObjectRole.object || null,
549
+ this.listConfig = {
550
+ status: false,
551
+ paging: false,
552
+ rowHoverHighlight: false,
553
+ noResults: {
554
+ message: '',
555
+ },
556
+ group: {
557
+ initialExpand: true,
558
+ groupBy: (data) => {
559
+ return data;
560
+ },
561
+ compareBy: (data) => {
562
+ return data.category || 'General';
563
+ },
564
+ },
565
+ fetch: () => {
566
+ return of({
567
+ data: this.levelPermissions.sort((a, b) => {
568
+ a = a.name.toUpperCase();
569
+ b = b.name.toUpperCase();
570
+ if (a < b) {
571
+ return -1;
572
+ }
573
+ else if (a > b) {
574
+ return 1;
575
+ }
576
+ return 0;
577
+ }),
661
578
  });
662
- });
663
- return aclEntries;
664
- }, []);
579
+ },
580
+ };
581
+ }
582
+ bulkChange(value, groupChildren, group) {
583
+ groupChildren
584
+ .forEach((permission) => {
585
+ const access = permission.accesses
586
+ .find((access) => value === access);
587
+ if (access || !value) {
588
+ this.aclRolePermissions[permission.value] = value;
589
+ }
590
+ });
591
+ setTimeout(() => {
592
+ this.submitButton.disabled = false;
593
+ this.permissionChange();
594
+ });
595
+ }
596
+ permissionChange() {
597
+ this.aclRolePermissions = {
598
+ ...this.aclRolePermissions,
599
+ };
600
+ this._cdRef.markForCheck();
601
+ }
602
+ levelChange() {
603
+ this._updatePermissions();
604
+ this._updateRoleConfigs();
605
+ this.list.reload();
606
+ }
607
+ getRole() {
608
+ if (!this._data.aclRole.id) {
609
+ return of(this._data.aclRole);
610
+ }
611
+ const query = {
612
+ aclPermissions: true,
613
+ aclRoleConfigs: true,
614
+ };
615
+ if (!this.environment) {
616
+ query.environmentId = null;
617
+ }
618
+ return this._data.loadAclRole(this._data.aclRole, query);
665
619
  }
666
620
  save = () => {
667
- const aclObjectEntry = {
668
- ...this.aclObjectEntry,
669
- aclEntries: this.aclEntries,
621
+ const aclRoleConfigs = this.roleConfigs
622
+ .map((roleConfig) => {
623
+ return {
624
+ name: roleConfig.name,
625
+ value: this.aclRoleConfigValues[roleConfig.name],
626
+ };
627
+ });
628
+ const aclRole = {
629
+ ...this.aclRole,
630
+ permissions: this.levelPermissions.map((permission) => {
631
+ return {
632
+ value: permission.value,
633
+ access: this.aclRolePermissions[permission.value] || 0,
634
+ };
635
+ }),
636
+ aclRoleConfigs,
670
637
  };
671
- return this._data.saveAclObjectEntry(aclObjectEntry)
672
- .pipe(tap((data) => {
638
+ return this._data.saveAclRole(aclRole)
639
+ .pipe(tap((response) => {
673
640
  this._message.success('Saved Changes');
674
- this.close(data);
641
+ this.close(response);
675
642
  }));
676
643
  };
677
644
  close(data = null) {
678
645
  this._dialogRef.close(data);
679
646
  }
680
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
681
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclEntryComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "<form fsForm [submit]=\"save\">\n <fs-dialog>\n <div mat-dialog-title>{{ titleEdit? titleEdit : titleAdd }}</div>\n <mat-dialog-content>\n @if (aclObjectRole) {\n <div>\n @if (aclObjectEntry.object) {\n <fs-label-field>\n <fs-label>{{indexedAclRoleLevels[aclObjectEntry.level]}}</fs-label>\n {{aclObjectEntry.object.name}}\n </fs-label-field>\n }\n <fs-acl-object-roles\n [aclRoles]=\"aclRoles\"\n [aclObjectRoles]=\"[aclObjectRole]\"\n [required]=\"required\"\n (change)=\"aclObjectRoleChange($event)\">\n </fs-acl-object-roles>\n </div>\n }\n </mat-dialog-content>\n <mat-dialog-actions>\n <button mat-button type=\"submit\" color=\"primary\">Save</button>\n <button mat-button mat-dialog-close type=\"button\">Cancel</button>\n </mat-dialog-actions>\n </fs-dialog>\n</form>\n", styles: ["::ng-deep .account-roles-autocomplete-panel .mat-option{line-height:normal}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text{display:flex;flex-direction:row;align-items:center}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text fs-badge{margin-right:5px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormDirective, selector: "[fsForm]", inputs: ["wrapperSelector", "messageSelector", "hintSelector", "labelSelector", "autocomplete", "shortcuts", "confirm", "confirmDialog", "confirmDrawer", "confirmBrowser", "confirmTabs", "dirtySubmitButton", "submit", "successDelay", "errorDelay", "tabGroup", "deactivationGuard"], outputs: ["fsForm", "invalid", "valid", "submitted", "reseted", "cleared"], exportAs: ["fsForm"] }, { kind: "directive", type: i2.FsButtonDirective, selector: "[mat-raised-button]:not([fsFormButtonStandalone]),[mat-button]:not([fsFormButtonStandalone]),[mat-flat-button]:not([fsFormButtonStandalone]),[mat-stroked-button]:not([fsFormButtonStandalone])", inputs: ["name", "dirtySubmit", "form"] }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i3.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: FsLabelModule }, { kind: "component", type: i4.FsLabelComponent, selector: "fs-label" }, { kind: "component", type: i4.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["appearance", "showOutline", "disabled", "focused", "hoverable", "padless"] }, { kind: "component", type: FsAclObjectRolesComponent, selector: "fs-acl-object-roles", inputs: ["aclRoles", "required", "multiple", "disabled", "aclObjectRoles", "rolesLabel", "levelLabel"], outputs: ["change"] }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }] });
647
+ allPermissionsChange(all) {
648
+ this._updatePermissions();
649
+ if (all) {
650
+ this._applyMaxPermissionAccess();
651
+ }
652
+ else {
653
+ this._applyNonePermissionAccess();
654
+ }
655
+ }
656
+ ngOnDestroy() {
657
+ this._destroy$.next(null);
658
+ this._destroy$.complete();
659
+ }
660
+ _updatePermissions() {
661
+ this.levelPermissions = this.permissions
662
+ .filter((permission) => {
663
+ return permission.levels.some((item) => {
664
+ return item === this.aclRole.level;
665
+ });
666
+ });
667
+ }
668
+ _updateRoleConfigs() {
669
+ if (this._data.loadRoleConfigs) {
670
+ this._data.loadRoleConfigs()
671
+ .subscribe((roleConfigs) => {
672
+ this.roleConfigs = roleConfigs
673
+ .filter((roleConfig) => roleConfig.level === this.aclRole.level);
674
+ this._cdRef.markForCheck();
675
+ });
676
+ }
677
+ }
678
+ _applyMaxPermissionAccess() {
679
+ this.permissions.forEach((permission) => {
680
+ this.aclRolePermissions[permission.value] = Math.max(...permission.accesses);
681
+ });
682
+ }
683
+ _applyNonePermissionAccess() {
684
+ this.permissions.forEach((permission) => {
685
+ this.aclRolePermissions[permission.value] = AclRoleAccess.None;
686
+ });
687
+ }
688
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRoleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
689
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclRoleComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "list", first: true, predicate: FsListComponent, descendants: true }, { propertyName: "submitButton", first: true, predicate: ["submit"], descendants: true }], ngImport: i0, template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n @if (aclRole) {\n <div mat-dialog-title>\n @if (!disabled) {\n {{ aclRole.id ? 'Edit' : 'Create' }}\n }\n @if (disabled) {\n View\n }\n role\n </div>\n <mat-dialog-content>\n <div class=\"fs-row.gap-lg.align-start\">\n <div class=\"fs-column left-column\">\n <mat-form-field>\n <mat-label>\n Name\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.name\"\n [disabled]=\"disabled\"\n name=\"name\"\n fsFormRequired>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Description\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.description\"\n [disabled]=\"disabled\"\n name=\"description\">\n </mat-form-field>\n @if (aclRole.id || aclLevels.length === 1) {\n <fs-label-field>\n <fs-label>\n Level\n </fs-label>\n {{ indexedAclLevels[aclRole.level] }}\n </fs-label-field>\n } @else {\n <div class=\"level\">\n <fs-radio-group\n [(ngModel)]=\"aclRole.level\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"levelChange()\"\n fsFormRequired\n label=\"Level\"\n orientation=\"vertical\"\n name=\"level\">\n @for (item of aclLevels; track item.value) {\n <mat-radio-button\n [value]=\"item.value\"\n [disabled]=\"!!aclRole.protected\">\n {{ item.name }}\n </mat-radio-button>\n }\n </fs-radio-group>\n </div>\n }\n @if (levelPermissions.length) {\n <fs-label-field>\n <fs-label>\n All permissions\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRole.allPermissions\"\n (ngModelChange)=\"allPermissionsChange($event)\"\n [disabled]=\"!!aclRole.protected || disabled\"\n name=\"allPermissions\">\n Enable\n </mat-checkbox>\n </fs-label-field>\n }\n @for (roleConfig of roleConfigs; track roleConfig.name) {\n <div\n class=\"fs-column\"\n >\n @if (roleConfig.type === 'checkbox') {\n <fs-label-field>\n <fs-label>\n {{ roleConfig.label }}\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [disabled]=\"disabled\"\n [name]=\"roleConfig.name\">\n Enable\n </mat-checkbox>\n <fs-label-message>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </fs-label-message>\n </fs-label-field>\n }\n @if (roleConfig.type === 'select') {\n <mat-form-field>\n <mat-select\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [name]=\"roleConfig.name\"\n [required]=\"roleConfig.required\"\n [disabled]=\"disabled\"\n [placeholder]=\"roleConfig.label\">\n @for (item of roleConfig.values; track item.value) {\n <mat-option\n [value]=\"item.value\">\n {{ item.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </mat-form-field>\n }\n </div>\n }\n </div>\n @if (aclRole.level) {\n <div\n [hidden]=\"!levelPermissions.length\"\n class=\"permissions fs-column\">\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Permissions\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n class=\"permission-group\">\n <div class=\"permission-group\">\n {{ row.category || 'General' }}\n </div>\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"permission\">\n {{ row.name }}\n </div>\n <div class=\"description small\">\n {{ row.description }}\n </div>\n </ng-template>\n </fs-list-column>\n <fs-list-column\n title=\"Access\"\n width=\"1%\"\n class=\"access\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n let-group=\"group\"\n let-groupChildren=\"groupChildren\"\n class=\"permission-group\"\n align=\"right\">\n @if (!aclRole.allPermissions && !disabled) {\n <fs-menu>\n @for (access of AclRoleAccesses | builkOptionsFilter: groupChildren; track access.value) {\n <ng-template\n fs-menu-item\n (click)=\"bulkChange(access.value, groupChildren, group)\">\n {{ access.name }}\n </ng-template>\n }\n </fs-menu>\n }\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"permission\"\n let-permission=\"row\">\n @if (aclRole.allPermissions || disabled) {\n <span>\n {{ indexedAccesses[aclRolePermissions[permission.value]] }}\n </span>\n } @else {\n @if (permission|aclRolePermissionAvailable:aclRolePermissions) {\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclRolePermissions[permission.value]\"\n [disabled]=\"!!aclRole.protected\"\n required\n [name]=\"'access-' + permission.value\"\n (ngModelChange)=\"permissionChange()\">\n @for (access of AclRoleAccesses; track access.value) {\n @if (access.value === 0 || permission.accesses.indexOf(access.value) !== -1) {\n <mat-option\n [value]=\"access.value\">\n {{ access.name }}\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n } @else {\n Unavailable\n }\n }\n </ng-template>\n </fs-list-column>\n </fs-list>\n </div>\n }\n </div>\n </mat-dialog-content>\n <mat-dialog-actions>\n @if (!disabled) {\n <button\n #submit\n mat-button\n type=\"submit\"\n color=\"primary\">\n {{ aclRole.id ? 'Save' : 'Create' }}\n </button>\n }\n <button\n mat-button\n [mat-dialog-close]=\"null\"\n type=\"button\">\n {{ disabled ? 'Done' : 'Cancel' }}\n </button>\n </mat-dialog-actions>\n }\n </fs-dialog>\n</form>", styles: [".permissions{flex:1}.permissions ::ng-deep .fs-list-row-group{background-color:#e4e4e4;font-size:112%}.permissions ::ng-deep fs-list .access{white-space:nowrap}.permissions ::ng-deep .mat-form-field{width:100px}.permissions ::ng-deep .mat-form-field .mat-form-field-wrapper{padding-bottom:0}.permissions ::ng-deep .mat-form-field .mat-form-field-infix{border-top:0}.permissions ::ng-deep .mat-form-field .mat-form-field-underline{bottom:0}.permissions ::ng-deep fs-radio-group{width:100%}.permissions ::ng-deep fs-label-field{width:100%}.permissions .level{width:100%}.left-column{width:40%;max-width:400px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { 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: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: FsFormModule }, { kind: "directive", type: i2.FsFormDirective, selector: "[fsForm]", inputs: ["wrapperSelector", "messageSelector", "hintSelector", "labelSelector", "autocomplete", "shortcuts", "confirm", "confirmDialog", "confirmDrawer", "confirmBrowser", "confirmTabs", "dirtySubmitButton", "submit", "successDelay", "errorDelay", "tabGroup", "deactivationGuard"], outputs: ["fsForm", "invalid", "valid", "submitted", "reseted", "cleared"], exportAs: ["fsForm"] }, { kind: "directive", type: i2.FsFormRequiredDirective, selector: "[fsFormRequired],[ngModel][required]", inputs: ["fsFormRequired", "required", "fsFormRequiredMessage"] }, { kind: "directive", type: i2.FsFormNoFsValidatorsDirective, selector: "[ngModel]:not([required]):not([fsFormRequired]):not([fsFormCompare]):not([fsFormDateRange]):not([fsFormEmail]):not([fsFormEmails]):not([fsFormFunction]):not([fsFormGreater]):not([fsFormGreaterEqual]):not([fsFormInteger]):not([fsFormLesser]):not([fsFormMax]):not([fsFormMaxLength]):not([fsFormMin]):not([fsFormMinLength]):not([fsFormNumeric]):not([fsFormPattern]):not([fsFormPhone]):not([fsFormUrl]):not([validate])" }, { kind: "directive", type: i2.FsButtonDirective, selector: "[mat-raised-button]:not([fsFormButtonStandalone]),[mat-button]:not([fsFormButtonStandalone]),[mat-flat-button]:not([fsFormButtonStandalone]),[mat-stroked-button]:not([fsFormButtonStandalone])", inputs: ["name", "dirtySubmit", "form"] }, { kind: "ngmodule", type: FsDialogModule }, { kind: "component", type: i3.FsDialogComponent, selector: "fs-dialog", inputs: ["mobileMode", "mobileButtonPlacement", "mobileWidth", "mode", "buttonLayout"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: FsLabelModule }, { kind: "component", type: i4.FsLabelComponent, selector: "fs-label" }, { kind: "component", type: i4.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["appearance", "showOutline", "disabled", "focused", "hoverable", "padless"] }, { kind: "component", type: i4.FsLabelMessageComponent, selector: "fs-label-message" }, { kind: "ngmodule", type: FsRadioGroupModule }, { kind: "component", type: i5.FsRadioGroupComponent, selector: "fs-radio-group", inputs: ["orientation", "label", "name", "disabled", "radioPosition", "compareWith", "required"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: FsListModule }, { kind: "component", type: i1$3.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines"], outputs: ["filtersReady"] }, { kind: "directive", type: i1$3.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i1$3.FsListCellDirective, selector: "[fs-list-cell]", inputs: ["colspan", "align", "class"] }, { kind: "directive", type: i1$3.FsListGroupHeaderDirective, selector: "[fs-list-group-cell],[fs-list-group-header]" }, { kind: "ngmodule", type: FsMenuModule }, { kind: "component", type: i7.FsMenuComponent, selector: "fs-menu", inputs: ["class", "buttonClass", "buttonType", "buttonColor"], outputs: ["opened", "closed"] }, { kind: "directive", type: i7.FsMenuItemDirective, selector: "fs-menu-group,[fs-menu-item]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "pipe", type: BulkOptionsFilterPipe, name: "builkOptionsFilter" }, { kind: "pipe", type: AclRolePermissionAvailablePipe, name: "aclRolePermissionAvailable" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
682
690
  }
683
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntryComponent, decorators: [{
691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRoleComponent, decorators: [{
684
692
  type: Component,
685
- args: [{ standalone: true, imports: [
693
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
686
694
  FormsModule,
687
695
  FsFormModule,
688
696
  FsDialogModule,
689
697
  MatDialogTitle,
690
698
  CdkScrollable,
691
699
  MatDialogContent,
700
+ MatFormField,
701
+ MatLabel,
702
+ MatInput,
692
703
  FsLabelModule,
693
- FsAclObjectRolesComponent,
704
+ FsRadioGroupModule,
705
+ MatRadioButton,
706
+ MatCheckbox,
707
+ MatHint,
708
+ MatSelect,
709
+ MatOption,
710
+ FsListModule,
711
+ FsMenuModule,
694
712
  MatDialogActions,
695
713
  MatButton,
696
714
  MatDialogClose,
697
- ], template: "<form fsForm [submit]=\"save\">\n <fs-dialog>\n <div mat-dialog-title>{{ titleEdit? titleEdit : titleAdd }}</div>\n <mat-dialog-content>\n @if (aclObjectRole) {\n <div>\n @if (aclObjectEntry.object) {\n <fs-label-field>\n <fs-label>{{indexedAclRoleLevels[aclObjectEntry.level]}}</fs-label>\n {{aclObjectEntry.object.name}}\n </fs-label-field>\n }\n <fs-acl-object-roles\n [aclRoles]=\"aclRoles\"\n [aclObjectRoles]=\"[aclObjectRole]\"\n [required]=\"required\"\n (change)=\"aclObjectRoleChange($event)\">\n </fs-acl-object-roles>\n </div>\n }\n </mat-dialog-content>\n <mat-dialog-actions>\n <button mat-button type=\"submit\" color=\"primary\">Save</button>\n <button mat-button mat-dialog-close type=\"button\">Cancel</button>\n </mat-dialog-actions>\n </fs-dialog>\n</form>\n", styles: ["::ng-deep .account-roles-autocomplete-panel .mat-option{line-height:normal}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text{display:flex;flex-direction:row;align-items:center}::ng-deep .account-roles-autocomplete-panel .mat-option .mat-option-text fs-badge{margin-right:5px}\n"] }]
698
- }], ctorParameters: () => [] });
699
-
700
- class FsAclRolePopoverComponent {
701
- _appAclService = inject(FsAppAclService);
702
- aclRole;
703
- objectName;
704
- permissions = [];
705
- ngOnInit() {
706
- const aclRolePermissions = this.aclRole.permissions || [];
707
- this._appAclService.getPermissions()
708
- .subscribe((response) => {
709
- this.permissions = response.filter(item => {
710
- return aclRolePermissions.some(permission => {
711
- return item.value === permission.value;
712
- });
713
- });
714
- });
715
- }
716
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolePopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
717
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclRolePopoverComponent, isStandalone: true, selector: "fs-acl-role-popover", inputs: { aclRole: "aclRole", objectName: "objectName" }, ngImport: i0, template: "\n<fs-popover [template]=\"popover\" [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n\n<ng-template #popover>\n <div class=\"name small\">{{aclRole.name}}@if (objectName) {\n <span>: {{objectName}}</span>\n }</div>\n\n @if (permissions.length) {\n @for (permission of permissions; track permission) {\n <div class=\"permission\">\n <div>{{permission.name}}</div>\n <div class=\"small\">{{permission.description}}</div>\n </div>\n }\n } @else {\n None\n }\n\n</ng-template>\n", styles: [".name{padding-bottom:10px}.permission+.permission{padding-top:5px}:host{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: FsPopoverModule }, { kind: "component", type: i1$2.FsPopoverComponent, selector: "fs-popover" }] });
718
- }
719
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolePopoverComponent, decorators: [{
720
- type: Component,
721
- args: [{ selector: 'fs-acl-role-popover', standalone: true, imports: [FsPopoverModule], template: "\n<fs-popover [template]=\"popover\" [maxWidth]=\"400\">\n <ng-content></ng-content>\n</fs-popover>\n\n<ng-template #popover>\n <div class=\"name small\">{{aclRole.name}}@if (objectName) {\n <span>: {{objectName}}</span>\n }</div>\n\n @if (permissions.length) {\n @for (permission of permissions; track permission) {\n <div class=\"permission\">\n <div>{{permission.name}}</div>\n <div class=\"small\">{{permission.description}}</div>\n </div>\n }\n } @else {\n None\n }\n\n</ng-template>\n", styles: [".name{padding-bottom:10px}.permission+.permission{padding-top:5px}:host{cursor:pointer}\n"] }]
722
- }], propDecorators: { aclRole: [{
723
- type: Input
724
- }], objectName: [{
725
- type: Input
715
+ BulkOptionsFilterPipe,
716
+ AclRolePermissionAvailablePipe,
717
+ ], template: "<form\n fsForm\n [submit]=\"save\">\n <fs-dialog>\n @if (aclRole) {\n <div mat-dialog-title>\n @if (!disabled) {\n {{ aclRole.id ? 'Edit' : 'Create' }}\n }\n @if (disabled) {\n View\n }\n role\n </div>\n <mat-dialog-content>\n <div class=\"fs-row.gap-lg.align-start\">\n <div class=\"fs-column left-column\">\n <mat-form-field>\n <mat-label>\n Name\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.name\"\n [disabled]=\"disabled\"\n name=\"name\"\n fsFormRequired>\n </mat-form-field>\n <mat-form-field>\n <mat-label>\n Description\n </mat-label>\n <input\n matInput\n [(ngModel)]=\"aclRole.description\"\n [disabled]=\"disabled\"\n name=\"description\">\n </mat-form-field>\n @if (aclRole.id || aclLevels.length === 1) {\n <fs-label-field>\n <fs-label>\n Level\n </fs-label>\n {{ indexedAclLevels[aclRole.level] }}\n </fs-label-field>\n } @else {\n <div class=\"level\">\n <fs-radio-group\n [(ngModel)]=\"aclRole.level\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"levelChange()\"\n fsFormRequired\n label=\"Level\"\n orientation=\"vertical\"\n name=\"level\">\n @for (item of aclLevels; track item.value) {\n <mat-radio-button\n [value]=\"item.value\"\n [disabled]=\"!!aclRole.protected\">\n {{ item.name }}\n </mat-radio-button>\n }\n </fs-radio-group>\n </div>\n }\n @if (levelPermissions.length) {\n <fs-label-field>\n <fs-label>\n All permissions\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRole.allPermissions\"\n (ngModelChange)=\"allPermissionsChange($event)\"\n [disabled]=\"!!aclRole.protected || disabled\"\n name=\"allPermissions\">\n Enable\n </mat-checkbox>\n </fs-label-field>\n }\n @for (roleConfig of roleConfigs; track roleConfig.name) {\n <div\n class=\"fs-column\"\n >\n @if (roleConfig.type === 'checkbox') {\n <fs-label-field>\n <fs-label>\n {{ roleConfig.label }}\n </fs-label>\n <mat-checkbox\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [disabled]=\"disabled\"\n [name]=\"roleConfig.name\">\n Enable\n </mat-checkbox>\n <fs-label-message>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </fs-label-message>\n </fs-label-field>\n }\n @if (roleConfig.type === 'select') {\n <mat-form-field>\n <mat-select\n [(ngModel)]=\"aclRoleConfigValues[roleConfig.name]\"\n [name]=\"roleConfig.name\"\n [required]=\"roleConfig.required\"\n [disabled]=\"disabled\"\n [placeholder]=\"roleConfig.label\">\n @for (item of roleConfig.values; track item.value) {\n <mat-option\n [value]=\"item.value\">\n {{ item.name }}\n </mat-option>\n }\n </mat-select>\n <mat-hint>\n {{ roleConfig.description }}\n </mat-hint>\n </mat-form-field>\n }\n </div>\n }\n </div>\n @if (aclRole.level) {\n <div\n [hidden]=\"!levelPermissions.length\"\n class=\"permissions fs-column\">\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Permissions\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n class=\"permission-group\">\n <div class=\"permission-group\">\n {{ row.category || 'General' }}\n </div>\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"permission\">\n {{ row.name }}\n </div>\n <div class=\"description small\">\n {{ row.description }}\n </div>\n </ng-template>\n </fs-list-column>\n <fs-list-column\n title=\"Access\"\n width=\"1%\"\n class=\"access\">\n <ng-template\n fs-list-group-cell\n let-row=\"row\"\n let-group=\"group\"\n let-groupChildren=\"groupChildren\"\n class=\"permission-group\"\n align=\"right\">\n @if (!aclRole.allPermissions && !disabled) {\n <fs-menu>\n @for (access of AclRoleAccesses | builkOptionsFilter: groupChildren; track access.value) {\n <ng-template\n fs-menu-item\n (click)=\"bulkChange(access.value, groupChildren, group)\">\n {{ access.name }}\n </ng-template>\n }\n </fs-menu>\n }\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"permission\"\n let-permission=\"row\">\n @if (aclRole.allPermissions || disabled) {\n <span>\n {{ indexedAccesses[aclRolePermissions[permission.value]] }}\n </span>\n } @else {\n @if (permission|aclRolePermissionAvailable:aclRolePermissions) {\n <mat-form-field class=\"form-field-padless\">\n <mat-select\n [(ngModel)]=\"aclRolePermissions[permission.value]\"\n [disabled]=\"!!aclRole.protected\"\n required\n [name]=\"'access-' + permission.value\"\n (ngModelChange)=\"permissionChange()\">\n @for (access of AclRoleAccesses; track access.value) {\n @if (access.value === 0 || permission.accesses.indexOf(access.value) !== -1) {\n <mat-option\n [value]=\"access.value\">\n {{ access.name }}\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n } @else {\n Unavailable\n }\n }\n </ng-template>\n </fs-list-column>\n </fs-list>\n </div>\n }\n </div>\n </mat-dialog-content>\n <mat-dialog-actions>\n @if (!disabled) {\n <button\n #submit\n mat-button\n type=\"submit\"\n color=\"primary\">\n {{ aclRole.id ? 'Save' : 'Create' }}\n </button>\n }\n <button\n mat-button\n [mat-dialog-close]=\"null\"\n type=\"button\">\n {{ disabled ? 'Done' : 'Cancel' }}\n </button>\n </mat-dialog-actions>\n }\n </fs-dialog>\n</form>", styles: [".permissions{flex:1}.permissions ::ng-deep .fs-list-row-group{background-color:#e4e4e4;font-size:112%}.permissions ::ng-deep fs-list .access{white-space:nowrap}.permissions ::ng-deep .mat-form-field{width:100px}.permissions ::ng-deep .mat-form-field .mat-form-field-wrapper{padding-bottom:0}.permissions ::ng-deep .mat-form-field .mat-form-field-infix{border-top:0}.permissions ::ng-deep .mat-form-field .mat-form-field-underline{bottom:0}.permissions ::ng-deep fs-radio-group{width:100%}.permissions ::ng-deep fs-label-field{width:100%}.permissions .level{width:100%}.left-column{width:40%;max-width:400px}\n"] }]
718
+ }], propDecorators: { list: [{
719
+ type: ViewChild,
720
+ args: [FsListComponent]
721
+ }], submitButton: [{
722
+ type: ViewChild,
723
+ args: ['submit', { static: false }]
726
724
  }] } });
727
725
 
728
- class FsAclEntriesComponent {
726
+ class FsAclRolesComponent {
729
727
  _appAclService = inject(FsAppAclService);
730
728
  _dialog = inject(MatDialog);
731
- _confirm = inject(FsPrompt);
732
- loadAclEntries;
733
- loadAclRoles;
734
- saveAclObjectEntry;
735
- environmentShow = true;
736
- environmentLabel = 'Environment';
737
- environmentKey = 'environment';
738
- actions = [];
739
- aclEntriesList = null;
740
- aclEntriesConfig = null;
741
- permissions = [];
729
+ deleteAclRole;
730
+ restoreAclRole;
731
+ saveAclRole;
732
+ loadAclRoles;
733
+ loadAclRole;
734
+ loadRoleConfigs;
735
+ aclLevels = [];
736
+ disabledAclRole;
737
+ list = new QueryList();
738
+ listConfig;
739
+ permissions;
740
+ indexedAclRoleLevels = {};
742
741
  _destroy$ = new Subject();
743
742
  ngOnInit() {
744
- this._appAclService.getPermissions()
745
- .subscribe(response => {
746
- this.permissions = response;
747
- });
748
- this.aclEntriesConfig = {
749
- status: false,
750
- paging: false,
751
- actions: this.actions,
752
- rowActions: [
753
- {
754
- label: 'Remove All Roles',
755
- click: (aclObjectEntry) => {
756
- this._confirm
757
- .confirm({
758
- title: 'Remove All Roles',
759
- commitLabel: 'Save',
760
- template: `Please note that removing roles may prevent users from being able to successfully login.<br>
761
- These changes are effective immediately.<br>
762
- Are you sure you would like to continue?`,
763
- }).subscribe(() => {
764
- const data = { ...aclObjectEntry, aclEntries: [] };
765
- this.saveAclObjectEntry(data)
766
- .subscribe(() => {
767
- this.aclEntriesList.reload();
768
- });
769
- });
770
- }
771
- }
772
- ],
773
- fetch: () => {
774
- return new Observable((observer) => {
775
- this.loadAclEntries({
776
- aclRoles: true,
777
- aclRolePermissions: true,
778
- objects: true,
779
- aclRoleState: 'active',
780
- })
781
- .subscribe((aclEntries) => {
782
- const objects = aclEntries
783
- .filter((aclEntry) => (!!aclEntry.object))
784
- .reduce((items, item) => {
785
- return {
786
- ...items,
787
- [item.object.id]: item.object,
788
- };
789
- }, {});
790
- const environments = aclEntries
791
- .filter((aclEntry) => (!!aclEntry[this.environmentKey]))
792
- .reduce((items, item) => {
793
- const environment = item[this.environmentKey];
794
- return {
795
- ...items,
796
- [environment.id]: environment,
797
- };
798
- }, {});
799
- const groupedAclEntries = groupBy(aclEntries, (item) => {
800
- const environmentId = (item[this.environmentKey])?.id;
801
- return [item.aclRole.level, environmentId, item.objectId];
802
- });
803
- let aclObjectEntries = Object.keys(groupedAclEntries)
804
- .reduce((accum, key) => {
805
- const parts = key.split(',');
806
- return [
807
- ...accum,
808
- {
809
- object: objects[parts[2]],
810
- level: parts[0],
811
- [`${this.environmentKey}Id`]: parts[1] ? parseInt(parts[1]) : null,
812
- [this.environmentKey]: environments[parts[1]],
813
- aclEntries: groupedAclEntries[key],
814
- }
815
- ];
816
- }, []);
817
- const hasApp = aclObjectEntries.some((item) => {
818
- return item.aclEntries.some((entry) => {
819
- return !entry.objectId;
820
- });
821
- });
822
- if (!hasApp) {
823
- aclObjectEntries.unshift({
824
- object: null,
825
- aclEntries: [],
826
- level: 'app',
827
- environmentId: null,
828
- });
829
- }
830
- aclObjectEntries = sortBy(aclObjectEntries, (item) => {
831
- return item.object ? item.level : '';
832
- });
833
- observer.next({ data: aclObjectEntries });
834
- observer.complete();
835
- });
743
+ new Observable((observer) => {
744
+ if (this.aclLevels.length) {
745
+ observer.next(this.aclLevels);
746
+ observer.complete();
747
+ }
748
+ else {
749
+ this._appAclService.getLevels()
750
+ .subscribe((aclLevels) => {
751
+ observer.next(aclLevels);
752
+ observer.complete();
836
753
  });
837
- },
838
- };
754
+ }
755
+ })
756
+ .subscribe((aclLevels) => {
757
+ this.aclLevels = aclLevels;
758
+ this.indexedAclRoleLevels = list(this.aclLevels, 'name', 'value');
759
+ this._loadListConfig();
760
+ });
839
761
  }
840
- update(aclObjectEntry) {
841
- const data = {
842
- aclObjectEntry,
843
- required: false,
844
- loadAclRoles: this.loadAclRoles,
845
- saveAclObjectEntry: this.saveAclObjectEntry
846
- };
847
- this._dialog.open(FsAclEntryComponent, {
848
- data: data
762
+ openDialog(aclRole = { id: null }) {
763
+ this._dialog.open(FsAclRoleComponent, {
764
+ width: '70%',
765
+ data: {
766
+ aclRole,
767
+ aclLevels: this.aclLevels,
768
+ loadAclRole: this.loadAclRole,
769
+ saveAclRole: this.saveAclRole,
770
+ loadRoleConfigs: this.loadRoleConfigs,
771
+ disabled: this.disabledAclRole
772
+ ? this.disabledAclRole(aclRole)
773
+ : false,
774
+ },
849
775
  })
850
776
  .afterClosed()
851
- .pipe(takeUntil(this._destroy$))
852
- .subscribe(() => {
853
- this.aclEntriesList.reload();
777
+ .pipe(takeUntil(this._destroy$), filter((response) => !!response))
778
+ .subscribe((response) => {
779
+ this.list.forEach((list) => {
780
+ list.reload();
781
+ });
854
782
  });
855
783
  }
856
784
  ngOnDestroy() {
857
785
  this._destroy$.next(null);
858
786
  this._destroy$.complete();
859
787
  }
860
- reload() {
861
- this.aclEntriesList.reload();
788
+ _loadListConfig() {
789
+ this.listConfig = {
790
+ sort: { value: 'hierarchy' },
791
+ filters: [
792
+ {
793
+ name: 'keyword',
794
+ type: ItemType.Keyword,
795
+ label: 'Search',
796
+ },
797
+ {
798
+ name: 'level',
799
+ label: 'Level',
800
+ type: ItemType.Select,
801
+ values: this.aclLevels,
802
+ hide: this.aclLevels.length <= 1,
803
+ },
804
+ {
805
+ name: 'state',
806
+ label: 'Show deleted',
807
+ type: ItemType.Checkbox,
808
+ unchecked: 'active',
809
+ checked: 'deleted',
810
+ },
811
+ ],
812
+ actions: [
813
+ {
814
+ click: (event) => {
815
+ this.openDialog();
816
+ },
817
+ label: 'Create',
818
+ },
819
+ ],
820
+ rowActions: [
821
+ {
822
+ click: (data) => {
823
+ return this.deleteAclRole(data);
824
+ },
825
+ remove: {
826
+ title: 'Confirm',
827
+ template: 'Are you sure you would like to delete this role?',
828
+ },
829
+ menu: true,
830
+ label: 'Delete',
831
+ show: (row) => {
832
+ const hideDelete = this.disabledAclRole
833
+ ? this.disabledAclRole(row)
834
+ : false;
835
+ return !!this.deleteAclRole
836
+ && row.state !== 'deleted'
837
+ && !hideDelete;
838
+ },
839
+ },
840
+ {
841
+ click: (data) => {
842
+ return this.restoreAclRole(data)
843
+ .pipe(tap(() => {
844
+ this.list.forEach((l) => {
845
+ l.reload();
846
+ });
847
+ }), takeUntil(this._destroy$))
848
+ .subscribe();
849
+ },
850
+ label: 'Restore',
851
+ show: (row) => !!this.restoreAclRole && row.state === 'deleted',
852
+ },
853
+ ],
854
+ fetch: (query) => {
855
+ query.permissions = true;
856
+ return this.loadAclRoles(query)
857
+ .pipe(map((data) => data));
858
+ },
859
+ };
862
860
  }
863
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntriesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
864
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclEntriesComponent, isStandalone: true, selector: "fs-acl-entries", inputs: { loadAclEntries: "loadAclEntries", loadAclRoles: "loadAclRoles", saveAclObjectEntry: "saveAclObjectEntry", environmentShow: "environmentShow", environmentLabel: "environmentLabel", environmentKey: "environmentKey", actions: "actions" }, viewQueries: [{ propertyName: "aclEntriesList", first: true, predicate: FsListComponent, descendants: true }], ngImport: i0, template: "<fs-list [config]=\"aclEntriesConfig\">\n <fs-list-column>\n <ng-template fs-list-header>\n Context\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n @if (row.object) {\n <div class=\"fs-row.gap-sm\">\n @if (row.object.imageUrl) {\n <fs-badge\n shape=\"circle\"\n [image]=\"row.object.imageUrl\">\n </fs-badge>\n }\n <span>\n <div>\n <small>\n {{ row.object.class }}\n </small>\n </div>\n <a (click)=\"update(row)\">\n {{ row.object.name }}\n </a>\n </span>\n </div>\n } @else {\n <a (click)=\"update(row)\">\n App\n </a>\n }\n </ng-template>\n </fs-list-column>\n <fs-list-column [show]=\"environmentShow\">\n <ng-template fs-list-header>\n {{ environmentLabel }}\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n {{ row.environment?.name }}\n </ng-template>\n </fs-list-column>\n <fs-list-column>\n <ng-template fs-list-header>\n Roles\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"fs-column\">\n @for (aclEntry of row.aclEntries; track aclEntry) {\n <div div>\n @switch (row.level) {\n @case ('app') {\n <fs-acl-role-popover\n [aclRole]=\"aclEntry.aclRole\"\n objectName=\"App\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n @default {\n @if (row.object) {\n <fs-acl-role-popover [aclRole]=\"aclEntry.aclRole\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n }\n }\n </div>\n }\n </div>\n </ng-template>\n </fs-list-column>\n</fs-list>", styles: [""], dependencies: [{ kind: "ngmodule", type: FsListModule }, { kind: "component", type: i1$1.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines"], outputs: ["filtersReady"] }, { kind: "directive", type: i1$1.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i1$1.FsListCellDirective, selector: "[fs-list-cell]", inputs: ["colspan", "align", "class"] }, { kind: "directive", type: i1$1.FsListHeaderDirective, selector: "[fs-list-header]", inputs: ["colspan", "align", "class"] }, { kind: "ngmodule", type: FsBadgeModule }, { kind: "component", type: i2$1.FsBadgeComponent, selector: "fs-badge", inputs: ["color", "text", "tooltip", "size", "shape", "image", "icon", "iconSize", "iconSizePercent", "iconColor", "backgroundSize"] }, { kind: "component", type: FsAclRolePopoverComponent, selector: "fs-acl-role-popover", inputs: ["aclRole", "objectName"] }] });
861
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
862
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: FsAclRolesComponent, isStandalone: true, selector: "fs-acl-roles", inputs: { deleteAclRole: "deleteAclRole", restoreAclRole: "restoreAclRole", saveAclRole: "saveAclRole", loadAclRoles: "loadAclRoles", loadAclRole: "loadAclRole", loadRoleConfigs: "loadRoleConfigs", aclLevels: "aclLevels", disabledAclRole: "disabledAclRole" }, viewQueries: [{ propertyName: "list", predicate: FsListComponent, descendants: true }], ngImport: i0, template: "@if (listConfig) {\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Name\" name=\"name\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n @if (row.state !== 'deleted') {\n <a (click)=\"openDialog(row)\">{{ row.name }}</a>\n } @else {\n {{ row.name }}\n }\n <div class=\"small\">{{row.description}}</div>\n </ng-template>\n </fs-list-column>\n <fs-list-column name=\"hierarchy\" title=\"Level\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n {{ indexedAclRoleLevels[row.level] }}\n </ng-template>\n </fs-list-column>\n <fs-list-column title=\"Permissions\">\n <ng-template fs-list-cell let-row=\"row\">\n <div class=\"permissions\">\n @for (permission of row.permissions; track permission.id) {\n @if (permission.access) {\n <span class=\"permission\">\n <acl-permission-popover [permission]=\"permission\">{{permission.name}}</acl-permission-popover>\n </span>\n }\n }\n </div>\n </ng-template>\n </fs-list-column>\n </fs-list>\n}\n", styles: [".permissions .permission+.permission:before{content:\", \"}\n"], dependencies: [{ kind: "ngmodule", type: FsListModule }, { kind: "component", type: i1$3.FsListComponent, selector: "fs-list", inputs: ["config", "loaderLines"], outputs: ["filtersReady"] }, { kind: "directive", type: i1$3.FsListColumnDirective, selector: "fs-list-column", inputs: ["show", "title", "name", "customizable", "sortable", "sortableDefault", "sortableDirection", "direction", "align", "width", "class"] }, { kind: "directive", type: i1$3.FsListCellDirective, selector: "[fs-list-cell]", inputs: ["colspan", "align", "class"] }, { kind: "component", type: FsAclPermissionPopoverComponent, selector: "acl-permission-popover", inputs: ["permission"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
865
863
  }
866
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclEntriesComponent, decorators: [{
864
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolesComponent, decorators: [{
867
865
  type: Component,
868
- args: [{ selector: 'fs-acl-entries', standalone: true, imports: [FsListModule, FsBadgeModule, FsAclRolePopoverComponent], template: "<fs-list [config]=\"aclEntriesConfig\">\n <fs-list-column>\n <ng-template fs-list-header>\n Context\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n @if (row.object) {\n <div class=\"fs-row.gap-sm\">\n @if (row.object.imageUrl) {\n <fs-badge\n shape=\"circle\"\n [image]=\"row.object.imageUrl\">\n </fs-badge>\n }\n <span>\n <div>\n <small>\n {{ row.object.class }}\n </small>\n </div>\n <a (click)=\"update(row)\">\n {{ row.object.name }}\n </a>\n </span>\n </div>\n } @else {\n <a (click)=\"update(row)\">\n App\n </a>\n }\n </ng-template>\n </fs-list-column>\n <fs-list-column [show]=\"environmentShow\">\n <ng-template fs-list-header>\n {{ environmentLabel }}\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n {{ row.environment?.name }}\n </ng-template>\n </fs-list-column>\n <fs-list-column>\n <ng-template fs-list-header>\n Roles\n </ng-template>\n <ng-template\n fs-list-cell\n let-row=\"row\">\n <div class=\"fs-column\">\n @for (aclEntry of row.aclEntries; track aclEntry) {\n <div div>\n @switch (row.level) {\n @case ('app') {\n <fs-acl-role-popover\n [aclRole]=\"aclEntry.aclRole\"\n objectName=\"App\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n @default {\n @if (row.object) {\n <fs-acl-role-popover [aclRole]=\"aclEntry.aclRole\">\n {{ aclEntry.aclRole.name }}\n </fs-acl-role-popover>\n }\n }\n }\n </div>\n }\n </div>\n </ng-template>\n </fs-list-column>\n</fs-list>" }]
869
- }], propDecorators: { loadAclEntries: [{
866
+ args: [{ selector: 'fs-acl-roles', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [FsListModule, FsAclPermissionPopoverComponent], template: "@if (listConfig) {\n <fs-list [config]=\"listConfig\">\n <fs-list-column title=\"Name\" name=\"name\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n @if (row.state !== 'deleted') {\n <a (click)=\"openDialog(row)\">{{ row.name }}</a>\n } @else {\n {{ row.name }}\n }\n <div class=\"small\">{{row.description}}</div>\n </ng-template>\n </fs-list-column>\n <fs-list-column name=\"hierarchy\" title=\"Level\" [sortable]=\"true\">\n <ng-template fs-list-cell let-row=\"row\">\n {{ indexedAclRoleLevels[row.level] }}\n </ng-template>\n </fs-list-column>\n <fs-list-column title=\"Permissions\">\n <ng-template fs-list-cell let-row=\"row\">\n <div class=\"permissions\">\n @for (permission of row.permissions; track permission.id) {\n @if (permission.access) {\n <span class=\"permission\">\n <acl-permission-popover [permission]=\"permission\">{{permission.name}}</acl-permission-popover>\n </span>\n }\n }\n </div>\n </ng-template>\n </fs-list-column>\n </fs-list>\n}\n", styles: [".permissions .permission+.permission:before{content:\", \"}\n"] }]
867
+ }], propDecorators: { deleteAclRole: [{
870
868
  type: Input
871
- }], loadAclRoles: [{
869
+ }], restoreAclRole: [{
872
870
  type: Input
873
- }], saveAclObjectEntry: [{
871
+ }], saveAclRole: [{
874
872
  type: Input
875
- }], environmentShow: [{
873
+ }], loadAclRoles: [{
876
874
  type: Input
877
- }], environmentLabel: [{
875
+ }], loadAclRole: [{
878
876
  type: Input
879
- }], environmentKey: [{
877
+ }], loadRoleConfigs: [{
880
878
  type: Input
881
- }], actions: [{
879
+ }], aclLevels: [{
882
880
  type: Input
883
- }], aclEntriesList: [{
884
- type: ViewChild,
881
+ }], disabledAclRole: [{
882
+ type: Input
883
+ }], list: [{
884
+ type: ViewChildren,
885
885
  args: [FsListComponent]
886
886
  }] } });
887
887
 
888
+ class FsAppAclModule {
889
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAppAclModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
890
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: FsAppAclModule, imports: [FsAclEntriesComponent,
891
+ FsAclEntryComponent,
892
+ FsAclObjectRolesComponent,
893
+ FsAclPermissionPopoverComponent,
894
+ FsAclRoleComponent,
895
+ FsAclRolePopoverComponent,
896
+ FsAclRolesComponent], exports: [FsAclEntriesComponent,
897
+ FsAclEntryComponent,
898
+ FsAclObjectRolesComponent,
899
+ FsAclPermissionPopoverComponent,
900
+ FsAclRoleComponent,
901
+ FsAclRolePopoverComponent,
902
+ FsAclRolesComponent] });
903
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAppAclModule, imports: [FsAclEntriesComponent,
904
+ FsAclEntryComponent,
905
+ FsAclObjectRolesComponent,
906
+ FsAclPermissionPopoverComponent,
907
+ FsAclRoleComponent,
908
+ FsAclRolePopoverComponent,
909
+ FsAclRolesComponent] });
910
+ }
911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAppAclModule, decorators: [{
912
+ type: NgModule,
913
+ args: [{
914
+ imports: [
915
+ FsAclEntriesComponent,
916
+ FsAclEntryComponent,
917
+ FsAclObjectRolesComponent,
918
+ FsAclPermissionPopoverComponent,
919
+ FsAclRoleComponent,
920
+ FsAclRolePopoverComponent,
921
+ FsAclRolesComponent,
922
+ ],
923
+ exports: [
924
+ FsAclEntriesComponent,
925
+ FsAclEntryComponent,
926
+ FsAclObjectRolesComponent,
927
+ FsAclPermissionPopoverComponent,
928
+ FsAclRoleComponent,
929
+ FsAclRolePopoverComponent,
930
+ FsAclRolesComponent,
931
+ ],
932
+ }]
933
+ }] });
934
+
888
935
  /**
889
936
  * Generated bundle index. Do not edit.
890
937
  */
891
938
 
892
- export { FS_APP_ACL_CONFIG, FsAclEntriesComponent, FsAclEntryComponent, FsAclObjectRolesComponent, FsAclPermissionPopoverComponent, FsAclRoleComponent, FsAclRolePopoverComponent, FsAclRolesComponent, FsAppAclService };
939
+ export { FS_APP_ACL_CONFIG, FsAclEntriesComponent, FsAclEntryComponent, FsAclObjectRolesComponent, FsAclPermissionPopoverComponent, FsAclRoleComponent, FsAclRolePopoverComponent, FsAclRolesComponent, FsAppAclModule, FsAppAclService };
893
940
  //# sourceMappingURL=firestitch-app-acl.mjs.map