@cauca-911/management 22.0.7 → 22.0.9-beta1

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,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Injector, inject, Injectable, computed, ChangeDetectionStrategy, Component, ViewChild, signal, viewChild, resource, effect, untracked, model, input, HostListener, forwardRef, ViewEncapsulation, output } from '@angular/core';
3
- import { pendingChangesGuard, DialogService, PageTitleComponent, LoadingSpinnerIndicatorComponent, LoadingErrorComponent, StrokedButtonComponent, RaisedButtonComponent, ListPaginatorComponent, IconButtonComponent, LoadingStateService, GroupContainerComponent, ConfirmationResult, SavingErrorBoxComponent, MenuItemComponent, ExpandablePanelComponent, FieldErrorsComponent, PasswordSelectionComponent, PhoneNumberInputComponent, ControlFieldErrorsComponent } from '@cauca-911/material';
3
+ import { pendingChangesGuard, DialogService, PageTitleComponent, LoadingSpinnerIndicatorComponent, LoadingErrorComponent, StrokedButtonComponent, RaisedButtonComponent, ListPaginatorComponent, IconButtonComponent, LoadingStateService, GroupContainerComponent, ConfirmationResult, SavingErrorBoxComponent, MenuItemComponent, ExpandablePanelComponent, FieldErrorsComponent, PasswordSelectionComponent, PhoneNumberInputComponent, ControlErrorStateDirective, ControlFieldErrorsComponent, DropdownChipAutocompleteComponent } from '@cauca-911/material';
4
4
  import * as i1 from '@angular/material/card';
5
5
  import { MatCardModule } from '@angular/material/card';
6
6
  import { TranslatePipe } from '@ngx-translate/core';
@@ -24,7 +24,7 @@ import * as i1$1 from '@angular/material/dialog';
24
24
  import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule, MatDialog } from '@angular/material/dialog';
25
25
  import * as i4 from '@angular/material/icon';
26
26
  import { MatIconModule, MatIcon } from '@angular/material/icon';
27
- import { toSignal, toObservable, rxResource } from '@angular/core/rxjs-interop';
27
+ import { toSignal, toObservable, rxResource, takeUntilDestroyed } from '@angular/core/rxjs-interop';
28
28
  import { v4 } from 'uuid';
29
29
  import * as i4$1 from '@angular/material/list';
30
30
  import { MatListModule } from '@angular/material/list';
@@ -39,10 +39,6 @@ import { MatColumnDef, MatHeaderCell, MatHeaderCellDef, MatCell, MatCellDef, Mat
39
39
  import { schema, required, maxLength, validateHttp, email, readonly, pattern, FormField } from '@angular/forms/signals';
40
40
  import * as i3$2 from '@angular/material/progress-spinner';
41
41
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
42
- import * as i2$2 from '@angular/material/select';
43
- import { MatSelectModule } from '@angular/material/select';
44
- import * as i3$3 from 'ngx-mat-select-search';
45
- import { NgxMatSelectSearchModule } from 'ngx-mat-select-search';
46
42
 
47
43
  const MANAGEMENT_URL_PREFIX = new InjectionToken('MANAGEMENT_URL_PREFIX');
48
44
  const MANAGEMENT_ROUTE_SEGMENT = new InjectionToken('MANAGEMENT_ROUTE_SEGMENT');
@@ -169,7 +165,7 @@ class GroupListGridComponent {
169
165
  }
170
166
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GroupListGridComponent, [{
171
167
  type: Component,
172
- args: [{ selector: 'cauca-group-list-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatSort, OdataGridComponent, SortableDataGridColumnComponent, SortableDataGridCheckColumnComponent, DataGridCommandsColumnComponent, TranslatePipe], template: "<cauca-odata-grid matSort\n [showTableOptions]=\"true\"\n class=\"groups-datagrid\"\n aria-describedby=\"Groups table\"\n resourceName=\"GroupList\"\n [showAddButton]=\"true\"\n (addButtonClick)=\"createGroup()\"\n [addButtonLabel]=\"'groups.addButtonLabel'| translate\"\n [baseSort]=\"['name']\"\n [filterPredicate]=\"filterPredicate\"\n [displayedColumns]=\"columns()\">\n\n <cauca-sortable-data-grid-column id=\"name\" prop=\"name\" [label]=\"'groups.groupNameColumnLabel'|translate\"/>\n <cauca-sortable-data-grid-check-column id=\"is-assignable-all-users\" prop=\"assignableByAllUsers\" [label]=\"'groups.assignableByAllUsersColumnLabel'|translate\" width=\"200px\" />\n <cauca-data-grid-commands-column id=\"buttons\" prop=\"buttons\" [canDelete]=\"true\" [canEdit]=\"true\" editLinkField=\"id\" (deleteClick)=\"deleteGroup($event)\" />\n\n</cauca-odata-grid>\n" }]
168
+ args: [{ selector: 'cauca-group-list-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatSort, OdataGridComponent, SortableDataGridColumnComponent, SortableDataGridCheckColumnComponent, DataGridCommandsColumnComponent, TranslatePipe], template: "<cauca-odata-grid matSort\r\n [showTableOptions]=\"true\"\r\n class=\"groups-datagrid\"\r\n aria-describedby=\"Groups table\"\r\n resourceName=\"GroupList\"\r\n [showAddButton]=\"true\"\r\n (addButtonClick)=\"createGroup()\"\r\n [addButtonLabel]=\"'groups.addButtonLabel'| translate\"\r\n [baseSort]=\"['name']\"\r\n [filterPredicate]=\"filterPredicate\"\r\n [displayedColumns]=\"columns()\">\r\n\r\n <cauca-sortable-data-grid-column id=\"name\" prop=\"name\" [label]=\"'groups.groupNameColumnLabel'|translate\"/>\r\n <cauca-sortable-data-grid-check-column id=\"is-assignable-all-users\" prop=\"assignableByAllUsers\" [label]=\"'groups.assignableByAllUsersColumnLabel'|translate\" width=\"200px\" />\r\n <cauca-data-grid-commands-column id=\"buttons\" prop=\"buttons\" [canDelete]=\"true\" [canEdit]=\"true\" editLinkField=\"id\" (deleteClick)=\"deleteGroup($event)\" />\r\n\r\n</cauca-odata-grid>\r\n" }]
173
169
  }], null, { table: [{
174
170
  type: ViewChild,
175
171
  args: [OdataGridComponent, { static: true }]
@@ -192,7 +188,7 @@ class GroupsPageComponent {
192
188
  }
193
189
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GroupsPageComponent, [{
194
190
  type: Component,
195
- args: [{ selector: 'cauca-groups-page', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatCardModule, PageTitleComponent, GroupListGridComponent], template: "<cauca-page-title\n [showBreadcrumb]=\"true\"\n caption=\"menu.groups\"\n baseCrumb=\"menu.management\"\n breadcrumb=\"menu.groups\" />\n\n<mat-card class=\"page-content\">\n\n <mat-card-content class=\"page-content-grid\">\n <cauca-group-list-grid />\n </mat-card-content>\n\n</mat-card>\n" }]
191
+ args: [{ selector: 'cauca-groups-page', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatCardModule, PageTitleComponent, GroupListGridComponent], template: "<cauca-page-title\r\n [showBreadcrumb]=\"true\"\r\n caption=\"menu.groups\"\r\n baseCrumb=\"menu.management\"\r\n breadcrumb=\"menu.groups\" />\r\n\r\n<mat-card class=\"page-content\">\r\n\r\n <mat-card-content class=\"page-content-grid\">\r\n <cauca-group-list-grid />\r\n </mat-card-content>\r\n\r\n</mat-card>\r\n" }]
196
192
  }], null, null); })();
197
193
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GroupsPageComponent, { className: "GroupsPageComponent", filePath: "lib/pages/groups-page/groups-page.component.ts", lineNumber: 13 }); })();
198
194
 
@@ -363,7 +359,7 @@ class UserSearchService {
363
359
  }], null, null); })();
364
360
 
365
361
  const _c0$5 = ["resultPaginator"];
366
- const _forTrack0$5 = ($index, $item) => $item.id;
362
+ const _forTrack0$4 = ($index, $item) => $item.id;
367
363
  function GroupUserSelectionDialogComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
368
364
  i0.ɵɵelementStart(0, "div", 8);
369
365
  i0.ɵɵtext(1);
@@ -415,7 +411,7 @@ function GroupUserSelectionDialogComponent_Conditional_17_Template(rf, ctx) { if
415
411
  const _r1 = i0.ɵɵgetCurrentView();
416
412
  i0.ɵɵelementStart(0, "mat-selection-list", 18);
417
413
  i0.ɵɵlistener("selectionChange", function GroupUserSelectionDialogComponent_Conditional_17_Template_mat_selection_list_selectionChange_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSelectionChange($event)); });
418
- i0.ɵɵrepeaterCreate(1, GroupUserSelectionDialogComponent_Conditional_17_For_2_Template, 4, 6, "mat-list-option", 19, _forTrack0$5);
414
+ i0.ɵɵrepeaterCreate(1, GroupUserSelectionDialogComponent_Conditional_17_For_2_Template, 4, 6, "mat-list-option", 19, _forTrack0$4);
419
415
  i0.ɵɵelementEnd();
420
416
  i0.ɵɵconditionalCreate(3, GroupUserSelectionDialogComponent_Conditional_17_Conditional_3_Template, 2, 2, "cauca-list-paginator", 20);
