@firestitch/app-acl 18.0.15 → 18.0.16

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.
@@ -503,6 +503,7 @@ class FsAclRoleComponent {
503
503
  aclRolePermissions = {};
504
504
  loadRoleConfigs;
505
505
  disabled;
506
+ permissionSelectable;
506
507
  _destroy$ = new Subject();
507
508
  ngOnInit() {
508
509
  forkJoin(this.getRole(), this._appAclService.getPermissions())
@@ -511,6 +512,7 @@ class FsAclRoleComponent {
511
512
  this.permissions = aclPermissions;
512
513
  this.aclLevels = this._data.aclLevels;
513
514
  this.disabled = this._data.disabled;
515
+ this.permissionSelectable = this._data.permissionSelectable;
514
516
  this.indexedAclLevels = list(this.aclLevels, 'name', 'value');
515
517
  this.indexedAccesses = list(AclRoleAccesses, 'name', 'value');
516
518
  this.aclRole = {
@@ -587,7 +589,9 @@ class FsAclRoleComponent {
587
589
  .forEach((permission) => {
588
590
  const access = permission.accesses
589
591
  .find((access) => value === access);
590
- if (access || !value) {
592
+ // Setting None (0) is always allowed (it removes access); granting a
593
+ // real access is skipped for permissions the consumer marks unselectable.
594
+ if ((access || !value) && (!value || this.isPermissionSelectable(permission))) {
591
595
  this.aclRolePermissions[permission.value] = value;
592
596
  }
593
597
  });
@@ -656,6 +660,26 @@ class FsAclRoleComponent {
656
660
  this._applyNonePermissionAccess();
657
661
  }
658
662
  }
663
+ /**
664
+ * Whether a permission may be granted at the given access. Defaults to true
665
+ * (selectable) when the consuming project supplies no permissionSelectable
666
+ * guard, so behaviour is unchanged for existing callers.
667
+ */
668
+ isPermissionSelectable(permission, access) {
669
+ return !this.permissionSelectable
670
+ || this.permissionSelectable(permission, access);
671
+ }
672
+ /**
673
+ * "All permissions" is only offerable when every permission at the current
674
+ * level is itself selectable (enabling it would grant them all). Defaults to
675
+ * true when no guard is supplied.
676
+ */
677
+ allPermissionsSelectable() {
678
+ return !this.permissionSelectable
679
+ || this.levelPermissions.every((permission) => {
680
+ return this.isPermissionSelectable(permission);
681
+ });
682
+ }
659
683
  ngOnDestroy() {
660
684
  this._destroy$.next(null);
661
685
  this._destroy$.complete();
@@ -689,7 +713,7 @@ class FsAclRoleComponent {
689
713
  });
690
714
  }
691
715
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRoleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
692
- 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 });
716
+ 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 || !allPermissionsSelectable()\"\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 (!isPermissionSelectable(permission)) {\n Not permitted\n } @else 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 });
693
717
  }
694
718
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRoleComponent, decorators: [{
695
719
  type: Component,
@@ -717,7 +741,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImpor
717
741
  MatDialogClose,
718
742
  BulkOptionsFilterPipe,
719
743
  AclRolePermissionAvailablePipe,
720
- ], 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"] }]
744
+ ], 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 || !allPermissionsSelectable()\"\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 (!isPermissionSelectable(permission)) {\n Not permitted\n } @else 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"] }]
721
745
  }], propDecorators: { list: [{
722
746
  type: ViewChild,
723
747
  args: [FsListComponent]
@@ -737,6 +761,12 @@ class FsAclRolesComponent {
737
761
  loadRoleConfigs;
738
762
  aclLevels = [];
739
763
  disabledAclRole;
764
+ /**
765
+ * Optional guard letting the consuming project decide whether a permission (at
766
+ * a given access) may be granted on a role. Returns true = selectable. When
767
+ * not provided, everything is selectable, so existing consumers are unchanged.
768
+ */
769
+ permissionSelectable;
740
770
  list = new QueryList();
741
771
  listConfig;
742
772
  permissions;
@@ -774,6 +804,7 @@ class FsAclRolesComponent {
774
804
  disabled: this.disabledAclRole
775
805
  ? this.disabledAclRole(aclRole)
776
806
  : false,
807
+ permissionSelectable: this.permissionSelectable,
777
808
  },
778
809
  })
779
810
  .afterClosed()
@@ -862,7 +893,7 @@ class FsAclRolesComponent {
862
893
  };
863
894
  }
864
895
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
865
- 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 });
896
+ 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", permissionSelectable: "permissionSelectable" }, 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 });
866
897
  }
867
898
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: FsAclRolesComponent, decorators: [{
868
899
  type: Component,
@@ -883,6 +914,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImpor
883
914
  type: Input
884
915
  }], disabledAclRole: [{
885
916
  type: Input
917
+ }], permissionSelectable: [{
918
+ type: Input
886
919
  }], list: [{
887
920
  type: ViewChildren,
888
921
  args: [FsListComponent]