@sinequa/atomic-angular 0.4.12 → 0.4.19-dev.2

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,17 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, inject, HostBinding, Component, Pipe, InjectionToken, computed, ChangeDetectorRef, DestroyRef, LOCALE_ID, Inject, Optional, input, output, signal, effect, assertInInjectionContext, runInInjectionContext, Injector, EventEmitter, Directive, viewChild, ElementRef, afterNextRender, untracked, linkedSignal, model, TemplateRef, HostListener, Renderer2, contentChildren, contentChild, booleanAttribute, resource, ViewContainerRef, viewChildren, numberAttribute, afterEveryRender } from '@angular/core';
3
- import { BehaviorSubject, Subscription, catchError, EMPTY, firstValueFrom, map, pipe, tap, switchMap, Subject, of, throwError, filter, shareReplay, fromEvent, debounceTime, from } from 'rxjs';
3
+ import { BehaviorSubject, Subscription, catchError, EMPTY, firstValueFrom, map, Subject, of, tap, throwError, filter, shareReplay, fromEvent, debounceTime, from, switchMap } from 'rxjs';
4
4
  import { TranslocoService, TranslocoPipe, provideTranslocoScope } from '@jsverse/transloco';
5
5
  import { DropdownComponent, DropdownContentComponent, InputComponent, ButtonComponent, cn, EllipsisIcon, ChevronRightIcon, MenuComponent, MenuContentComponent, MenuItemComponent, BadgeComponent, DialogComponent, DialogHeaderComponent, DialogTitleComponent, DialogContentComponent, DialogFooterComponent, ListItemComponent, SwitchComponent, SelectOptionDirective, DialogService, TabsComponent, TabsListComponent, TabComponent, ChevronLeftIconComponent, ChevronsLeftIconComponent, ChevronsRightIconComponent, Separator, SheetCloseDirective, SheetService, ButtonGroup, InputGroupInput, InputGroupComponent, InputGroupAddonComponent, SearchIcon, FilterIcon, DateRangePickerDirective, LoadingCircleIconComponent, CircleCheckIconComponent, PopoverComponent, HorizontalDividerComponent, CardComponent, CardHeaderComponent, CardContentComponent, CardFooterComponent, PopoverContentComponent, BookmarkIcon, UserIcon, TrashIcon, FolderIcon, VerticalDividerComponent, BreakpointObserverService, FlagEnglishIconComponent, FlagFrenchIconComponent, EditIcon, UndoIcon, AvatarComponent, AvatarFallbackComponent, AvatarImageComponent } from '@sinequa/ui';
6
6
  import highlightWords from 'highlight-words';
7
7
  import { ActivatedRoute, Router, NavigationEnd, RouterLink, RouterModule } from '@angular/router';
8
8
  import { withDevtools } from '@angular-architects/ngrx-toolkit';
9
9
  import { signalStore, signalStoreFeature, withState, withMethods, patchState, getState, withComputed } from '@ngrx/signals';
10
- import { globalConfig, EngineType, extraColumns, sysLang, getQueryParamsFromUrl, logout, login, info, warn, notify, error, setGlobalConfig, addConcepts, queryParamsFromUrl, patchUserSettings, deleteUserSettings, fetchUserSettings, buildPathsAndLevels, escapeExpr, isAuthenticated, isExpired, fetchSuggest, isObject, Audit, getMetadata, bisect, isNotInputEvent, fetchSponsoredLinks, fetchQuery, translateAggregationToDateOptions, aggItemRegex, parseValueAndOperatorFromItem, fetchSuggestField, debug, fetchSimilarDocuments, fetchChangePassword, fetchSendPasswordResetEmail, expiresSoon, suggestionsToTreeAggregationNodes, labels, fetchLabels, guid, getRelativeDate, createUserProfile, deleteUserProfileProperty, patchUserProfile, isJsonable, addAuditAdditionalInfo, getToken, setToken, createHeaders } from '@sinequa/atomic';
11
- import { HttpClient, HttpParams, httpResource, HttpResponse, HttpHeaders } from '@angular/common/http';
10
+ import { globalConfig, EngineType, extraColumns, sysLang, getQueryParamsFromUrl, logout, login, info, warn, notify, error, setGlobalConfig, addConcepts, queryParamsFromUrl, patchUserSettings, deleteUserSettings, fetchUserSettings, buildPathsAndLevels, escapeExpr, isAuthenticated, isExpired, debug, fetchSuggest, isObject, Audit, getMetadata, bisect, isNotInputEvent, fetchSponsoredLinks, fetchQuery, translateAggregationToDateOptions, aggItemRegex, parseValueAndOperatorFromItem, fetchSuggestField, fetchSimilarDocuments, fetchChangePassword, fetchSendPasswordResetEmail, expiresSoon, suggestionsToTreeAggregationNodes, labels, fetchLabels, guid, getRelativeDate, createUserProfile, deleteUserProfileProperty, patchUserProfile, isJsonable, addAuditAdditionalInfo, getToken, setToken, createHeaders } from '@sinequa/atomic';
11
+ import { HttpClient, HttpParams, httpResource, HttpResponse, HttpHeaders, HttpContextToken } from '@angular/common/http';
12
12
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
13
13
  import { DatePipe, DATE_PIPE_DEFAULT_TIMEZONE, DATE_PIPE_DEFAULT_OPTIONS, Location, NgTemplateOutlet, NgStyle, NgClass, NgComponentOutlet } from '@angular/common';
14
- import { rxMethod } from '@ngrx/signals/rxjs-interop';
15
14
  import { Title, DomSanitizer } from '@angular/platform-browser';
16
15
  import { cva } from 'class-variance-authority';
17
16
  import * as i1 from '@angular/forms';
@@ -323,7 +322,7 @@ function withAppFeatures() {
323
322
  }
324
323
  });
325
324
  // Also include columns from the default index "_"
326
- const schema = app.indexes._.columns;
325
+ const schema = app.indexes._?.columns;
327
326
  if (schema) {
328
327
  Object.keys(schema).forEach((schemaKey) => {
329
328
  const col = schema[schemaKey.toLocaleLowerCase()];
@@ -337,29 +336,29 @@ function withAppFeatures() {
337
336
  });
338
337
  }
339
338
  });
339
+ // Include columns from all queries
340
+ Object.keys(app.queries).forEach((queryKey) => {
341
+ const query = app.queries[queryKey];
342
+ if (query.columnsInfo?.columns) {
343
+ Object.values(query.columnsInfo.columns).forEach((c) => {
344
+ const col = schema[c.name.toLocaleLowerCase()];
345
+ if (!col)
346
+ return;
347
+ columnMap[c.name.toLocaleLowerCase()] = col;
348
+ // Add aliases to the map
349
+ if (c.aliases) {
350
+ c.aliases
351
+ .split(/[,;|]/)
352
+ .map((a) => a.trim())
353
+ .forEach((alias) => {
354
+ columnMap[alias.toLocaleLowerCase()] = col;
355
+ });
356
+ }
357
+ });
358
+ }
359
+ });
360
+ patchState(store, { columnMap });
340
361
  }
341
- // Include columns from all queries
342
- Object.keys(app.queries).forEach((queryKey) => {
343
- const query = app.queries[queryKey];
344
- if (query.columnsInfo?.columns) {
345
- Object.values(query.columnsInfo.columns).forEach((c) => {
346
- const col = schema[c.name.toLocaleLowerCase()];
347
- if (!col)
348
- return;
349
- columnMap[c.name.toLocaleLowerCase()] = col;
350
- // Add aliases to the map
351
- if (c.aliases) {
352
- c.aliases
353
- .split(/[,;|]/)
354
- .map((a) => a.trim())
355
- .forEach((alias) => {
356
- columnMap[alias.toLocaleLowerCase()] = col;
357
- });
358
- }
359
- });
360
- }
361
- });
362
- patchState(store, { columnMap });
363
362
  })));
364
363
  },
365
364
  /**
@@ -375,7 +374,7 @@ function withAppFeatures() {
375
374
  /**
376
375
  * Updates the application state with the provided CCApp object.
377
376
  *
378
- * @param {CCApp} app - The application object containing the new state values.
377
+ * @param {Partial<CCAppState>} app - The application object containing the new state values.
379
378
  */