421
417
  } if (rf & 2) {
@@ -601,12 +597,12 @@ class GroupUserSelectionDialogComponent {
601
597
  ListPaginatorComponent,
602
598
  MatTooltipModule,
603
599
  IconButtonComponent,
604
- ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [UserSearchService, LoadingStateService], template: "<div mat-dialog-title>\n <div class=\"h6\">{{ 'groupEdition.userSelectionTitle' | translate }}</div>\n <cauca-icon-button id=\"closeButton\" (buttonClick)=\"closeClick()\" icon=\"close\" />\n</div>\n\n<mat-dialog-content class=\"dialog-content\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"search-field\">\n <mat-label>{{ 'groupEdition.searchUserPlaceholder' | translate }}</mat-label>\n <input matInput type=\"text\" [value]=\"searchTerm()\" (input)=\"searchTerm.set($any($event.target).value)\" />\n <mat-icon matSuffix>search</mat-icon>\n </mat-form-field>\n\n @if (searchTerm().length >= 0 && searchTerm().length < MIN_SEARCH_LENGTH) {\n <div class=\"search-hint body2\">{{ 'groupEdition.searchMinChars' | translate }}</div>\n }\n\n <div class=\"results-region\">\n <cauca-loading-error (retryRequest)=\"searchResource.reload()\" />\n\n @if (searchResource.isLoading() && !results().length) {\n <cauca-loading-spinner-indicator />\n } @else if (results().length) {\n <mat-selection-list class=\"results-list\" [compareWith]=\"compareUserById\" (selectionChange)=\"onSelectionChange($event)\">\n @for (user of results(); track user.id; let i = $index) {\n <mat-list-option\n [value]=\"user\"\n [selected]=\"selectedUserIds().has(user.id)\"\n color=\"primary\"\n class=\"result-item\"\n [class.result-item--even]=\"i % 2 === 1\">\n <span matListItemTitle>{{ user.fullName }}</span>\n @if (user.additionalInformation) {\n <span matListItemSubtitle>{{ user.additionalInformation }}</span>\n }\n </mat-list-option>\n }\n </mat-selection-list>\n\n @if (totalCount() > PAGE_SIZE) {\n <cauca-list-paginator\n #resultPaginator\n [itemsCount]=\"totalCount()\"\n [pageSize]=\"PAGE_SIZE\"\n (pageChange)=\"onPageChange($event)\" />\n }\n } @else if (!searchResource.isLoading() && totalCount() === 0 && debouncedSearch().length >= MIN_SEARCH_LENGTH) {\n <div class=\"no-results body2\">{{ 'noResult' | translate }}</div>\n }\n </div>\n</mat-dialog-content>\n\n<mat-dialog-actions class=\"dialog-actions\">\n <div class=\"selected-users-panel\">\n <span class=\"selected-users-label caption\">{{ 'groupEdition.selectedUsersLabel' | translate }}</span>\n <div class=\"selected-users-names body2\" [matTooltip]=\"selectedUsersLabel()\">{{ selectedUsersLabel() }}</div>\n </div>\n <cauca-stroked-button color=\"primary\" label=\"cancel\" (buttonClick)=\"cancel()\" />\n <cauca-raised-button\n color=\"primary\"\n label=\"ok\"\n [isDisabled]=\"selectedUsers().length === 0\"\n (buttonClick)=\"confirm()\" />\n</mat-dialog-actions>\n", styles: [".dialog-content{display:flex;flex-direction:column;gap:16px}[mat-dialog-title]{display:flex;align-items:center}[mat-dialog-title] div:first-child{flex:1}.search-field{margin-top:16px;width:100%;margin-bottom:8px}.search-hint,.no-results{padding:8px 0;color:#0000008a}.results-region{height:360px;overflow:hidden;display:flex;flex-direction:column}.results-list{flex:1 1 auto;min-height:0;overflow-y:auto;padding:0;max-height:400px;border:1px solid rgba(0,0,0,.23);border-radius:4px}.result-item{cursor:pointer}mat-list-option{margin-bottom:0}mat-list-option:nth-child(odd){background-color:#0000000d}mat-list-option:hover{transition:all ease-in-out .1s;background-color:#00000012}.dialog-actions{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.selected-users-panel{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.selected-users-label{color:#0000008a;font-weight:500}.selected-users-names{color:#000000de;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
600
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [UserSearchService, LoadingStateService], template: "<div mat-dialog-title>\r\n <div class=\"h6\">{{ 'groupEdition.userSelectionTitle' | translate }}</div>\r\n <cauca-icon-button id=\"closeButton\" (buttonClick)=\"closeClick()\" icon=\"close\" />\r\n</div>\r\n\r\n<mat-dialog-content class=\"dialog-content\">\r\n <mat-form-field subscriptSizing=\"dynamic\" class=\"search-field\">\r\n <mat-label>{{ 'groupEdition.searchUserPlaceholder' | translate }}</mat-label>\r\n <input matInput type=\"text\" [value]=\"searchTerm()\" (input)=\"searchTerm.set($any($event.target).value)\" />\r\n <mat-icon matSuffix>search</mat-icon>\r\n </mat-form-field>\r\n\r\n @if (searchTerm().length >= 0 && searchTerm().length < MIN_SEARCH_LENGTH) {\r\n <div class=\"search-hint body2\">{{ 'groupEdition.searchMinChars' | translate }}</div>\r\n }\r\n\r\n <div class=\"results-region\">\r\n <cauca-loading-error (retryRequest)=\"searchResource.reload()\" />\r\n\r\n @if (searchResource.isLoading() && !results().length) {\r\n <cauca-loading-spinner-indicator />\r\n } @else if (results().length) {\r\n <mat-selection-list class=\"results-list\" [compareWith]=\"compareUserById\" (selectionChange)=\"onSelectionChange($event)\">\r\n @for (user of results(); track user.id; let i = $index) {\r\n <mat-list-option\r\n [value]=\"user\"\r\n [selected]=\"selectedUserIds().has(user.id)\"\r\n color=\"primary\"\r\n class=\"result-item\"\r\n [class.result-item--even]=\"i % 2 === 1\">\r\n <span matListItemTitle>{{ user.fullName }}</span>\r\n @if (user.additionalInformation) {\r\n <span matListItemSubtitle>{{ user.additionalInformation }}</span>\r\n }\r\n </mat-list-option>\r\n }\r\n </mat-selection-list>\r\n\r\n @if (totalCount() > PAGE_SIZE) {\r\n <cauca-list-paginator\r\n #resultPaginator\r\n [itemsCount]=\"totalCount()\"\r\n [pageSize]=\"PAGE_SIZE\"\r\n (pageChange)=\"onPageChange($event)\" />\r\n }\r\n } @else if (!searchResource.isLoading() && totalCount() === 0 && debouncedSearch().length >= MIN_SEARCH_LENGTH) {\r\n <div class=\"no-results body2\">{{ 'noResult' | translate }}</div>\r\n }\r\n </div>\r\n</mat-dialog-content>\r\n\r\n<mat-dialog-actions class=\"dialog-actions\">\r\n <div class=\"selected-users-panel\">\r\n <span class=\"selected-users-label caption\">{{ 'groupEdition.selectedUsersLabel' | translate }}</span>\r\n <div class=\"selected-users-names body2\" [matTooltip]=\"selectedUsersLabel()\">{{ selectedUsersLabel() }}</div>\r\n </div>\r\n <cauca-stroked-button color=\"primary\" label=\"cancel\" (buttonClick)=\"cancel()\" />\r\n <cauca-raised-button\r\n color=\"primary\"\r\n label=\"ok\"\r\n [isDisabled]=\"selectedUsers().length === 0\"\r\n (buttonClick)=\"confirm()\" />\r\n</mat-dialog-actions>\r\n", styles: [".dialog-content{display:flex;flex-direction:column;gap:16px}[mat-dialog-title]{display:flex;align-items:center}[mat-dialog-title] div:first-child{flex:1}.search-field{margin-top:16px;width:100%;margin-bottom:8px}.search-hint,.no-results{padding:8px 0;color:#0000008a}.results-region{height:360px;overflow:hidden;display:flex;flex-direction:column}.results-list{flex:1 1 auto;min-height:0;overflow-y:auto;padding:0;max-height:400px;border:1px solid rgba(0,0,0,.23);border-radius:4px}.result-item{cursor:pointer}mat-list-option{margin-bottom:0}mat-list-option:nth-child(odd){background-color:#0000000d}mat-list-option:hover{transition:all ease-in-out .1s;background-color:#00000012}.dialog-actions{display:flex;align-items:flex-start;gap:8px;flex-wrap:wrap}.selected-users-panel{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.selected-users-label{color:#0000008a;font-weight:500}.selected-users-names{color:#000000de;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
605
601
  }], () => [], { paginator: [{ type: i0.ViewChild, args: ['resultPaginator', { isSignal: true }] }] }); })();
606
602
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GroupUserSelectionDialogComponent, { className: "GroupUserSelectionDialogComponent", filePath: "lib/components/group-user-selection-dialog/group-user-selection-dialog.component.ts", lineNumber: 46 }); })();
607
603
 
608
604
  const _c0$4 = ["paginator"];
