@sinequa/atomic-angular 0.4.20-dev.1 → 0.4.28

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.
@@ -2,12 +2,12 @@ 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
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
- 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';
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, CardComponent, CardHeaderComponent, CardContentComponent, CardFooterComponent, PopoverContentComponent, BookmarkIcon, UserIcon, TrashIcon, FolderIcon, VerticalDividerComponent, BreakpointObserverService, HorizontalDividerComponent, 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, 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';
10
+ import { globalConfig, EngineType, extraColumns, sysLang, getQueryParamsFromUrl, logout, login, info, warn, error, setGlobalConfig, notify, 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
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';
@@ -1242,6 +1242,8 @@ const initialPrincipal = {
1242
1242
  fullName: "",
1243
1243
  isAdministrator: false,
1244
1244
  isDelegatedAdmin: false,
1245
+ editablePartition: undefined,
1246
+ passwordExpirationDate: null,
1245
1247
  description: "",
1246
1248
  param1: "",
1247
1249
  param2: "",
@@ -1264,6 +1266,7 @@ const PrincipalStore = signalStore({ providedIn: 'root' }, withDevtools('Princip
1264
1266
  if (!fullName)
1265
1267
  return '';
1266
1268
  return fullName
1269
+ .trim()
1267
1270
  .split(' ')
1268
1271
  .map(word => word[0]?.toUpperCase())
1269
1272
  .join('');
@@ -1569,9 +1572,6 @@ async function signIn() {
1569
1572
  if (!response) {
1570
1573
  warn("No response from login, redirecting to login page", response);
1571
1574
  }
1572
- else {
1573
- notify.info("Successfully signed in");
1574
- }
1575
1575
  }
1576
1576
  catch (err) {
1577
1577
  error("Error during login", err);
@@ -4820,8 +4820,8 @@ class UserProfileService {
4820
4820
  * @param id - The ID of the user.
4821
4821
  * @returns An Observable that emits an the UserProfile object.
4822
4822
  */
4823
- getUserProfile(principal) {
4824
- return httpResource(() => (principal()?.userId ? `${this.API_URL}/${principal()?.userId}` : undefined), {
4823
+ getUserProfile(userId) {
4824
+ return httpResource(() => (userId() ? `${this.API_URL}/${userId()}` : undefined), {
4825
4825
  parse: (response) => {
4826
4826
  return response;
4827
4827
  }
@@ -5077,7 +5077,7 @@ class DocumentLocatorComponent {
5077
5077
 
5078
5078
  <div #documentLocator class="flex grow items-center gap-2 overflow-auto">
5079
5079
  @for (segment of visibleSegments(); track $index) {
5080
- <button decoration="underline" class="text-foreground h-auto cursor-pointer whitespace-nowrap p-0" (click)="navigateToSegment($index)">
5080
+ <button variant="link" class="text-foreground h-auto cursor-pointer whitespace-nowrap p-0" (click)="navigateToSegment($index)">
5081
5081
  {{ segment }}
5082
5082
  </button>
5083
5083
 
@@ -5140,7 +5140,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
5140
5140
 
5141
5141
  <div #documentLocator class="flex grow items-center gap-2 overflow-auto">
5142
5142
  @for (segment of visibleSegments(); track $index) {
5143
- <button decoration="underline" class="text-foreground h-auto cursor-pointer whitespace-nowrap p-0" (click)="navigateToSegment($index)">
5143
+ <button variant="link" class="text-foreground h-auto cursor-pointer whitespace-nowrap p-0" (click)="navigateToSegment($index)">
5144
5144
  {{ segment }}
5145
5145
  </button>
5146
5146
 
@@ -5553,11 +5553,11 @@ class CollectionsDialog {
5553
5553
  }
5554
5554
 
5555
5555
  <DialogFooter class="flex flex-col">
5556
- <button decoration="outline" #closeBtn (click)="onClose()" >
5556
+ <button variant="outline" #closeBtn (click)="onClose()" >
5557
5557
  {{ 'collections.close' | transloco }}
5558
5558
  </button>
5559
5559
  <button
5560
- [decoration]="creating() ? 'outline' : undefined"
5560
+ [variant]="creating() ? 'outline' : undefined"
5561
5561
  tabindex="0"
5562
5562
  [attr.title]="(creating() ? 'collections.cancelCreation' : 'collections.createCollection') | transloco"
5563
5563
  (click)="onCreate()">
@@ -5637,11 +5637,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
5637
5637
  }
5638
5638
 
5639
5639
  <DialogFooter class="flex flex-col">
5640
- <button decoration="outline" #closeBtn (click)="onClose()" >
5640
+ <button variant="outline" #closeBtn (click)="onClose()" >
5641
5641
  {{ 'collections.close' | transloco }}
5642
5642
  </button>
5643
5643
  <button
5644
- [decoration]="creating() ? 'outline' : undefined"
5644
+ [variant]="creating() ? 'outline' : undefined"
5645
5645
  tabindex="0"
5646
5646
  [attr.title]="(creating() ? 'collections.cancelCreation' : 'collections.createCollection') | transloco"
5647
5647
  (click)="onCreate()">
@@ -5892,7 +5892,7 @@ class ExportDialog {
5892
5892
  </section>
5893
5893
 
5894
5894
  <DialogFooter>
5895
- <button decoration="outline" (click)="dialog.close()">
5895
+ <button variant="outline" (click)="dialog.close()">
5896
5896
  {{ 'cancel' | transloco }}
5897
5897
  </button>
5898
5898
  <button tabindex="0" [attr.title]="'export.download' | transloco" (click)="onDownload()">
@@ -5981,7 +5981,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
5981
5981
  </section>
5982
5982
 
5983
5983
  <DialogFooter>
5984
- <button decoration="outline" (click)="dialog.close()">
5984
+ <button variant="outline" (click)="dialog.close()">
5985
5985
  {{ 'cancel' | transloco }}
5986
5986
  </button>
5987
5987
  <button tabindex="0" [attr.title]="'export.download' | transloco" (click)="onDownload()">
@@ -9538,12 +9538,12 @@ class AlertDialog {
9538
9538
  @if (alert || canUpdateQuery()) {
9539
9539
  <div class="flex w-full flex-col gap-2">
9540
9540
  @if (alert) {
9541
- <button decoration="outline" (click)="execute()" [disabled]="!canUpdateQuery()">
9541
+ <button variant="outline" (click)="execute()" [disabled]="!canUpdateQuery()">
9542
9542
  {{ 'alerts.execute' | transloco }}
9543
9543
  </button>
9544
9544
  }
9545
9545
  @if (canUpdateQuery()) {
9546
- <button [disabled]="updateStatus() !== 'idle'" decoration="outline" (click)="updateQuery()">
9546
+ <button [disabled]="updateStatus() !== 'idle'" variant="outline" (click)="updateQuery()">
9547
9547
  @switch (updateStatus()) {
9548
9548
  @case ('updating') {
9549
9549
  <LoadingCircle class="size-4 animate-spin" width="16" height="16" />
@@ -9562,7 +9562,7 @@ class AlertDialog {
9562
9562
  </div>
9563
9563
  }
9564
9564
  <div class="ml-auto flex justify-end gap-2">
9565
- <button decoration="outline" (click)="dialog.cancel()">
9565
+ <button variant="outline" (click)="dialog.cancel()">
9566
9566
  {{ 'cancel' | transloco }}
9567
9567
  </button>
9568
9568
  <button (click)="confirm()" [disabled]="invalidForm()">
@@ -9668,12 +9668,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
9668
9668
  @if (alert || canUpdateQuery()) {
9669
9669
  <div class="flex w-full flex-col gap-2">
9670
9670
  @if (alert) {
9671
- <button decoration="outline" (click)="execute()" [disabled]="!canUpdateQuery()">
9671
+ <button variant="outline" (click)="execute()" [disabled]="!canUpdateQuery()">
9672
9672
  {{ 'alerts.execute' | transloco }}
9673
9673
  </button>
9674
9674
  }
9675
9675
  @if (canUpdateQuery()) {
9676
- <button [disabled]="updateStatus() !== 'idle'" decoration="outline" (click)="updateQuery()">
9676
+ <button [disabled]="updateStatus() !== 'idle'" variant="outline" (click)="updateQuery()">
9677
9677
  @switch (updateStatus()) {
9678
9678
  @case ('updating') {
9679
9679
  <LoadingCircle class="size-4 animate-spin" width="16" height="16" />
@@ -9692,7 +9692,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
9692
9692
  </div>
9693
9693
  }
9694
9694
  <div class="ml-auto flex justify-end gap-2">
9695
- <button decoration="outline" (click)="dialog.cancel()">
9695
+ <button variant="outline" (click)="dialog.cancel()">
9696
9696
  {{ 'cancel' | transloco }}
9697
9697
  </button>
9698
9698
  <button (click)="confirm()" [disabled]="invalidForm()">
@@ -9748,11 +9748,11 @@ class AlertsComponent {
9748
9748
  this.tmpAlerts.splice(drop.currentIndex, 0, this.tmpAlerts.splice(drop.previousIndex, 1)[0]);
9749
9749
  }
9750
9750
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AlertsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9751
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AlertsComponent, isStandalone: true, selector: "Alerts", providers: [provideTranslocoScope('alerts')], viewQueries: [{ propertyName: "alertFormDialog", first: true, predicate: AlertDialog, descendants: true, isSignal: true }], ngImport: i0, template: "<ul\n role=\"list\"\n class=\"flex min-w-80 flex-col p-2\"\n cdkDropList\n [cdkDropListData]=\"tmpAlerts\"\n [cdkDropListDisabled]=\"!reordering()\"\n (cdkDropListDropped)=\"dropped($event)\">\n @if (floating) {\n <label class=\"text-xl font-bold\">{{ 'alerts.label' | transloco }}</label>\n <HorizontalDivider />\n }\n @for (alert of tmpAlerts; track $index) {\n <li role=\"listitem\" class=\"group h-10\" tabindex=\"0\" cdkDrag (click)=\"onClick($index)\" (keydown.enter)=\"onClick($index)\">\n <i class=\"fa-fw fas fa-bell shrink-0\" aria-hidden=\"true\"></i>\n <p class=\"line-clamp-1\">{{ alert.name }}</p>\n @if (!reordering()) {\n <button\n class=\"text-destructive hover:text-destructive invisible ms-auto transition-transform hover:scale-125 group-hover:visible\"\n title=\"{{ 'alerts.deleteAlert' | transloco }}\"\n [attr.aria-label]=\"'alerts.deleteAlert' | transloco\"\n (click)=\"deleteAlert($event, $index)\">\n <i class=\"fa-fw fa-regular fa-trash-can\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <i class=\"fa-fw fa-regular fa-bars\"></i>\n }\n </li>\n } @empty {\n <li role=\"listitem\" class=\"py-4 text-center text-neutral-500\">{{ 'alerts.noAlerts' | transloco }}</li>\n }\n</ul>\n<div class=\"flex flex-col gap-2 p-2\">\n <button decoration=\"outline\" class=\"w-full\" tabindex=\"0\" [attr.title]=\"'alerts.manageAlerts' | transloco\" [disabled]=\"!alerts().length\" (click)=\"reorder()\">\n {{ (reordering() ? 'save' : 'alerts.manageAlerts') | transloco }}\n </button>\n <button class=\"w-full\" [attr.title]=\"'alerts.createAlert' | transloco\" (click)=\"createAlert()\">\n {{ 'alerts.createAlert' | transloco }}\n </button>\n</div>\n", dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "component", type: HorizontalDividerComponent, selector: "horizontal-divider, HorizontalDivider, horizontaldivider" }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
9751
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AlertsComponent, isStandalone: true, selector: "Alerts", providers: [provideTranslocoScope('alerts')], viewQueries: [{ propertyName: "alertFormDialog", first: true, predicate: AlertDialog, descendants: true, isSignal: true }], ngImport: i0, template: "<ul\r\n role=\"list\"\r\n class=\"flex min-w-80 flex-col p-2\"\r\n cdkDropList\r\n [cdkDropListData]=\"tmpAlerts\"\r\n [cdkDropListDisabled]=\"!reordering()\"\r\n (cdkDropListDropped)=\"dropped($event)\">\r\n @if (floating) {\r\n <label class=\"text-xl font-bold\">{{ \"alerts.label\" | transloco }}</label>\r\n <Separator />\r\n }\r\n @for (alert of tmpAlerts; track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n cdkDrag\r\n (click)=\"onClick($index)\"\r\n (keydown.enter)=\"onClick($index)\">\r\n <i class=\"fa-fw fas fa-bell shrink-0\" aria-hidden=\"true\"></i>\r\n <p class=\"line-clamp-1\">{{ alert.name }}</p>\r\n @if (!reordering()) {\r\n <button\r\n class=\"text-destructive hover:text-destructive invisible ms-auto transition-transform group-hover:visible hover:scale-125\"\r\n title=\"{{ 'alerts.deleteAlert' | transloco }}\"\r\n [attr.aria-label]=\"'alerts.deleteAlert' | transloco\"\r\n (click)=\"deleteAlert($event, $index)\">\r\n <i class=\"fa-fw fa-regular fa-trash-can\" aria-hidden=\"true\"></i>\r\n </button>\r\n } @else {\r\n <i class=\"fa-fw fa-regular fa-bars\"></i>\r\n }\r\n </li>\r\n } @empty {\r\n <li role=\"listitem\" class=\"py-4 text-center text-neutral-500\">\r\n {{ \"alerts.noAlerts\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n<div class=\"flex flex-col gap-2 p-2\">\r\n <button\r\n variant=\"outline\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'alerts.manageAlerts' | transloco\"\r\n [disabled]=\"!alerts().length\"\r\n (click)=\"reorder()\">\r\n {{ (reordering() ? \"save\" : \"alerts.manageAlerts\") | transloco }}\r\n </button>\r\n <button\r\n class=\"w-full\"\r\n [attr.title]=\"'alerts.createAlert' | transloco\"\r\n (click)=\"createAlert()\">\r\n {{ \"alerts.createAlert\" | transloco }}\r\n </button>\r\n</div>\r\n", dependencies: [{ 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: DragDropModule }, { kind: "directive", type: i1$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
9752
9752
  }
9753
9753
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AlertsComponent, decorators: [{
9754
9754
  type: Component,
9755
- args: [{ selector: 'Alerts', standalone: true, imports: [TranslocoPipe, ButtonComponent, HorizontalDividerComponent, ListItemComponent, DragDropModule], providers: [provideTranslocoScope('alerts')], template: "<ul\n role=\"list\"\n class=\"flex min-w-80 flex-col p-2\"\n cdkDropList\n [cdkDropListData]=\"tmpAlerts\"\n [cdkDropListDisabled]=\"!reordering()\"\n (cdkDropListDropped)=\"dropped($event)\">\n @if (floating) {\n <label class=\"text-xl font-bold\">{{ 'alerts.label' | transloco }}</label>\n <HorizontalDivider />\n }\n @for (alert of tmpAlerts; track $index) {\n <li role=\"listitem\" class=\"group h-10\" tabindex=\"0\" cdkDrag (click)=\"onClick($index)\" (keydown.enter)=\"onClick($index)\">\n <i class=\"fa-fw fas fa-bell shrink-0\" aria-hidden=\"true\"></i>\n <p class=\"line-clamp-1\">{{ alert.name }}</p>\n @if (!reordering()) {\n <button\n class=\"text-destructive hover:text-destructive invisible ms-auto transition-transform hover:scale-125 group-hover:visible\"\n title=\"{{ 'alerts.deleteAlert' | transloco }}\"\n [attr.aria-label]=\"'alerts.deleteAlert' | transloco\"\n (click)=\"deleteAlert($event, $index)\">\n <i class=\"fa-fw fa-regular fa-trash-can\" aria-hidden=\"true\"></i>\n </button>\n } @else {\n <i class=\"fa-fw fa-regular fa-bars\"></i>\n }\n </li>\n } @empty {\n <li role=\"listitem\" class=\"py-4 text-center text-neutral-500\">{{ 'alerts.noAlerts' | transloco }}</li>\n }\n</ul>\n<div class=\"flex flex-col gap-2 p-2\">\n <button decoration=\"outline\" class=\"w-full\" tabindex=\"0\" [attr.title]=\"'alerts.manageAlerts' | transloco\" [disabled]=\"!alerts().length\" (click)=\"reorder()\">\n {{ (reordering() ? 'save' : 'alerts.manageAlerts') | transloco }}\n </button>\n <button class=\"w-full\" [attr.title]=\"'alerts.createAlert' | transloco\" (click)=\"createAlert()\">\n {{ 'alerts.createAlert' | transloco }}\n </button>\n</div>\n" }]
9755
+ args: [{ selector: 'Alerts', standalone: true, imports: [TranslocoPipe, ButtonComponent, ListItemComponent, DragDropModule, Separator], providers: [provideTranslocoScope('alerts')], template: "<ul\r\n role=\"list\"\r\n class=\"flex min-w-80 flex-col p-2\"\r\n cdkDropList\r\n [cdkDropListData]=\"tmpAlerts\"\r\n [cdkDropListDisabled]=\"!reordering()\"\r\n (cdkDropListDropped)=\"dropped($event)\">\r\n @if (floating) {\r\n <label class=\"text-xl font-bold\">{{ \"alerts.label\" | transloco }}</label>\r\n <Separator />\r\n }\r\n @for (alert of tmpAlerts; track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n cdkDrag\r\n (click)=\"onClick($index)\"\r\n (keydown.enter)=\"onClick($index)\">\r\n <i class=\"fa-fw fas fa-bell shrink-0\" aria-hidden=\"true\"></i>\r\n <p class=\"line-clamp-1\">{{ alert.name }}</p>\r\n @if (!reordering()) {\r\n <button\r\n class=\"text-destructive hover:text-destructive invisible ms-auto transition-transform group-hover:visible hover:scale-125\"\r\n title=\"{{ 'alerts.deleteAlert' | transloco }}\"\r\n [attr.aria-label]=\"'alerts.deleteAlert' | transloco\"\r\n (click)=\"deleteAlert($event, $index)\">\r\n <i class=\"fa-fw fa-regular fa-trash-can\" aria-hidden=\"true\"></i>\r\n </button>\r\n } @else {\r\n <i class=\"fa-fw fa-regular fa-bars\"></i>\r\n }\r\n </li>\r\n } @empty {\r\n <li role=\"listitem\" class=\"py-4 text-center text-neutral-500\">\r\n {{ \"alerts.noAlerts\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n<div class=\"flex flex-col gap-2 p-2\">\r\n <button\r\n variant=\"outline\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'alerts.manageAlerts' | transloco\"\r\n [disabled]=\"!alerts().length\"\r\n (click)=\"reorder()\">\r\n {{ (reordering() ? \"save\" : \"alerts.manageAlerts\") | transloco }}\r\n </button>\r\n <button\r\n class=\"w-full\"\r\n [attr.title]=\"'alerts.createAlert' | transloco\"\r\n (click)=\"createAlert()\">\r\n {{ \"alerts.createAlert\" | transloco }}\r\n </button>\r\n</div>\r\n" }]
9756
9756
  }], ctorParameters: () => [], propDecorators: { alertFormDialog: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AlertDialog), { isSignal: true }] }] } });
9757
9757
 
9758
9758
  class ChangePasswordComponent {
@@ -10703,7 +10703,7 @@ class BookmarksComponent {
10703
10703
  this.range.set(this.range() + (this.config.itemsPerPage ?? 10));
10704
10704
  }
10705
10705
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: BookmarksComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10706
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: BookmarksComponent, isStandalone: true, selector: "bookmarks, Bookmarks", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("bookmarks")], ngImport: i0, template: "@if (floating) {\n <div class=\"p-2\">\n <label class=\"text-xl font-bold\">{{ 'bookmarks.label' | transloco }}</label>\n <Separator />\n </div>\n}\n\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\n @for (bookmark of paginatedBookmarks(); track $index) {\n <li role=\"listitem\" class=\"group h-10\" tabindex=\"0\" (click)=\"onClick(bookmark)\" (keydown.enter)=\"onClick(bookmark)\">\n <BookmarkIcon solid class=\"shrink-0\" />\n\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\n\n @if (bookmark.author) {\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\n <UserIcon class=\"size-3\"/>\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\n </Badge>\n }\n @if (bookmark.parentFolder) {\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\n <FolderIcon class=\"size-3\"/>\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\n </Badge>\n }\n\n <button\n variant=\"ghost\"\n size=\"icon\"\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\n class=\"text-destructive ms-auto group-hover:visible\"\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\n (click)=\"onDelete(bookmark, $event)\">\n <TrashIcon />\n </button>\n </li>\n } @empty {\n <li class=\"py-4 text-center text-neutral-500\">{{ 'bookmarks.noBookmarks' | transloco }}</li>\n }\n</ul>\n\n<div class=\"flex flex-col px-2\">\n @if (hasMore() && config.showLoadMore) {\n <button variant=\"ghost\" class=\"w-full\" tabindex=\"0\" [attr.title]=\"'loadMore' | transloco\" (click)=\"loadMore($event)\">\n {{ 'loadMore' | transloco }}\n </button>\n }\n <button decoration=\"underline\" class=\"ml-auto\" [attr.title]=\"'seeMore' | transloco\" [routerLink]=\"[config.routerLink]\">{{ 'seeMore' | transloco }}</button>\n</div>\n", styles: [":host ul{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: BookmarkIcon, selector: "bookmark-icon, BookmarkIcon", inputs: ["class", "solid"] }, { kind: "component", type: UserIcon, selector: "user-icon, UserIcon", inputs: ["class"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "component", type: FolderIcon, selector: "folder-icon, FolderIcon", inputs: ["class"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10706
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: BookmarksComponent, isStandalone: true, selector: "bookmarks, Bookmarks", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("bookmarks")], ngImport: i0, template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{ \"bookmarks.label\" | transloco }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\r\n @for (bookmark of paginatedBookmarks(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(bookmark)\"\r\n (keydown.enter)=\"onClick(bookmark)\">\r\n <BookmarkIcon solid class=\"shrink-0\" />\r\n\r\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\r\n\r\n @if (bookmark.author) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <UserIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\r\n </Badge>\r\n }\r\n @if (bookmark.parentFolder) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <FolderIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\r\n </Badge>\r\n }\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\r\n class=\"text-destructive ms-auto group-hover:visible\"\r\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\r\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\r\n (click)=\"onDelete(bookmark, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"py-4 text-center text-neutral-500\">\r\n {{ \"bookmarks.noBookmarks\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"ghost\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n", styles: [":host ul{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: BookmarkIcon, selector: "bookmark-icon, BookmarkIcon", inputs: ["class", "solid"] }, { kind: "component", type: UserIcon, selector: "user-icon, UserIcon", inputs: ["class"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "component", type: FolderIcon, selector: "folder-icon, FolderIcon", inputs: ["class"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10707
10707
  }
10708
10708
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: BookmarksComponent, decorators: [{
10709
10709
  type: Component,
@@ -10718,7 +10718,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
10718
10718
  TrashIcon,
10719
10719
  FolderIcon,
10720
10720
  BadgeComponent
10721
- ], providers: [provideTranslocoScope("bookmarks")], template: "@if (floating) {\n <div class=\"p-2\">\n <label class=\"text-xl font-bold\">{{ 'bookmarks.label' | transloco }}</label>\n <Separator />\n </div>\n}\n\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\n @for (bookmark of paginatedBookmarks(); track $index) {\n <li role=\"listitem\" class=\"group h-10\" tabindex=\"0\" (click)=\"onClick(bookmark)\" (keydown.enter)=\"onClick(bookmark)\">\n <BookmarkIcon solid class=\"shrink-0\" />\n\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\n\n @if (bookmark.author) {\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\n <UserIcon class=\"size-3\"/>\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\n </Badge>\n }\n @if (bookmark.parentFolder) {\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\n <FolderIcon class=\"size-3\"/>\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\n </Badge>\n }\n\n <button\n variant=\"ghost\"\n size=\"icon\"\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\n class=\"text-destructive ms-auto group-hover:visible\"\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\n (click)=\"onDelete(bookmark, $event)\">\n <TrashIcon />\n </button>\n </li>\n } @empty {\n <li class=\"py-4 text-center text-neutral-500\">{{ 'bookmarks.noBookmarks' | transloco }}</li>\n }\n</ul>\n\n<div class=\"flex flex-col px-2\">\n @if (hasMore() && config.showLoadMore) {\n <button variant=\"ghost\" class=\"w-full\" tabindex=\"0\" [attr.title]=\"'loadMore' | transloco\" (click)=\"loadMore($event)\">\n {{ 'loadMore' | transloco }}\n </button>\n }\n <button decoration=\"underline\" class=\"ml-auto\" [attr.title]=\"'seeMore' | transloco\" [routerLink]=\"[config.routerLink]\">{{ 'seeMore' | transloco }}</button>\n</div>\n", styles: [":host ul{scrollbar-width:thin}\n"] }]
10721
+ ], providers: [provideTranslocoScope("bookmarks")], template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{ \"bookmarks.label\" | transloco }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\r\n @for (bookmark of paginatedBookmarks(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(bookmark)\"\r\n (keydown.enter)=\"onClick(bookmark)\">\r\n <BookmarkIcon solid class=\"shrink-0\" />\r\n\r\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\r\n\r\n @if (bookmark.author) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <UserIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\r\n </Badge>\r\n }\r\n @if (bookmark.parentFolder) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <FolderIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\r\n </Badge>\r\n }\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\r\n class=\"text-destructive ms-auto group-hover:visible\"\r\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\r\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\r\n (click)=\"onDelete(bookmark, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"py-4 text-center text-neutral-500\">\r\n {{ \"bookmarks.noBookmarks\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"ghost\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n", styles: [":host ul{scrollbar-width:thin}\n"] }]
10722
10722
  }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }] } });
10723
10723
 
10724
10724
  class DeleteCollectionDialog {
@@ -10751,7 +10751,7 @@ class DeleteCollectionDialog {
10751
10751
  <p>{{ 'collections.confirmDelete' | transloco }} {{ collection()?.name }}?</p>
10752
10752
 
10753
10753
  <DialogFooter>
10754
- <button decoration="outline" (click)="dialog.cancel()">
10754
+ <button variant="outline" (click)="dialog.cancel()">
10755
10755
  {{ 'cancel' | transloco }}
10756
10756
  </button>
10757
10757
 
@@ -10788,7 +10788,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
10788
10788
  <p>{{ 'collections.confirmDelete' | transloco }} {{ collection()?.name }}?</p>
10789
10789
 
10790
10790
  <DialogFooter>
10791
- <button decoration="outline" (click)="dialog.cancel()">
10791
+ <button variant="outline" (click)="dialog.cancel()">
10792
10792
  {{ 'cancel' | transloco }}
10793
10793
  </button>
10794
10794
 
@@ -10843,7 +10843,7 @@ class CollectionsComponent {
10843
10843
  this.range.set(this.range() + (this.config.itemsPerPage ?? 10));
10844
10844
  }
10845
10845
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CollectionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10846
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: CollectionsComponent, isStandalone: true, selector: "app-collections", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("collections")], viewQueries: [{ propertyName: "deleteCollectionDialog", first: true, predicate: DeleteCollectionDialog, descendants: true, isSignal: true }], ngImport: i0, template: "@if (floating) {\n <div class=\"p-2\">\n <label class=\"text-xl font-bold\">{{ 'collections.label' | transloco }}</label>\n <Separator />\n </div>\n}\n\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\">\n @for (collection of paginatedCollections(); track $index) {\n <li\n role=\"listitem\"\n class=\"group grid grid-cols-[min-content_auto_min-content] items-center\"\n tabindex=\"0\"\n (click)=\"onClick(collection)\"\n (keydown.enter)=\"onClick(collection)\">\n <i class=\"fas fa-inbox ps-2\"></i>\n\n <p class=\"mx-2 line-clamp-1\">{{ collection.name }}</p>\n\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible group-hover:visible\"\n title=\"{{ 'collections.deleteCollection' | transloco }}\"\n [attr.aria-label]=\"'collections.deleteCollection' | transloco\"\n (click)=\"onDelete(collection, $index, $event)\">\n <TrashIcon />\n </button>\n </li>\n } @empty {\n <li class=\"list-none py-4 text-center text-neutral-500\">{{ 'collections.noCollections' | transloco }}</li>\n }\n</ul>\n\n<div class=\"flex flex-col px-2\">\n @if (hasMore() && config.showLoadMore) {\n <button decoration=\"outline\" class=\"w-full\" tabindex=\"0\" [attr.title]=\"'loadMore' | transloco\" (click)=\"loadMore($event)\">\n {{ 'loadMore' | transloco }}\n </button>\n }\n <button decoration=\"underline\" class=\"ml-auto\" [attr.title]=\"'seeMore' | transloco\" [routerLink]=\"[config.routerLink]\">{{ 'seeMore' | transloco }}</button>\n</div>\n\n<delete-collection-dialog />\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: DeleteCollectionDialog, selector: "delete-collection-dialog" }, { 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: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10846
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: CollectionsComponent, isStandalone: true, selector: "app-collections", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("collections")], viewQueries: [{ propertyName: "deleteCollectionDialog", first: true, predicate: DeleteCollectionDialog, descendants: true, isSignal: true }], ngImport: i0, template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{\r\n \"collections.label\" | transloco\r\n }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\">\r\n @for (collection of paginatedCollections(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group grid grid-cols-[min-content_auto_min-content] items-center\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(collection)\"\r\n (keydown.enter)=\"onClick(collection)\">\r\n <i class=\"fas fa-inbox ps-2\"></i>\r\n\r\n <p class=\"mx-2 line-clamp-1\">{{ collection.name }}</p>\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n class=\"text-destructive invisible group-hover:visible\"\r\n title=\"{{ 'collections.deleteCollection' | transloco }}\"\r\n [attr.aria-label]=\"'collections.deleteCollection' | transloco\"\r\n (click)=\"onDelete(collection, $index, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"list-none py-4 text-center text-neutral-500\">\r\n {{ \"collections.noCollections\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"outline\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n\r\n<delete-collection-dialog />\r\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: DeleteCollectionDialog, selector: "delete-collection-dialog" }, { 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: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
10847
10847
  }
10848
10848
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CollectionsComponent, decorators: [{
10849
10849
  type: Component,
@@ -10855,7 +10855,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
10855
10855
  ListItemComponent,
10856
10856
  Separator,
10857
10857
  TrashIcon
10858
- ], providers: [provideTranslocoScope("collections")], template: "@if (floating) {\n <div class=\"p-2\">\n <label class=\"text-xl font-bold\">{{ 'collections.label' | transloco }}</label>\n <Separator />\n </div>\n}\n\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\">\n @for (collection of paginatedCollections(); track $index) {\n <li\n role=\"listitem\"\n class=\"group grid grid-cols-[min-content_auto_min-content] items-center\"\n tabindex=\"0\"\n (click)=\"onClick(collection)\"\n (keydown.enter)=\"onClick(collection)\">\n <i class=\"fas fa-inbox ps-2\"></i>\n\n <p class=\"mx-2 line-clamp-1\">{{ collection.name }}</p>\n\n <button\n variant=\"ghost\"\n size=\"icon\"\n class=\"text-destructive invisible group-hover:visible\"\n title=\"{{ 'collections.deleteCollection' | transloco }}\"\n [attr.aria-label]=\"'collections.deleteCollection' | transloco\"\n (click)=\"onDelete(collection, $index, $event)\">\n <TrashIcon />\n </button>\n </li>\n } @empty {\n <li class=\"list-none py-4 text-center text-neutral-500\">{{ 'collections.noCollections' | transloco }}</li>\n }\n</ul>\n\n<div class=\"flex flex-col px-2\">\n @if (hasMore() && config.showLoadMore) {\n <button decoration=\"outline\" class=\"w-full\" tabindex=\"0\" [attr.title]=\"'loadMore' | transloco\" (click)=\"loadMore($event)\">\n {{ 'loadMore' | transloco }}\n </button>\n }\n <button decoration=\"underline\" class=\"ml-auto\" [attr.title]=\"'seeMore' | transloco\" [routerLink]=\"[config.routerLink]\">{{ 'seeMore' | transloco }}</button>\n</div>\n\n<delete-collection-dialog />\n" }]
10858
+ ], providers: [provideTranslocoScope("collections")], template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{\r\n \"collections.label\" | transloco\r\n }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\">\r\n @for (collection of paginatedCollections(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group grid grid-cols-[min-content_auto_min-content] items-center\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(collection)\"\r\n (keydown.enter)=\"onClick(collection)\">\r\n <i class=\"fas fa-inbox ps-2\"></i>\r\n\r\n <p class=\"mx-2 line-clamp-1\">{{ collection.name }}</p>\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n class=\"text-destructive invisible group-hover:visible\"\r\n title=\"{{ 'collections.deleteCollection' | transloco }}\"\r\n [attr.aria-label]=\"'collections.deleteCollection' | transloco\"\r\n (click)=\"onDelete(collection, $index, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"list-none py-4 text-center text-neutral-500\">\r\n {{ \"collections.noCollections\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"outline\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n\r\n<delete-collection-dialog />\r\n" }]
10859
10859
  }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], deleteCollectionDialog: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DeleteCollectionDialog), { isSignal: true }] }] } });
10860
10860
 
10861
10861
  class OverrideUserDialogComponent {
@@ -10954,7 +10954,7 @@ class OverrideUserDialogComponent {
10954
10954
  </div>
10955
10955
 
10956
10956
  <DialogFooter>
10957
- <button decoration="outline" (click)="dialog.close()">
10957
+ <button variant="outline" (click)="dialog.close()">
10958
10958
  {{ 'cancel' | transloco }}
10959
10959
  </button>
10960
10960
 
@@ -11019,7 +11019,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
11019
11019
  </div>
11020
11020
 
11021
11021
  <DialogFooter>
11022
- <button decoration="outline" (click)="dialog.close()">
11022
+ <button variant="outline" (click)="dialog.close()">
11023
11023
  {{ 'cancel' | transloco }}
11024
11024
  </button>
11025
11025
 
@@ -11058,7 +11058,7 @@ class ResetUserSettingsDialogComponent {
11058
11058
  <p>{{ 'dialogs.resetUserSettings.message' | transloco }}</p>
11059
11059
 
11060
11060
  <DialogFooter>
11061
- <button decoration="outline" (click)="dialog.close()">
11061
+ <button variant="outline" (click)="dialog.close()">
11062
11062
  {{ 'cancel' | transloco }}
11063
11063
  </button>
11064
11064
 
@@ -11095,7 +11095,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
11095
11095
  <p>{{ 'dialogs.resetUserSettings.message' | transloco }}</p>
11096
11096
 
11097
11097
  <DialogFooter>
11098
- <button decoration="outline" (click)="dialog.close()">
11098
+ <button variant="outline" (click)="dialog.close()">
11099
11099
  {{ 'cancel' | transloco }}
11100
11100
  </button>
11101
11101
 
@@ -12474,7 +12474,7 @@ class FeedbackDialogComponent {
12474
12474
  }
12475
12475
 
12476
12476
  <DialogFooter>
12477
- <button decoration="outline" (click)="dialog.close()">
12477
+ <button variant="outline" (click)="dialog.close()">
12478
12478
  {{ 'cancel' | transloco }}
12479
12479
  </button>
12480
12480
  <button [disabled]="!comment()" (click)="submit()">
@@ -12519,7 +12519,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
12519
12519
  }
12520
12520
 
12521
12521
  <DialogFooter>
12522
- <button decoration="outline" (click)="dialog.close()">
12522
+ <button variant="outline" (click)="dialog.close()">
12523
12523
  {{ 'cancel' | transloco }}
12524
12524
  </button>
12525
12525
  <button [disabled]="!comment()" (click)="submit()">
@@ -12800,9 +12800,10 @@ class AggregationTreeComponent {
12800
12800
  error("The aggregation tree component does not support list aggregations. Please use the <Aggregation /> component instead.");
12801
12801
  }
12802
12802
  // overrides "expandedLevel" from custom JSON file
12803
- const expandedLevel = this.expandedLevel() ?? agg.expandedLevel ?? 0;
12804
- console.log(`${agg.name} expandedlLevel`, this.expandedLevel(), agg.expandedLevel, expandedLevel);
12805
- this.expandItems(agg.items, expandedLevel);
12803
+ const expandedLevel = this.expandedLevel() ?? agg.expandedLevel;
12804
+ if (expandedLevel) {
12805
+ this.expandItems(agg.items, expandedLevel);
12806
+ }
12806
12807
  // overrides "searchable" properties with the input if any
12807
12808
  agg.searchable = this.searchable() ?? agg.searchable;
12808
12809
  return agg;
@@ -12890,6 +12891,8 @@ class AggregationTreeComponent {
12890
12891
  constructor() {
12891
12892
  this.query = buildQuery();
12892
12893
  effect(() => {
12894
+ // if the aggregation store changes, remove previous session storage
12895
+ getState(this.aggregationsStore);
12893
12896
  sessionStorage.removeItem(`agg-${this.column()}`);
12894
12897
  });
12895
12898
  effect(() => {
@@ -13287,9 +13290,9 @@ class AggregationTreeComponent {
13287
13290
  if (!node.$opened && node.items?.length >= 0 && level < expandedLevel) {
13288
13291
  node.$opened = true;
13289
13292
  }
13290
- if (node.$opened && level >= expandedLevel) {
13291
- node.$opened = false;
13292
- }
13293
+ // if(node.$opened && level >= expandedLevel) {
13294
+ // node.$opened = false;
13295
+ // }
13293
13296
  return false;
13294
13297
  });
13295
13298
  }
@@ -14775,11 +14778,11 @@ class SearchFooterComponent {
14775
14778
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: SearchFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
14776
14779
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: SearchFooterComponent, isStandalone: true, selector: "search-footer, searchfooter, SearchFooter", inputs: { hasMore: { classPropertyName: "hasMore", publicName: "hasMore", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { loadMore: "loadMore" }, ngImport: i0, template: ` <div class="flex flex-col px-2">
14777
14780
  @if (hasMore() && config().showLoadMore) {
14778
- <button decoration="outline" class="w-full" tabindex="0" [attr.title]="'loadMore' | transloco" (click)="onLoadMore($event)">
14781
+ <button variant="outline" class="w-full" tabindex="0" [attr.title]="'loadMore' | transloco" (click)="onLoadMore($event)">
14779
14782
  {{ 'loadMore' | transloco }}
14780
14783
  </button>
14781
14784
  }
14782
- <button decoration="underline" class="ml-auto" [attr.title]="'seeMore' | transloco" [routerLink]="[config().routerLink]">
14785
+ <button variant="link" class="ml-auto" [attr.title]="'seeMore' | transloco" [routerLink]="[config().routerLink]">
14783
14786
  {{ 'seeMore' | transloco }}
14784
14787
  </button>
14785
14788
  </div>`, isInline: true, dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "size"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
@@ -14791,11 +14794,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
14791
14794
  imports: [TranslocoPipe, RouterLink, ButtonComponent],
14792
14795
  template: ` <div class="flex flex-col px-2">
14793
14796
  @if (hasMore() && config().showLoadMore) {
14794
- <button decoration="outline" class="w-full" tabindex="0" [attr.title]="'loadMore' | transloco" (click)="onLoadMore($event)">
14797
+ <button variant="outline" class="w-full" tabindex="0" [attr.title]="'loadMore' | transloco" (click)="onLoadMore($event)">
14795
14798
  {{ 'loadMore' | transloco }}
14796
14799
  </button>
14797
14800
  }
14798
- <button decoration="underline" class="ml-auto" [attr.title]="'seeMore' | transloco" [routerLink]="[config().routerLink]">
14801
+ <button variant="link" class="ml-auto" [attr.title]="'seeMore' | transloco" [routerLink]="[config().routerLink]">
14799
14802
  {{ 'seeMore' | transloco }}
14800
14803
  </button>
14801
14804
  </div>`
@@ -15079,7 +15082,7 @@ class SavedSearchDialog {
15079
15082
  (ngModelChange)="saveName.set($event)" />
15080
15083
 
15081
15084
  <DialogFooter>
15082
- <button decoration="outline" (click)="dialog.close()">
15085
+ <button variant="outline" (click)="dialog.close()">
15083
15086
  {{ 'cancel' | transloco }}
15084
15087
  </button>
15085
15088
  <button (click)="confirm()" [disabled]="!saveName()">
@@ -15124,7 +15127,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
15124
15127
  (ngModelChange)="saveName.set($event)" />
15125
15128
 
15126
15129
  <DialogFooter>
15127
- <button decoration="outline" (click)="dialog.close()">
15130
+ <button variant="outline" (click)="dialog.close()">
15128
15131
  {{ 'cancel' | transloco }}
15129
15132
  </button>
15130
15133
  <button (click)="confirm()" [disabled]="!saveName()">
@@ -15218,15 +15221,7 @@ class UserProfileFormComponent {
15218
15221
  }, ...(ngDevMode ? [{ debugName: "keys" }] : []));
15219
15222
  formKeys = computed(() => this.keys().filter(k => k !== "profilePhoto"), ...(ngDevMode ? [{ debugName: "formKeys" }] : []));
15220
15223
  allowProfilePhoto = computed(() => this.keys().some(k => k === "profilePhoto"), ...(ngDevMode ? [{ debugName: "allowProfilePhoto" }] : []));
15221
- initials = computed(() => {
15222
- const fullName = this.userProfile()?.data?.fullName;
15223
- if (!fullName)
15224
- return undefined;
15225
- return fullName
15226
- .split(" ")
15227
- .map((word) => word[0].toUpperCase())
15228
- .join("");
15229
- }, ...(ngDevMode ? [{ debugName: "initials" }] : []));
15224
+ initials = computed(() => this.principalStore.initials(), ...(ngDevMode ? [{ debugName: "initials" }] : []));
15230
15225
  username = computed(() => this.principalStore.name() || this.principalStore.email() || null, ...(ngDevMode ? [{ debugName: "username" }] : []));
15231
15226
  propertyToEdit = signal(undefined, ...(ngDevMode ? [{ debugName: "propertyToEdit" }] : []));
15232
15227
  value = model(undefined, ...(ngDevMode ? [{ debugName: "value" }] : []));
@@ -15236,17 +15231,13 @@ class UserProfileFormComponent {
15236
15231
  { code: "fr", label: "Français", icon: FlagFrenchIconComponent }
15237
15232
  ];
15238
15233
  changingPassword = signal(false, ...(ngDevMode ? [{ debugName: "changingPassword" }] : []));
15239
- principal = computed(() => this.principalStore.principal?.(), ...(ngDevMode ? [{ debugName: "principal" }] : []));
15240
- customData = computed(() => {
15241
- const customData = this.appStore.general()?.features?.userProfile?.customData;
15242
- const profileKeys = this.userProfile()?.customData;
15243
- return (customData?.length ? customData : (profileKeys ? Object.keys(profileKeys) : []))
15244
- .filter(key => !this.keys().some(k => k.toLowerCase() === key.toLowerCase())); // hide any duplicates in customData keys from data's
15245
- }, ...(ngDevMode ? [{ debugName: "customData" }] : []));
15234
+ customData = computed(() => (this.appStore.general()?.features?.userProfile?.customData || [])
15235
+ .filter(key => !this.keys().some(k => k.toLowerCase() === key.toLowerCase())), ...(ngDevMode ? [{ debugName: "customData" }] : []));
15246
15236
  allowChangePassword = computed(() => {
15247
15237
  const { useCredentials } = globalConfig;
15248
15238
  const { allowChangePassword = false } = this.appStore.general()?.features || {};
15249
- return allowChangePassword && useCredentials && this.principal().editablePartition;
15239
+ const editablePartition = this.principalStore.editablePartition?.() || false;
15240
+ return allowChangePassword && useCredentials && editablePartition;
15250
15241
  }, ...(ngDevMode ? [{ debugName: "allowChangePassword" }] : []));
15251
15242
  constructor() {
15252
15243
  this.currentLanguage.set(this.transloco.getActiveLang());
@@ -15257,26 +15248,31 @@ class UserProfileFormComponent {
15257
15248
  }
15258
15249
  });
15259
15250
  }
15260
- userProfileResource = this.userProfileService.getUserProfile(this.principal);
15251
+ userProfileResource = this.userProfileService.getUserProfile(this.principalStore.userId);
15261
15252
  userProfile = linkedSignal(() => {
15262
15253
  if (this.userProfileResource.hasValue()) {
15263
15254
  return this.userProfileResource.value();
15264
15255
  }
15265
- const { userId: id, email: mail, fullName } = this.principal() || {};
15256
+ const { userId: id, email: mail, fullName } = getState(this.principalStore);
15266
15257
  if (!id || !mail || !fullName) {
15267
15258
  return undefined;
15268
15259
  }
15269
15260
  return { data: { id, mail, fullName } };
15270
15261
  }, ...(ngDevMode ? [{ debugName: "userProfile" }] : []));
15271
15262
  async createUserProfile() {
15272
- const { userId: id, email: mail, fullName } = this.principal() || {};
15263
+ const { userId: id, email: mail, fullName } = getState(this.principalStore);
15273
15264
  if (!id) {
15274
15265
  return;
15275
15266
  }
15276
- const response = await createUserProfile({ data: { id, mail, fullName } });
15277
- if (response) {
15278
- info("Created user profile", response);
15279
- this.userProfileResource.set(response);
15267
+ try {
15268
+ const response = await createUserProfile({ data: { id, mail, fullName } });
15269
+ if (response) {
15270
+ info("Created user profile", response);
15271
+ this.userProfileResource.set(response);
15272
+ }
15273
+ }
15274
+ catch (err) {
15275
+ notify.error(err.message);
15280
15276
  }
15281
15277
  }
15282
15278
  /**
@@ -15288,7 +15284,7 @@ class UserProfileFormComponent {
15288
15284
  onEdit(category, propertyName) {
15289
15285
  const data = this.userProfile()?.[category];
15290
15286
  const value = data?.[propertyName];
15291
- this.value.set(value || "");
15287
+ this.value.set(value?.trim() || "");
15292
15288
  this.propertyToEdit.set(`${category}.${propertyName}`);
15293
15289
  }
15294
15290
  /**
@@ -15298,15 +15294,20 @@ class UserProfileFormComponent {
15298
15294
  * @param propertyName property name
15299
15295
  */
15300
15296
  async onDeleteData(category, propertyName) {
15301
- const response = await deleteUserProfileProperty(this.userProfile(), category, propertyName);
15302
- if (response) {
15303
- info("Deleted user profile property", response);
15304
- const userProfile = JSON.parse(JSON.stringify(this.userProfile()));
15305
- userProfile[category][propertyName] = undefined;
15306
- this.userProfileResource.set(userProfile);
15297
+ try {
15298
+ const response = await deleteUserProfileProperty(this.userProfile(), category, propertyName);
15299
+ if (response) {
15300
+ info("Deleted user profile property", response);
15301
+ const userProfile = JSON.parse(JSON.stringify(this.userProfile()));
15302
+ userProfile[category][propertyName] = undefined;
15303
+ this.userProfileResource.set(userProfile);
15304
+ }
15305
+ else {
15306
+ info("Could not delete user profile property", response);
15307
+ }
15307
15308
  }
15308
- else {
15309
- info("Could not delete user profile property", response);
15309
+ catch (err) {
15310
+ notify.error(err.message);
15310
15311
  }
15311
15312
  }
15312
15313
  /**
@@ -15320,19 +15321,24 @@ class UserProfileFormComponent {
15320
15321
  const userProfile = JSON.parse(JSON.stringify(this.userProfile()));
15321
15322
  if (!userProfile[category])
15322
15323
  userProfile[category] = {};
15323
- userProfile[category][propertyName] = this.value();
15324
- const response = await patchUserProfile(userProfile, category, propertyName);
15325
- if (response) {
15326
- const newUserProfile = this.userProfile();
15327
- this.userProfileResource.set({
15328
- ...newUserProfile,
15329
- ...response,
15330
- data: { ...(newUserProfile?.data || {}), ...(response.data || {}) },
15331
- customData: { ...(newUserProfile?.customData || {}), ...(response.customData || {}) }
15332
- });
15324
+ userProfile[category][propertyName] = this.value()?.trim() || "";
15325
+ try {
15326
+ const response = await patchUserProfile(userProfile, category, propertyName);
15327
+ if (response) {
15328
+ const newUserProfile = this.userProfile();
15329
+ this.userProfileResource.set({
15330
+ ...newUserProfile,
15331
+ ...response,
15332
+ data: { ...(newUserProfile?.data || {}), ...(response.data || {}) },
15333
+ customData: { ...(newUserProfile?.customData || {}), ...(response.customData || {}) }
15334
+ });
15335
+ }
15336
+ this.value.set(undefined);
15337
+ this.propertyToEdit.set(undefined);
15338
+ }
15339
+ catch (err) {
15340
+ notify.error(err.message);
15333
15341
  }
15334
- this.value.set(undefined);
15335
- this.propertyToEdit.set(undefined);
15336
15342
  }
15337
15343
  /**
15338
15344
  * Get the value of a data key
@@ -15376,7 +15382,7 @@ class UserProfileFormComponent {
15376
15382
  }
15377
15383
  }
15378
15384
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: UserProfileFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15379
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", 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" }] });
15385
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", 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 cursor-pointer\"\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: "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" }] });
15380
15386
  }
15381
15387
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: UserProfileFormComponent, decorators: [{
15382
15388
  type: Component,
@@ -15384,7 +15390,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
15384
15390
  FormsModule,
15385
15391
  RouterModule,
15386
15392
  TranslocoPipe,
15387
- InputComponent,
15388
15393
  TrashIcon,
15389
15394
  EditIcon,
15390
15395
  UndoIcon,
@@ -15394,19 +15399,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
15394
15399
  AvatarImageComponent,
15395
15400
  ButtonComponent,
15396
15401
  ChangePasswordComponent
15397
- ], 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" }]
15402
+ ], 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 cursor-pointer\"\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" }]
15398
15403
  }], 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"] }] } });
15399
15404
 
15400
15405
  class UserProfileDialog {
15401
15406
  dialog = viewChild(DialogComponent, ...(ngDevMode ? [{ debugName: "dialog" }] : []));
15402
15407
  opened = signal(false, ...(ngDevMode ? [{ debugName: "opened" }] : []));
15403
15408
  open() {
15404
- this.dialog()?.showModal();
15409
+ this.dialog()?.open();
15405
15410
  this.opened.set(true);
15406
15411
  }
15407
15412
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: UserProfileDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
15408
15413
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: UserProfileDialog, isStandalone: true, selector: "user-profile-dialog, userprofiledialog, UserProfileDialog", providers: [provideTranslocoScope("user-profile")], viewQueries: [{ propertyName: "dialog", first: true, predicate: DialogComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
15409
- <dialog #dialog>
15414
+ <div dialog #dialog="dialog">
15410
15415
  <DialogContent class="max-h-11/12 overflow-auto">
15411
15416
  <DialogHeader>
15412
15417
  <DialogTitle>{{ 'userProfile.title' | transloco }}</DialogTitle>
@@ -15415,9 +15420,8 @@ class UserProfileDialog {
15415
15420
  @if (opened()) {
15416
15421
  <user-profile-form />
15417
15422
  }
15418
-
15419
- </DialogContent>
15420
- </dialog>
15423
+ </DialogContent>
15424
+ </div>
15421
15425
  `, isInline: true, dependencies: [{ kind: "component", type: DialogComponent, selector: "dialog, [dialog]", outputs: ["closed"], exportAs: ["dialog"] }, { kind: "component", type: DialogHeaderComponent, selector: "DialogHeader" }, { kind: "directive", type: DialogContentComponent, selector: "DialogContent", inputs: ["class"] }, { kind: "component", type: UserProfileFormComponent, selector: "user-profile-form, UserProfileForm, userprofileform", inputs: ["value", "currentLanguage"], outputs: ["valueChange", "currentLanguageChange"] }, { kind: "directive", type: DialogTitleComponent, selector: "DialogTitle", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
15422
15426
  }
15423
15427
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: UserProfileDialog, decorators: [{
@@ -15435,7 +15439,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
15435
15439
  ],
15436
15440
  providers: [provideTranslocoScope("user-profile")],
15437
15441
  template: `
15438
- <dialog #dialog>
15442
+ <div dialog #dialog="dialog">
15439
15443
  <DialogContent class="max-h-11/12 overflow-auto">
15440
15444
  <DialogHeader>
15441
15445
  <DialogTitle>{{ 'userProfile.title' | transloco }}</DialogTitle>
@@ -15444,9 +15448,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
15444
15448
  @if (opened()) {
15445
15449
  <user-profile-form />
15446
15450
  }
15447
-
15448
- </DialogContent>
15449
- </dialog>
15451
+ </DialogContent>
15452
+ </div>
15450
15453
  `
15451
15454
  }]
15452
15455
  }], propDecorators: { dialog: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DialogComponent), { isSignal: true }] }] } });
@@ -15612,6 +15615,9 @@ const toastInterceptorFn = (request, next) => {
15612
15615
  }
15613
15616
  }
15614
15617
  if ([400, 403, 500, 503].includes(status)) {
15618
+ if (status === 400 && url.includes("api/v2/user-profile")) {
15619
+ return next(request);
15620
+ }
15615
15621
  // Avoid showing error toasts for preview requests
15616
15622
  if (url.includes("api/v1/preview") === false) {
15617
15623
  const { errorMessage = err.statusText, errorCodeText = `Error ${status}` } = error;