380
379
  update(app) {
381
380
  patchState(store, (state) => {
@@ -633,7 +632,8 @@ function withAppFeatures() {
633
632
  sources: computed(() => parseCustomJson("sources", {})),
634
633
  filters: computed(() => parseCustomJson("filters", [])),
635
634
  general: computed(() => parseCustomJson("general", {})),
636
- assistants: computed(() => parseCustomJson("assistants", {}))
635
+ assistants: computed(() => parseCustomJson("assistants", {})),
636
+ agents: computed(() => parseCustomJson("agents", {}))
637
637
  };
638
638
  }), withMethods((store) => ({
639
639
  /**
@@ -739,6 +739,12 @@ function withAppFeatures() {
739
739
  if (assistants === undefined || Object.keys(assistants).length === 0)
740
740
  return false;
741
741
  return !!assistants[assistantName]?.defaultValues?.service_id;
742
+ },
743
+ isAgentAllowed(agentName) {
744
+ const agents = store.agents();
745
+ if (agents === undefined || Object.keys(agents).length === 0)
746
+ return false;
747
+ return !!agents[agentName]?.defaultAgent;
742
748
  }
743
749
  })));
744
750
  }
@@ -1107,7 +1113,7 @@ class DropdownInputComponent {
1107
1113
  }
1108
1114
  </DropdownContent>
1109
1115
  </Dropdown>
1110
- `, isInline: true, dependencies: [{ kind: "component", type: DropdownComponent, selector: "dropdown, Dropdown", inputs: ["disabled"] }, { kind: "component", type: DropdownListComponent, selector: "dropdown-list, DropdownList", inputs: ["items"], outputs: ["onClick"] }, { kind: "directive", type: DropdownContentComponent, selector: "dropdown-content, dropdowncontent, DropdownContent", inputs: ["class", "position", "strategy", "offset"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: SyslangPipe, name: "syslang" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
1116
+ `, isInline: true, dependencies: [{ kind: "component", type: DropdownComponent, selector: "dropdown, Dropdown", inputs: ["disabled"] }, { kind: "component", type: DropdownListComponent, selector: "dropdown-list, DropdownList", inputs: ["items"], outputs: ["onClick"] }, { kind: "directive", type: DropdownContentComponent, selector: "dropdown-content, dropdowncontent, DropdownContent", inputs: ["class", "position", "strategy", "offset"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: SyslangPipe, name: "syslang" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
1111
1117
  }
1112
1118
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DropdownInputComponent, decorators: [{
1113
1119
  type: Component,
@@ -1264,7 +1270,7 @@ const PrincipalStore = signalStore({ providedIn: 'root' }, withDevtools('Princip
1264
1270
  }),
1265
1271
  })), withMethods((store) => ({
1266
1272
  /**
1267
- * @deprecated use the property from the store directly instead (e.g. principalStore.fullName() instead of principalStore.principal().fullName)
1273
+ * @deprecated use getState(PrincipalStore))
1268
1274
  */
1269
1275
  principal() {
1270
1276
  const { userOverrideActive: _, ...rest } = getState(store);
@@ -1282,24 +1288,20 @@ function withPrincipalFeatures() {
1282
1288
  const http = inject(HttpClient);
1283
1289
  const API_URL = `${globalConfig.backendUrl}/api/v1`;
1284
1290
  return {
1285
- initialize: rxMethod(pipe(tap(() => patchState(store, { state: 'loading' })), switchMap(() => {
1286
- let params = new HttpParams()
1291
+ initialize() {
1292
+ patchState(store, { state: 'loading' });
1293
+ const params = new HttpParams()
1287
1294
  .set('action', 'get')
1288
1295
  .set('noAuthentication', 'true');
1289
- return http.get(`${API_URL}/principal`, { params });
1290
- }), tap((principal) => {
1291
- const { userOverrideActive = false } = globalConfig;
1292
- patchState(store, {
1293
- ...initialPrincipal,
1294
- ...principal,
1295
- userOverrideActive,
1296
- state: 'loaded'
1297
- });
1298
- }), catchError((error) => {
1299
- console.error('Principal fetch failed', error);
1300
- patchState(store, { state: 'error' });
1301
- return EMPTY;
1302
- })))
1296
+ return firstValueFrom(http.get(`${API_URL}/principal`, { params }).pipe(catchError((error) => {
1297
+ console.error('Principal fetch failed', error);
1298
+ patchState(store, { state: 'error' });
1299
+ throw error;
1300
+ }), map((principal) => {
1301
+ const { userOverrideActive = false } = globalConfig;
1302
+ patchState(store, { ...initialPrincipal, ...principal, userOverrideActive, state: 'loaded' });
1303
+ })));
1304
+ }
1303
1305
  };
1304
1306
  }));
1305
1307
  }
@@ -1408,7 +1410,7 @@ function getQueryNameFromRoute() {
1408
1410
  const { t, n } = route.snapshot.queryParams;
1409
1411
  // ! This is a workaround for the case where the queryName is not defined in the route data
1410
1412
  // "search" is the parent route of the search results, and "t" is the query parameter for the tab
1411
- const { queryName } = routes.config.filter(p => p.path === 'search')[0].children?.find(route => route.path === t)?.data || n || {};
1413
+ const { queryName } = routes.config.filter(p => p.path === 'search')[0]?.children?.find(route => route.path === t)?.data || n || {};
1412
1414
  if (queryName)
1413
1415
  return queryName;
1414
1416
  // fallback to queryName from route data
@@ -3110,11 +3112,14 @@ class AggregationsService {
3110
3112
  const agg = this.getAggregation(name, column);
3111
3113
  if (!agg)
3112
3114
  return null;
3113
- const { items = [], display = agg.name, icon, hidden, searchable = true } = this.appStore.getAggregationCustomization(agg.column, agg.name) || {};
3115
+ const { items = [], display = agg.name, icon, hidden, expandedLevel, searchable = true } = this.appStore.getAggregationCustomization(agg.column, agg.name) || {};
3114
3116
  agg.display = display;
3115
3117
  agg.icon = icon;
3116
3118
  agg.hidden = hidden;
3117
3119
  agg.searchable = searchable;
3120
+ if (agg.isTree && expandedLevel) {
3121
+ agg.expandedLevel = expandedLevel;
3122
+ }
3118
3123
  // if the aggregation's column is a "concepts", disable the search
3119
3124
  if (this.nonSearchableColumns.some((column) => column === agg.column)) {
3120
3125
  agg.searchable = false;
@@ -3327,6 +3332,7 @@ function AuthGuard() {
3327
3332
  const { loginPath, useCredentials, useSSO } = globalConfig;
3328
3333
  if (state.url.startsWith("/login"))
3329
3334
  return true;
3335
+ // If the user is not authenticated, navigate to the login page or loading page based on the authentication method
3330
3336
  if (!isAuthenticated() && !useSSO) {
3331
3337
  if (useCredentials) {
3332
3338
  router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
@@ -3343,80 +3349,34 @@ function AuthGuard() {
3343
3349
  }
3344
3350
  }
3345
3351
  catch {
3346
- // If initialization fails, navigate to the login page
3352
+ error("Failed to initialize PrincipalStore. Redirecting to login.");
3353
+ // TODO: we might want to navigate to an error page instead of the login page in SSO mode, as the issue is not related to authentication but rather to fetching user details
3347
3354
  router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
3348
3355
  return false;
3349
3356
  }
3350
- if (principalStore.state() !== "loaded") {
3351
- // If the principal store is not loaded, navigate to the login page
3352
- router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
3353
- return false;
3354
- }
3355
- const { id, passwordExpirationDate, editablePartition, name } = getState(principalStore);
3356
- if (!id) {
3357
+ // check if the "princiapl" infos are loaded, if not navigate to the login page
3358
+ const { passwordExpirationDate, editablePartition, name, state: principalState } = getState(principalStore);
3359
+ if (principalState !== "loaded") {
3360
+ info("PrincipalStore state is still initial after initialization attempt. Redirecting to login.");
3357
3361
  router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
3358
3362
  return false;
3359
3363
  }
3360
- const exp = passwordExpirationDate;
3361
- const editable = !!editablePartition;
3362
- if (editable && exp && isExpired(exp)) {
3363
- sessionStorage.setItem("passwordExpiredFlow", "true");
3364
- const username = (name || "").trim();
3365
- router.navigate(["/login"], {
3366
- queryParams: { mode: "changepassword", alert: "passwordExpired", username, returnUrl: state.url }
3367
- });
3368
- return false;
3369
- }
3370
- return true;
3371
- };
3372
- }
3373
-
3374
- /**
3375
- * Password-expiry guard: blocks navigation when the password is expired
3376
- * and redirects to the change-password .
3377
- */
3378
- function PasswordExpiryGuard() {
3379
- return async (_, state) => {
3380
- const router = inject(Router);
3381
- const principalStore = inject(PrincipalStore);
3382
- const { loginPath, useCredentials, useSSO } = globalConfig;
3383
- if (!isAuthenticated() && !useSSO) {
3384
- if (useCredentials) {
3385
- router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
3386
- }
3387
- else {
3388
- router.navigate(["loading"], { queryParams: { returnUrl: state.url } });
3389
- }
3390
- return false;
3391
- }
3392
- try {
3393
- if (!principalStore.principal?.()) {
3394
- await principalStore.initialize();
3364
+ // check if the password is expired and if the partition is editable
3365
+ // changing password is only possible when user use credentials to auhtenticate
3366
+ // only in credentials mode
3367
+ if (useCredentials) {
3368
+ const exp = passwordExpirationDate;
3369
+ const editable = !!editablePartition;
3370
+ if (editable && exp && isExpired(exp)) {
3371
+ sessionStorage.setItem("passwordExpiredFlow", "true");
3372
+ const username = (name || "").trim();
3373
+ router.navigate(["/login"], {
3374
+ queryParams: { mode: "changepassword", alert: "passwordExpired", username, returnUrl: state.url }
3375
+ });
3376
+ return false;
3395
3377
  }
3396
3378
  }
3397
- catch {
3398
- router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
3399
- return false;
3400
- }
3401
- const p = principalStore.principal?.();
3402
- if (!p) {
3403
- router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
3404
- return false;
3405
- }
3406
- const exp = p.passwordExpirationDate;
3407
- const editable = !!p.editablePartition;
3408
- if (!editable || !exp) {
3409
- router.navigate([loginPath], { queryParams: { returnUrl: state.url } });
3410
- return false;
3411
- }
3412
- if (isExpired(exp)) {
3413
- sessionStorage.setItem("passwordExpiredFlow", "true");
3414
- const username = (p.name || "").trim();
3415
- router.navigate(["/login"], {
3416
- queryParams: { mode: "changepassword", alert: "passwordExpired", username, returnUrl: state.url }
3417
- });
3418
- return false;
3419
- }
3379
+ debug("User is authenticated and principal store is initialized. Access granted.");
3420
3380
  return true;
3421
3381
  };
3422
3382
  }
@@ -3598,7 +3558,7 @@ class ApplicationService {
3598
3558
  const searchPath = this.router.config.find((route) => route.path === "search") || {
3599
3559
  path: "search",
3600
3560
  component: this.components.find((c) => c.path === "search")?.component || this.defaultLayoutComponent(),
3601
- canActivate: [AuthGuard(), PasswordExpiryGuard()],
3561
+ canActivate: [AuthGuard()],
3602
3562
  children: []
3603
3563
  };
3604
3564
  const wildcardPath = searchPath.children?.find((route) => route.path === "**") || {
@@ -5365,7 +5325,7 @@ class LoadingComponent {
5365
5325
  }
5366
5326
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LoadingComponent, deps: [{ token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component });
5367
5327
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: LoadingComponent, isStandalone: true, selector: "app-wait", ngImport: i0, template: `
5368
- <div class="flex h-[100dvh] w-full items-center justify-center">
5328
+ <div class="flex h-dvh w-full items-center justify-center">
5369
5329
  <div class="flex flex-col items-center space-y-4">
5370
5330
  <span class="loader"></span>
5371
5331
  </div>
@@ -5375,7 +5335,7 @@ class LoadingComponent {
5375
5335
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LoadingComponent, decorators: [{
5376
5336
  type: Component,
5377
5337
  args: [{ selector: 'app-wait', standalone: true, imports: [], template: `
5378
- <div class="flex h-[100dvh] w-full items-center justify-center">
5338
+ <div class="flex h-dvh w-full items-center justify-center">
5379
5339
  <div class="flex flex-col items-center space-y-4">
5380
5340
  <span class="loader"></span>
5381
5341
  </div>
@@ -5616,7 +5576,7 @@ class CollectionsDialog {
5616
5576
  </DialogFooter>
5617
5577
  </DialogContent>
5618
5578
  </dialog>
5619
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
5579
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
5620
5580
  }
5621
5581
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CollectionsDialog, decorators: [{
5622
5582
  type: Component,
@@ -5824,7 +5784,7 @@ class ExportDialog {
5824
5784
  destroyRef = inject(DestroyRef);
5825
5785
  open(selection) {
5826
5786
  const app = getState(this.appStore);
5827
- const webservice = app.queryExport;
5787
+ const webservice = app.queryExport.toLocaleLowerCase();
5828
5788
  let queryExport;
5829
5789
  if (selection && selection.length > 0)
5830
5790
  this.selection.set(selection);
@@ -7433,7 +7393,7 @@ class PreviewNavigator {
7433
7393
  [disabled]="isLast()">
7434
7394
  <chevrons-right />
7435
7395
  </button>
7436
- `, isInline: true, dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: ChevronLeftIconComponent, selector: "chevron-left, ChevronLeft, chevronleft", inputs: ["class"] }, { kind: "component", type: ChevronsLeftIconComponent, selector: "chevrons-left, ChevronsLeft, chevronsleft", inputs: ["class"] }, { kind: "component", type: ChevronsRightIconComponent, selector: "chevrons-right, ChevronsRight, chevronsright", inputs: ["class"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }] });
7396
+ `, isInline: true, dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: ChevronLeftIconComponent, selector: "chevron-left, ChevronLeft, chevronleft", inputs: ["class"] }, { kind: "component", type: ChevronsLeftIconComponent, selector: "chevrons-left, ChevronsLeft, chevronsleft", inputs: ["class"] }, { kind: "component", type: ChevronsRightIconComponent, selector: "chevrons-right, ChevronsRight, chevronsright", inputs: ["class"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }] });
7437
7397
  }
7438
7398
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PreviewNavigator, decorators: [{
7439
7399
  type: Component,
@@ -8117,7 +8077,7 @@ class AdvancedFiltersComponent {
8117
8077
  return res;
8118
8078
  }
8119
8079
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AdvancedFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8120
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AdvancedFiltersComponent, isStandalone: true, selector: "advanced-filters", host: { classAttribute: "contents" }, providers: [SyslangPipe, TranslocoPipe, provideTranslocoScope("drawers")], ngImport: i0, template: "<div class=\"flex h-full flex-col overflow-auto\">\n <sheet-navbar class=\"border-foreground/10 block border-b pb-2\">\n <button [attr.title]=\"'drawers.search' | transloco\" (click)=\"onSearch()\">\n {{ 'drawers.search' | transloco }}\n </button>\n </sheet-navbar>\n\n <div class=\"flex h-full grow flex-col overflow-auto p-4\">\n <section class=\"flex flex-col gap-4\" [formGroup]=\"form\">\n <!-- FIND IN -->\n <h1 class=\"text-xl font-bold\">{{ 'drawers.findInContent' | transloco }}</h1>\n <div class=\"flex items-center gap-4\" formGroupName=\"content\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInContent' | transloco }}</span>\n <select\n id=\"content-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input\n [variant]=\"inputVariant()\"\n id=\"content-value\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"getPlaceholder('content.operator')\"\n formControlName=\"value\" />\n </div>\n @if (enableFieldedSearch()) {\n <div class=\"flex items-center gap-4\" formGroupName=\"title\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInTitle' | transloco }}</span>\n <select\n id=\"title-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input id=\"title-value\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" [placeholder]=\"getPlaceholder('title.operator')\" formControlName=\"value\" />\n </div>\n }\n\n <!-- TABS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.inScope' | transloco }}&nbsp;&quot;{{ currentTab() }}&quot;</h1>\n\n <Tabs>\n <TabsList variant=\"ghost\">\n @for (tab of tabs(); track $index) {\n <Tab class=\"w-fit\" [value]=\"tab.path\" [active]=\"tab.path === currentTab()\" (click)=\"onTabChange(tab.path)\">\n {{ tab.display | syslang | transloco }}\n </Tab>\n }\n </TabsList>\n </Tabs>\n\n <!-- FILTERS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.applyFilters' | transloco }}</h1>\n @for (filter of filters(); track $index) {\n <DropdownInput\n [suggestions]=\"suggestions()\"\n [selected]=\"getItems(filter.column)\"\n [label]=\"filter.display || filter.alias | syslang | transloco\"\n [placeholder]=\"'drawers.startTyping' | transloco\"\n [noResultLabel]=\"'drawers.noResult' | transloco\"\n (onFocus)=\"setFilterFocus($event, filter)\"\n (onKeyUp)=\"onInputTyping($event)\"\n (removeItem)=\"removeItem($event, filter)\"\n (addItem)=\"addItem($event, filter)\" />\n } @empty {\n {{ 'drawers.noFilters' | transloco }}\n }\n </section>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: DropdownInputComponent, selector: "dropdown-input, DropdownInput", inputs: ["label", "placeholder", "noResultLabel", "suggestions", "selected"], outputs: ["onFocus", "onKeyUp", "removeItem", "addItem"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: TabsComponent, selector: "tabs, Tabs", inputs: ["class"] }, { kind: "directive", type: TabComponent, selector: "tab, Tab", inputs: ["class", "variant", "size", "value", "active"], outputs: ["clicked"] }, { kind: "directive", type: TabsListComponent, selector: "tabs-list, TabsList", inputs: ["class", "variant", "size"] }, { kind: "component", type: SheetNavbarComponent, selector: "SheetNavbar, sheetnavbar, sheet-navbar" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
8080
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AdvancedFiltersComponent, isStandalone: true, selector: "advanced-filters", host: { classAttribute: "contents" }, providers: [SyslangPipe, TranslocoPipe, provideTranslocoScope("drawers")], ngImport: i0, template: "<div class=\"flex h-full flex-col overflow-auto\">\n <sheet-navbar class=\"border-foreground/10 block border-b pb-2\">\n <button [attr.title]=\"'drawers.search' | transloco\" (click)=\"onSearch()\">\n {{ 'drawers.search' | transloco }}\n </button>\n </sheet-navbar>\n\n <div class=\"flex h-full grow flex-col overflow-auto p-4\">\n <section class=\"flex flex-col gap-4\" [formGroup]=\"form\">\n <!-- FIND IN -->\n <h1 class=\"text-xl font-bold\">{{ 'drawers.findInContent' | transloco }}</h1>\n <div class=\"flex items-center gap-4\" formGroupName=\"content\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInContent' | transloco }}</span>\n <select\n id=\"content-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input\n [variant]=\"inputVariant()\"\n id=\"content-value\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"getPlaceholder('content.operator')\"\n formControlName=\"value\" />\n </div>\n @if (enableFieldedSearch()) {\n <div class=\"flex items-center gap-4\" formGroupName=\"title\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInTitle' | transloco }}</span>\n <select\n id=\"title-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input id=\"title-value\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" [placeholder]=\"getPlaceholder('title.operator')\" formControlName=\"value\" />\n </div>\n }\n\n <!-- TABS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.inScope' | transloco }}&nbsp;&quot;{{ currentTab() }}&quot;</h1>\n\n <Tabs>\n <TabsList variant=\"ghost\">\n @for (tab of tabs(); track $index) {\n <Tab class=\"w-fit\" [value]=\"tab.path\" [active]=\"tab.path === currentTab()\" (click)=\"onTabChange(tab.path)\">\n {{ tab.display | syslang | transloco }}\n </Tab>\n }\n </TabsList>\n </Tabs>\n\n <!-- FILTERS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.applyFilters' | transloco }}</h1>\n @for (filter of filters(); track $index) {\n <DropdownInput\n [suggestions]=\"suggestions()\"\n [selected]=\"getItems(filter.column)\"\n [label]=\"filter.display || filter.alias | syslang | transloco\"\n [placeholder]=\"'drawers.startTyping' | transloco\"\n [noResultLabel]=\"'drawers.noResult' | transloco\"\n (onFocus)=\"setFilterFocus($event, filter)\"\n (onKeyUp)=\"onInputTyping($event)\"\n (removeItem)=\"removeItem($event, filter)\"\n (addItem)=\"addItem($event, filter)\" />\n } @empty {\n {{ 'drawers.noFilters' | transloco }}\n }\n </section>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: DropdownInputComponent, selector: "dropdown-input, DropdownInput", inputs: ["label", "placeholder", "noResultLabel", "suggestions", "selected"], outputs: ["onFocus", "onKeyUp", "removeItem", "addItem"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: TabsComponent, selector: "tabs, Tabs", inputs: ["class"] }, { kind: "directive", type: TabComponent, selector: "tab, Tab", inputs: ["class", "variant", "size", "value", "active"], outputs: ["clicked"] }, { kind: "directive", type: TabsListComponent, selector: "tabs-list, TabsList", inputs: ["class", "variant", "size"] }, { kind: "component", type: SheetNavbarComponent, selector: "SheetNavbar, sheetnavbar, sheet-navbar" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
8121
8081
  }
8122
8082
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AdvancedFiltersComponent, decorators: [{
8123
8083
  type: Component,
@@ -8592,7 +8552,7 @@ class AggregationListComponent {
8592
8552
  this.isCollapsed.set(e.newState === "closed");
8593
8553
  }
8594
8554
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8595
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationListComponent, isStandalone: true, selector: "AggregationList, aggregation-list, aggregationlist", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, showFiltersCount: { classPropertyName: "showFiltersCount", publicName: "showFiltersCount", isSignal: true, isRequired: false, transformFunction: null }, searchText: { classPropertyName: "searchText", publicName: "searchText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect", searchText: "searchTextChange" }, host: { properties: { "class": "cn(\"block h-[inherit] max-h-[inherit]\",class())" } }, viewQueries: [{ propertyName: "scrollElement", first: true, predicate: ["scrollElement"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregation component no longer supports tree aggregations. Please use\r\n the &lt;AggregationTree /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n {{ \"filters.apply\" | transloco }}\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div\r\n class=\"absolute w-full\"\r\n [style.transform]=\"'translateY(' + vItem.start + 'px)'\"\r\n role=\"listitem\">\r\n <AggregationListItem\r\n [node]=\"item\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationItem:has(+AggregationItem){margin-bottom:var(--agg-item-gap, 0)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: AggregationListItemComponent, selector: "aggregation-list-item, AggregationListItem, aggregationlistitem", inputs: ["node", "field"], outputs: ["onSelect", "onOpen", "onFilter"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "directive", type: ButtonGroup, selector: "button-group, ButtonGroup", inputs: ["class", "orientation"] }, { kind: "directive", type: InputGroupInput, selector: "input[input-group]", inputs: ["class", "type", "placeholder", "disabled"] }, { kind: "directive", type: InputGroupComponent, selector: "input-group, inputgroup, InputGroup", inputs: ["class"] }, { kind: "directive", type: InputGroupAddonComponent, selector: "input-group-addon, inputgroupaddon, InputGroupAddon", inputs: ["class", "align"] }, { kind: "component", type: SearchIcon, selector: "SearchIcon", inputs: ["class"] }, { kind: "component", type: FilterIcon, selector: "filter-icon, FilterIcon", inputs: ["class"] }, { kind: "pipe", type: SyslangPipe, name: "syslang" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
8555
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationListComponent, isStandalone: true, selector: "AggregationList, aggregation-list, aggregationlist", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, showFiltersCount: { classPropertyName: "showFiltersCount", publicName: "showFiltersCount", isSignal: true, isRequired: false, transformFunction: null }, searchText: { classPropertyName: "searchText", publicName: "searchText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect", searchText: "searchTextChange" }, host: { properties: { "class": "cn(\"block h-[inherit] max-h-[inherit]\",class())" } }, viewQueries: [{ propertyName: "scrollElement", first: true, predicate: ["scrollElement"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregation component no longer supports tree aggregations. Please use\r\n the &lt;AggregationTree /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow truncate\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n {{ \"filters.apply\" | transloco }}\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin max-h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div\r\n class=\"absolute w-full\"\r\n [style.transform]=\"'translateY(' + vItem.start + 'px)'\"\r\n role=\"listitem\">\r\n <AggregationListItem\r\n [node]=\"item\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationItem:has(+AggregationItem){margin-bottom:var(--agg-item-gap, 0)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: AggregationListItemComponent, selector: "aggregation-list-item, AggregationListItem, aggregationlistitem", inputs: ["node", "field"], outputs: ["onSelect", "onOpen", "onFilter"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "directive", type: ButtonGroup, selector: "button-group, ButtonGroup", inputs: ["class", "orientation"] }, { kind: "directive", type: InputGroupInput, selector: "input[input-group]", inputs: ["class", "type", "placeholder", "disabled"] }, { kind: "directive", type: InputGroupComponent, selector: "input-group, inputgroup, InputGroup", inputs: ["class"] }, { kind: "directive", type: InputGroupAddonComponent, selector: "input-group-addon, inputgroupaddon, InputGroupAddon", inputs: ["class", "align"] }, { kind: "component", type: SearchIcon, selector: "SearchIcon", inputs: ["class"] }, { kind: "component", type: FilterIcon, selector: "filter-icon, FilterIcon", inputs: ["class"] }, { kind: "pipe", type: SyslangPipe, name: "syslang" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
8596
8556
  }
8597
8557
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationListComponent, decorators: [{
8598
8558
  type: Component,
@@ -8614,7 +8574,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8614
8574
  AggregationListItemComponent
8615
8575
  ], standalone: true, host: {
8616
8576
  "[class]": 'cn("block h-[inherit] max-h-[inherit]",class())'
8617
- }, template: "@if (aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregation component no longer supports tree aggregations. Please use\r\n the &lt;AggregationTree /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n {{ \"filters.apply\" | transloco }}\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div\r\n class=\"absolute w-full\"\r\n [style.transform]=\"'translateY(' + vItem.start + 'px)'\"\r\n role=\"listitem\">\r\n <AggregationListItem\r\n [node]=\"item\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationItem:has(+AggregationItem){margin-bottom:var(--agg-item-gap, 0)}\n"] }]
8577
+ }, template: "@if (aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregation component no longer supports tree aggregations. Please use\r\n the &lt;AggregationTree /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow truncate\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n {{ \"filters.apply\" | transloco }}\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin max-h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div\r\n class=\"absolute w-full\"\r\n [style.transform]=\"'translateY(' + vItem.start + 'px)'\"\r\n role=\"listitem\">\r\n <AggregationListItem\r\n [node]=\"item\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationItem:has(+AggregationItem){margin-bottom:var(--agg-item-gap, 0)}\n"] }]
8618
8578
  }], ctorParameters: () => [], propDecorators: { scrollElement: [{ type: i0.ViewChild, args: ["scrollElement", { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ["searchInput", { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], showFiltersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFiltersCount", required: false }] }], searchText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchText", required: false }] }, { type: i0.Output, args: ["searchTextChange"] }] } });
8619
8579
 
8620
8580
  class AggregationDateComponent extends AggregationListComponent {
@@ -8814,7 +8774,7 @@ class AggregationDateComponent extends AggregationListComponent {
8814
8774
  }
8815
8775
  }
8816
8776
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationDateComponent, deps: [{ token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component });
8817
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationDateComponent, isStandalone: true, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, displayEmptyDistributionIntervals: { classPropertyName: "displayEmptyDistributionIntervals", publicName: "displayEmptyDistributionIntervals", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], viewQueries: [{ propertyName: "datepicker", first: true, predicate: DateRangePickerDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"custom range\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n #radiorange\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-custom-range\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n\r\n <div\r\n class=\"@container flex grow gap-1 p-1 @max-[340px]:flex-wrap\"\r\n daterangepicker\r\n datepicker-buttons\r\n [datepicker-language]=\"lang()\"\r\n [datepicker-min]=\"form.get('customRange.from')?.value || undefined\"\r\n [datepicker-max]=\"\r\n form.get('customRange.to')?.value ?? today.toISOString()\r\n \"\r\n (click)=\"radiorange.click()\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10\">{{\r\n \"from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-end\" class=\"min-w-10 text-right\">{{\r\n \"to\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: DateRangePickerDirective, selector: "[daterangepicker]", inputs: ["datepicker-title", "datepicker-autohide", "datepicker-clear", "datepicker-today", "datepicker-buttons", "datepicker-today-highlight", "datepicker-language", "datepicker-format", "datepicker-max", "datepicker-min", "datepicker-orientation"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
8777
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationDateComponent, isStandalone: true, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, displayEmptyDistributionIntervals: { classPropertyName: "displayEmptyDistributionIntervals", publicName: "displayEmptyDistributionIntervals", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], viewQueries: [{ propertyName: "datepicker", first: true, predicate: DateRangePickerDirective, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"custom range\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n #radiorange\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-custom-range\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n\r\n <div\r\n class=\"@container flex grow gap-1 p-1 @max-[340px]:flex-wrap\"\r\n daterangepicker\r\n datepicker-buttons\r\n [datepicker-language]=\"lang()\"\r\n [datepicker-min]=\"form.get('customRange.from')?.value || undefined\"\r\n [datepicker-max]=\"\r\n form.get('customRange.to')?.value ?? today.toISOString()\r\n \"\r\n (click)=\"radiorange.click()\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10\">{{\r\n \"from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-end\" class=\"min-w-10 text-right\">{{\r\n \"to\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: DateRangePickerDirective, selector: "[daterangepicker]", inputs: ["datepicker-title", "datepicker-autohide", "datepicker-clear", "datepicker-today", "datepicker-buttons", "datepicker-today-highlight", "datepicker-language", "datepicker-format", "datepicker-max", "datepicker-min", "datepicker-orientation"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
8818
8778
  }
8819
8779
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationDateComponent, decorators: [{
8820
8780
  type: Component,
@@ -8839,7 +8799,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8839
8799
  */
8840
8800
  class DateComponent extends AggregationDateComponent {
8841
8801
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DateComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
8842
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DateComponent, isStandalone: true, selector: "date-filter,DateFilter", host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"custom range\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n #radiorange\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-custom-range\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n\r\n <div\r\n class=\"@container flex grow gap-1 p-1 @max-[340px]:flex-wrap\"\r\n daterangepicker\r\n datepicker-buttons\r\n [datepicker-language]=\"lang()\"\r\n [datepicker-min]=\"form.get('customRange.from')?.value || undefined\"\r\n [datepicker-max]=\"\r\n form.get('customRange.to')?.value ?? today.toISOString()\r\n \"\r\n (click)=\"radiorange.click()\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10\">{{\r\n \"from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-end\" class=\"min-w-10 text-right\">{{\r\n \"to\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: DateRangePickerDirective, selector: "[daterangepicker]", inputs: ["datepicker-title", "datepicker-autohide", "datepicker-clear", "datepicker-today", "datepicker-buttons", "datepicker-today-highlight", "datepicker-language", "datepicker-format", "datepicker-max", "datepicker-min", "datepicker-orientation"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
8802
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DateComponent, isStandalone: true, selector: "date-filter,DateFilter", host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"custom range\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n #radiorange\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-custom-range\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n\r\n <div\r\n class=\"@container flex grow gap-1 p-1 @max-[340px]:flex-wrap\"\r\n daterangepicker\r\n datepicker-buttons\r\n [datepicker-language]=\"lang()\"\r\n [datepicker-min]=\"form.get('customRange.from')?.value || undefined\"\r\n [datepicker-max]=\"\r\n form.get('customRange.to')?.value ?? today.toISOString()\r\n \"\r\n (click)=\"radiorange.click()\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10\">{{\r\n \"from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-end\" class=\"min-w-10 text-right\">{{\r\n \"to\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n class=\"h-8 min-w-[13ch]\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: DateRangePickerDirective, selector: "[daterangepicker]", inputs: ["datepicker-title", "datepicker-autohide", "datepicker-clear", "datepicker-today", "datepicker-buttons", "datepicker-today-highlight", "datepicker-language", "datepicker-format", "datepicker-max", "datepicker-min", "datepicker-orientation"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
8843
8803
  }
8844
8804
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DateComponent, decorators: [{
8845
8805
  type: Component,
@@ -9612,7 +9572,7 @@ class AlertDialog {
9612
9572
  </DialogFooter>
9613
9573
  </DialogContent>
9614
9574
  </dialog>
9615
- `, isInline: true, styles: [".weekdays-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "component", type: LoadingCircleIconComponent, selector: "loading-circle, LoadingCircle, loadingcircle", inputs: ["class"] }, { kind: "component", type: CircleCheckIconComponent, selector: "circle-check, CircleCheck, circlecheck", inputs: ["class"] }, { kind: "directive", type: SelectOptionDirective, selector: "option", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
9575
+ `, isInline: true, styles: [".weekdays-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "component", type: LoadingCircleIconComponent, selector: "loading-circle, LoadingCircle, loadingcircle", inputs: ["class"] }, { kind: "component", type: CircleCheckIconComponent, selector: "circle-check, CircleCheck, circlecheck", inputs: ["class"] }, { kind: "directive", type: SelectOptionDirective, selector: "option", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
9616
9576
  }
9617
9577
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AlertDialog, decorators: [{
9618
9578
  type: Component,
@@ -9825,8 +9785,8 @@ class ChangePasswordComponent {
9825
9785
  if (fromInput?.trim())
9826
9786
  return fromInput.trim();
9827
9787
  if (isAuthenticated()) {
9828
- const p = this.principalStore.principal?.();
9829
- const name = p?.name?.trim();
9788
+ const p = getState(this.principalStore);
9789
+ const name = p.name.trim();
9830
9790
  if (name)
9831
9791
  return name;
9832
9792
  }
@@ -9861,7 +9821,6 @@ class ChangePasswordComponent {
9861
9821
  if (!username) {
9862
9822
  notify.info(this.transloco.translate("login.loginAfterPasswordChangeMissingUser"), { duration: 3000 });
9863
9823
  this.router.navigate(["/login"]);
9864
- this.success.emit();
9865
9824
  return;
9866
9825
  }
9867
9826
  await this.clearLocalAuthState();
@@ -10015,14 +9974,11 @@ class ChangePasswordComponent {
10015
9974
  </button>
10016
9975
  </CardFooter>
10017
9976
  </Card>
10018
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i2.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: CardComponent, selector: ".card, card, Card", inputs: ["class", "variant", "hover"] }, { kind: "directive", type: CardHeaderComponent, selector: ".card-header, card-header, CardHeader, cardheader", inputs: ["class"] }, { kind: "directive", type: CardContentComponent, selector: ".card-content, card-content, CardContent, cardcontent", inputs: ["class"] }, { kind: "directive", type: CardFooterComponent, selector: ".card-footer, card-footer, CardFooter, cardfooter", inputs: ["class"] }, { kind: "directive", type: InputGroupInput, selector: "input[input-group]", inputs: ["class", "type", "placeholder", "disabled"] }, { kind: "directive", type: InputGroupComponent, selector: "input-group, inputgroup, InputGroup", inputs: ["class"] }, { kind: "directive", type: InputGroupAddonComponent, selector: "input-group-addon, inputgroupaddon, InputGroupAddon", inputs: ["class", "align"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
9977
+ `, isInline: true, styles: ["input::-ms-reveal{display:none}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i2.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: CardComponent, selector: ".card, card, Card", inputs: ["class", "variant", "hover"] }, { kind: "directive", type: CardHeaderComponent, selector: ".card-header, card-header, CardHeader, cardheader", inputs: ["class"] }, { kind: "directive", type: CardContentComponent, selector: ".card-content, card-content, CardContent, cardcontent", inputs: ["class"] }, { kind: "directive", type: CardFooterComponent, selector: ".card-footer, card-footer, CardFooter, cardfooter", inputs: ["class"] }, { kind: "directive", type: InputGroupInput, selector: "input[input-group]", inputs: ["class", "type", "placeholder", "disabled"] }, { kind: "directive", type: InputGroupComponent, selector: "input-group, inputgroup, InputGroup", inputs: ["class"] }, { kind: "directive", type: InputGroupAddonComponent, selector: "input-group-addon, inputgroupaddon, InputGroupAddon", inputs: ["class", "align"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10019
9978
  }
10020
9979
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ChangePasswordComponent, decorators: [{
10021
9980
  type: Component,
10022
- args: [{
10023
- selector: "change-password, ChangePassword, changepassword",
10024
- providers: [provideTranslocoScope("login")],
10025
- imports: [
9981
+ args: [{ selector: "change-password, ChangePassword, changepassword", providers: [provideTranslocoScope("login")], imports: [
10026
9982
  FormsModule,
10027
9983
  A11yModule,
10028
9984
  TranslocoPipe,
@@ -10034,8 +9990,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
10034
9990
  InputGroupInput,
10035
9991
  InputGroupComponent,
10036
9992
  InputGroupAddonComponent
10037
- ],
10038
- template: `
9993
+ ], template: `
10039
9994
  <Card hover="no" cdkTrapFocus cdkTrapFocusAutoCapture="true" class="bg-card rounded-xl shadow-sm">
10040
9995
  <CardHeader class="flex flex-col items-center gap-3">
10041
9996
  <img class="h-12 content-(--logo-large)" alt="logo" />
@@ -10143,8 +10098,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
10143
10098
  </button>
10144
10099
  </CardFooter>
10145
10100
  </Card>
10146
- `
10147
- }]
10101
+ `, styles: ["input::-ms-reveal{display:none}\n"] }]
10148
10102
  }], propDecorators: { success: [{ type: i0.Output, args: ["success"] }], cancel: [{ type: i0.Output, args: ["cancel"] }], username: [{ type: i0.Input, args: [{ isSignal: true, alias: "username", required: false }] }], alert: [{ type: i0.Input, args: [{ isSignal: true, alias: "alert", required: false }] }], redirectAfterSuccess: [{ type: i0.Input, args: [{ isSignal: true, alias: "redirectAfterSuccess", required: false }] }], redirectAfterCancel: [{ type: i0.Input, args: [{ isSignal: true, alias: "redirectAfterCancel", required: false }] }], currentPassword: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPassword", required: false }] }, { type: i0.Output, args: ["currentPasswordChange"] }], newPassword: [{ type: i0.Input, args: [{ isSignal: true, alias: "newPassword", required: false }] }, { type: i0.Output, args: ["newPasswordChange"] }], confirmPassword: [{ type: i0.Input, args: [{ isSignal: true, alias: "confirmPassword", required: false }] }, { type: i0.Output, args: ["confirmPasswordChange"] }] } });
10149
10103
 
10150
10104
  class ForgotPasswordComponent {
@@ -10217,7 +10171,7 @@ class ForgotPasswordComponent {
10217
10171
 
10218
10172
  </CardFooter>
10219
10173
  </Card>
10220
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: CardComponent, selector: ".card, card, Card", inputs: ["class", "variant", "hover"] }, { kind: "directive", type: CardHeaderComponent, selector: ".card-header, card-header, CardHeader, cardheader", inputs: ["class"] }, { kind: "directive", type: CardContentComponent, selector: ".card-content, card-content, CardContent, cardcontent", inputs: ["class"] }, { kind: "directive", type: CardFooterComponent, selector: ".card-footer, card-footer, CardFooter, cardfooter", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10174
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: CardComponent, selector: ".card, card, Card", inputs: ["class", "variant", "hover"] }, { kind: "directive", type: CardHeaderComponent, selector: ".card-header, card-header, CardHeader, cardheader", inputs: ["class"] }, { kind: "directive", type: CardContentComponent, selector: ".card-content, card-content, CardContent, cardcontent", inputs: ["class"] }, { kind: "directive", type: CardFooterComponent, selector: ".card-footer, card-footer, CardFooter, cardfooter", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10221
10175
  }
10222
10176
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ForgotPasswordComponent, decorators: [{
10223
10177
  type: Component,
@@ -10292,56 +10246,40 @@ class SignInComponent {
10292
10246
  username: this.username(),
10293
10247
  password: this.password()
10294
10248
  }), ...(ngDevMode ? [{ debugName: "credentials" }] : []));
10295
- isValid = computed(() => !!this.credentials().username?.length && !!this.credentials().password?.length, ...(ngDevMode ? [{ debugName: "isValid" }] : []));
10296
- authenticated = signal(isAuthenticated(), ...(ngDevMode ? [{ debugName: "authenticated" }] : []));
10297
- user = signal(null, ...(ngDevMode ? [{ debugName: "user" }] : []));
10298
- returnUrl = signal(null, ...(ngDevMode ? [{ debugName: "returnUrl" }] : []));
10299
- expiresSoonNotified = signal(false, ...(ngDevMode ? [{ debugName: "expiresSoonNotified" }] : []));
10249
+ isValid = computed(() => !!this.credentials().username?.length &&
10250
+ !!this.credentials().password?.length, ...(ngDevMode ? [{ debugName: "isValid" }] : []));
10300
10251
  router = inject(Router);
10301
10252
  route = inject(ActivatedRoute);
10302
- principalService = inject(PrincipalService);
10303
10253
  applicationService = inject(ApplicationService);
10304
10254
  principalStore = inject(PrincipalStore);
10305
10255
  transloco = inject(TranslocoService);
10256
+ authenticated = signal(isAuthenticated(), ...(ngDevMode ? [{ debugName: "authenticated" }] : []));
10257
+ user = signal(getState(this.principalStore), ...(ngDevMode ? [{ debugName: "user" }] : []));
10258
+ expiresSoonNotified = signal(false, ...(ngDevMode ? [{ debugName: "expiresSoonNotified" }] : []));
10306
10259
  constructor(destroyRef) {
10307
10260
  this.destroyRef = destroyRef;
10308
10261
  effect(() => {
10309
- if (this.authenticated()) {
10310
- this.principalService
10311
- .getPrincipal()
10312
- .pipe(takeUntilDestroyed(this.destroyRef))
10313
- .subscribe((principal) => this.user.set(principal));
10314
- }
10315
- });
10316
- effect(() => {
10317
- const principal = this.user();
10262
+ const principal = getState(this.principalStore);
10318
10263
  if (this.authenticated() && principal && !this.expiresSoonNotified()) {
10319
- this.checkPasswordExpiresSoon(principal);
10320
- }
10321
- });
10322
- effect(() => {
10323
- if (this.returnUrl() !== null) {
10324
- const [url] = this.returnUrl() || ["/"];
10325
- this.router.navigateByUrl(url);
10264
+ this.checkPasswordExpiresSoon();
10326
10265
  }
10327
10266
  });
10328
10267
  fromEvent(window, "authenticated")
10329
10268
  .pipe(takeUntilDestroyed(this.destroyRef))
10330
- .subscribe((event) => {
10269
+ .subscribe(event => {
10331
10270
  this.authenticated.set(event.detail.authenticated);
10332
10271
  const url = this.route.snapshot.queryParams["returnUrl"] || null;
10333
- if (url !== null)
10334
- this.returnUrl.set([url]);
10335
- if (isAuthenticated()) {
10272
+ if (url !== null) {
10336
10273
  this.router.navigateByUrl(url ?? "/");
10337
10274
  }
10338
10275
  });
10339
10276
  }
10340
- checkPasswordExpiresSoon(principal) {
10341
- if (!principal?.editablePartition || !principal.passwordExpirationDate) {
10277
+ checkPasswordExpiresSoon() {
10278
+ const { editablePartition, passwordExpirationDate } = getState(this.principalStore);
10279
+ if (!editablePartition || !passwordExpirationDate) {
10342
10280
  return;
10343
10281
  }
10344
- if (expiresSoon(principal.passwordExpirationDate, 7)) {
10282
+ if (expiresSoon(passwordExpirationDate, 7)) {
10345
10283
  notify.warning(this.transloco.translate("login.passwordExpiresSoon"), {
10346
10284
  duration: Number.POSITIVE_INFINITY,
10347
10285
  action: {
@@ -10362,12 +10300,10 @@ class SignInComponent {
10362
10300
  async handleLogout() {
10363
10301
  await logout();
10364
10302
  this.authenticated.set(false);
10365
- this.user.set(null);
10366
- this.returnUrl.set(null);
10367
10303
  this.router.navigate(["/login"]);
10368
10304
  }
10369
10305
  async handleLogin() {
10370
- login().catch((error) => {
10306
+ login().catch(error => {
10371
10307
  warn("An error occurred while logging in", error);
10372
10308
  this.router.navigate(["error"]);
10373
10309
  });
@@ -10381,14 +10317,14 @@ class SignInComponent {
10381
10317
  return;
10382
10318
  const { createRoutes = false } = globalConfig;
10383
10319
  await this.applicationService.initialize(createRoutes);
10384
- const p = this.principalStore.principal?.();
10385
- this.checkPasswordExpiresSoon(p ?? null);
10320
+ this.checkPasswordExpiresSoon();
10386
10321
  const url = this.route.snapshot.queryParams["returnUrl"] || "/";
10387
10322
  this.router.navigateByUrl(url);
10388
10323
  }
10389
10324
  catch (err) {
10390
10325
  const { status, errorMessage } = err;
10391
- if (status === 401 && errorMessage?.toLowerCase().includes("password expired")) {
10326
+ if (status === 401 &&
10327
+ errorMessage?.toLowerCase().includes("password expired")) {
10392
10328
  sessionStorage.setItem("passwordExpiredFlow", "true");
10393
10329
  this.router.navigate(["/login"], {
10394
10330
  queryParams: {
@@ -10404,91 +10340,79 @@ class SignInComponent {
10404
10340
  }
10405
10341
  handleBack() {
10406
10342
  this.authenticated.set(false);
10407
- this.user.set(null);
10408
- this.returnUrl.set(null);
10409
10343
  this.router.navigate(["/"]);
10410
10344
  }
10411
10345
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SignInComponent, deps: [{ token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component });
10412
10346
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: SignInComponent, isStandalone: true, selector: "signIn, signin, sign-in", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, username: { classPropertyName: "username", publicName: "username", isSignal: true, isRequired: false, transformFunction: null }, password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { forgotPassword: "forgotPassword", username: "usernameChange", password: "passwordChange" }, host: { properties: { "class": "cn('grid h-dvh w-full place-content-center', class())" } }, providers: [provideTranslocoScope("login")], ngImport: i0, template: `
10413
- <Card
10414
- hover="no"
10415
- cdkTrapFocus
10416
- cdkTrapFocusAutoCapture="true"
10417
- class="bg-card rounded-xl shadow-sm"
10418
- >
10419
- @if (authenticated()) {
10420
- <CardHeader class="flex flex-row items-start gap-4">
10421
- <img class="content-(--logo-large) h-12" alt="logo" />
10422
- <div class="space-y-1">
10423
- <h3 class="text-2xl font-semibold leading-tight">
10424
- {{
10425
- 'login.welcomeBack' | transloco : { name: user()?.fullName ?? '' }
10426
- }}
10427
- </h3>
10428
- <p class="text-muted-foreground text-sm">
10429
- {{ 'login.youAreLoggedIn' | transloco }}
10430
- </p>
10431
- </div>
10432
- </CardHeader>
10433
-
10434
- <CardFooter class="grid grid-cols-2 gap-3">
10435
- <button type="button" (click)="handleLogout()">
10436
- {{ 'login.disconnect' | transloco }}
10437
- </button>
10438
- <button type="button" (click)="handleBack()">{{ 'login.back' | transloco }}</button>
10439
- </CardFooter>
10440
- } @else {
10441
- <CardHeader class="flex flex-col items-center gap-3 text-center">
10442
- <img class="content-(--logo-large) h-12" alt="logo" />
10443
- </CardHeader>
10444
-
10445
- <CardContent class="grid gap-4">
10446
- @if (!config.autoOAuthProvider && !config.autoSAMLProvider) {
10447
- <div class="grid gap-2">
10448
- <label class="text-sm font-medium" for="username">{{
10449
- 'login.username' | transloco
10450
- }}</label>
10451
- <input
10452
- id="username"
10453
- type="text"
10454
- required
10455
- [(ngModel)]="username"
10456
- (keydown.enter)="handleLoginWithCredentials()"
10457
- />
10458
- </div>
10347
+ @if (!authenticated()) {
10348
+ <Card
10349
+ hover="no"
10350
+ cdkTrapFocus
10351
+ cdkTrapFocusAutoCapture="true"
10352
+ class="bg-card rounded-xl shadow-sm">
10353
+ <CardHeader class="flex flex-col items-center gap-3 text-center">
10354
+ <img class="h-12 content-(--logo-large)" alt="logo" />
10355
+ </CardHeader>
10356
+
10357
+ <CardContent class="grid gap-4">
10358
+ @let useCredentials =
10359
+ !config.autoOAuthProvider && !config.autoSAMLProvider;
10360
+ @if (useCredentials) {
10361
+ <!-- authentication using credentials -->
10362
+ <div class="grid gap-2">
10363
+ <label class="text-sm font-medium" for="username">{{
10364
+ "login.username" | transloco
10365
+ }}</label>
10366
+ <input
10367
+ id="username"
10368
+ type="text"
10369
+ required
10370
+ [(ngModel)]="username"
10371
+ (keydown.enter)="handleLoginWithCredentials()" />
10372
+ </div>
10459
10373
 
10460
10374
  <div class="grid gap-2">
10461
- <label class="text-sm font-medium" for="password">{{ 'login.password' | transloco }}</label>
10462
- <input id="password" type="password" required [(ngModel)]="password" (keydown.enter)="handleLoginWithCredentials()" />
10375
+ <label class="text-sm font-medium" for="password">{{
10376
+ "login.password" | transloco
10377
+ }}</label>
10378
+ <input
10379
+ id="password"
10380
+ type="password"
10381
+ required
10382
+ [(ngModel)]="password"
10383
+ (keydown.enter)="handleLoginWithCredentials()" />
10463
10384
  </div>
10464
10385
 
10465
- <span
10466
- class="cursor-pointer text-xs text-muted-foreground hover:underline justify-self-start"
10467
- role="button"
10468
- tabindex="0"
10386
+ <span
10387
+ class="text-muted-foreground cursor-pointer justify-self-start text-xs hover:underline"
10388
+ role="button"
10389
+ tabindex="0"
10469
10390
  (click)="forgotPassword.emit()"
10470
- (keydown.enter)="forgotPassword.emit()">
10471
- {{ 'login.forgotPassword' | transloco }}
10472
- </span>
10473
- <button [disabled]="!isValid()" (click)="handleLoginWithCredentials()">
10474
- {{ 'login.connect' | transloco }}
10391
+ (keydown.enter)="forgotPassword.emit()">
10392
+ {{ "login.forgotPassword" | transloco }}
10393
+ </span>
10394
+ <button
10395
+ [disabled]="!isValid()"
10396
+ (click)="handleLoginWithCredentials()">
10397
+ {{ "login.connect" | transloco }}
10475
10398
  </button>
10476
-
10477
- } @else {
10399
+ }
10400
+ @else {
10401
+ <!-- authentication using OAuth or SAML provider -->
10478
10402
  <button (click)="handleLogin()">
10479
- {{ 'login.SignInWith' | transloco: { provider: config.autoOAuthProvider ? 'OAuth' : 'SAML' } }}
10403
+ {{ "login.SignInWith" | transloco : { provider: config.autoOAuthProvider ? "OAuth" : "SAML" } }}
10480
10404
  </button>
10481
10405
  }
10482
10406
  </CardContent>
10483
- }
10484
- </Card>
10485
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i2.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: CardComponent, selector: ".card, card, Card", inputs: ["class", "variant", "hover"] }, { kind: "directive", type: CardHeaderComponent, selector: ".card-header, card-header, CardHeader, cardheader", inputs: ["class"] }, { kind: "directive", type: CardContentComponent, selector: ".card-content, card-content, CardContent, cardcontent", inputs: ["class"] }, { kind: "directive", type: CardFooterComponent, selector: ".card-footer, card-footer, CardFooter, cardfooter", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10407
+ </Card>
10408
+ } @else {
10409
+ <app-wait />
10410
+ }
10411
+ `, isInline: true, styles: ["input{background-color:var(--background)}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i2.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: CardComponent, selector: ".card, card, Card", inputs: ["class", "variant", "hover"] }, { kind: "directive", type: CardHeaderComponent, selector: ".card-header, card-header, CardHeader, cardheader", inputs: ["class"] }, { kind: "directive", type: CardContentComponent, selector: ".card-content, card-content, CardContent, cardcontent", inputs: ["class"] }, { kind: "component", type: LoadingComponent, selector: "app-wait" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10486
10412
  }
10487
10413
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SignInComponent, decorators: [{
10488
10414
  type: Component,
10489
- args: [{
10490
- selector: "signIn, signin, sign-in",
10491
- imports: [
10415
+ args: [{ selector: "signIn, signin, sign-in", imports: [
10492
10416
  RouterModule,
10493
10417
  FormsModule,
10494
10418
  A11yModule,
@@ -10498,87 +10422,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
10498
10422
  CardComponent,
10499
10423
  CardHeaderComponent,
10500
10424
  CardContentComponent,
10501
- CardFooterComponent
10502
- ],
10503
- providers: [provideTranslocoScope("login")],
10504
- template: `
10505
- <Card
10506
- hover="no"
10507
- cdkTrapFocus
10508
- cdkTrapFocusAutoCapture="true"
10509
- class="bg-card rounded-xl shadow-sm"
10510
- >
10511
- @if (authenticated()) {
10512
- <CardHeader class="flex flex-row items-start gap-4">
10513
- <img class="content-(--logo-large) h-12" alt="logo" />
10514
- <div class="space-y-1">
10515
- <h3 class="text-2xl font-semibold leading-tight">
10516
- {{
10517
- 'login.welcomeBack' | transloco : { name: user()?.fullName ?? '' }
10518
- }}
10519
- </h3>
10520
- <p class="text-muted-foreground text-sm">
10521
- {{ 'login.youAreLoggedIn' | transloco }}
10522
- </p>
10523
- </div>
10524
- </CardHeader>
10525
-
10526
- <CardFooter class="grid grid-cols-2 gap-3">
10527
- <button type="button" (click)="handleLogout()">
10528
- {{ 'login.disconnect' | transloco }}
10529
- </button>
10530
- <button type="button" (click)="handleBack()">{{ 'login.back' | transloco }}</button>
10531
- </CardFooter>
10532
- } @else {
10533
- <CardHeader class="flex flex-col items-center gap-3 text-center">
10534
- <img class="content-(--logo-large) h-12" alt="logo" />
10535
- </CardHeader>
10536
-
10537
- <CardContent class="grid gap-4">
10538
- @if (!config.autoOAuthProvider && !config.autoSAMLProvider) {
10539
- <div class="grid gap-2">
10540
- <label class="text-sm font-medium" for="username">{{
10541
- 'login.username' | transloco
10542
- }}</label>
10543
- <input
10544
- id="username"
10545
- type="text"
10546
- required
10547
- [(ngModel)]="username"
10548
- (keydown.enter)="handleLoginWithCredentials()"
10549
- />
10550
- </div>
10425
+ LoadingComponent
10426
+ ], providers: [provideTranslocoScope("login")], template: `
10427
+ @if (!authenticated()) {
10428
+ <Card
10429
+ hover="no"
10430
+ cdkTrapFocus
10431
+ cdkTrapFocusAutoCapture="true"
10432
+ class="bg-card rounded-xl shadow-sm">
10433
+ <CardHeader class="flex flex-col items-center gap-3 text-center">
10434
+ <img class="h-12 content-(--logo-large)" alt="logo" />
10435
+ </CardHeader>
10436
+
10437
+ <CardContent class="grid gap-4">
10438
+ @let useCredentials =
10439
+ !config.autoOAuthProvider && !config.autoSAMLProvider;
10440
+ @if (useCredentials) {
10441
+ <!-- authentication using credentials -->
10442
+ <div class="grid gap-2">
10443
+ <label class="text-sm font-medium" for="username">{{
10444
+ "login.username" | transloco
10445
+ }}</label>
10446
+ <input
10447
+ id="username"
10448
+ type="text"
10449
+ required
10450
+ [(ngModel)]="username"
10451
+ (keydown.enter)="handleLoginWithCredentials()" />
10452
+ </div>
10551
10453
 
10552
10454
  <div class="grid gap-2">
10553
- <label class="text-sm font-medium" for="password">{{ 'login.password' | transloco }}</label>
10554
- <input id="password" type="password" required [(ngModel)]="password" (keydown.enter)="handleLoginWithCredentials()" />
10455
+ <label class="text-sm font-medium" for="password">{{
10456
+ "login.password" | transloco
10457
+ }}</label>
10458
+ <input
10459
+ id="password"
10460
+ type="password"
10461
+ required
10462
+ [(ngModel)]="password"
10463
+ (keydown.enter)="handleLoginWithCredentials()" />
10555
10464
  </div>
10556
10465
 
10557
- <span
10558
- class="cursor-pointer text-xs text-muted-foreground hover:underline justify-self-start"
10559
- role="button"
10560
- tabindex="0"
10466
+ <span
10467
+ class="text-muted-foreground cursor-pointer justify-self-start text-xs hover:underline"
10468
+ role="button"
10469
+ tabindex="0"
10561
10470
  (click)="forgotPassword.emit()"
10562
- (keydown.enter)="forgotPassword.emit()">
10563
- {{ 'login.forgotPassword' | transloco }}
10564
- </span>
10565
- <button [disabled]="!isValid()" (click)="handleLoginWithCredentials()">
10566
- {{ 'login.connect' | transloco }}
10471
+ (keydown.enter)="forgotPassword.emit()">
10472
+ {{ "login.forgotPassword" | transloco }}
10473
+ </span>
10474
+ <button
10475
+ [disabled]="!isValid()"
10476
+ (click)="handleLoginWithCredentials()">
10477
+ {{ "login.connect" | transloco }}
10567
10478
  </button>
10568
-
10569
- } @else {
10479
+ }
10480
+ @else {
10481
+ <!-- authentication using OAuth or SAML provider -->
10570
10482
  <button (click)="handleLogin()">
10571
- {{ 'login.SignInWith' | transloco: { provider: config.autoOAuthProvider ? 'OAuth' : 'SAML' } }}
10483
+ {{ "login.SignInWith" | transloco : { provider: config.autoOAuthProvider ? "OAuth" : "SAML" } }}
10572
10484
  </button>
10573
10485
  }
10574
10486
  </CardContent>
10575
- }
10576
- </Card>
10577
- `,
10578
- host: {
10487
+ </Card>
10488
+ } @else {
10489
+ <app-wait />
10490
+ }
10491
+ `, host: {
10579
10492
  "[class]": "cn('grid h-dvh w-full place-content-center', class())"
10580
- }
10581
- }]
10493
+ }, styles: ["input{background-color:var(--background)}\n"] }]
10582
10494
  }], ctorParameters: () => [{ type: i0.DestroyRef }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], forgotPassword: [{ type: i0.Output, args: ["forgotPassword"] }], username: [{ type: i0.Input, args: [{ isSignal: true, alias: "username", required: false }] }, { type: i0.Output, args: ["usernameChange"] }], password: [{ type: i0.Input, args: [{ isSignal: true, alias: "password", required: false }] }, { type: i0.Output, args: ["passwordChange"] }] } });
10583
10495
 
10584
10496
  class AuthPageComponent {
@@ -10994,7 +10906,6 @@ class OverrideUserDialogComponent {
10994
10906
  })
10995
10907
  .catch((err) => {
10996
10908
  error("An error occured while overriding (initialize)", err);
10997
- notify.error("An error occured while overriding (initialize)", { duration: 2000 });
10998
10909
  setGlobalConfig({ userOverrideActive: false, userOverride: undefined });
10999
10910
  });
11000
10911
  }
@@ -11053,7 +10964,7 @@ class OverrideUserDialogComponent {
11053
10964
  </DialogFooter>
11054
10965
  </DialogContent>
11055
10966
  </dialog>
11056
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10967
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
11057
10968
  }
11058
10969
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: OverrideUserDialogComponent, decorators: [{
11059
10970
  type: Component,
@@ -11789,7 +11700,7 @@ class DrawerAdvancedFiltersComponent extends DrawerComponent {
11789
11700
  return res;
11790
11701
  }
11791
11702
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DrawerAdvancedFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11792
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DrawerAdvancedFiltersComponent, isStandalone: true, selector: "advanced-filters", host: { classAttribute: "fixed bg-background grid h-full top-0 -right-full justify-end" }, providers: [DrawerService, SyslangPipe, TranslocoPipe, provideTranslocoScope("drawers")], usesInheritance: true, ngImport: i0, template: "<div (click)=\"drawer.toggleExtension()\" (keydown.escape)=\"drawer.toggleExtension()\" [attr.aria-hidden]=\"true\"></div>\n\n<div class=\"flex h-full flex-col overflow-auto\">\n <DrawerNavbar class=\"border-foreground/10 block border-b\">\n <button [attr.title]=\"'drawers.search' | transloco\" (click)=\"onSearch()\">\n {{ 'drawers.search' | transloco }}\n </button>\n </DrawerNavbar>\n\n <div class=\"flex h-full grow flex-col overflow-auto\">\n <section class=\"flex flex-col gap-4 p-6\" [formGroup]=\"form\">\n <!-- FIND IN -->\n <h1 class=\"text-xl font-bold\">{{ 'drawers.findInContent' | transloco }}</h1>\n <div class=\"flex items-center gap-4\" formGroupName=\"content\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInContent' | transloco }}</span>\n <select\n id=\"content-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input\n [variant]=\"inputVariant()\"\n id=\"content-value\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"getPlaceholder('content.operator')\"\n formControlName=\"value\" />\n </div>\n @if (enableFieldedSearch()) {\n <div class=\"flex items-center gap-4\" formGroupName=\"title\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInTitle' | transloco }}</span>\n <select\n id=\"title-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input id=\"title-value\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" [placeholder]=\"getPlaceholder('title.operator')\" formControlName=\"value\" />\n </div>\n }\n\n <!-- TABS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.inScope' | transloco }}&nbsp;&quot;{{ currentTab() }}&quot;</h1>\n\n <Tabs>\n <TabsList variant=\"ghost\">\n @for (tab of tabs(); track $index) {\n <Tab class=\"w-fit\" [value]=\"tab.path\" [active]=\"tab.path === currentTab()\" (click)=\"onTabChange(tab.path)\">\n {{ tab.display | syslang | transloco }}\n </Tab>\n }\n </TabsList>\n </Tabs>\n\n <!-- FILTERS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.applyFilters' | transloco }}</h1>\n @for (filter of filters(); track $index) {\n <DropdownInput\n [suggestions]=\"suggestions()\"\n [selected]=\"getItems(filter.column)\"\n [label]=\"filter.display || filter.alias | syslang | transloco\"\n [placeholder]=\"'drawers.startTyping' | transloco\"\n [noResultLabel]=\"'drawers.noResult' | transloco\"\n (onFocus)=\"setFilterFocus($event, filter)\"\n (onKeyUp)=\"onInputTyping($event)\"\n (removeItem)=\"removeItem($event, filter)\"\n (addItem)=\"addItem($event, filter)\" />\n } @empty {\n {{ 'drawers.noFilters' | transloco }}\n }\n </section>\n </div>\n</div>\n", styles: [":host{--drawer-width: 46;--drawer-subdrawer-width: 400px;width:calc(100vw / 100 * var(--drawer-width) + var(--drawer-subdrawer-width));z-index:var(--z-drawer);grid-template-columns:0 1fr var(--drawer-subdrawer-width);transition:right .3s ease-in-out,transform .3s ease-in-out}:host[drawer-opened=true]{right:calc(var(--drawer-subdrawer-width) * -1);box-shadow:var(--drawer-box-shadow)}:host[drawer-extended=true]{width:100vw;right:calc(var(--spacing) * 0);grid-template-columns:1fr calc(var(--drawer-width) * 1%) var(--drawer-subdrawer-width);box-shadow:unset}:is() .dropdown{width:100%}:is() .dropdown-content{width:50%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: DrawerNavbarComponent, selector: "DrawerNavbar, drawernavbar" }, { kind: "component", type: DropdownInputComponent, selector: "dropdown-input, DropdownInput", inputs: ["label", "placeholder", "noResultLabel", "suggestions", "selected"], outputs: ["onFocus", "onKeyUp", "removeItem", "addItem"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: TabsComponent, selector: "tabs, Tabs", inputs: ["class"] }, { kind: "directive", type: TabComponent, selector: "tab, Tab", inputs: ["class", "variant", "size", "value", "active"], outputs: ["clicked"] }, { kind: "directive", type: TabsListComponent, selector: "tabs-list, TabsList", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
11703
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DrawerAdvancedFiltersComponent, isStandalone: true, selector: "advanced-filters", host: { classAttribute: "fixed bg-background grid h-full top-0 -right-full justify-end" }, providers: [DrawerService, SyslangPipe, TranslocoPipe, provideTranslocoScope("drawers")], usesInheritance: true, ngImport: i0, template: "<div (click)=\"drawer.toggleExtension()\" (keydown.escape)=\"drawer.toggleExtension()\" [attr.aria-hidden]=\"true\"></div>\n\n<div class=\"flex h-full flex-col overflow-auto\">\n <DrawerNavbar class=\"border-foreground/10 block border-b\">\n <button [attr.title]=\"'drawers.search' | transloco\" (click)=\"onSearch()\">\n {{ 'drawers.search' | transloco }}\n </button>\n </DrawerNavbar>\n\n <div class=\"flex h-full grow flex-col overflow-auto\">\n <section class=\"flex flex-col gap-4 p-6\" [formGroup]=\"form\">\n <!-- FIND IN -->\n <h1 class=\"text-xl font-bold\">{{ 'drawers.findInContent' | transloco }}</h1>\n <div class=\"flex items-center gap-4\" formGroupName=\"content\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInContent' | transloco }}</span>\n <select\n id=\"content-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input\n [variant]=\"inputVariant()\"\n id=\"content-value\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [placeholder]=\"getPlaceholder('content.operator')\"\n formControlName=\"value\" />\n </div>\n @if (enableFieldedSearch()) {\n <div class=\"flex items-center gap-4\" formGroupName=\"title\">\n <span class=\"w-1/3 font-semibold\">{{ 'drawers.findInTitle' | transloco }}</span>\n <select\n id=\"title-operator\"\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 w-full rounded-md border px-2 hover:outline focus:outline\"\n formControlName=\"operator\">\n @for (data of selectData; track $index) {\n <option [value]=\"data.operator\">{{ 'drawers.' + data.display | transloco }}</option>\n }\n </select>\n <input id=\"title-value\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" [placeholder]=\"getPlaceholder('title.operator')\" formControlName=\"value\" />\n </div>\n }\n\n <!-- TABS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.inScope' | transloco }}&nbsp;&quot;{{ currentTab() }}&quot;</h1>\n\n <Tabs>\n <TabsList variant=\"ghost\">\n @for (tab of tabs(); track $index) {\n <Tab class=\"w-fit\" [value]=\"tab.path\" [active]=\"tab.path === currentTab()\" (click)=\"onTabChange(tab.path)\">\n {{ tab.display | syslang | transloco }}\n </Tab>\n }\n </TabsList>\n </Tabs>\n\n <!-- FILTERS -->\n <h1 class=\"mt-4 text-xl font-bold\">{{ 'drawers.applyFilters' | transloco }}</h1>\n @for (filter of filters(); track $index) {\n <DropdownInput\n [suggestions]=\"suggestions()\"\n [selected]=\"getItems(filter.column)\"\n [label]=\"filter.display || filter.alias | syslang | transloco\"\n [placeholder]=\"'drawers.startTyping' | transloco\"\n [noResultLabel]=\"'drawers.noResult' | transloco\"\n (onFocus)=\"setFilterFocus($event, filter)\"\n (onKeyUp)=\"onInputTyping($event)\"\n (removeItem)=\"removeItem($event, filter)\"\n (addItem)=\"addItem($event, filter)\" />\n } @empty {\n {{ 'drawers.noFilters' | transloco }}\n }\n </section>\n </div>\n</div>\n", styles: [":host{--drawer-width: 46;--drawer-subdrawer-width: 400px;width:calc(100vw / 100 * var(--drawer-width) + var(--drawer-subdrawer-width));z-index:var(--z-drawer);grid-template-columns:0 1fr var(--drawer-subdrawer-width);transition:right .3s ease-in-out,transform .3s ease-in-out}:host[drawer-opened=true]{right:calc(var(--drawer-subdrawer-width) * -1);box-shadow:var(--drawer-box-shadow)}:host[drawer-extended=true]{width:100vw;right:calc(var(--spacing) * 0);grid-template-columns:1fr calc(var(--drawer-width) * 1%) var(--drawer-subdrawer-width);box-shadow:unset}:is() .dropdown{width:100%}:is() .dropdown-content{width:50%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: DrawerNavbarComponent, selector: "DrawerNavbar, drawernavbar" }, { kind: "component", type: DropdownInputComponent, selector: "dropdown-input, DropdownInput", inputs: ["label", "placeholder", "noResultLabel", "suggestions", "selected"], outputs: ["onFocus", "onKeyUp", "removeItem", "addItem"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: TabsComponent, selector: "tabs, Tabs", inputs: ["class"] }, { kind: "directive", type: TabComponent, selector: "tab, Tab", inputs: ["class", "variant", "size", "value", "active"], outputs: ["clicked"] }, { kind: "directive", type: TabsListComponent, selector: "tabs-list, TabsList", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
11793
11704
  }
11794
11705
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DrawerAdvancedFiltersComponent, decorators: [{
11795
11706
  type: Component,
@@ -12770,10 +12681,9 @@ class AggregationTreeItemComponent {
12770
12681
  }
12771
12682
  }
12772
12683
  onChildSelect(item) {
12773
- this.onSelect.emit(undefined);
12774
12684
  // if some items are selected visually, this means all these items got selected visually and if one
12775
12685
  // got changed we need to change their selection status
12776
- if (item && this.linkChildren() && this.node().items.some((i) => i.$selectedVisually)) {
12686
+ if (item && this.linkChildren() && !item.$selected && this.node().items.some((i) => i.$selectedVisually)) {
12777
12687
  this.node().items.forEach((i) => {
12778
12688
  if (i !== item) {
12779
12689
  i.$selectedVisually = false;
@@ -12785,6 +12695,7 @@ class AggregationTreeItemComponent {
12785
12695
  this.node().$selected = false;
12786
12696
  this.node().$selectedVisually = false;
12787
12697
  }
12698
+ this.onSelect.emit(this.node());
12788
12699
  }
12789
12700
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationTreeItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12790
12701
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationTreeItemComponent, isStandalone: true, selector: "aggregation-tree-item, AggregationTreeItem, aggregationtreeitem", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, path: { classPropertyName: "path", publicName: "path", isSignal: true, isRequired: true, transformFunction: null }, field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect", onOpen: "onOpen", onFilter: "onFilter" }, host: { properties: { "attr.disabled": "this.disabled" } }, ngImport: i0, template: "<a\r\n role=\"listitem\"\r\n [attr.aria-selected]=\"node().$selected || node().$selectedVisually\"\r\n [attr.aria-label]=\"name() | syslang\"\r\n [style.--level]=\"level()\"\r\n [class]=\"\r\n cn(\r\n 'flex grow items-center gap-2 p-1 leading-7',\r\n node().count === 0 && 'disabled pointer-events-none text-neutral-300',\r\n (node().$selected || node().$selectedVisually) &&\r\n 'bg-primary-100 text-primary dark:text-primary-foreground'\r\n )\r\n \"\r\n (click)=\"select(node(), $event, true)\">\r\n <!-- chrevron is visible only if the node has children -->\r\n <button\r\n (click)=\"open($event, node())\"\r\n class=\"transition-transform ease-in hover:scale-125\"\r\n aria-label=\"Open\">\r\n <ChevronRight\r\n [class]=\"\r\n cn(\r\n 'size-4 translate-x-1',\r\n node().$opened && 'rotate-90',\r\n !node().hasChildren && 'hidden'\r\n )\r\n \"\r\n width=\"16\"\r\n height=\"16\" />\r\n </button>\r\n\r\n <input\r\n type=\"checkbox\"\r\n role=\"checkbox\"\r\n value=\"{{ node().value }}\"\r\n [attr.disabled]=\"node().count === 0 ? true : null\"\r\n [attr.aria-disabled]=\"node().count === 0\"\r\n (keydown.enter)=\"select(node(), $event)\"\r\n [checked]=\"node().$selected || node().$selectedVisually\" />\r\n\r\n @if (node().icon) {\r\n <i\r\n class=\"fa-fw {{ node().icon }} self-center justify-self-center\"\r\n aria-hidden=\"true\"></i>\r\n }\r\n <span\r\n [class]=\"\r\n cn(\r\n 'line-clamp-1 break-all text-ellipsis',\r\n quickFilter() && 'hover:underline'\r\n )\r\n \"\r\n [title]=\"\r\n quickFilter()\r\n ? ((isFiltered() ? 'filters.removeFilter' : 'filters.addFilter')\r\n | transloco) +\r\n ': ' +\r\n (name() | syslang)\r\n : (name() | syslang)\r\n \"\r\n (click)=\"onTextClick($event)\">\r\n @for (\r\n chunk of (name() | syslang) ?? \"\" | highlightWord: searchText() : 10;\r\n track $index\r\n ) {\r\n <span [class]=\"{ 'font-bold': chunk.match }\" aria-hidden=\"true\">{{\r\n chunk.text\r\n }}</span>\r\n }\r\n </span>\r\n @if (showCount() && node().count > 0) {\r\n <span class=\"ml-auto px-1 text-xs empty:hidden\" aria-hidden=\"true\">{{\r\n node().count\r\n }}</span>\r\n }\r\n</a>\r\n\r\n@if (node().hasChildren && node().$opened) {\r\n @for (item of node().items; track $index) {\r\n <AggregationTreeItem\r\n [node]=\"item\"\r\n [path]=\"childrenPath()\"\r\n [field]=\"field()\"\r\n (onOpen)=\"onOpen.emit($event)\"\r\n (onFilter)=\"onFilter.emit()\"\r\n (onSelect)=\"onChildSelect($event)\" />\r\n }\r\n}\r\n", styles: [":host{display:block;-webkit-user-select:none;user-select:none}:host a{padding-left:calc((var(--agg-tree-indent, .5rem) * var(--level)))}a{line-height:var(--agg-item-height, inherit)}\n"], dependencies: [{ kind: "component", type: AggregationTreeItemComponent, selector: "aggregation-tree-item, AggregationTreeItem, aggregationtreeitem", inputs: ["node", "path", "field"], outputs: ["onSelect", "onOpen", "onFilter"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "pipe", type: HighlightWordPipe, name: "highlightWord" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
@@ -12826,6 +12737,7 @@ class AggregationTreeComponent {
12826
12737
  id = input(null, ...(ngDevMode ? [{ debugName: "id" }] : []));
12827
12738
  name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
12828
12739
  column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
12740
+ expandedLevel = input(undefined, ...(ngDevMode ? [{ debugName: "expandedLevel", transform: numberAttribute }] : [{ transform: numberAttribute }]));
12829
12741
  onSelect = output();
12830
12742
  /**
12831
12743
  * Determines whether the aggregation component can be collapsed or expanded.
@@ -12881,6 +12793,9 @@ class AggregationTreeComponent {
12881
12793
  if (!agg.isTree) {
12882
12794
  error("The aggregation tree component does not support list aggregations. Please use the <Aggregation /> component instead.");
12883
12795
  }
12796
+ // overrides "expandedLevel" from custom JSON file
12797
+ const expandedLevel = this.expandedLevel() ?? agg.expandedLevel ?? 0;
12798
+ this.expandItems(agg.items, expandedLevel);
12884
12799
  // overrides "searchable" properties with the input if any
12885
12800
  agg.searchable = this.searchable() ?? agg.searchable;
12886
12801
  return agg;
@@ -13359,8 +13274,58 @@ class AggregationTreeComponent {
13359
13274
  const e = event;
13360
13275
  this.isCollapsed.set(e.newState === "closed");
13361
13276
  }
13277
+ expandItems(items, expandedLevel) {
13278
+ this.traverse(items, (lineage, node, level) => {
13279
+ if (!node.$opened && node.items?.length >= 0 && level < expandedLevel) {
13280
+ node.$opened = true;
13281
+ }
13282
+ if (node.$opened && level >= expandedLevel) {
13283
+ node.$opened = false;
13284
+ }
13285
+ return false;
13286
+ });
13287
+ }
13288
+ /**
13289
+ * Traverses a tree structure, executing a callback function at every node
13290
+ * @param nodes the nodes to traverse
13291
+ * @param callback the callback function
13292
+ */
13293
+ traverse(nodes, callback) {
13294
+ if (!nodes || nodes.length === 0) {
13295
+ return false;
13296
+ }
13297
+ if (!callback) {
13298
+ return false;
13299
+ }
13300
+ const lineage = [];
13301
+ const stack = [];
13302
+ let _i = nodes.length;
13303
+ while (_i--) {
13304
+ stack.push(nodes[_i]);
13305
+ }
13306
+ while (stack.length) {
13307
+ const node = stack.pop();
13308
+ if (!node) {
13309
+ lineage.pop();
13310
+ }
13311
+ else {
13312
+ lineage.push(node);
13313
+ if (callback(lineage, node, lineage.length - 1)) {
13314
+ return true;
13315
+ }
13316
+ stack.push(undefined);
13317
+ if (node.items && node.items.length > 0) {
13318
+ _i = node.items.length;
13319
+ while (_i--) {
13320
+ stack.push(node.items[_i]);
13321
+ }
13322
+ }
13323
+ }
13324
+ }
13325
+ return false;
13326
+ }
13362
13327
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13363
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationTreeComponent, isStandalone: true, selector: "AggregationTree, aggregation-tree, aggregationtree", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, showFiltersCount: { classPropertyName: "showFiltersCount", publicName: "showFiltersCount", isSignal: true, isRequired: false, transformFunction: null }, searchText: { classPropertyName: "searchText", publicName: "searchText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect", searchText: "searchTextChange" }, host: { properties: { "class": "cn(\"block h-[inherit] max-h-[inherit] w-[inherit]\",class())" } }, viewQueries: [{ propertyName: "virtualItems", predicate: ["virtualItem"], descendants: true, isSignal: true }, { propertyName: "scrollElement", first: true, predicate: ["scrollElement"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (!aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregationTree component does not support list aggregations. Please use\r\n the &lt;Aggregation /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n <span class=\"sr-only\">{{ \"filters.apply\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n <div\r\n class=\"absolute top-0 left-0 w-full\"\r\n [style.transform]=\"\r\n 'translateY(' +\r\n (virtualizer.getVirtualItems()[0]\r\n ? virtualizer.getVirtualItems()[0].start\r\n : 0) +\r\n 'px)'\r\n \"\r\n role=\"listitem\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div #virtualItem [attr.data-index]=\"vItem.index\">\r\n <AggregationTreeItem\r\n [node]=\"item\"\r\n [path]=\"[]\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onOpen)=\"open($event)\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationTreeItem:has(+AggregationTreeItem){margin-bottom:var(--agg-item-gap, 0)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: AggregationTreeItemComponent, selector: "aggregation-tree-item, AggregationTreeItem, aggregationtreeitem", inputs: ["node", "path", "field"], outputs: ["onSelect", "onOpen", "onFilter"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "directive", type: ButtonGroup, selector: "button-group, ButtonGroup", inputs: ["class", "orientation"] }, { kind: "directive", type: InputGroupInput, selector: "input[input-group]", inputs: ["class", "type", "placeholder", "disabled"] }, { kind: "directive", type: InputGroupComponent, selector: "input-group, inputgroup, InputGroup", inputs: ["class"] }, { kind: "directive", type: InputGroupAddonComponent, selector: "input-group-addon, inputgroupaddon, InputGroupAddon", inputs: ["class", "align"] }, { kind: "component", type: SearchIcon, selector: "SearchIcon", inputs: ["class"] }, { kind: "component", type: FilterIcon, selector: "filter-icon, FilterIcon", inputs: ["class"] }, { kind: "pipe", type: SyslangPipe, name: "syslang" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
13328
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationTreeComponent, isStandalone: true, selector: "AggregationTree, aggregation-tree, aggregationtree", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, expandedLevel: { classPropertyName: "expandedLevel", publicName: "expandedLevel", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, showFiltersCount: { classPropertyName: "showFiltersCount", publicName: "showFiltersCount", isSignal: true, isRequired: false, transformFunction: null }, searchText: { classPropertyName: "searchText", publicName: "searchText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect", searchText: "searchTextChange" }, host: { properties: { "class": "cn(\"block h-[inherit] max-h-[inherit] w-[inherit]\",class())" } }, viewQueries: [{ propertyName: "virtualItems", predicate: ["virtualItem"], descendants: true, isSignal: true }, { propertyName: "scrollElement", first: true, predicate: ["scrollElement"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (!aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregationTree component does not support list aggregations. Please use\r\n the &lt;Aggregation /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow truncate\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n <span class=\"sr-only\">{{ \"filters.apply\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin max-h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n <div\r\n class=\"absolute top-0 left-0 w-full\"\r\n [style.transform]=\"\r\n 'translateY(' +\r\n (virtualizer.getVirtualItems()[0]\r\n ? virtualizer.getVirtualItems()[0].start\r\n : 0) +\r\n 'px)'\r\n \"\r\n role=\"listitem\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div #virtualItem [attr.data-index]=\"vItem.index\">\r\n <AggregationTreeItem\r\n [node]=\"item\"\r\n [path]=\"[]\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onOpen)=\"open($event)\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationTreeItem:has(+AggregationTreeItem){margin-bottom:var(--agg-item-gap, 0)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: AggregationTreeItemComponent, selector: "aggregation-tree-item, AggregationTreeItem, aggregationtreeitem", inputs: ["node", "path", "field"], outputs: ["onSelect", "onOpen", "onFilter"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "directive", type: ButtonGroup, selector: "button-group, ButtonGroup", inputs: ["class", "orientation"] }, { kind: "directive", type: InputGroupInput, selector: "input[input-group]", inputs: ["class", "type", "placeholder", "disabled"] }, { kind: "directive", type: InputGroupComponent, selector: "input-group, inputgroup, InputGroup", inputs: ["class"] }, { kind: "directive", type: InputGroupAddonComponent, selector: "input-group-addon, inputgroupaddon, InputGroupAddon", inputs: ["class", "align"] }, { kind: "component", type: SearchIcon, selector: "SearchIcon", inputs: ["class"] }, { kind: "component", type: FilterIcon, selector: "filter-icon, FilterIcon", inputs: ["class"] }, { kind: "pipe", type: SyslangPipe, name: "syslang" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
13364
13329
  }
13365
13330
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationTreeComponent, decorators: [{
13366
13331
  type: Component,
@@ -13381,8 +13346,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
13381
13346
  FilterIcon
13382
13347
  ], standalone: true, host: {
13383
13348
  "[class]": 'cn("block h-[inherit] max-h-[inherit] w-[inherit]",class())'
13384
- }, template: "@if (!aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregationTree component does not support list aggregations. Please use\r\n the &lt;Aggregation /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n <span class=\"sr-only\">{{ \"filters.apply\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n <div\r\n class=\"absolute top-0 left-0 w-full\"\r\n [style.transform]=\"\r\n 'translateY(' +\r\n (virtualizer.getVirtualItems()[0]\r\n ? virtualizer.getVirtualItems()[0].start\r\n : 0) +\r\n 'px)'\r\n \"\r\n role=\"listitem\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div #virtualItem [attr.data-index]=\"vItem.index\">\r\n <AggregationTreeItem\r\n [node]=\"item\"\r\n [path]=\"[]\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onOpen)=\"open($event)\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationTreeItem:has(+AggregationTreeItem){margin-bottom:var(--agg-item-gap, 0)}\n"] }]
13385
- }], ctorParameters: () => [], propDecorators: { virtualItems: [{ type: i0.ViewChildren, args: ['virtualItem', { isSignal: true }] }], scrollElement: [{ type: i0.ViewChild, args: ["scrollElement", { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ["searchInput", { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], showFiltersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFiltersCount", required: false }] }], searchText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchText", required: false }] }, { type: i0.Output, args: ["searchTextChange"] }] } });
13349
+ }, template: "@if (!aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregationTree component does not support list aggregations. Please use\r\n the &lt;Aggregation /&gt; component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow truncate\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n <span class=\"sr-only\">{{ \"filters.apply\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin max-h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n <div\r\n class=\"absolute top-0 left-0 w-full\"\r\n [style.transform]=\"\r\n 'translateY(' +\r\n (virtualizer.getVirtualItems()[0]\r\n ? virtualizer.getVirtualItems()[0].start\r\n : 0) +\r\n 'px)'\r\n \"\r\n role=\"listitem\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div #virtualItem [attr.data-index]=\"vItem.index\">\r\n <AggregationTreeItem\r\n [node]=\"item\"\r\n [path]=\"[]\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onOpen)=\"open($event)\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationTreeItem:has(+AggregationTreeItem){margin-bottom:var(--agg-item-gap, 0)}\n"] }]
13350
+ }], ctorParameters: () => [], propDecorators: { virtualItems: [{ type: i0.ViewChildren, args: ['virtualItem', { isSignal: true }] }], scrollElement: [{ type: i0.ViewChild, args: ["scrollElement", { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ["searchInput", { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], expandedLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedLevel", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], showFiltersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFiltersCount", required: false }] }], searchText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchText", required: false }] }, { type: i0.Output, args: ["searchTextChange"] }] } });
13386
13351
 
13387
13352
  /**
13388
13353
  * The `AggregationComponent` is responsible for rendering the appropriate aggregation component based on the type of aggregation (date, tree, or list). It uses the `AggregationsService` to retrieve the aggregation data and determines which component to display based on the column type and whether it is a tree structure. The component also provides inputs for configuring its behavior, such as collapsibility, searchability, and showing filter counts.
@@ -13450,6 +13415,7 @@ class AggregationComponent {
13450
13415
  * "Undefined" and not "false" because this input overrides the custom json settings
13451
13416
  */
13452
13417
  searchable = input(undefined, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
13418
+ expandedLevel = input(undefined, ...(ngDevMode ? [{ debugName: "expandedLevel", transform: numberAttribute }] : [{ transform: numberAttribute }]));
13453
13419
  /**
13454
13420
  * An output event that emits an array of selected `AggregationItem` objects when the user selects items in the aggregation component. This allows parent components to listen for selection changes and react accordingly, such as applying filters or updating the UI based on the selected items.
13455
13421
  */
@@ -13493,7 +13459,7 @@ class AggregationComponent {
13493
13459
  return this.appStore.isDateColumn(column);
13494
13460
  }
13495
13461
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13496
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationComponent, isStandalone: true, selector: "Aggregation, aggregation", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, showFiltersCount: { classPropertyName: "showFiltersCount", publicName: "showFiltersCount", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { properties: { "class": "cn(\"block h-[inherit] max-h-[inherit]\",class())" } }, viewQueries: [{ propertyName: "aggregationDate", first: true, predicate: AggregationDateComponent, descendants: true, isSignal: true }, { propertyName: "aggregationTree", first: true, predicate: AggregationTreeComponent, descendants: true, isSignal: true }, { propertyName: "aggregationList", first: true, predicate: AggregationListComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
13462
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AggregationComponent, isStandalone: true, selector: "Aggregation, aggregation", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, showFiltersCount: { classPropertyName: "showFiltersCount", publicName: "showFiltersCount", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, expandedLevel: { classPropertyName: "expandedLevel", publicName: "expandedLevel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, host: { properties: { "class": "cn(\"block h-[inherit] max-h-[inherit]\",class())" } }, viewQueries: [{ propertyName: "aggregationDate", first: true, predicate: AggregationDateComponent, descendants: true, isSignal: true }, { propertyName: "aggregationTree", first: true, predicate: AggregationTreeComponent, descendants: true, isSignal: true }, { propertyName: "aggregationList", first: true, predicate: AggregationListComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
13497
13463
  @if (isDate(aggregation()?.column)) {
13498
13464
  <AggregationDate
13499
13465
  class="max-w-80"
@@ -13516,6 +13482,7 @@ class AggregationComponent {
13516
13482
  [collapsible]="collapsible()"
13517
13483
  [showFiltersCount]="showFiltersCount()"
13518
13484
  [searchable]="searchable()"
13485
+ [expandedLevel]="expandedLevel()"
13519
13486
  (onSelect)="onSelect.emit($event)"
13520
13487
  />
13521
13488
  }
@@ -13532,7 +13499,7 @@ class AggregationComponent {
13532
13499
  (onSelect)="onSelect.emit($event)"
13533
13500
  />
13534
13501
  }
13535
- `, isInline: true, dependencies: [{ kind: "component", type: AggregationListComponent, selector: "AggregationList, aggregation-list, aggregationlist", inputs: ["class", "id", "name", "column", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "searchTextChange"] }, { kind: "component", type: AggregationTreeComponent, selector: "AggregationTree, aggregation-tree, aggregationtree", inputs: ["class", "id", "name", "column", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "searchTextChange"] }, { kind: "component", type: AggregationDateComponent, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: ["title", "displayEmptyDistributionIntervals"] }] });
13502
+ `, isInline: true, dependencies: [{ kind: "component", type: AggregationListComponent, selector: "AggregationList, aggregation-list, aggregationlist", inputs: ["class", "id", "name", "column", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "searchTextChange"] }, { kind: "component", type: AggregationTreeComponent, selector: "AggregationTree, aggregation-tree, aggregationtree", inputs: ["class", "id", "name", "column", "expandedLevel", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "searchTextChange"] }, { kind: "component", type: AggregationDateComponent, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: ["title", "displayEmptyDistributionIntervals"] }] });
13536
13503
  }
13537
13504
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AggregationComponent, decorators: [{
13538
13505
  type: Component,
@@ -13562,6 +13529,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
13562
13529
  [collapsible]="collapsible()"
13563
13530
  [showFiltersCount]="showFiltersCount()"
13564
13531
  [searchable]="searchable()"
13532
+ [expandedLevel]="expandedLevel()"
13565
13533
  (onSelect)="onSelect.emit($event)"
13566
13534
  />
13567
13535
  }
@@ -13583,7 +13551,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
13583
13551
  "[class]": 'cn("block h-[inherit] max-h-[inherit]",class())'
13584
13552
  }
13585
13553
  }]
13586
- }], propDecorators: { aggregationDate: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AggregationDateComponent), { isSignal: true }] }], aggregationTree: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AggregationTreeComponent), { isSignal: true }] }], aggregationList: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AggregationListComponent), { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], showFiltersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFiltersCount", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
13554
+ }], propDecorators: { aggregationDate: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AggregationDateComponent), { isSignal: true }] }], aggregationTree: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AggregationTreeComponent), { isSignal: true }] }], aggregationList: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AggregationListComponent), { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], showFiltersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFiltersCount", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], expandedLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedLevel", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }] } });
13587
13555
 
13588
13556
  class AsideFiltersComponent {
13589
13557
  cn = cn;
@@ -13610,7 +13578,7 @@ class AsideFiltersComponent {
13610
13578
  <Aggregation id="aside-filters" [name]="agg.name" [column]="agg.column" showFiltersCount />
13611
13579
  }
13612
13580
  </div>
13613
- `, isInline: true, dependencies: [{ kind: "component", type: AggregationComponent, selector: "Aggregation, aggregation", inputs: ["class", "id", "name", "column", "showFiltersCount", "collapsible", "collapsed", "searchable"], outputs: ["onSelect"] }] });
13581
+ `, isInline: true, dependencies: [{ kind: "component", type: AggregationComponent, selector: "Aggregation, aggregation", inputs: ["class", "id", "name", "column", "showFiltersCount", "collapsible", "collapsed", "searchable", "expandedLevel"], outputs: ["onSelect"] }] });
13614
13582
  }
13615
13583
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AsideFiltersComponent, decorators: [{
13616
13584
  type: Component,
@@ -13635,6 +13603,7 @@ class FilterButtonComponent {
13635
13603
  column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
13636
13604
  position = input("bottom-start", ...(ngDevMode ? [{ debugName: "position" }] : []));
13637
13605
  offset = input(8, ...(ngDevMode ? [{ debugName: "offset" }] : []));
13606
+ expandedLevel = input(undefined, ...(ngDevMode ? [{ debugName: "expandedLevel", transform: numberAttribute }] : [{ transform: numberAttribute }]));
13638
13607
  variant = signal("ghost", ...(ngDevMode ? [{ debugName: "variant" }] : []));
13639
13608
  filter = signal({
13640
13609
  name: "",
@@ -13665,7 +13634,7 @@ class FilterButtonComponent {
13665
13634
  column: this.column(),
13666
13635
  icon,
13667
13636
  hidden,
13668
- display: agg?.isTree ? display : (f?.display ?? f?.value ?? display),
13637
+ display: f?.display ?? f?.value ?? display,
13669
13638
  isTree: agg?.isTree || false,
13670
13639
  count,
13671
13640
  disabled: !!(!agg?.items || agg.items?.length === 0),
@@ -13690,7 +13659,7 @@ class FilterButtonComponent {
13690
13659
  return this.appStore.isDateColumn(column);
13691
13660
  }
13692
13661
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FilterButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13693
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FilterButtonComponent, isStandalone: true, selector: "filter-button, FilterButton", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "listitem" }, properties: { "class.hidden": "filter().hidden" } }, viewQueries: [{ propertyName: "popoverRef", first: true, predicate: PopoverComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
13662
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FilterButtonComponent, isStandalone: true, selector: "filter-button, FilterButton", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, expandedLevel: { classPropertyName: "expandedLevel", publicName: "expandedLevel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "listitem" }, properties: { "class.hidden": "filter().hidden" } }, viewQueries: [{ propertyName: "popoverRef", first: true, predicate: PopoverComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
13694
13663
  <Popover [disabled]="filter().disabled" class="group">
13695
13664
  <button
13696
13665
  [variant]="variant()"
@@ -13708,7 +13677,8 @@ class FilterButtonComponent {
13708
13677
  <span [innerHTML]="filter().legacyFilter | operator | syslang | transloco"></span>
13709
13678
  } @else {
13710
13679
  <!-- display the first filter value or the aggregation name if no value is set -->
13711
- <span class="max-w-40 truncate">{{ filter().display || filter().name | syslang | transloco }}</span>
13680
+ @let display = filter().display || filter().name | syslang | transloco;
13681
+ <span class="max-w-40 truncate" [title]="display">{{ display }}</span>
13712
13682
  }
13713
13683
 
13714
13684
  <!-- show the count of selected items -->
@@ -13732,11 +13702,12 @@ class FilterButtonComponent {
13732
13702
  id="filter-{{ filter().column }}"
13733
13703
  [name]="filter().name"
13734
13704
  [column]="filter().column"
13705
+ [expandedLevel]="expandedLevel()"
13735
13706
  />
13736
13707
  }
13737
13708
  </PopoverContent>
13738
13709
  </Popover>
13739
- `, isInline: true, dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: PopoverComponent, selector: "popover, Popover", inputs: ["disabled", "closeOnScroll"], outputs: ["closed"] }, { kind: "directive", type: PopoverContentComponent, selector: "popover-content, PopoverContent, popovercontent", inputs: ["class", "position", "keepOpen", "offset", "strategy"], exportAs: ["popoverContent"] }, { kind: "component", type: AggregationComponent, selector: "Aggregation, aggregation", inputs: ["class", "id", "name", "column", "showFiltersCount", "collapsible", "collapsed", "searchable"], outputs: ["onSelect"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: OperatorPipe, name: "operator" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
13710
+ `, isInline: true, dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: PopoverComponent, selector: "popover, Popover", inputs: ["disabled", "closeOnScroll"], outputs: ["closed"] }, { kind: "directive", type: PopoverContentComponent, selector: "popover-content, PopoverContent, popovercontent", inputs: ["class", "position", "keepOpen", "offset", "strategy"], exportAs: ["popoverContent"] }, { kind: "component", type: AggregationComponent, selector: "Aggregation, aggregation", inputs: ["class", "id", "name", "column", "showFiltersCount", "collapsible", "collapsed", "searchable", "expandedLevel"], outputs: ["onSelect"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: OperatorPipe, name: "operator" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
13740
13711
  }
13741
13712
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FilterButtonComponent, decorators: [{
13742
13713
  type: Component,
@@ -13771,7 +13742,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
13771
13742
  <span [innerHTML]="filter().legacyFilter | operator | syslang | transloco"></span>
13772
13743
  } @else {
13773
13744
  <!-- display the first filter value or the aggregation name if no value is set -->
13774
- <span class="max-w-40 truncate">{{ filter().display || filter().name | syslang | transloco }}</span>
13745
+ @let display = filter().display || filter().name | syslang | transloco;
13746
+ <span class="max-w-40 truncate" [title]="display">{{ display }}</span>
13775
13747
  }
13776
13748
 
13777
13749
  <!-- show the count of selected items -->
@@ -13795,6 +13767,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
13795
13767
  id="filter-{{ filter().column }}"
13796
13768
  [name]="filter().name"
13797
13769
  [column]="filter().column"
13770
+ [expandedLevel]="expandedLevel()"
13798
13771
  />
13799
13772
  }
13800
13773
  </PopoverContent>
@@ -13805,7 +13778,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
13805
13778
  role: "listitem"
13806
13779
  }
13807
13780
  }]
13808
- }], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], popoverRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => PopoverComponent), { isSignal: true }] }] } });
13781
+ }], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], expandedLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedLevel", required: false }] }], popoverRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => PopoverComponent), { isSignal: true }] }] } });
13809
13782
 
13810
13783
  const FILTERS_BREAKPOINT = new InjectionToken('FILTERS_BREAKPOINT', { factory: () => 5 });
13811
13784
 
@@ -13905,7 +13878,7 @@ class MoreComponent {
13905
13878
  [name]="filter.name"
13906
13879
  [column]="filter.column" />
13907
13880
  }
13908
- `, isInline: true, styles: [":host{scrollbar-width:none}\n"], dependencies: [{ kind: "component", type: AggregationComponent, selector: "Aggregation, aggregation", inputs: ["class", "id", "name", "column", "showFiltersCount", "collapsible", "collapsed", "searchable"], outputs: ["onSelect"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
13881
+ `, isInline: true, styles: [":host{scrollbar-width:none}\n"], dependencies: [{ kind: "component", type: AggregationComponent, selector: "Aggregation, aggregation", inputs: ["class", "id", "name", "column", "showFiltersCount", "collapsible", "collapsed", "searchable", "expandedLevel"], outputs: ["onSelect"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
13909
13882
  }
13910
13883
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MoreComponent, decorators: [{
13911
13884
  type: Component,
@@ -14048,6 +14021,7 @@ class FiltersBarComponent {
14048
14021
  * @defaultValue 8px
14049
14022
  */
14050
14023
  offset = input(8, ...(ngDevMode ? [{ debugName: "offset" }] : []));
14024
+ expandedLevel = input(undefined, ...(ngDevMode ? [{ debugName: "expandedLevel", transform: numberAttribute }] : [{ transform: numberAttribute }]));
14051
14025
  /**
14052
14026
  * Event emitted when the clear filters button is clicked.
14053
14027
  * This event can be used to perform additional actions when filters are cleared.
@@ -14181,7 +14155,7 @@ class FiltersBarComponent {
14181
14155
  });
14182
14156
  }
14183
14157
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FiltersBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
14184
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FiltersBarComponent, isStandalone: true, selector: "filters-bar, FiltersBar, filtersbar", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, morePosition: { classPropertyName: "morePosition", publicName: "morePosition", isSignal: true, isRequired: false, transformFunction: null }, aggregations: { classPropertyName: "aggregations", publicName: "aggregations", isSignal: true, isRequired: false, transformFunction: null }, includeFilters: { classPropertyName: "includeFilters", publicName: "includeFilters", isSignal: true, isRequired: false, transformFunction: null }, excludeFilters: { classPropertyName: "excludeFilters", publicName: "excludeFilters", isSignal: true, isRequired: false, transformFunction: null }, filtersCount: { classPropertyName: "filtersCount", publicName: "filtersCount", isSignal: true, isRequired: false, transformFunction: null }, showMoreFiltersButton: { classPropertyName: "showMoreFiltersButton", publicName: "showMoreFiltersButton", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClearFilters: "onClearFilters", onClearBasket: "onClearBasket" }, host: { listeners: { "click": "handleClick($event)" }, properties: { "class": "cn('block relative', class())" } }, providers: [provideTranslocoScope("filters")], viewQueries: [{ propertyName: "moreButtonRef", first: true, predicate: MoreButtonComponent, descendants: true, isSignal: true }, { propertyName: "filterButtonRefs", predicate: FilterButtonComponent, descendants: true, isSignal: true }, { propertyName: "overflowManagerRef", first: true, predicate: OverflowManagerDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
14158
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FiltersBarComponent, isStandalone: true, selector: "filters-bar, FiltersBar, filtersbar", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, morePosition: { classPropertyName: "morePosition", publicName: "morePosition", isSignal: true, isRequired: false, transformFunction: null }, aggregations: { classPropertyName: "aggregations", publicName: "aggregations", isSignal: true, isRequired: false, transformFunction: null }, includeFilters: { classPropertyName: "includeFilters", publicName: "includeFilters", isSignal: true, isRequired: false, transformFunction: null }, excludeFilters: { classPropertyName: "excludeFilters", publicName: "excludeFilters", isSignal: true, isRequired: false, transformFunction: null }, filtersCount: { classPropertyName: "filtersCount", publicName: "filtersCount", isSignal: true, isRequired: false, transformFunction: null }, showMoreFiltersButton: { classPropertyName: "showMoreFiltersButton", publicName: "showMoreFiltersButton", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, expandedLevel: { classPropertyName: "expandedLevel", publicName: "expandedLevel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClearFilters: "onClearFilters", onClearBasket: "onClearBasket" }, host: { listeners: { "click": "handleClick($event)" }, properties: { "class": "cn('block relative', class())" } }, providers: [provideTranslocoScope("filters")], viewQueries: [{ propertyName: "moreButtonRef", first: true, predicate: MoreButtonComponent, descendants: true, isSignal: true }, { propertyName: "filterButtonRefs", predicate: FilterButtonComponent, descendants: true, isSignal: true }, { propertyName: "overflowManagerRef", first: true, predicate: OverflowManagerDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
14185
14159
  <ng-container overflowManager [direction]="direction()" [target]="el.nativeElement" (count)="adjustFiltersCount($event)">
14186
14160
  @if (hasFilters()) {
14187
14161
  <button
@@ -14215,7 +14189,7 @@ class FiltersBarComponent {
14215
14189
  role="list"
14216
14190
  aria-label="Filters list">
14217
14191
  @for (filter of authorizedFilters(); track filter.name) {
14218
- <FilterButton class="max-w-60" overflowItem [name]="filter.name" [column]="filter.column" [position]="position()" [offset]="offset()" />
14192
+ <FilterButton class="max-w-60" overflowItem [name]="filter.name" [column]="filter.column" [position]="position()" [offset]="offset()" [expandedLevel]="expandedLevel()" />
14219
14193
  }
14220
14194
 
14221
14195
  <!-- More button to show more filters if there are any, it's hidden by default -->
@@ -14233,7 +14207,7 @@ class FiltersBarComponent {
14233
14207
  </div>
14234
14208
  }
14235
14209
  </ng-container>
14236
- `, isInline: true, dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: MoreButtonComponent, selector: "more-button, MoreButton", inputs: ["count", "position", "includedFilters", "excludedFilters", "aggregations"] }, { kind: "component", type: FilterButtonComponent, selector: "filter-button, FilterButton", inputs: ["name", "column", "position", "offset"] }, { kind: "directive", type: OverflowManagerDirective, selector: "[overflowManager]", inputs: ["target", "margin", "direction"], outputs: ["count"] }, { kind: "directive", type: OverflowItemDirective, selector: "[overflowItem]" }, { kind: "directive", type: OverflowStopDirective, selector: "[overflowStop]" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
14210
+ `, isInline: true, dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: MoreButtonComponent, selector: "more-button, MoreButton", inputs: ["count", "position", "includedFilters", "excludedFilters", "aggregations"] }, { kind: "component", type: FilterButtonComponent, selector: "filter-button, FilterButton", inputs: ["name", "column", "position", "offset", "expandedLevel"] }, { kind: "directive", type: OverflowManagerDirective, selector: "[overflowManager]", inputs: ["target", "margin", "direction"], outputs: ["count"] }, { kind: "directive", type: OverflowItemDirective, selector: "[overflowItem]" }, { kind: "directive", type: OverflowStopDirective, selector: "[overflowStop]" }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
14237
14211
  }
14238
14212
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FiltersBarComponent, decorators: [{
14239
14213
  type: Component,
@@ -14284,7 +14258,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
14284
14258
  role="list"
14285
14259
  aria-label="Filters list">
14286
14260
  @for (filter of authorizedFilters(); track filter.name) {
14287
- <FilterButton class="max-w-60" overflowItem [name]="filter.name" [column]="filter.column" [position]="position()" [offset]="offset()" />
14261
+ <FilterButton class="max-w-60" overflowItem [name]="filter.name" [column]="filter.column" [position]="position()" [offset]="offset()" [expandedLevel]="expandedLevel()" />
14288
14262
  }
14289
14263
 
14290
14264
  <!-- More button to show more filters if there are any, it's hidden by default -->
@@ -14308,7 +14282,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
14308
14282
  "(click)": "handleClick($event)"
14309
14283
  }
14310
14284
  }]
14311
- }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], morePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "morePosition", required: false }] }], aggregations: [{ type: i0.Input, args: [{ isSignal: true, alias: "aggregations", required: false }] }], includeFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "includeFilters", required: false }] }], excludeFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludeFilters", required: false }] }], filtersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "filtersCount", required: false }] }], showMoreFiltersButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMoreFiltersButton", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], onClearFilters: [{ type: i0.Output, args: ["onClearFilters"] }], onClearBasket: [{ type: i0.Output, args: ["onClearBasket"] }], moreButtonRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MoreButtonComponent), { isSignal: true }] }], filterButtonRefs: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => FilterButtonComponent), { isSignal: true }] }], overflowManagerRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => OverflowManagerDirective), { isSignal: true }] }] } });
14285
+ }], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], morePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "morePosition", required: false }] }], aggregations: [{ type: i0.Input, args: [{ isSignal: true, alias: "aggregations", required: false }] }], includeFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "includeFilters", required: false }] }], excludeFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludeFilters", required: false }] }], filtersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "filtersCount", required: false }] }], showMoreFiltersButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMoreFiltersButton", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], expandedLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedLevel", required: false }] }], onClearFilters: [{ type: i0.Output, args: ["onClearFilters"] }], onClearBasket: [{ type: i0.Output, args: ["onClearBasket"] }], moreButtonRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MoreButtonComponent), { isSignal: true }] }], filterButtonRefs: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => FilterButtonComponent), { isSignal: true }] }], overflowManagerRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => OverflowManagerDirective), { isSignal: true }] }] } });
14312
14286
 
14313
14287
  class LabelService {
14314
14288
  appStore = inject(AppStore);
@@ -14632,7 +14606,7 @@ class MultiSelectLabelsComponent {
14632
14606
  {{ 'labels.error' | transloco }}
14633
14607
  </div>
14634
14608
  }
14635
- `, isInline: true, styles: [".anchor:has(.popover:popover-open){z-index:var(--z-menu, 1000);border-radius:var(--radius) var(--radius) 0 0}.anchor .popover::backdrop{background-color:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.popover{width:anchor-size(width);top:anchor(bottom);left:anchor(left)}@supports (-moz-appearance: none){.popover{margin:calc(33.3333333333vh + 30px) 25vw;width:50vw}}@supports (background: -webkit-named-image(i)){.popover{margin:calc(33.3333333333vh + 30px) 25vw;width:50vw}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
14609
+ `, isInline: true, styles: [".anchor:has(.popover:popover-open){z-index:var(--z-menu, 1000);border-radius:var(--radius) var(--radius) 0 0}.anchor .popover::backdrop{background-color:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.popover{width:anchor-size(width);top:anchor(bottom);left:anchor(left)}@supports (-moz-appearance: none){.popover{margin:calc(33.3333333333vh + 30px) 25vw;width:50vw}}@supports (background: -webkit-named-image(i)){.popover{margin:calc(33.3333333333vh + 30px) 25vw;width:50vw}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
14636
14610
  }
14637
14611
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MultiSelectLabelsComponent, decorators: [{
14638
14612
  type: Component,
@@ -15106,7 +15080,7 @@ class SavedSearchDialog {
15106
15080
  </DialogFooter>
15107
15081
  </DialogContent>
15108
15082
  </dialog>
15109
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
15083
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "directive", type: DialogFooterComponent, selector: "DialogFooter", inputs: ["class"] }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
15110
15084
  }
15111
15085
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SavedSearchDialog, decorators: [{
15112
15086
  type: Component,
@@ -15229,11 +15203,13 @@ class UserProfileFormComponent {
15229
15203
  appStore = inject(AppStore);
15230
15204
  transloco = inject(TranslocoService);
15231
15205
  createInputElement = viewChild("avatarInput", ...(ngDevMode ? [{ debugName: "createInputElement" }] : []));
15232
- dataKeys = ["fullName", "mail", "jobTitle", "group", "organisation", "location", "skills"];
15206
+ dataKeys = ["fullName", "mail", "jobTitle", "group", "organisation", "location", "skills", "profilePhoto"];
15233
15207
  keys = computed(() => {
15234
15208
  const data = this.appStore.general()?.features?.userProfile?.data;
15235
- return data?.length ? data : this.dataKeys;
15209
+ return data?.length ? this.dataKeys.filter(key => data.some(k => k === key)) : this.dataKeys;
15236
15210
  }, ...(ngDevMode ? [{ debugName: "keys" }] : []));
15211
+ formKeys = computed(() => this.keys().filter(k => k !== "profilePhoto"), ...(ngDevMode ? [{ debugName: "formKeys" }] : []));
15212
+ allowProfilePhoto = computed(() => this.keys().some(k => k === "profilePhoto"), ...(ngDevMode ? [{ debugName: "allowProfilePhoto" }] : []));
15237
15213
  initials = computed(() => {
15238
15214
  const fullName = this.userProfile()?.data?.fullName;
15239
15215
  if (!fullName)
@@ -15243,6 +15219,7 @@ class UserProfileFormComponent {
15243
15219
  .map((word) => word[0].toUpperCase())
15244
15220
  .join("");
15245
15221
  }, ...(ngDevMode ? [{ debugName: "initials" }] : []));
15222
+ username = computed(() => this.principalStore.name() || this.principalStore.email() || null, ...(ngDevMode ? [{ debugName: "username" }] : []));
15246
15223
  propertyToEdit = signal(undefined, ...(ngDevMode ? [{ debugName: "propertyToEdit" }] : []));
15247
15224
  value = model(undefined, ...(ngDevMode ? [{ debugName: "value" }] : []));
15248
15225
  currentLanguage = model(...(ngDevMode ? [undefined, { debugName: "currentLanguage" }] : []));
@@ -15391,7 +15368,7 @@ class UserProfileFormComponent {
15391
15368
  }
15392
15369
  }
15393
15370
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15394
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: UserProfileFormComponent, isStandalone: true, selector: "user-profile-form, UserProfileForm, userprofileform", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, currentLanguage: { classPropertyName: "currentLanguage", publicName: "currentLanguage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", currentLanguage: "currentLanguageChange" }, providers: [provideTranslocoScope("user-profile", "login")], viewQueries: [{ propertyName: "createInputElement", first: true, predicate: ["avatarInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (userProfileResource.hasValue()) {\n @let profile = userProfile();\n <div class=\"flex flex-col gap-2 p-4\">\n <div class=\"mb-4 flex\">\n <!-- AVATAR -->\n <Avatar\n class=\"bg-accent text-accent-foreground hover:bg-accent/80 hover:text-accent-foreground/80 size-14 cursor-pointer\"\n (click)=\"avatarInput.click()\">\n @if (profile?.data?.profilePhoto) {\n <AvatarImage\n [src]=\"profile?.data?.profilePhoto!\"\n width=\"44\"\n height=\"44\"\n alt=\"avatar\" />\n }\n <AvatarFallback class=\"text-lg\">\n @if (initials()) {\n <span>{{ initials() }}</span>\n } @else {\n <UserIcon class=\"size-7 p-1\" />\n }\n </AvatarFallback>\n </Avatar>\n @if (profile?.data?.profilePhoto) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', 'profilePhoto')\">\n <TrashIcon />\n </button>\n }\n <div class=\"grow\"></div>\n <div class=\"flex flex-col gap-4\">\n <!-- LANGUAGE -->\n <select\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 rounded-md border px-2 hover:outline focus:outline\"\n [(ngModel)]=\"currentLanguage\"\n (change)=\"changeLanguage()\">\n @for (lang of AllLanguages; track lang.code) {\n <option [value]=\"lang.code\">\n {{ lang.label }}\n </option>\n }\n </select>\n <!-- CHANGE PASSWORD -->\n @if (allowChangePassword()) {\n <button\n [disabled]=\"changingPassword()\"\n (click)=\"changingPassword.set(true)\">\n {{ \"login.changePassword\" | transloco }}\n </button>\n }\n </div>\n </div>\n @if (changingPassword()) {\n <ChangePassword\n [redirectAfterSuccess]=\"false\"\n [redirectAfterCancel]=\"false\"\n (cancel)=\"changingPassword.set(false)\"\n (success)=\"changingPassword.set(false)\" />\n } @else {\n @for (key of keys(); track key) {\n <div>\n <p>{{ `userProfile.data.${key}` | transloco }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('data', key)\">\n @if (propertyToEdit() === \"data.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"data\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"data.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('data', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('data', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n @for (key of customData(); track key) {\n <div>\n <p>{{ key }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('customData', key)\">\n @if (propertyToEdit() === \"customData.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"customData\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"customData.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('customData', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('customData', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('customData', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n }\n </div>\n} @else if (userProfileResource.isLoading()) {\n <span>Loading...</span>\n} @else if (userProfileResource.error()) {\n <p>Please contact an administrator to create your user profile.</p>\n}\n\n<!-- AVATAR UPLOAD -->\n<input\n #avatarInput\n class=\"hidden\"\n type=\"file\"\n accept=\"image/*\"\n (change)=\"uploadAvatar($event)\" />\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "component", type: EditIcon, selector: "edit-icon, EditIcon, editicon", inputs: ["class"] }, { kind: "component", type: UndoIcon, selector: "UndoIcon, undoicon, undo-icon", inputs: ["class"] }, { kind: "component", type: AvatarComponent, selector: "avatar, Avatar", inputs: ["class"] }, { kind: "component", type: AvatarFallbackComponent, selector: "avatar-fallback, avatarfallback, AvatarFallback", inputs: ["class"] }, { kind: "component", type: UserIcon, selector: "user-icon, UserIcon", inputs: ["class"] }, { kind: "component", type: AvatarImageComponent, selector: "avatar-image, AvatarImage, avatarimage", inputs: ["class", "src", "alt", "width", "height", "referrerPolicy", "crossOrigin"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: ChangePasswordComponent, selector: "change-password, ChangePassword, changepassword", inputs: ["username", "alert", "redirectAfterSuccess", "redirectAfterCancel", "currentPassword", "newPassword", "confirmPassword"], outputs: ["success", "cancel", "currentPasswordChange", "newPasswordChange", "confirmPasswordChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
15371
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: UserProfileFormComponent, isStandalone: true, selector: "user-profile-form, UserProfileForm, userprofileform", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, currentLanguage: { classPropertyName: "currentLanguage", publicName: "currentLanguage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", currentLanguage: "currentLanguageChange" }, providers: [provideTranslocoScope("user-profile", "login")], viewQueries: [{ propertyName: "createInputElement", first: true, predicate: ["avatarInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (userProfileResource.hasValue()) {\n @let profile = userProfile();\n <div class=\"flex flex-col gap-2 p-4\">\n <div class=\"mb-4 flex\">\n @if (allowProfilePhoto()) {\n <!-- AVATAR -->\n <Avatar\n class=\"bg-accent text-accent-foreground hover:bg-accent/80 hover:text-accent-foreground/80 size-14 cursor-pointer\"\n (click)=\"avatarInput.click()\">\n @if (profile?.data?.profilePhoto) {\n <AvatarImage\n [src]=\"profile?.data?.profilePhoto!\"\n width=\"44\"\n height=\"44\"\n alt=\"avatar\" />\n }\n <AvatarFallback class=\"text-lg\">\n @if (initials()) {\n <span>{{ initials() }}</span>\n } @else {\n <UserIcon class=\"size-7 p-1\" />\n }\n </AvatarFallback>\n </Avatar>\n @if (profile?.data?.profilePhoto) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', 'profilePhoto')\">\n <TrashIcon />\n </button>\n }\n }\n <div class=\"grow\"></div>\n <div class=\"flex flex-col gap-4\">\n <!-- LANGUAGE -->\n <select\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 rounded-md border px-2 hover:outline focus:outline\"\n [(ngModel)]=\"currentLanguage\"\n (change)=\"changeLanguage()\">\n @for (lang of AllLanguages; track lang.code) {\n <option [value]=\"lang.code\">\n {{ lang.label }}\n </option>\n }\n </select>\n <!-- CHANGE PASSWORD -->\n @if (allowChangePassword()) {\n <button\n [disabled]=\"changingPassword()\"\n (click)=\"changingPassword.set(true)\">\n {{ \"login.changePassword\" | transloco }}\n </button>\n }\n </div>\n </div>\n @if (changingPassword()) {\n <ChangePassword\n [username]=\"username()\"\n [redirectAfterSuccess]=\"false\"\n [redirectAfterCancel]=\"false\"\n (cancel)=\"changingPassword.set(false)\"\n (success)=\"changingPassword.set(false)\" />\n } @else {\n @for (key of formKeys(); track key) {\n <div>\n <p>{{ `userProfile.data.${key}` | transloco }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('data', key)\">\n @if (propertyToEdit() === \"data.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"data\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"data.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('data', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('data', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n @for (key of customData(); track key) {\n <div>\n <p>{{ key }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('customData', key)\">\n @if (propertyToEdit() === \"customData.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"customData\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"customData.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('customData', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('customData', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('customData', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n }\n </div>\n} @else if (userProfileResource.isLoading()) {\n <span>Loading...</span>\n} @else if (userProfileResource.error()) {\n <p>Please contact an administrator to create your user profile.</p>\n}\n\n<!-- AVATAR UPLOAD -->\n<input\n #avatarInput\n class=\"hidden\"\n type=\"file\"\n accept=\"image/*\"\n (change)=\"uploadAvatar($event)\" />\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "component", type: EditIcon, selector: "edit-icon, EditIcon, editicon", inputs: ["class"] }, { kind: "component", type: UndoIcon, selector: "UndoIcon, undoicon, undo-icon", inputs: ["class"] }, { kind: "component", type: AvatarComponent, selector: "avatar, Avatar", inputs: ["class"] }, { kind: "component", type: AvatarFallbackComponent, selector: "avatar-fallback, avatarfallback, AvatarFallback", inputs: ["class"] }, { kind: "component", type: UserIcon, selector: "user-icon, UserIcon", inputs: ["class"] }, { kind: "component", type: AvatarImageComponent, selector: "avatar-image, AvatarImage, avatarimage", inputs: ["class", "src", "alt", "width", "height", "referrerPolicy", "crossOrigin"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: ChangePasswordComponent, selector: "change-password, ChangePassword, changepassword", inputs: ["username", "alert", "redirectAfterSuccess", "redirectAfterCancel", "currentPassword", "newPassword", "confirmPassword"], outputs: ["success", "cancel", "currentPasswordChange", "newPasswordChange", "confirmPasswordChange"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
15395
15372
  }
15396
15373
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileFormComponent, decorators: [{
15397
15374
  type: Component,
@@ -15409,7 +15386,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
15409
15386
  AvatarImageComponent,
15410
15387
  ButtonComponent,
15411
15388
  ChangePasswordComponent
15412
- ], providers: [provideTranslocoScope("user-profile", "login")], template: "@if (userProfileResource.hasValue()) {\n @let profile = userProfile();\n <div class=\"flex flex-col gap-2 p-4\">\n <div class=\"mb-4 flex\">\n <!-- AVATAR -->\n <Avatar\n class=\"bg-accent text-accent-foreground hover:bg-accent/80 hover:text-accent-foreground/80 size-14 cursor-pointer\"\n (click)=\"avatarInput.click()\">\n @if (profile?.data?.profilePhoto) {\n <AvatarImage\n [src]=\"profile?.data?.profilePhoto!\"\n width=\"44\"\n height=\"44\"\n alt=\"avatar\" />\n }\n <AvatarFallback class=\"text-lg\">\n @if (initials()) {\n <span>{{ initials() }}</span>\n } @else {\n <UserIcon class=\"size-7 p-1\" />\n }\n </AvatarFallback>\n </Avatar>\n @if (profile?.data?.profilePhoto) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', 'profilePhoto')\">\n <TrashIcon />\n </button>\n }\n <div class=\"grow\"></div>\n <div class=\"flex flex-col gap-4\">\n <!-- LANGUAGE -->\n <select\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 rounded-md border px-2 hover:outline focus:outline\"\n [(ngModel)]=\"currentLanguage\"\n (change)=\"changeLanguage()\">\n @for (lang of AllLanguages; track lang.code) {\n <option [value]=\"lang.code\">\n {{ lang.label }}\n </option>\n }\n </select>\n <!-- CHANGE PASSWORD -->\n @if (allowChangePassword()) {\n <button\n [disabled]=\"changingPassword()\"\n (click)=\"changingPassword.set(true)\">\n {{ \"login.changePassword\" | transloco }}\n </button>\n }\n </div>\n </div>\n @if (changingPassword()) {\n <ChangePassword\n [redirectAfterSuccess]=\"false\"\n [redirectAfterCancel]=\"false\"\n (cancel)=\"changingPassword.set(false)\"\n (success)=\"changingPassword.set(false)\" />\n } @else {\n @for (key of keys(); track key) {\n <div>\n <p>{{ `userProfile.data.${key}` | transloco }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('data', key)\">\n @if (propertyToEdit() === \"data.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"data\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"data.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('data', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('data', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n @for (key of customData(); track key) {\n <div>\n <p>{{ key }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('customData', key)\">\n @if (propertyToEdit() === \"customData.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"customData\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"customData.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('customData', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('customData', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('customData', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n }\n </div>\n} @else if (userProfileResource.isLoading()) {\n <span>Loading...</span>\n} @else if (userProfileResource.error()) {\n <p>Please contact an administrator to create your user profile.</p>\n}\n\n<!-- AVATAR UPLOAD -->\n<input\n #avatarInput\n class=\"hidden\"\n type=\"file\"\n accept=\"image/*\"\n (change)=\"uploadAvatar($event)\" />\n" }]
15389
+ ], providers: [provideTranslocoScope("user-profile", "login")], template: "@if (userProfileResource.hasValue()) {\n @let profile = userProfile();\n <div class=\"flex flex-col gap-2 p-4\">\n <div class=\"mb-4 flex\">\n @if (allowProfilePhoto()) {\n <!-- AVATAR -->\n <Avatar\n class=\"bg-accent text-accent-foreground hover:bg-accent/80 hover:text-accent-foreground/80 size-14 cursor-pointer\"\n (click)=\"avatarInput.click()\">\n @if (profile?.data?.profilePhoto) {\n <AvatarImage\n [src]=\"profile?.data?.profilePhoto!\"\n width=\"44\"\n height=\"44\"\n alt=\"avatar\" />\n }\n <AvatarFallback class=\"text-lg\">\n @if (initials()) {\n <span>{{ initials() }}</span>\n } @else {\n <UserIcon class=\"size-7 p-1\" />\n }\n </AvatarFallback>\n </Avatar>\n @if (profile?.data?.profilePhoto) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', 'profilePhoto')\">\n <TrashIcon />\n </button>\n }\n }\n <div class=\"grow\"></div>\n <div class=\"flex flex-col gap-4\">\n <!-- LANGUAGE -->\n <select\n class=\"hover:outline-primary focus:outline-primary border-foreground/10 bg-background hover:bg-muted focus:bg-muted h-8 rounded-md border px-2 hover:outline focus:outline\"\n [(ngModel)]=\"currentLanguage\"\n (change)=\"changeLanguage()\">\n @for (lang of AllLanguages; track lang.code) {\n <option [value]=\"lang.code\">\n {{ lang.label }}\n </option>\n }\n </select>\n <!-- CHANGE PASSWORD -->\n @if (allowChangePassword()) {\n <button\n [disabled]=\"changingPassword()\"\n (click)=\"changingPassword.set(true)\">\n {{ \"login.changePassword\" | transloco }}\n </button>\n }\n </div>\n </div>\n @if (changingPassword()) {\n <ChangePassword\n [username]=\"username()\"\n [redirectAfterSuccess]=\"false\"\n [redirectAfterCancel]=\"false\"\n (cancel)=\"changingPassword.set(false)\"\n (success)=\"changingPassword.set(false)\" />\n } @else {\n @for (key of formKeys(); track key) {\n <div>\n <p>{{ `userProfile.data.${key}` | transloco }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('data', key)\">\n @if (propertyToEdit() === \"data.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"data\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"data.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('data', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('data', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('data', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n @for (key of customData(); track key) {\n <div>\n <p>{{ key }}</p>\n <div class=\"group flex flex-row\">\n <div\n class=\"grow whitespace-pre-line\"\n [class.text-muted-foreground]=\"!getDataValue('customData', key)\">\n @if (propertyToEdit() === \"customData.\" + key) {\n <textarea\n class=\"hover:outline-primary focus:outline-primary border-foreground/20 hover:bg-muted focus:bg-muted mt-2 w-full rounded-md border px-2 pt-1 hover:outline focus:outline\"\n id=\"user-profile-{{ key }}\"\n [(ngModel)]=\"value\"></textarea>\n } @else {\n {{\n getDataValue(\"customData\", key) ||\n (\"userProfile.notDefined\" | transloco)\n }}\n }\n </div>\n @if (propertyToEdit() === \"customData.\" + key) {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"mx-2 cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onSaveData('customData', key)\">\n <i class=\"fa-fw fas fa-save ml-2\"></i>\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"cursor-pointer\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"propertyToEdit.set(undefined)\">\n <UndoIcon />\n </button>\n } @else {\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"invisible mx-2 cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.editProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.editProperty' | transloco\"\n (click)=\"onEdit('customData', key)\">\n <EditIcon />\n </button>\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible cursor-pointer group-hover:visible\"\n title=\"{{ 'userProfile.deleteProperty' | transloco }}\"\n [attr.aria-label]=\"'userProfile.deleteProperty' | transloco\"\n (click)=\"onDeleteData('customData', key)\">\n <TrashIcon />\n </button>\n }\n </div>\n </div>\n }\n }\n </div>\n} @else if (userProfileResource.isLoading()) {\n <span>Loading...</span>\n} @else if (userProfileResource.error()) {\n <p>Please contact an administrator to create your user profile.</p>\n}\n\n<!-- AVATAR UPLOAD -->\n<input\n #avatarInput\n class=\"hidden\"\n type=\"file\"\n accept=\"image/*\"\n (change)=\"uploadAvatar($event)\" />\n" }]
15413
15390
  }], ctorParameters: () => [], propDecorators: { createInputElement: [{ type: i0.ViewChild, args: ["avatarInput", { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], currentLanguage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentLanguage", required: false }] }, { type: i0.Output, args: ["currentLanguageChange"] }] } });
15414
15391
 
15415
15392
  class UserProfileDialog {
@@ -15596,6 +15573,7 @@ const errorInterceptorFn = (request, next) => {
15596
15573
  }));
15597
15574
  };
15598
15575
 
15576
+ const SHOW_ERROR_TOKEN = new HttpContextToken(() => true);
15599
15577
  /**
15600
15578
  * Intercepts HTTP requests and handles errors by displaying toast notifications.
15601
15579
  *
@@ -15613,6 +15591,18 @@ const toastInterceptorFn = (request, next) => {
15613
15591
  }
15614
15592
  return next(request).pipe(catchError$1((err) => {
15615
15593
  const { status, statusText, error, url } = err;
15594
+ if (status === 401 && globalConfig.userOverrideActive && error?.errorCode == 6) {
15595
+ if (request.context.get(SHOW_ERROR_TOKEN)) {
15596
+ const errorMsg = error?.errorMessage || 'The account may be deactivated or inaccessible';
15597
+ notify.error(`Cannot override user: Unauthorized access`, {
15598
+ description: errorMsg,
15599
+ closeButton: true,
15600
+ duration: 5000
15601
+ });
15602
+ request.context.set(SHOW_ERROR_TOKEN, false);
15603
+ return throwError(() => err);
15604
+ }
15605
+ }
15616
15606
  if ([400, 403, 500, 503].includes(status)) {
15617
15607
  // Avoid showing error toasts for preview requests
15618
15608
  if (url.includes("api/v1/preview") === false) {
@@ -15648,5 +15638,5 @@ const queryNameResolver = () => {
15648
15638
  * Generated bundle index. Do not edit.
15649
15639
  */
15650
15640
 
15651
- export { AGGREGATIONS_NAMES, AGGREGATIONS_NAMES_PRESET_DEFAULT, APP_FEATURES, AdvancedFiltersComponent, AdvancedSearch, AdvancedSearchComponent, AggregationComponent, AggregationDateComponent, AggregationListComponent, AggregationTreeComponent, AggregationsService, AggregationsStore, Alert, AlertDialog, AlertsComponent, AppService, AppStore, ApplicationService, ApplicationStore, ArticleEntities, ArticleExtracts, ArticleLabels, ArticleSimilarDocuments, AsideFiltersComponent, AuditFeedbackType, AuditService, AuthGuard, AuthPageComponent, AutocompleteService, BOOKMARKS_CONFIG, BOOKMARKS_OPTIONS, BackdropComponent, BackdropService, BookmarkButtonComponent, BookmarksComponent, COLLECTIONS_CONFIG, COLLECTIONS_OPTIONS, COMPONENTS_FOR_DOCUMENT_TYPE, ChangePasswordComponent, ChildMarkerDirective, CollectionsComponent, CollectionsDialog, DRAWER_COMPONENT, DRAWER_STACK_MAX_COUNT, DateComponent, DeleteCollectionDialog, DidYouMeanComponent, DocumentLocatorComponent, DrawerAdvancedFiltersComponent, DrawerComponent, DrawerNavbarComponent, DrawerPreviewComponent, DrawerService, DrawerStackComponent, DrawerStackService, DropdownInputComponent, DropdownListComponent, ErrorComponent, ExportDialog, ExportService, FILTERS_BREAKPOINT, FILTER_DATE_ALLOW_CUSTOM_RANGE, FeedbackDialogComponent, FileSizePipe, FilterButtonComponent, FiltersBarComponent, HIGHLIGHTS, HighlightWordPipe, InfinityScrollDirective, InlineWorker, JsonMethodPluginService, KeyboardNavigatorDirective, LabelService, LabelsEditDialog, LoadingComponent, MetadataComponent, MissingTermsComponent, MoreButtonComponent, MoreComponent, MultiSelectLabelsComponent, MultiSelectionToolbarComponent, NON_SEARCHABLE_COLUMNS, NON_SEARCHABLE_DEFAULTS, NavbarTabsComponent, NavigationService, NoResultComponent, OpenArticleOnCtrlEnterDirective, OperatorPipe, OverflowItemDirective, OverflowManagerDirective, OverflowStopDirective, OverrideUserDialogComponent, PREVIEW_CONFIG, PagerComponent, PasswordExpiryGuard, PreviewNavigator, PreviewService, PrincipalService, PrincipalStore, QueryParamsStore, QueryService, RECENT_SEARCHES_CONFIG, RECENT_SEARCHES_OPTIONS, ROUTE_COMPONENTS, RecentSearchesComponent, ResetUserSettingsDialogComponent, SAVED_SEARCHES_CONFIG, SAVED_SEARCHES_OPTIONS, SavedSearchDialog, SavedSearchesComponent, SavedSearchesService, SearchFeedbackComponent, SearchInputFooter, SearchService, SelectArticleDirective, SelectArticleOnClickDirective, SelectionHistoryService, SelectionService, SelectionStore, ShowBookmarkDirective, SignInComponent, SortSelectorComponent, SourceComponent, SourceIconPipe, SponsoredResultsComponent, SyslangPipe, THEMES, TextChunkService, ThemeProviderDirective, ThemeSelectorComponent, ThemeStore, ThemeToggleComponent, TranslocoDateImpurePipe, UserProfileDialog, UserProfileFormComponent, UserProfileService, UserSettingsStore, applyThemeToNativeElement, auditInterceptorFn, authInterceptorFn, bodyInterceptorFn, buildQuery, debouncedSignal, errorInterceptorFn, getCurrentPath, getCurrentQueryName, getQueryNameFromRoute, processCssVars, queryNameResolver, signIn, themeColorNameToCssVariable, themeColorsToCssVariables, toastInterceptorFn, withAggregationsFeatures, withAlertsFeatures, withAppFeatures, withApplicationFeatures, withAssistantFeatures, withBasketsFeatures, withBookmarkFeatures, withBootstrapApp, withExtractsFeatures, withFetch, withMultiSelectionFeatures, withPrincipalFeatures, withQueryParamsFeatures, withRecentSearchesFeatures, withSavedSearchesFeatures, withSelectionFeatures, withThemeBodyHook, withThemes, withThemesFeatures, withUserSettingsFeatures };
15641
+ export { AGGREGATIONS_NAMES, AGGREGATIONS_NAMES_PRESET_DEFAULT, APP_FEATURES, AdvancedFiltersComponent, AdvancedSearch, AdvancedSearchComponent, AggregationComponent, AggregationDateComponent, AggregationListComponent, AggregationTreeComponent, AggregationsService, AggregationsStore, Alert, AlertDialog, AlertsComponent, AppService, AppStore, ApplicationService, ApplicationStore, ArticleEntities, ArticleExtracts, ArticleLabels, ArticleSimilarDocuments, AsideFiltersComponent, AuditFeedbackType, AuditService, AuthGuard, AuthPageComponent, AutocompleteService, BOOKMARKS_CONFIG, BOOKMARKS_OPTIONS, BackdropComponent, BackdropService, BookmarkButtonComponent, BookmarksComponent, COLLECTIONS_CONFIG, COLLECTIONS_OPTIONS, COMPONENTS_FOR_DOCUMENT_TYPE, ChangePasswordComponent, ChildMarkerDirective, CollectionsComponent, CollectionsDialog, DRAWER_COMPONENT, DRAWER_STACK_MAX_COUNT, DateComponent, DeleteCollectionDialog, DidYouMeanComponent, DocumentLocatorComponent, DrawerAdvancedFiltersComponent, DrawerComponent, DrawerNavbarComponent, DrawerPreviewComponent, DrawerService, DrawerStackComponent, DrawerStackService, DropdownInputComponent, DropdownListComponent, ErrorComponent, ExportDialog, ExportService, FILTERS_BREAKPOINT, FILTER_DATE_ALLOW_CUSTOM_RANGE, FeedbackDialogComponent, FileSizePipe, FilterButtonComponent, FiltersBarComponent, HIGHLIGHTS, HighlightWordPipe, InfinityScrollDirective, InlineWorker, JsonMethodPluginService, KeyboardNavigatorDirective, LabelService, LabelsEditDialog, LoadingComponent, MetadataComponent, MissingTermsComponent, MoreButtonComponent, MoreComponent, MultiSelectLabelsComponent, MultiSelectionToolbarComponent, NON_SEARCHABLE_COLUMNS, NON_SEARCHABLE_DEFAULTS, NavbarTabsComponent, NavigationService, NoResultComponent, OpenArticleOnCtrlEnterDirective, OperatorPipe, OverflowItemDirective, OverflowManagerDirective, OverflowStopDirective, OverrideUserDialogComponent, PREVIEW_CONFIG, PagerComponent, PreviewNavigator, PreviewService, PrincipalService, PrincipalStore, QueryParamsStore, QueryService, RECENT_SEARCHES_CONFIG, RECENT_SEARCHES_OPTIONS, ROUTE_COMPONENTS, RecentSearchesComponent, ResetUserSettingsDialogComponent, SAVED_SEARCHES_CONFIG, SAVED_SEARCHES_OPTIONS, SavedSearchDialog, SavedSearchesComponent, SavedSearchesService, SearchFeedbackComponent, SearchInputFooter, SearchService, SelectArticleDirective, SelectArticleOnClickDirective, SelectionHistoryService, SelectionService, SelectionStore, ShowBookmarkDirective, SignInComponent, SortSelectorComponent, SourceComponent, SourceIconPipe, SponsoredResultsComponent, SyslangPipe, THEMES, TextChunkService, ThemeProviderDirective, ThemeSelectorComponent, ThemeStore, ThemeToggleComponent, TranslocoDateImpurePipe, UserProfileDialog, UserProfileFormComponent, UserProfileService, UserSettingsStore, applyThemeToNativeElement, auditInterceptorFn, authInterceptorFn, bodyInterceptorFn, buildQuery, debouncedSignal, errorInterceptorFn, getCurrentPath, getCurrentQueryName, getQueryNameFromRoute, processCssVars, queryNameResolver, signIn, themeColorNameToCssVariable, themeColorsToCssVariables, toastInterceptorFn, withAggregationsFeatures, withAlertsFeatures, withAppFeatures, withApplicationFeatures, withAssistantFeatures, withBasketsFeatures, withBookmarkFeatures, withBootstrapApp, withExtractsFeatures, withFetch, withMultiSelectionFeatures, withPrincipalFeatures, withQueryParamsFeatures, withRecentSearchesFeatures, withSavedSearchesFeatures, withSelectionFeatures, withThemeBodyHook, withThemes, withThemesFeatures, withUserSettingsFeatures };
15652
15642
  //# sourceMappingURL=sinequa-atomic-angular.mjs.map