609
- const _forTrack0$4 = ($index, $item) => $item.id;
605
+ const _forTrack0$3 = ($index, $item) => $item.id;
610
606
  function GroupUserEditionListComponent_For_10_Conditional_5_Template(rf, ctx) { if (rf & 1) {
611
607
  i0.ɵɵelementStart(0, "div", 11);
612
608
  i0.ɵɵtext(1);
@@ -756,7 +752,7 @@ class GroupUserEditionListComponent {
756
752
  i0.ɵɵtext(7, "search");
757
753
  i0.ɵɵelementEnd()();
758
754
  i0.ɵɵelementStart(8, "mat-list", 5);
759
- i0.ɵɵrepeaterCreate(9, GroupUserEditionListComponent_For_10_Template, 8, 5, "mat-list-item", 6, _forTrack0$4, false, GroupUserEditionListComponent_ForEmpty_11_Template, 2, 1);
755
+ i0.ɵɵrepeaterCreate(9, GroupUserEditionListComponent_For_10_Template, 8, 5, "mat-list-item", 6, _forTrack0$3, false, GroupUserEditionListComponent_ForEmpty_11_Template, 2, 1);
760
756
  i0.ɵɵelementEnd();
761
757
  i0.ɵɵconditionalCreate(12, GroupUserEditionListComponent_Conditional_12_Template, 2, 2, "cauca-list-paginator", 7);
762
758
  i0.ɵɵelementStart(13, "cauca-raised-button", 8);
@@ -775,7 +771,7 @@ class GroupUserEditionListComponent {
775
771
  }
776
772
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GroupUserEditionListComponent, [{
777
773
  type: Component,
778
- args: [{ selector: 'cauca-group-user-edition-list', standalone: true, imports: [TranslatePipe, IconButtonComponent, RaisedButtonComponent, ListPaginatorComponent, MatFormFieldModule, MatInputModule, MatIconModule, FormsModule, MatListModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], template: "<div class=\"user-edition-list\">\n\n <mat-form-field subscriptSizing=\"dynamic\" class=\"filter-field\">\n <mat-label>{{ 'groupEdition.filterUsersPlaceholder' | translate }}</mat-label>\n <input matInput type=\"text\" [value]=\"filterTerm()\" (input)=\"filterTerm.set($any($event.target).value)\" />\n <mat-icon matSuffix>search</mat-icon>\n </mat-form-field>\n\n <mat-list class=\"users-list\">\n @for (user of pagedUsers(); track user.id) {\n <mat-list-item class=\"user-item\">\n <mat-icon matListItemIcon>person</mat-icon>\n <div matListItemTitle class=\"user-name\">{{ user.fullName }}</div>\n @if (user.additionalInformation) {\n <div matListItemLine class=\"user-additional-information\">{{ user.additionalInformation }}</div>\n }\n <cauca-icon-button\n matListItemMeta\n class=\"delete-button\"\n icon=\"delete\"\n color=\"error\"\n (buttonClick)=\"removeUser(user)\"\n [attr.aria-label]=\"'groupEdition.removeUserLabel' | translate\" />\n </mat-list-item>\n } @empty {\n @if (filterTerm()) {\n <div class=\"no-users body2\">{{ 'groupEdition.noFilteredUsers' | translate }}</div>\n } @else {\n <div class=\"no-users body2\">{{ 'groupEdition.noUsers' | translate }}</div>\n }\n }\n </mat-list>\n\n @if (filteredUsers().length > PAGE_SIZE) {\n <cauca-list-paginator\n #paginator\n [itemsCount]=\"filteredUsers().length\"\n [pageSize]=\"PAGE_SIZE\"\n (pageChange)=\"onPageChange($event)\" />\n }\n\n <cauca-raised-button\n class=\"add-users-button\"\n color=\"primary\"\n label=\"groupEdition.addUsersButton\"\n (buttonClick)=\"openAddUsersDialog()\" />\n</div>\n", styles: [".user-edition-list{display:flex;flex-direction:column;gap:16px}.add-users-button{align-self:flex-end}.users-list{border:1px solid rgba(0,0,0,.23);border-radius:4px;padding:0;max-height:400px;overflow-y:auto}mat-list-item{margin-bottom:0}.filter-field{width:100%}.user-item{border-bottom:1px solid rgba(0,0,0,.12)}.user-item:last-child{border-bottom:none}.empty-state{display:flex;flex-direction:column;align-items:center;padding:32px 16px;text-align:center;color:#0009}.empty-state .empty-icon{font-size:48px;width:48px;height:48px;margin-bottom:16px;opacity:.6}.empty-state .empty-message{margin:0;font-size:14px}.add-button-container{display:flex;justify-content:flex-end;margin-top:16px}.no-users{padding:16px 0;color:#00000061;text-align:center}mat-list-item:nth-child(odd){background-color:#0000000d}mat-list-item:hover{transition:all ease-in-out .1s;background-color:#00000012}\n"] }]
774
+ args: [{ selector: 'cauca-group-user-edition-list', standalone: true, imports: [TranslatePipe, IconButtonComponent, RaisedButtonComponent, ListPaginatorComponent, MatFormFieldModule, MatInputModule, MatIconModule, FormsModule, MatListModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], template: "<div class=\"user-edition-list\">\r\n\r\n <mat-form-field subscriptSizing=\"dynamic\" class=\"filter-field\">\r\n <mat-label>{{ 'groupEdition.filterUsersPlaceholder' | translate }}</mat-label>\r\n <input matInput type=\"text\" [value]=\"filterTerm()\" (input)=\"filterTerm.set($any($event.target).value)\" />\r\n <mat-icon matSuffix>search</mat-icon>\r\n </mat-form-field>\r\n\r\n <mat-list class=\"users-list\">\r\n @for (user of pagedUsers(); track user.id) {\r\n <mat-list-item class=\"user-item\">\r\n <mat-icon matListItemIcon>person</mat-icon>\r\n <div matListItemTitle class=\"user-name\">{{ user.fullName }}</div>\r\n @if (user.additionalInformation) {\r\n <div matListItemLine class=\"user-additional-information\">{{ user.additionalInformation }}</div>\r\n }\r\n <cauca-icon-button\r\n matListItemMeta\r\n class=\"delete-button\"\r\n icon=\"delete\"\r\n color=\"error\"\r\n (buttonClick)=\"removeUser(user)\"\r\n [attr.aria-label]=\"'groupEdition.removeUserLabel' | translate\" />\r\n </mat-list-item>\r\n } @empty {\r\n @if (filterTerm()) {\r\n <div class=\"no-users body2\">{{ 'groupEdition.noFilteredUsers' | translate }}</div>\r\n } @else {\r\n <div class=\"no-users body2\">{{ 'groupEdition.noUsers' | translate }}</div>\r\n }\r\n }\r\n </mat-list>\r\n\r\n @if (filteredUsers().length > PAGE_SIZE) {\r\n <cauca-list-paginator\r\n #paginator\r\n [itemsCount]=\"filteredUsers().length\"\r\n [pageSize]=\"PAGE_SIZE\"\r\n (pageChange)=\"onPageChange($event)\" />\r\n }\r\n\r\n <cauca-raised-button\r\n class=\"add-users-button\"\r\n color=\"primary\"\r\n label=\"groupEdition.addUsersButton\"\r\n (buttonClick)=\"openAddUsersDialog()\" />\r\n</div>\r\n", styles: [".user-edition-list{display:flex;flex-direction:column;gap:16px}.add-users-button{align-self:flex-end}.users-list{border:1px solid rgba(0,0,0,.23);border-radius:4px;padding:0;max-height:400px;overflow-y:auto}mat-list-item{margin-bottom:0}.filter-field{width:100%}.user-item{border-bottom:1px solid rgba(0,0,0,.12)}.user-item:last-child{border-bottom:none}.empty-state{display:flex;flex-direction:column;align-items:center;padding:32px 16px;text-align:center;color:#0009}.empty-state .empty-icon{font-size:48px;width:48px;height:48px;margin-bottom:16px;opacity:.6}.empty-state .empty-message{margin:0;font-size:14px}.add-button-container{display:flex;justify-content:flex-end;margin-top:16px}.no-users{padding:16px 0;color:#00000061;text-align:center}mat-list-item:nth-child(odd){background-color:#0000000d}mat-list-item:hover{transition:all ease-in-out .1s;background-color:#00000012}\n"] }]
779
775
  }], () => [], { paginator: [{ type: i0.ViewChild, args: ['paginator', { isSignal: true }] }] }); })();
780
776
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GroupUserEditionListComponent, { className: "GroupUserEditionListComponent", filePath: "lib/components/group-user-edition-list/group-user-edition-list.component.ts", lineNumber: 24 }); })();
781
777
 
@@ -829,7 +825,7 @@ class PermissionManagementService {
829
825
  }]
830
826
  }], null, null); })();
831
827
 
832
- const _forTrack0$3 = ($index, $item) => $item.id;
828
+ const _forTrack0$2 = ($index, $item) => $item.id;
833
829
  function GroupPermissionListComponent_For_9_Template(rf, ctx) { if (rf & 1) {
834
830
  const _r1 = i0.ɵɵgetCurrentView();
835
831
  i0.ɵɵelementStart(0, "mat-list-item", 4)(1, "mat-checkbox", 6);
@@ -914,7 +910,7 @@ class GroupPermissionListComponent {
914
910
  i0.ɵɵtext(6, "search");
915
911
  i0.ɵɵelementEnd()();
916
912
  i0.ɵɵelementStart(7, "mat-selection-list", 3);
917
- i0.ɵɵrepeaterCreate(8, GroupPermissionListComponent_For_9_Template, 3, 4, "mat-list-item", 4, _forTrack0$3, false, GroupPermissionListComponent_ForEmpty_10_Template, 6, 3, "div", 5);
913
+ i0.ɵɵrepeaterCreate(8, GroupPermissionListComponent_For_9_Template, 3, 4, "mat-list-item", 4, _forTrack0$2, false, GroupPermissionListComponent_ForEmpty_10_Template, 6, 3, "div", 5);
918
914
  i0.ɵɵelementEnd();
919
915
  } if (rf & 2) {
920
916
  i0.ɵɵadvance(2);
@@ -928,7 +924,7 @@ class GroupPermissionListComponent {
928
924
  }
929
925
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GroupPermissionListComponent, [{
930
926
  type: Component,
931
- args: [{ selector: 'cauca-group-permission-list', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatListModule, MatFormField, MatLabel, MatInput, MatSuffix, TranslatePipe, FormsModule, MatIcon, MatCheckboxModule], template: "<mat-form-field subscriptSizing=\"dynamic\" appearance=\"outline\" class=\"full-width-field grid-search-box\">\n <mat-label>{{ 'dataGrid.keywordsLabel' | translate }}</mat-label>\n <input matInput [(ngModel)]=\"searchText\">\n <mat-icon matSuffix>search</mat-icon>\n</mat-form-field>\n\n<mat-selection-list id=\"permission-list\">\n @for (permission of filteredPermissionsValues(); track permission.id) {\n <mat-list-item class=\"permission-item\">\n <mat-checkbox\n [color]=\"permission.allowed === null ? undefined : 'primary'\"\n [indeterminate]=\"permission.allowed === null\"\n [checked]=\"permission.allowed\"\n (click)=\"onValueChange(permission)\" >\n {{permission.name}}\n </mat-checkbox>\n </mat-list-item>\n } @empty {\n <div class=\"no-result\">\n <mat-icon class=\"no-result-icon\">grid_off</mat-icon>\n <div class=\"no-result-text body2\">{{ 'noResult' | translate }}</div>\n </div>\n }\n\n</mat-selection-list>\n", styles: [":host{display:flex;flex-direction:column;gap:16px}#permission-list{max-height:400px;overflow-y:auto;border:1px solid rgba(0,0,0,.23);border-radius:4px;padding:0}.permission-item{border-bottom:1px solid rgba(0,0,0,.12)}.permission-item:last-child{border-bottom:none}mat-list-item{margin-bottom:0}.permission-checkbox,.filter-field{width:100%}.no-result{display:flex;flex-direction:column;align-items:center;padding:24px 0;color:#00000061}.no-result-icon{font-size:48px;width:48px;height:48px;margin-bottom:8px}.no-result-text{text-align:center}mat-list-item:nth-child(odd){background-color:#0000000d}mat-list-item:hover{transition:all ease-in-out .1s;background-color:#00000012}\n"] }]
927
+ args: [{ selector: 'cauca-group-permission-list', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatListModule, MatFormField, MatLabel, MatInput, MatSuffix, TranslatePipe, FormsModule, MatIcon, MatCheckboxModule], template: "<mat-form-field subscriptSizing=\"dynamic\" appearance=\"outline\" class=\"full-width-field grid-search-box\">\r\n <mat-label>{{ 'dataGrid.keywordsLabel' | translate }}</mat-label>\r\n <input matInput [(ngModel)]=\"searchText\">\r\n <mat-icon matSuffix>search</mat-icon>\r\n</mat-form-field>\r\n\r\n<mat-selection-list id=\"permission-list\">\r\n @for (permission of filteredPermissionsValues(); track permission.id) {\r\n <mat-list-item class=\"permission-item\">\r\n <mat-checkbox\r\n [color]=\"permission.allowed === null ? undefined : 'primary'\"\r\n [indeterminate]=\"permission.allowed === null\"\r\n [checked]=\"permission.allowed\"\r\n (click)=\"onValueChange(permission)\" >\r\n {{permission.name}}\r\n </mat-checkbox>\r\n </mat-list-item>\r\n } @empty {\r\n <div class=\"no-result\">\r\n <mat-icon class=\"no-result-icon\">grid_off</mat-icon>\r\n <div class=\"no-result-text body2\">{{ 'noResult' | translate }}</div>\r\n </div>\r\n }\r\n\r\n</mat-selection-list>\r\n", styles: [":host{display:flex;flex-direction:column;gap:16px}#permission-list{max-height:400px;overflow-y:auto;border:1px solid rgba(0,0,0,.23);border-radius:4px;padding:0}.permission-item{border-bottom:1px solid rgba(0,0,0,.12)}.permission-item:last-child{border-bottom:none}mat-list-item{margin-bottom:0}.permission-checkbox,.filter-field{width:100%}.no-result{display:flex;flex-direction:column;align-items:center;padding:24px 0;color:#00000061}.no-result-icon{font-size:48px;width:48px;height:48px;margin-bottom:8px}.no-result-text{text-align:center}mat-list-item:nth-child(odd){background-color:#0000000d}mat-list-item:hover{transition:all ease-in-out .1s;background-color:#00000012}\n"] }]
932
928
  }], null, { searchText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchText", required: false }] }, { type: i0.Output, args: ["searchTextChange"] }] }); })();
933
929
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GroupPermissionListComponent, { className: "GroupPermissionListComponent", filePath: "lib/components/group-permission-list/group-permission-list.component.ts", lineNumber: 23 }); })();
934
930
 
@@ -985,7 +981,7 @@ class GroupEditionFormComponent {
985
981
  }
986
982
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GroupEditionFormComponent, [{
987
983
  type: Component,
988
- args: [{ selector: 'cauca-group-edition-form', changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, MatFormFieldModule, MatInputModule, MatSlideToggleModule, MatDividerModule, ReactiveFormsModule, GroupContainerComponent, GroupUserEditionListComponent, GroupPermissionListComponent], template: "<div [formGroup]=\"state.form\">\n\n <cauca-group-container id=\"group-options\" caption=\"groupEdition.groupNameFieldLabel\">\n <mat-form-field id=\"group-name\">\n <mat-label>{{ 'groupEdition.nameFieldLabel' | translate }}</mat-label>\n <input matInput type=\"text\" formControlName=\"name\" required>\n @if (state.form.get(\"name\").hasError('required')) {<mat-error>{{'error.requiredField' | translate}}</mat-error>}\n </mat-form-field>\n <mat-slide-toggle id=\"assignable-by-all-users\" formControlName=\"assignableByAllUsers\" color=\"primary\">{{'groupEdition.assignableByAllUsersLabel' | translate}}</mat-slide-toggle>\n </cauca-group-container>\n\n <mat-divider />\n\n <cauca-group-container id=\"group-users\" caption=\"groupEdition.groupUsersFieldLabel\">\n <cauca-group-user-edition-list />\n </cauca-group-container>\n\n <mat-divider />\n\n <cauca-group-container id=\"group-permissions\" caption=\"groupEdition.groupPermissionsFieldLabel\">\n <cauca-group-permission-list />\n </cauca-group-container>\n\n</div>\n", styles: [".form{display:flex;flex-direction:column;gap:16px}.row{display:flex;align-items:stretch;gap:16px}.row>*{flex:1}\n"] }]
984
+ args: [{ selector: 'cauca-group-edition-form', changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, MatFormFieldModule, MatInputModule, MatSlideToggleModule, MatDividerModule, ReactiveFormsModule, GroupContainerComponent, GroupUserEditionListComponent, GroupPermissionListComponent], template: "<div [formGroup]=\"state.form\">\r\n\r\n <cauca-group-container id=\"group-options\" caption=\"groupEdition.groupNameFieldLabel\">\r\n <mat-form-field id=\"group-name\">\r\n <mat-label>{{ 'groupEdition.nameFieldLabel' | translate }}</mat-label>\r\n <input matInput type=\"text\" formControlName=\"name\" required>\r\n @if (state.form.get(\"name\").hasError('required')) {<mat-error>{{'error.requiredField' | translate}}</mat-error>}\r\n </mat-form-field>\r\n <mat-slide-toggle id=\"assignable-by-all-users\" formControlName=\"assignableByAllUsers\" color=\"primary\">{{'groupEdition.assignableByAllUsersLabel' | translate}}</mat-slide-toggle>\r\n </cauca-group-container>\r\n\r\n <mat-divider />\r\n\r\n <cauca-group-container id=\"group-users\" caption=\"groupEdition.groupUsersFieldLabel\">\r\n <cauca-group-user-edition-list />\r\n </cauca-group-container>\r\n\r\n <mat-divider />\r\n\r\n <cauca-group-container id=\"group-permissions\" caption=\"groupEdition.groupPermissionsFieldLabel\">\r\n <cauca-group-permission-list />\r\n </cauca-group-container>\r\n\r\n</div>\r\n", styles: [".form{display:flex;flex-direction:column;gap:16px}.row{display:flex;align-items:stretch;gap:16px}.row>*{flex:1}\n"] }]
989
985
  }], null, null); })();
990
986
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GroupEditionFormComponent, { className: "GroupEditionFormComponent", filePath: "lib/components/group-edition-form/group-edition-form.component.ts", lineNumber: 20 }); })();
991
987
 
@@ -1141,7 +1137,7 @@ class GroupEditionPageComponent {
1141
1137
  GroupEditionStateService,
1142
1138
  LoadingStateService,
1143
1139
  GroupManagementService,
1144
- ], template: "<cauca-page-title\n [caption]=\"title()\"\n baseCrumb=\"menu.management\"\n [breadcrumb]=\"title()\"\n [location]=\"currentLocation()\"\n [showBreadcrumb]=\"true\" />\n\n<mat-card>\n\n <mat-card-content>\n\n <cauca-loading-spinner-indicator />\n <cauca-loading-error (retryRequest)=\"loadData()\" />\n\n @if (isLoaded()) {\n <cauca-group-edition-form />\n }\n\n @if (showSavingError()) {\n <div class=\"spacer\"></div>\n <cauca-saving-error-box [show]=\"showSavingError()\" />\n }\n\n </mat-card-content>\n\n <mat-card-actions>\n <div class=\"spacer\"></div>\n <cauca-stroked-button class=\"cancel-button\" color=\"primary\" label=\"cancel\" [isDisabled]=\"isSaving()\" (buttonClick)=\"cancel()\" />\n <cauca-raised-button class=\"save-button\" color=\"primary\" label=\"save\" [isInProgress]=\"isSaving()\" (buttonClick)=\"save()\" />\n </mat-card-actions>\n\n</mat-card>\n", styles: [":host{width:100%}.spacer{flex:1 1 auto}mat-card-actions{gap:8px}\n"] }]
1140
+ ], template: "<cauca-page-title\r\n [caption]=\"title()\"\r\n baseCrumb=\"menu.management\"\r\n [breadcrumb]=\"title()\"\r\n [location]=\"currentLocation()\"\r\n [showBreadcrumb]=\"true\" />\r\n\r\n<mat-card>\r\n\r\n <mat-card-content>\r\n\r\n <cauca-loading-spinner-indicator />\r\n <cauca-loading-error (retryRequest)=\"loadData()\" />\r\n\r\n @if (isLoaded()) {\r\n <cauca-group-edition-form />\r\n }\r\n\r\n @if (showSavingError()) {\r\n <div class=\"spacer\"></div>\r\n <cauca-saving-error-box [show]=\"showSavingError()\" />\r\n }\r\n\r\n </mat-card-content>\r\n\r\n <mat-card-actions>\r\n <div class=\"spacer\"></div>\r\n <cauca-stroked-button class=\"cancel-button\" color=\"primary\" label=\"cancel\" [isDisabled]=\"isSaving()\" (buttonClick)=\"cancel()\" />\r\n <cauca-raised-button class=\"save-button\" color=\"primary\" label=\"save\" [isInProgress]=\"isSaving()\" (buttonClick)=\"save()\" />\r\n </mat-card-actions>\r\n\r\n</mat-card>\r\n", styles: [":host{width:100%}.spacer{flex:1 1 auto}mat-card-actions{gap:8px}\n"] }]
1145
1141
  }], null, { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], onBeforeUnload: [{
1146
1142
  type: HostListener,
1147
1143
  args: ['window:beforeunload', ['$event']]
@@ -1196,7 +1192,7 @@ var UserPermissionOriginKind;
1196
1192
  UserPermissionOriginKind[UserPermissionOriginKind["UserOverride"] = 1] = "UserOverride";
1197
1193
  })(UserPermissionOriginKind || (UserPermissionOriginKind = {}));
1198
1194
 
1199
- const _forTrack0$2 = ($index, $item) => $item.idModulePermission;
1195
+ const _forTrack0$1 = ($index, $item) => $item.idModulePermission;
1200
1196
  function UserPermissionListComponent_For_9_Conditional_2_Template(rf, ctx) { if (rf & 1) {
1201
1197
  i0.ɵɵtext(0, " check ");
1202
1198
  } }
@@ -1306,7 +1302,7 @@ class UserPermissionListComponent {
1306
1302
  i0.ɵɵtext(6, "search");
1307
1303
  i0.ɵɵelementEnd()();
1308
1304
  i0.ɵɵelementStart(7, "mat-list", 4);
1309
- i0.ɵɵrepeaterCreate(8, UserPermissionListComponent_For_9_Template, 16, 11, "mat-list-item", 5, _forTrack0$2, false, UserPermissionListComponent_ForEmpty_10_Template, 6, 3, "div", 6);
1305
+ i0.ɵɵrepeaterCreate(8, UserPermissionListComponent_For_9_Template, 16, 11, "mat-list-item", 5, _forTrack0$1, false, UserPermissionListComponent_ForEmpty_10_Template, 6, 3, "div", 6);
1310
1306
  i0.ɵɵelementEnd();
1311
1307
  } if (rf & 2) {
1312
1308
  i0.ɵɵadvance(2);
@@ -1319,7 +1315,7 @@ class UserPermissionListComponent {
1319
1315
  }
1320
1316
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserPermissionListComponent, [{
1321
1317
  type: Component,
1322
- args: [{ selector: 'cauca-user-permission-list', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatListModule, MatFormField, MatLabel, MatInput, MatSuffix, MatIcon, MatMenuModule, TranslatePipe, IconButtonComponent], template: "<mat-form-field subscriptSizing=\"dynamic\" appearance=\"outline\" class=\"search-field\">\n <mat-label>{{ 'dataGrid.keywordsLabel' | translate }}</mat-label>\n <input matInput type=\"text\" [value]=\"searchText()\" (input)=\"searchText.set($any($event.target).value)\">\n <mat-icon matSuffix>search</mat-icon>\n</mat-form-field>\n\n<mat-list id=\"permission-list\">\n @for (permission of filteredPermissions(); track permission.idModulePermission) {\n <mat-list-item class=\"permission-item\">\n\n <mat-icon matListItemIcon\n [class.allowed]=\"permission.status === PermissionStatus.Allowed\"\n [class.denied]=\"permission.status !== PermissionStatus.Allowed\">\n @if (permission.status === PermissionStatus.Allowed) {\n check\n } @else {\n block\n }\n </mat-icon>\n\n <div matListItemTitle>{{ permission.name }}</div>\n\n <cauca-icon-button\n matListItemMeta\n icon=\"info\"\n [matMenuTriggerFor]=\"originsMenu\" />\n\n <mat-menu #originsMenu=\"matMenu\">\n <div class=\"origins-menu-content\" (click)=\"$event.stopPropagation()\">\n <div class=\"origin-item body2\">{{ 'userPermissionDetails.originsLabel' | translate }}</div>\n @for (origin of permission.origins; track $index) {\n <div class=\"origin-item\">\n <mat-icon [class.allowed]=\"origin.isAllowed\" [class.denied]=\"!origin.isAllowed\">\n @if (origin.isAllowed) {\n check\n } @else {\n block\n }\n </mat-icon>\n <span class=\"origin-name body1\">\n {{ origin.kind === UserPermissionOriginKind.UserOverride\n ? ('userPermissionDetails.userOverrideOrigin' | translate)\n : origin.groupName }}\n </span>\n </div>\n } @empty {\n <div class=\"origin-item\">\n <span class=\"no-origins\">{{ 'userPermissionDetails.noOrigins' | translate }}</span>\n </div>\n }\n </div>\n </mat-menu>\n\n </mat-list-item>\n } @empty {\n <div class=\"no-result\">\n <mat-icon class=\"no-result-icon\">grid_off</mat-icon>\n <div class=\"no-result-text body2\">{{ 'noResult' | translate }}</div>\n </div>\n }\n</mat-list>\n", styles: [":host{display:flex;flex-direction:column;gap:16px}.search-field{width:100%}#permission-list{max-height:400px;overflow-y:auto;border:1px solid rgba(0,0,0,.23);border-radius:4px;padding:0}.permission-item{border-bottom:1px solid rgba(0,0,0,.12)}.permission-item:last-child{border-bottom:none}mat-list-item{margin-bottom:0}mat-list-item:nth-child(odd){background-color:#0000000d}mat-list-item:hover{transition:all ease-in-out .1s;background-color:#00000012}.mat-icon.allowed{color:var(--color-success, green)}.mat-icon.denied{color:var(--color-error, red)}.origins-menu-content{padding:8px;max-width:320px}.origin-item{display:flex;align-items:flex-start;gap:8px;padding:8px}.origin-item .mat-icon{flex-shrink:0}.origin-name{min-width:0;overflow-wrap:anywhere}.no-result{display:flex;flex-direction:column;align-items:center;padding:24px 0;color:#00000061}.no-result-icon{font-size:48px;width:48px;height:48px;margin-bottom:8px}.no-result-text{text-align:center}\n"] }]
1318
+ args: [{ selector: 'cauca-user-permission-list', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatListModule, MatFormField, MatLabel, MatInput, MatSuffix, MatIcon, MatMenuModule, TranslatePipe, IconButtonComponent], template: "<mat-form-field subscriptSizing=\"dynamic\" appearance=\"outline\" class=\"search-field\">\r\n <mat-label>{{ 'dataGrid.keywordsLabel' | translate }}</mat-label>\r\n <input matInput type=\"text\" [value]=\"searchText()\" (input)=\"searchText.set($any($event.target).value)\">\r\n <mat-icon matSuffix>search</mat-icon>\r\n</mat-form-field>\r\n\r\n<mat-list id=\"permission-list\">\r\n @for (permission of filteredPermissions(); track permission.idModulePermission) {\r\n <mat-list-item class=\"permission-item\">\r\n\r\n <mat-icon matListItemIcon\r\n [class.allowed]=\"permission.status === PermissionStatus.Allowed\"\r\n [class.denied]=\"permission.status !== PermissionStatus.Allowed\">\r\n @if (permission.status === PermissionStatus.Allowed) {\r\n check\r\n } @else {\r\n block\r\n }\r\n </mat-icon>\r\n\r\n <div matListItemTitle>{{ permission.name }}</div>\r\n\r\n <cauca-icon-button\r\n matListItemMeta\r\n icon=\"info\"\r\n [matMenuTriggerFor]=\"originsMenu\" />\r\n\r\n <mat-menu #originsMenu=\"matMenu\">\r\n <div class=\"origins-menu-content\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"origin-item body2\">{{ 'userPermissionDetails.originsLabel' | translate }}</div>\r\n @for (origin of permission.origins; track $index) {\r\n <div class=\"origin-item\">\r\n <mat-icon [class.allowed]=\"origin.isAllowed\" [class.denied]=\"!origin.isAllowed\">\r\n @if (origin.isAllowed) {\r\n check\r\n } @else {\r\n block\r\n }\r\n </mat-icon>\r\n <span class=\"origin-name body1\">\r\n {{ origin.kind === UserPermissionOriginKind.UserOverride\r\n ? ('userPermissionDetails.userOverrideOrigin' | translate)\r\n : origin.groupName }}\r\n </span>\r\n </div>\r\n } @empty {\r\n <div class=\"origin-item\">\r\n <span class=\"no-origins\">{{ 'userPermissionDetails.noOrigins' | translate }}</span>\r\n </div>\r\n }\r\n </div>\r\n </mat-menu>\r\n\r\n </mat-list-item>\r\n } @empty {\r\n <div class=\"no-result\">\r\n <mat-icon class=\"no-result-icon\">grid_off</mat-icon>\r\n <div class=\"no-result-text body2\">{{ 'noResult' | translate }}</div>\r\n </div>\r\n }\r\n</mat-list>\r\n", styles: [":host{display:flex;flex-direction:column;gap:16px}.search-field{width:100%}#permission-list{max-height:400px;overflow-y:auto;border:1px solid rgba(0,0,0,.23);border-radius:4px;padding:0}.permission-item{border-bottom:1px solid rgba(0,0,0,.12)}.permission-item:last-child{border-bottom:none}mat-list-item{margin-bottom:0}mat-list-item:nth-child(odd){background-color:#0000000d}mat-list-item:hover{transition:all ease-in-out .1s;background-color:#00000012}.mat-icon.allowed{color:var(--color-success, green)}.mat-icon.denied{color:var(--color-error, red)}.origins-menu-content{padding:8px;max-width:320px}.origin-item{display:flex;align-items:flex-start;gap:8px;padding:8px}.origin-item .mat-icon{flex-shrink:0}.origin-name{min-width:0;overflow-wrap:anywhere}.no-result{display:flex;flex-direction:column;align-items:center;padding:24px 0;color:#00000061}.no-result-icon{font-size:48px;width:48px;height:48px;margin-bottom:8px}.no-result-text{text-align:center}\n"] }]
1323
1319
  }], null, { permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: true }] }] }); })();
1324
1320
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserPermissionListComponent, { className: "UserPermissionListComponent", filePath: "lib/components/user-permission-list/user-permission-list.component.ts", lineNumber: 20 }); })();
1325
1321
 
@@ -1387,7 +1383,7 @@ class UserPermissionsDialogComponent {
1387
1383
  LoadingErrorComponent,
1388
1384
  RaisedButtonComponent,
1389
1385
  UserPermissionListComponent,
1390
- ], providers: [LoadingStateService], template: "<div mat-dialog-title>\n <div class=\"title-block\">\n <div class=\"h6\">{{ 'userPermissionDetails.title' | translate }}</div>\n @if (data.userDisplayName) {\n <div class=\"subtitle body2\">{{ data.userDisplayName }}</div>\n }\n </div>\n</div>\n\n<mat-dialog-content class=\"dialog-content\">\n <cauca-loading-spinner-indicator />\n <cauca-loading-error (retryRequest)=\"permissionsResource.reload()\" />\n\n <cauca-user-permission-list [permissions]=\"permissions()\" />\n</mat-dialog-content>\n\n<mat-dialog-actions align=\"end\">\n <cauca-raised-button color=\"primary\" label=\"close\" (buttonClick)=\"closeDialog()\" />\n</mat-dialog-actions>\n", styles: [".title-block{display:flex;flex-direction:column}.subtitle{color:#0000008a}.dialog-content{display:flex;flex-direction:column;gap:16px;min-width:480px}\n"] }]
1386
+ ], providers: [LoadingStateService], template: "<div mat-dialog-title>\r\n <div class=\"title-block\">\r\n <div class=\"h6\">{{ 'userPermissionDetails.title' | translate }}</div>\r\n @if (data.userDisplayName) {\r\n <div class=\"subtitle body2\">{{ data.userDisplayName }}</div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<mat-dialog-content class=\"dialog-content\">\r\n <cauca-loading-spinner-indicator />\r\n <cauca-loading-error (retryRequest)=\"permissionsResource.reload()\" />\r\n\r\n <cauca-user-permission-list [permissions]=\"permissions()\" />\r\n</mat-dialog-content>\r\n\r\n<mat-dialog-actions align=\"end\">\r\n <cauca-raised-button color=\"primary\" label=\"close\" (buttonClick)=\"closeDialog()\" />\r\n</mat-dialog-actions>\r\n", styles: [".title-block{display:flex;flex-direction:column}.subtitle{color:#0000008a}.dialog-content{display:flex;flex-direction:column;gap:16px;min-width:480px}\n"] }]
1391
1387
  }], null, null); })();
1392
1388
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserPermissionsDialogComponent, { className: "UserPermissionsDialogComponent", filePath: "lib/components/user-permissions-dialog/user-permissions-dialog.component.ts", lineNumber: 31 }); })();
1393
1389
 
@@ -1480,12 +1476,12 @@ class ScopeListGridColumnComponent extends BaseGridColumnComponent {
1480
1476
  args: [{ selector: 'cauca-scope-list-grid-column', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: BaseGridColumnComponent, useExisting: forwardRef(() => ScopeListGridColumnComponent) }], imports: [
1481
1477
  MatColumnDef, MatHeaderCell, MatHeaderCellDef, MatCell, MatCellDef, MatFooterCell, MatFooterCellDef,
1482
1478
  NgStyle, MatTooltip, TranslatePipe,
1483
- ], template: "<ng-container matColumnDef=\"{{ prop() }}\">\n\n <th mat-header-cell *matHeaderCellDef [ngStyle]=\"{'width': width()}\">\n {{ label() ?? capitalize(prop()) }}\n </th>\n\n <td mat-cell *matCellDef=\"let row\">\n @if (row[prop()] === allToken) {\n <span>{{ allLabel() | translate }}</span>\n } @else if (showToolTip()) {\n <span [matTooltip]=\"row[prop()]\">{{ row[prop()] }}</span>\n } @else {\n <span>{{ row[prop()] }}</span>\n }\n </td>\n\n <td mat-footer-cell *matFooterCellDef></td>\n\n</ng-container>\n" }]
1479
+ ], template: "<ng-container matColumnDef=\"{{ prop() }}\">\r\n\r\n <th mat-header-cell *matHeaderCellDef [ngStyle]=\"{'width': width()}\">\r\n {{ label() ?? capitalize(prop()) }}\r\n </th>\r\n\r\n <td mat-cell *matCellDef=\"let row\">\r\n @if (row[prop()] === allToken) {\r\n <span>{{ allLabel() | translate }}</span>\r\n } @else if (showToolTip()) {\r\n <span [matTooltip]=\"row[prop()]\">{{ row[prop()] }}</span>\r\n } @else {\r\n <span>{{ row[prop()] }}</span>\r\n }\r\n </td>\r\n\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n\r\n</ng-container>\r\n" }]
1484
1480
  }], () => [], { allLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "allLabel", required: true }] }] }); })();
1485
1481
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ScopeListGridColumnComponent, { className: "ScopeListGridColumnComponent", filePath: "lib/components/scope-list-grid-column/scope-list-grid-column.component.ts", lineNumber: 28 }); })();
1486
1482
 
1487
1483
  const _c0$2 = () => ["userName"];
1488
- const _forTrack0$1 = ($index, $item) => $item.prop;
1484
+ const _forTrack0 = ($index, $item) => $item.prop;
1489
1485
  function UserListGridComponent_For_9_Case_0_Template(rf, ctx) { if (rf & 1) {
1490
1486
  i0.ɵɵelement(0, "cauca-scope-list-grid-column", 6);
1491
1487
  i0.ɵɵpipe(1, "translate");
@@ -1623,7 +1619,7 @@ class UserListGridComponent {
1623
1619
  i0.ɵɵpipe(5, "translate");
1624
1620
  i0.ɵɵelement(6, "cauca-sortable-data-grid-column", 4);
1625
1621
  i0.ɵɵpipe(7, "translate");
1626
- i0.ɵɵrepeaterCreate(8, UserListGridComponent_For_9_Template, 3, 1, null, null, _forTrack0$1);
1622
+ i0.ɵɵrepeaterCreate(8, UserListGridComponent_For_9_Template, 3, 1, null, null, _forTrack0);
1627
1623
  i0.ɵɵconditionalCreate(10, UserListGridComponent_Conditional_10_Template, 3, 3, "cauca-data-grid-menu-column", 5);
1628
1624
  i0.ɵɵelementEnd();
1629
1625
  } if (rf & 2) {
@@ -1646,7 +1642,7 @@ class UserListGridComponent {
1646
1642
  args: [{ selector: 'cauca-user-list-grid', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1647
1643
  MatSort, OdataGridComponent, SortableDataGridColumnComponent, SortableDataGridCheckColumnComponent,
1648
1644
  ScopeListGridColumnComponent, DataGridMenuColumnComponent, MenuItemComponent, TranslatePipe,
1649
- ], template: "<cauca-odata-grid\n matSort\n matSortActive=\"userName\"\n matSortDirection=\"asc\"\n aria-label=\"Users table\"\n resourceName=\"UserList\"\n [persistState]=\"persistState()\"\n [showTableOptions]=\"true\"\n [showRefreshButton]=\"true\"\n [showAddButton]=\"showAddButton()\"\n [addButtonLabel]=\"addButtonLabel() | translate\"\n (addButtonClick)=\"addClick.emit()\"\n [baseSort]=\"['userName']\"\n [filterPredicate]=\"filterPredicate\"\n [displayedColumns]=\"columns()\">\n\n <cauca-sortable-data-grid-column id=\"userName\" prop=\"userName\" [showToolTip]=\"true\"\n [label]=\"'userList.column.userName' | translate\"/>\n <cauca-sortable-data-grid-column id=\"firstName\" prop=\"firstName\" [showToolTip]=\"true\"\n [label]=\"'userList.column.firstName' | translate\"/>\n <cauca-sortable-data-grid-column id=\"lastName\" prop=\"lastName\" [showToolTip]=\"true\"\n [label]=\"'userList.column.lastName' | translate\"/>\n\n @for (column of extraColumns(); track column.prop) {\n @switch (column.kind) {\n @case ('scope') {\n <cauca-scope-list-grid-column [id]=\"column.prop\" [prop]=\"column.prop\"\n [width]=\"column.width ?? ''\"\n [showToolTip]=\"column.showToolTip ?? true\"\n [allLabel]=\"column.allLabel ?? ''\"\n [visibleByDefault]=\"column.visibleByDefault ?? true\"\n [label]=\"column.label | translate\"/>\n }\n @case ('check') {\n <cauca-sortable-data-grid-check-column [id]=\"column.prop\" [prop]=\"column.prop\"\n [width]=\"column.width ?? ''\"\n [visibleByDefault]=\"column.visibleByDefault ?? true\"\n [label]=\"column.label | translate\"/>\n }\n @default {\n <cauca-sortable-data-grid-column [id]=\"column.prop\" [prop]=\"column.prop\"\n [width]=\"column.width ?? ''\"\n [showToolTip]=\"column.showToolTip ?? true\"\n [visibleByDefault]=\"column.visibleByDefault ?? true\"\n [label]=\"column.label | translate\"/>\n }\n }\n }\n\n @if (hasRowActions()) {\n <cauca-data-grid-menu-column id=\"buttons\" prop=\"menu\"\n [canEdit]=\"canEdit()\"\n [canDelete]=\"canDelete()\"\n [editLinkField]=\"editLinkField()\"\n (deleteClick)=\"onDelete($event)\">\n <ng-template #menuTemplate let-row=\"row\">\n @if (showPermissions()) {\n <cauca-menu-item icon=\"list\" label=\"userList.viewPermissions\" [translateLabel]=\"true\"\n (buttonClick)=\"openPermissions(row)\"/>\n }\n </ng-template>\n </cauca-data-grid-menu-column>\n }\n\n</cauca-odata-grid>\n" }]
1645
+ ], template: "<cauca-odata-grid\r\n matSort\r\n matSortActive=\"userName\"\r\n matSortDirection=\"asc\"\r\n aria-label=\"Users table\"\r\n resourceName=\"UserList\"\r\n [persistState]=\"persistState()\"\r\n [showTableOptions]=\"true\"\r\n [showRefreshButton]=\"true\"\r\n [showAddButton]=\"showAddButton()\"\r\n [addButtonLabel]=\"addButtonLabel() | translate\"\r\n (addButtonClick)=\"addClick.emit()\"\r\n [baseSort]=\"['userName']\"\r\n [filterPredicate]=\"filterPredicate\"\r\n [displayedColumns]=\"columns()\">\r\n\r\n <cauca-sortable-data-grid-column id=\"userName\" prop=\"userName\" [showToolTip]=\"true\"\r\n [label]=\"'userList.column.userName' | translate\"/>\r\n <cauca-sortable-data-grid-column id=\"firstName\" prop=\"firstName\" [showToolTip]=\"true\"\r\n [label]=\"'userList.column.firstName' | translate\"/>\r\n <cauca-sortable-data-grid-column id=\"lastName\" prop=\"lastName\" [showToolTip]=\"true\"\r\n [label]=\"'userList.column.lastName' | translate\"/>\r\n\r\n @for (column of extraColumns(); track column.prop) {\r\n @switch (column.kind) {\r\n @case ('scope') {\r\n <cauca-scope-list-grid-column [id]=\"column.prop\" [prop]=\"column.prop\"\r\n [width]=\"column.width ?? ''\"\r\n [showToolTip]=\"column.showToolTip ?? true\"\r\n [allLabel]=\"column.allLabel ?? ''\"\r\n [visibleByDefault]=\"column.visibleByDefault ?? true\"\r\n [label]=\"column.label | translate\"/>\r\n }\r\n @case ('check') {\r\n <cauca-sortable-data-grid-check-column [id]=\"column.prop\" [prop]=\"column.prop\"\r\n [width]=\"column.width ?? ''\"\r\n [visibleByDefault]=\"column.visibleByDefault ?? true\"\r\n [label]=\"column.label | translate\"/>\r\n }\r\n @default {\r\n <cauca-sortable-data-grid-column [id]=\"column.prop\" [prop]=\"column.prop\"\r\n [width]=\"column.width ?? ''\"\r\n [showToolTip]=\"column.showToolTip ?? true\"\r\n [visibleByDefault]=\"column.visibleByDefault ?? true\"\r\n [label]=\"column.label | translate\"/>\r\n }\r\n }\r\n }\r\n\r\n @if (hasRowActions()) {\r\n <cauca-data-grid-menu-column id=\"buttons\" prop=\"menu\"\r\n [canEdit]=\"canEdit()\"\r\n [canDelete]=\"canDelete()\"\r\n [editLinkField]=\"editLinkField()\"\r\n (deleteClick)=\"onDelete($event)\">\r\n <ng-template #menuTemplate let-row=\"row\">\r\n @if (showPermissions()) {\r\n <cauca-menu-item icon=\"list\" label=\"userList.viewPermissions\" [translateLabel]=\"true\"\r\n (buttonClick)=\"openPermissions(row)\"/>\r\n }\r\n </ng-template>\r\n </cauca-data-grid-menu-column>\r\n }\r\n\r\n</cauca-odata-grid>\r\n" }]
1650
1646
  }], null, { extraColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraColumns", required: false }] }], showAddButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAddButton", required: false }] }], addButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addButtonLabel", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], canDelete: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDelete", required: false }] }], editLinkField: [{ type: i0.Input, args: [{ isSignal: true, alias: "editLinkField", required: false }] }], showPermissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPermissions", required: false }] }], persistState: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistState", required: false }] }], addClick: [{ type: i0.Output, args: ["addClick"] }], deleteClick: [{ type: i0.Output, args: ["deleteClick"] }], grid: [{ type: i0.ViewChild, args: [i0.forwardRef(() => OdataGridComponent), { isSignal: true }] }], sort: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatSort), { isSignal: true }] }] }); })();
1651
1647
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserListGridComponent, { className: "UserListGridComponent", filePath: "lib/components/user-list-grid/user-list-grid.component.ts", lineNumber: 27 }); })();
1652
1648
 
@@ -1701,7 +1697,7 @@ class UsersPageComponent {
1701
1697
  }
1702
1698
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UsersPageComponent, [{
1703
1699
  type: Component,
1704
- args: [{ selector: 'cauca-users-page', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatCardModule, PageTitleComponent, UserListGridComponent], template: "<cauca-page-title\n [showBreadcrumb]=\"true\"\n [caption]=\"caption()\"\n [baseCrumb]=\"baseCrumb()\"\n [breadcrumb]=\"breadcrumb()\"/>\n\n<mat-card class=\"page-content\">\n\n <mat-card-content class=\"page-content-grid\">\n <cauca-user-list-grid\n [extraColumns]=\"extraColumns()\"\n [showAddButton]=\"showAddButton()\"\n [addButtonLabel]=\"addButtonLabel()\"\n [canEdit]=\"canEdit()\"\n [canDelete]=\"canDelete()\"\n [editLinkField]=\"editLinkField()\"\n [showPermissions]=\"showPermissions()\"\n [persistState]=\"persistState()\"\n (addClick)=\"addClick.emit()\"\n (deleteClick)=\"deleteClick.emit($event)\"/>\n </mat-card-content>\n\n</mat-card>\n" }]
1700
+ args: [{ selector: 'cauca-users-page', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatCardModule, PageTitleComponent, UserListGridComponent], template: "<cauca-page-title\r\n [showBreadcrumb]=\"true\"\r\n [caption]=\"caption()\"\r\n [baseCrumb]=\"baseCrumb()\"\r\n [breadcrumb]=\"breadcrumb()\"/>\r\n\r\n<mat-card class=\"page-content\">\r\n\r\n <mat-card-content class=\"page-content-grid\">\r\n <cauca-user-list-grid\r\n [extraColumns]=\"extraColumns()\"\r\n [showAddButton]=\"showAddButton()\"\r\n [addButtonLabel]=\"addButtonLabel()\"\r\n [canEdit]=\"canEdit()\"\r\n [canDelete]=\"canDelete()\"\r\n [editLinkField]=\"editLinkField()\"\r\n [showPermissions]=\"showPermissions()\"\r\n [persistState]=\"persistState()\"\r\n (addClick)=\"addClick.emit()\"\r\n (deleteClick)=\"deleteClick.emit($event)\"/>\r\n </mat-card-content>\r\n\r\n</mat-card>\r\n" }]
1705
1701
  }], null, { caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], baseCrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "baseCrumb", required: false }] }], breadcrumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "breadcrumb", required: false }] }], extraColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraColumns", required: false }] }], showAddButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAddButton", required: false }] }], addButtonLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addButtonLabel", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], canDelete: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDelete", required: false }] }], editLinkField: [{ type: i0.Input, args: [{ isSignal: true, alias: "editLinkField", required: false }] }], showPermissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPermissions", required: false }] }], persistState: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistState", required: false }] }], addClick: [{ type: i0.Output, args: ["addClick"] }], deleteClick: [{ type: i0.Output, args: ["deleteClick"] }], grid: [{ type: i0.ViewChild, args: [i0.forwardRef(() => UserListGridComponent), { isSignal: true }] }] }); })();
1706
1702
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UsersPageComponent, { className: "UsersPageComponent", filePath: "lib/pages/users-page/users-page.component.ts", lineNumber: 14 }); })();
1707
1703
 
@@ -1889,7 +1885,7 @@ class UserLoginFieldsComponent {
1889
1885
  MatSlideToggleModule,
1890
1886
  PasswordSelectionComponent,
1891
1887
  TranslatePipe,
1892
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<cauca-expandable-panel [caption]=\"'userEdition.loginSectionCaption' | translate\">\n <div class=\"user-login-fields\">\n <mat-form-field id=\"user-name-field\" subscriptSizing=\"dynamic\">\n <mat-label>{{ 'management.userName' | translate }}</mat-label>\n <input matInput [attr.aria-label]=\"'management.userName' | translate\" [formField]=\"field().userName\">\n @if (isValidatingUserName()) {\n <mat-progress-spinner matSuffix diameter=\"16\" mode=\"indeterminate\"/>\n }\n </mat-form-field>\n <cauca-field-errors [field]=\"field().userName\"/>\n\n <div class=\"password-fields\">\n <cauca-password-selection [required]=\"isNew()\" [formField]=\"field().password\"/>\n </div>\n\n <mat-slide-toggle color=\"primary\" [formField]=\"field().twoFactorAuthenticatorEnabled\">\n {{ 'userEdition.twoFactorAuthenticatorEnabled' | translate }}\n </mat-slide-toggle>\n\n <ng-content/>\n </div>\n</cauca-expandable-panel>\n", styles: [":host{display:block}.user-login-fields{display:flex;flex-direction:column}.user-login-fields mat-form-field:not(:first-child),.user-login-fields .password-fields,.user-login-fields mat-slide-toggle{margin-top:1.25rem}\n"] }]
1888
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<cauca-expandable-panel [caption]=\"'userEdition.loginSectionCaption' | translate\">\r\n <div class=\"user-login-fields\">\r\n <mat-form-field id=\"user-name-field\" subscriptSizing=\"dynamic\">\r\n <mat-label>{{ 'management.userName' | translate }}</mat-label>\r\n <input matInput [attr.aria-label]=\"'management.userName' | translate\" [formField]=\"field().userName\">\r\n @if (isValidatingUserName()) {\r\n <mat-progress-spinner matSuffix diameter=\"16\" mode=\"indeterminate\"/>\r\n }\r\n </mat-form-field>\r\n <cauca-field-errors [field]=\"field().userName\"/>\r\n\r\n <div class=\"password-fields\">\r\n <cauca-password-selection [required]=\"isNew()\" [formField]=\"field().password\"/>\r\n </div>\r\n\r\n <mat-slide-toggle color=\"primary\" [formField]=\"field().twoFactorAuthenticatorEnabled\">\r\n {{ 'userEdition.twoFactorAuthenticatorEnabled' | translate }}\r\n </mat-slide-toggle>\r\n\r\n <ng-content/>\r\n </div>\r\n</cauca-expandable-panel>\r\n", styles: [":host{display:block}.user-login-fields{display:flex;flex-direction:column}.user-login-fields mat-form-field:not(:first-child),.user-login-fields .password-fields,.user-login-fields mat-slide-toggle{margin-top:1.25rem}\n"] }]
1893
1889
  }], null, { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], isNew: [{ type: i0.Input, args: [{ isSignal: true, alias: "isNew", required: false }] }], isValidatingUserName: [{ type: i0.Input, args: [{ isSignal: true, alias: "isValidatingUserName", required: false }] }] }); })();
1894
1890
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserLoginFieldsComponent, { className: "UserLoginFieldsComponent", filePath: "lib/components/user-login-fields/user-login-fields.component.ts", lineNumber: 28 }); })();
1895
1891
 
@@ -1996,21 +1992,10 @@ class UserPersonalInformationFieldsComponent {
1996
1992
  MatInputModule,
1997
1993
  PhoneNumberInputComponent,
1998
1994
  TranslatePipe,
1999
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<cauca-expandable-panel [caption]=\"'userEdition.personalInformationSectionCaption' | translate\">\n <div class=\"user-personal-information-fields\">\n <mat-form-field id=\"first-name-field\" subscriptSizing=\"dynamic\">\n <mat-label>{{ 'management.firstName' | translate }}</mat-label>\n <input matInput [attr.aria-label]=\"'management.firstName' | translate\" [formField]=\"field().firstName\">\n </mat-form-field>\n <cauca-field-errors [field]=\"field().firstName\"/>\n\n <mat-form-field id=\"last-name-field\" subscriptSizing=\"dynamic\">\n <mat-label>{{ 'management.lastName' | translate }}</mat-label>\n <input matInput [attr.aria-label]=\"'management.lastName' | translate\" [formField]=\"field().lastName\">\n </mat-form-field>\n <cauca-field-errors [field]=\"field().lastName\"/>\n\n <mat-form-field id=\"email-field\" subscriptSizing=\"dynamic\">\n <mat-label>{{ 'management.email' | translate }}</mat-label>\n <input matInput [attr.aria-label]=\"'management.email' | translate\" [formField]=\"field().email\">\n @if (isEmailReadOnly() && emailHint()) {\n <mat-hint>{{ emailHint() | translate }}</mat-hint>\n }\n </mat-form-field>\n <cauca-field-errors [field]=\"field().email\"/>\n\n <cauca-phone-number-input [formField]=\"field().phoneNumber\" [label]=\"'management.phoneNumber'\"/>\n\n <ng-content/>\n </div>\n</cauca-expandable-panel>\n", styles: [":host{display:block}.user-personal-information-fields{display:flex;flex-direction:column}.user-personal-information-fields mat-form-field:not(:first-child),.user-personal-information-fields cauca-phone-number-input{margin-top:1.25rem}\n"] }]
1995
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<cauca-expandable-panel [caption]=\"'userEdition.personalInformationSectionCaption' | translate\">\r\n <div class=\"user-personal-information-fields\">\r\n <mat-form-field id=\"first-name-field\" subscriptSizing=\"dynamic\">\r\n <mat-label>{{ 'management.firstName' | translate }}</mat-label>\r\n <input matInput [attr.aria-label]=\"'management.firstName' | translate\" [formField]=\"field().firstName\">\r\n </mat-form-field>\r\n <cauca-field-errors [field]=\"field().firstName\"/>\r\n\r\n <mat-form-field id=\"last-name-field\" subscriptSizing=\"dynamic\">\r\n <mat-label>{{ 'management.lastName' | translate }}</mat-label>\r\n <input matInput [attr.aria-label]=\"'management.lastName' | translate\" [formField]=\"field().lastName\">\r\n </mat-form-field>\r\n <cauca-field-errors [field]=\"field().lastName\"/>\r\n\r\n <mat-form-field id=\"email-field\" subscriptSizing=\"dynamic\">\r\n <mat-label>{{ 'management.email' | translate }}</mat-label>\r\n <input matInput [attr.aria-label]=\"'management.email' | translate\" [formField]=\"field().email\">\r\n @if (isEmailReadOnly() && emailHint()) {\r\n <mat-hint>{{ emailHint() | translate }}</mat-hint>\r\n }\r\n </mat-form-field>\r\n <cauca-field-errors [field]=\"field().email\"/>\r\n\r\n <cauca-phone-number-input [formField]=\"field().phoneNumber\" [label]=\"'management.phoneNumber'\"/>\r\n\r\n <ng-content/>\r\n </div>\r\n</cauca-expandable-panel>\r\n", styles: [":host{display:block}.user-personal-information-fields{display:flex;flex-direction:column}.user-personal-information-fields mat-form-field:not(:first-child),.user-personal-information-fields cauca-phone-number-input{margin-top:1.25rem}\n"] }]
2000
1996
  }], null, { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], isEmailReadOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEmailReadOnly", required: false }] }], emailHint: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailHint", required: false }] }] }); })();
2001
1997
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserPersonalInformationFieldsComponent, { className: "UserPersonalInformationFieldsComponent", filePath: "lib/components/user-personal-information-fields/user-personal-information-fields.component.ts", lineNumber: 24 }); })();
2002
1998
 
2003
- const _forTrack0 = ($index, $item) => $item.id;
2004
- function UserGroupsSelectorComponent_For_10_Template(rf, ctx) { if (rf & 1) {
2005
- i0.ɵɵelementStart(0, "mat-option", 3);
2006
- i0.ɵɵtext(1);
2007
- i0.ɵɵelementEnd();
2008
- } if (rf & 2) {
2009
- const option_r1 = ctx.$implicit;
2010
- i0.ɵɵproperty("value", option_r1.id);
2011
- i0.ɵɵadvance();
2012
- i0.ɵɵtextInterpolate(option_r1.name);
2013
- } }
2014
1999
  class UserGroupsSelectorComponent {
2015
2000
  constructor() {
2016
2001
  this.value = model([], /* @ts-ignore */
@@ -2033,79 +2018,94 @@ class UserGroupsSelectorComponent {
2033
2018
  ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
2034
2019
  this.errors = input([], /* @ts-ignore */
2035
2020
  ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
2021
+ this.assignedGroups = input([], /* @ts-ignore */
2022
+ ...(ngDevMode ? [{ debugName: "assignedGroups" }] : /* istanbul ignore next */ []));
2036
2023
  this.touch = output();
2037
- this.filterControl = new FormControl('');
2038
- this.options = computed(() => this.groups.value(), /* @ts-ignore */
2024
+ // `DropdownChipAutocompleteComponent` is a `ControlValueAccessor` and stays one per ADR-0005,
2025
+ // so a reactive control is the only channel through which its selection can be read back.
2026
+ this.selectedGroupIds = new FormControl([], { nonNullable: true });
2027
+ this.lockedGroups = computed(() => this.assignedGroups().filter((assigned) => !this.groups.value().some((group) => group.id === assigned.id)), /* @ts-ignore */
2028
+ ...(ngDevMode ? [{ debugName: "lockedGroups" }] : /* istanbul ignore next */ []));
2029
+ this.lockedGroupIds = computed(() => this.lockedGroups().map((group) => group.id), /* @ts-ignore */
2030
+ ...(ngDevMode ? [{ debugName: "lockedGroupIds" }] : /* istanbul ignore next */ []));
2031
+ this.options = computed(() => [...this.groups.value(), ...this.lockedGroups()], /* @ts-ignore */
2039
2032
  ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
2040
- this.filteredOptions = computed(() => {
2041
- const filter = toLowerCaseAndWithoutDiacritics(this.filterText() ?? '');
2042
- if (!filter) {
2043
- return this.options();
2044
- }
2045
- // MatSelect clears its selection model for any value whose option is not
2046
- // rendered, so a selection hidden by the filter is lost on the next pick.
2047
- const selected = new Set(this.value());
2048
- return this.options().filter((option) => selected.has(option.id) || toLowerCaseAndWithoutDiacritics(option.name).includes(filter));
2049
- }, /* @ts-ignore */
2050
- ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
2051
- this.isSelectDisabled = computed(() => this.disabled() || this.readonly() || this.options().length === 0, /* @ts-ignore */
2052
- ...(ngDevMode ? [{ debugName: "isSelectDisabled" }] : /* istanbul ignore next */ []));
2033
+ this.isControlDisabled = computed(() => this.disabled() || this.readonly() || this.groups.value().length === 0, /* @ts-ignore */
2034
+ ...(ngDevMode ? [{ debugName: "isControlDisabled" }] : /* istanbul ignore next */ []));
2053
2035
  this.assignableGroupsService = inject(AssignableGroupsService);
2054
- this.filterText = toSignal(this.filterControl.valueChanges, { initialValue: '' });
2055
2036
  this.groups = rxResource({
2056
2037
  stream: () => this.assignableGroupsService.getAssignableGroups(),
2057
2038
  defaultValue: [],
2058
2039
  });
2040
+ this.selectedGroupIds.valueChanges
2041
+ .pipe(takeUntilDestroyed())
2042
+ .subscribe((groupIds) => this.onSelectionChange(groupIds));
2043
+ effect(() => {
2044
+ const groupIds = this.value();
2045
+ if (!haveSameIds(groupIds, this.selectedGroupIds.value)) {
2046
+ this.selectedGroupIds.setValue(groupIds, { emitEvent: false });
2047
+ }
2048
+ });
2049
+ // Toggled through the control rather than a `[disabled]` binding, which logs a dev-mode
2050
+ // warning on a reactive-forms host.
2051
+ effect(() => {
2052
+ if (this.isControlDisabled()) {
2053
+ this.selectedGroupIds.disable({ emitEvent: false });
2054
+ }
2055
+ else {
2056
+ this.selectedGroupIds.enable({ emitEvent: false });
2057
+ }
2058
+ });
2059
2059
  }
2060
2060
  onSelectionChange(groupIds) {
2061
+ // `writeValue` on the chip autocomplete re-invokes its own change callback, so a value
2062
+ // pushed in by the bound field echoes back here; without this guard it would report a
2063
+ // programmatic write as a user touch.
2064
+ if (haveSameIds(groupIds, this.value())) {
2065
+ return;
2066
+ }
2061
2067
  this.value.set(groupIds);
2062
2068
  this.touch.emit();
2063
2069
  }
2064
2070
  static { this.ɵfac = function UserGroupsSelectorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || UserGroupsSelectorComponent)(); }; }
2065
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserGroupsSelectorComponent, selectors: [["cauca-user-groups-selector"]], inputs: { value: [1, "value"], label: [1, "label"], disabled: [1, "disabled"], readonly: [1, "readonly"], required: [1, "required"], invalid: [1, "invalid"], touched: [1, "touched"], name: [1, "name"], errors: [1, "errors"] }, outputs: { value: "valueChange", touch: "touch" }, decls: 12, vars: 17, consts: [["subscriptSizing", "dynamic", 1, "user-groups-selector-field"], ["multiple", "", 3, "valueChange", "value", "disabled", "required"], [3, "formControl", "placeholderLabel", "noEntriesFoundLabel"], [3, "value"], [3, "touched", "errors"]], template: function UserGroupsSelectorComponent_Template(rf, ctx) { if (rf & 1) {
2071
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserGroupsSelectorComponent, selectors: [["cauca-user-groups-selector"]], inputs: { value: [1, "value"], label: [1, "label"], disabled: [1, "disabled"], readonly: [1, "readonly"], required: [1, "required"], invalid: [1, "invalid"], touched: [1, "touched"], name: [1, "name"], errors: [1, "errors"], assignedGroups: [1, "assignedGroups"] }, outputs: { value: "valueChange", touch: "touch" }, decls: 6, vars: 15, consts: [["subscriptSizing", "dynamic", 1, "user-groups-selector-field"], ["caucaControlErrorState", "", "keyValue", "id", "displayValue", "name", 3, "touched", "errors", "formControl", "listAutoComplete", "lockedValues", "allowRemove", "canRemoveAll", "required"], [3, "touched", "errors"]], template: function UserGroupsSelectorComponent_Template(rf, ctx) { if (rf & 1) {
2066
2072
  i0.ɵɵelementStart(0, "mat-form-field", 0)(1, "mat-label");
2067
2073
  i0.ɵɵtext(2);
2068
2074
  i0.ɵɵpipe(3, "translate");
2069
2075
  i0.ɵɵelementEnd();
2070
- i0.ɵɵelementStart(4, "mat-select", 1);
2071
- i0.ɵɵlistener("valueChange", function UserGroupsSelectorComponent_Template_mat_select_valueChange_4_listener($event) { return ctx.onSelectionChange($event); });
2072
- i0.ɵɵelementStart(5, "mat-option");
2073
- i0.ɵɵelement(6, "ngx-mat-select-search", 2);
2074
- i0.ɵɵpipe(7, "translate");
2075
- i0.ɵɵpipe(8, "translate");
2076
+ i0.ɵɵelement(4, "cauca-dropdown-chip-autocomplete", 1);
2076
2077
  i0.ɵɵcontrolCreate();
2077
2078
  i0.ɵɵelementEnd();
2078
- i0.ɵɵrepeaterCreate(9, UserGroupsSelectorComponent_For_10_Template, 2, 2, "mat-option", 3, _forTrack0);
2079
- i0.ɵɵelementEnd()();
2080
- i0.ɵɵelement(11, "cauca-control-field-errors", 4);
2079
+ i0.ɵɵelement(5, "cauca-control-field-errors", 2);
2081
2080
  } if (rf & 2) {
2082
2081
  i0.ɵɵadvance(2);
2083
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(3, 11, ctx.label()));
2082
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(3, 13, ctx.label()));
2084
2083
  i0.ɵɵadvance(2);
2085
- i0.ɵɵproperty("value", ctx.value())("disabled", ctx.isSelectDisabled())("required", ctx.required());
2084
+ i0.ɵɵproperty("touched", ctx.touched())("errors", ctx.errors())("formControl", ctx.selectedGroupIds)("listAutoComplete", ctx.options())("lockedValues", ctx.lockedGroupIds())("allowRemove", !ctx.isControlDisabled())("canRemoveAll", !ctx.isControlDisabled())("required", ctx.required());
2086
2085
  i0.ɵɵattribute("aria-invalid", ctx.invalid())("name", ctx.name() || null);
2087
- i0.ɵɵadvance(2);
2088
- i0.ɵɵproperty("formControl", ctx.filterControl)("placeholderLabel", i0.ɵɵpipeBind1(7, 13, "search"))("noEntriesFoundLabel", i0.ɵɵpipeBind1(8, 15, "noResult"));
2089
2086
  i0.ɵɵcontrol();
2090
- i0.ɵɵadvance(3);
2091
- i0.ɵɵrepeater(ctx.filteredOptions());
2092
- i0.ɵɵadvance(2);
2087
+ i0.ɵɵadvance();
2093
2088
  i0.ɵɵproperty("touched", ctx.touched())("errors", ctx.errors());
2094
- } }, dependencies: [ControlFieldErrorsComponent,
2095
- MatFormFieldModule, i1$2.MatFormField, i1$2.MatLabel, MatSelectModule, i2$2.MatSelect, i2$2.MatOption, NgxMatSelectSearchModule, i3$3.MatSelectSearchComponent, ReactiveFormsModule, i5.NgControlStatus, i5.FormControlDirective, TranslatePipe], styles: ["[_nghost-%COMP%]{display:block}.user-groups-selector-field[_ngcontent-%COMP%]{width:100%}"] }); }
2089
+ } }, dependencies: [ControlErrorStateDirective,
2090
+ ControlFieldErrorsComponent,
2091
+ DropdownChipAutocompleteComponent,
2092
+ MatFormFieldModule, i1$2.MatFormField, i1$2.MatLabel, ReactiveFormsModule, i5.NgControlStatus, i5.RequiredValidator, i5.FormControlDirective, TranslatePipe], styles: ["[_nghost-%COMP%]{display:block}.user-groups-selector-field[_ngcontent-%COMP%]{width:100%}"] }); }
2096
2093
  }
2097
2094
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserGroupsSelectorComponent, [{
2098
2095
  type: Component,
2099
2096
  args: [{ selector: 'cauca-user-groups-selector', imports: [
2097
+ ControlErrorStateDirective,
2100
2098
  ControlFieldErrorsComponent,
2099
+ DropdownChipAutocompleteComponent,
2101
2100
  MatFormFieldModule,
2102
- MatSelectModule,
2103
- NgxMatSelectSearchModule,
2104
2101
  ReactiveFormsModule,
2105
2102
  TranslatePipe,
2106
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mat-form-field class=\"user-groups-selector-field\" subscriptSizing=\"dynamic\">\n <mat-label>{{ label() | translate }}</mat-label>\n <mat-select multiple [value]=\"value()\" [disabled]=\"isSelectDisabled()\"\n [required]=\"required()\"\n [attr.aria-invalid]=\"invalid()\"\n [attr.name]=\"name() || null\"\n (valueChange)=\"onSelectionChange($event)\">\n <mat-option>\n <ngx-mat-select-search\n [formControl]=\"filterControl\"\n [placeholderLabel]=\"'search' | translate\"\n [noEntriesFoundLabel]=\"'noResult' | translate\"/>\n </mat-option>\n\n @for (option of filteredOptions(); track option.id) {\n <mat-option [value]=\"option.id\">{{ option.name }}</mat-option>\n }\n </mat-select>\n</mat-form-field>\n\n<cauca-control-field-errors [touched]=\"touched()\" [errors]=\"errors()\"/>\n", styles: [":host{display:block}.user-groups-selector-field{width:100%}\n"] }]
2107
- }], null, { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }] }); })();
2108
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserGroupsSelectorComponent, { className: "UserGroupsSelectorComponent", filePath: "lib/components/user-groups-selector/user-groups-selector.component.ts", lineNumber: 28 }); })();
2103
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mat-form-field class=\"user-groups-selector-field\" subscriptSizing=\"dynamic\">\r\n <mat-label>{{ label() | translate }}</mat-label>\r\n\r\n <cauca-dropdown-chip-autocomplete\r\n caucaControlErrorState [touched]=\"touched()\" [errors]=\"errors()\"\r\n [formControl]=\"selectedGroupIds\"\r\n [listAutoComplete]=\"options()\"\r\n [lockedValues]=\"lockedGroupIds()\"\r\n keyValue=\"id\"\r\n displayValue=\"name\"\r\n [allowRemove]=\"!isControlDisabled()\"\r\n [canRemoveAll]=\"!isControlDisabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-invalid]=\"invalid()\"\r\n [attr.name]=\"name() || null\"/>\r\n</mat-form-field>\r\n\r\n<cauca-control-field-errors [touched]=\"touched()\" [errors]=\"errors()\"/>\r\n", styles: [":host{display:block}.user-groups-selector-field{width:100%}\n"] }]
2104
+ }], () => [], { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], assignedGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "assignedGroups", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }] }); })();
2105
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserGroupsSelectorComponent, { className: "UserGroupsSelectorComponent", filePath: "lib/components/user-groups-selector/user-groups-selector.component.ts", lineNumber: 29 }); })();
2106
+ function haveSameIds(left, right) {
2107
+ return left.length === right.length && left.every((id, index) => id === right[index]);
2108
+ }
2109
2109
 
2110
2110
  /*
2111
2111
  * Public API Surface of cauca-management