oip-common 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,14 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, inject, InjectionToken, signal, computed, effect, DestroyRef, ChangeDetectorRef, Component, Input, PLATFORM_ID, HostBinding, EventEmitter, Output, ViewChild, Renderer2, SecurityContext, ChangeDetectionStrategy, makeEnvironmentProviders, Pipe } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
- import * as i2$6 from 'primeng/api';
4
+ import * as i2$3 from 'primeng/api';
5
5
  import { MessageService, ConfirmationService, PrimeIcons, SharedModule } from 'primeng/api';
6
6
  import { HttpErrorResponse, HttpClient as HttpClient$1, HttpHeaders } from '@angular/common/http';
7
7
  import * as i2$4 from '@ngx-translate/core';
8
8
  import { TranslateService, TranslatePipe, TranslateModule } from '@ngx-translate/core';
9
9
  import * as i1$3 from '@angular/router';
10
10
  import { ActivatedRoute, Router, RouterModule, NavigationEnd, RouterLinkActive, RouterLink } from '@angular/router';
11
- import { lastValueFrom, BehaviorSubject, Subject, ReplaySubject, merge, from, filter as filter$1, combineLatest, of, map as map$1, Observable } from 'rxjs';
11
+ import { lastValueFrom, BehaviorSubject, Subject, of, tap, shareReplay, ReplaySubject, merge, from, finalize, firstValueFrom, filter as filter$1, combineLatest, map as map$1, Observable } from 'rxjs';
12
12
  import { filter, distinctUntilChanged, map, switchMap, catchError } from 'rxjs/operators';
13
13
  import { Title, DomSanitizer } from '@angular/platform-browser';
14
14
  import { PrimeNG } from 'primeng/config';
@@ -36,15 +36,15 @@ import * as i2$2 from 'primeng/avatar';
36
36
  import { AvatarModule } from 'primeng/avatar';
37
37
  import * as i1$4 from 'primeng/contextmenu';
38
38
  import { ContextMenuModule, ContextMenu } from 'primeng/contextmenu';
39
- import * as i2$3 from 'primeng/dialog';
39
+ import * as i3$3 from 'primeng/dialog';
40
40
  import { DialogModule } from 'primeng/dialog';
41
- import * as i3$3 from 'primeng/inputtext';
41
+ import * as i4 from 'primeng/inputtext';
42
42
  import { InputTextModule, InputText } from 'primeng/inputtext';
43
43
  import { trigger, state, transition, style, animate } from '@angular/animations';
44
44
  import * as i3$2 from 'primeng/ripple';
45
45
  import { RippleModule } from 'primeng/ripple';
46
46
  import { ConfirmDialog } from 'primeng/confirmdialog';
47
- import * as i4 from 'primeng/select';
47
+ import * as i5 from 'primeng/select';
48
48
  import { SelectModule, Select } from 'primeng/select';
49
49
  import * as i1$5 from 'primeng/fileupload';
50
50
  import { FileUploadModule } from 'primeng/fileupload';
@@ -58,7 +58,7 @@ import { TagModule, Tag } from 'primeng/tag';
58
58
  import { TextareaModule, Textarea } from 'primeng/textarea';
59
59
  import * as i4$1 from 'primeng/toolbar';
60
60
  import { ToolbarModule } from 'primeng/toolbar';
61
- import * as i5 from 'primeng/card';
61
+ import * as i5$1 from 'primeng/card';
62
62
  import { CardModule } from 'primeng/card';
63
63
  import { DividerModule } from 'primeng/divider';
64
64
  import * as i6 from 'primeng/panel';
@@ -611,6 +611,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
611
611
  class L10nService {
612
612
  constructor() {
613
613
  this.loadedTranslations = new Set();
614
+ this.loadingTranslations = new Map();
614
615
  this.httpClient = inject(HttpClient$1);
615
616
  this.translateService = inject(TranslateService);
616
617
  this.primeNg = inject(PrimeNG);
@@ -621,8 +622,8 @@ class L10nService {
621
622
  * @param component - Name of the component to load translations for
622
623
  */
623
624
  loadComponentTranslations(component) {
624
- const lang = this.translateService.currentLang;
625
- this.loadTranslations(component, lang);
625
+ const lang = this.translateService.currentLang || this.layoutService.language() || 'en';
626
+ return this.loadTranslations(component, lang);
626
627
  }
627
628
  /**
628
629
  * Gets the translated value of a key (or an array of keys)
@@ -640,19 +641,27 @@ class L10nService {
640
641
  loadTranslations(component, lang) {
641
642
  const key = `${component}.${lang}`;
642
643
  if (this.loadedTranslations.has(key)) {
643
- return;
644
- }
645
- try {
646
- this.httpClient.get(`./assets/i18n/${component}.${lang}.json`).subscribe((translations) => {
647
- const current = this.translateService.translations[lang] || {};
648
- this.translateService.setTranslation(lang, { ...current, ...translations }, true);
649
- this.loadedTranslations.add(key);
650
- });
644
+ return of(null);
651
645
  }
652
- catch (e) {
653
- console.error(`No translations found for ${component}.${lang}.json`);
654
- console.error(e);
646
+ const loading = this.loadingTranslations.get(key);
647
+ if (loading) {
648
+ return loading;
655
649
  }
650
+ const request = this.httpClient.get(`./assets/i18n/${component}.${lang}.json`).pipe(tap((translations) => {
651
+ const current = this.translateService.translations[lang] || {};
652
+ this.translateService.setTranslation(lang, { ...current, ...translations }, true);
653
+ this.loadedTranslations.add(key);
654
+ this.loadingTranslations.delete(key);
655
+ }), shareReplay(1));
656
+ this.loadingTranslations.set(key, request);
657
+ request.subscribe({
658
+ error: (e) => {
659
+ this.loadingTranslations.delete(key);
660
+ console.error(`No translations found for ${component}.${lang}.json`);
661
+ console.error(e);
662
+ }
663
+ });
664
+ return request;
656
665
  }
657
666
  /**
658
667
  * Changes the lang currently used
@@ -717,6 +726,11 @@ class KeycloakSecurityService extends OidcSecurityService {
717
726
  */
718
727
  constructor() {
719
728
  super();
729
+ this.refreshLockKeyPrefix = 'oip:keycloak-refresh-lock';
730
+ this.refreshResultKeyPrefix = 'oip:keycloak-refresh-result';
731
+ this.refreshLockTtlMs = 15000;
732
+ this.refreshWaitTimeoutMs = 10000;
733
+ this.refreshTabId = this.createRefreshTabId();
720
734
  /**
721
735
  * Handles angular OIDC events.
722
736
  */
@@ -759,6 +773,14 @@ class KeycloakSecurityService extends OidcSecurityService {
759
773
  getAccessToken(configId) {
760
774
  return merge(super.getAccessToken(configId), this.accessToken.asObservable()).pipe(distinctUntilChanged());
761
775
  }
776
+ forceRefreshSession(customParams, configId) {
777
+ if (!this.refreshSession$) {
778
+ this.refreshSession$ = from(this.runSynchronizedRefresh(customParams, configId)).pipe(finalize(() => {
779
+ this.refreshSession$ = undefined;
780
+ }), shareReplay({ bufferSize: 1, refCount: false }));
781
+ }
782
+ return this.refreshSession$;
783
+ }
762
784
  /**
763
785
  * Indicates whether the current user has the 'admin' role.
764
786
  *
@@ -807,6 +829,174 @@ class KeycloakSecurityService extends OidcSecurityService {
807
829
  return payload.exp < Math.floor(Date.now() / 1000);
808
830
  }));
809
831
  }
832
+ async runSynchronizedRefresh(customParams, configId) {
833
+ const webLocks = this.getWebLocks();
834
+ if (webLocks) {
835
+ return webLocks.request(this.getRefreshLockKey(configId), { mode: 'exclusive' }, async () => {
836
+ const currentState = await this.syncAuthState(configId);
837
+ if (!(await this.isCurrentAccessTokenExpired())) {
838
+ return currentState;
839
+ }
840
+ return this.refreshAsLockOwner(customParams, configId);
841
+ });
842
+ }
843
+ return this.runSynchronizedRefreshWithStorageLock(customParams, configId);
844
+ }
845
+ async runSynchronizedRefreshWithStorageLock(customParams, configId) {
846
+ const startedAt = Date.now();
847
+ if (this.tryAcquireRefreshLock(configId)) {
848
+ try {
849
+ const currentState = await this.syncAuthState(configId);
850
+ if (!(await this.isCurrentAccessTokenExpired())) {
851
+ return currentState;
852
+ }
853
+ return await this.refreshAsLockOwner(customParams, configId);
854
+ }
855
+ finally {
856
+ this.releaseRefreshLock(configId);
857
+ }
858
+ }
859
+ const waitResult = await this.waitForRefreshResult(startedAt, configId);
860
+ if (waitResult === 'success') {
861
+ return this.syncAuthState(configId);
862
+ }
863
+ if (waitResult === 'error') {
864
+ throw new Error('Token refresh failed in another tab.');
865
+ }
866
+ return this.runSynchronizedRefreshWithStorageLock(customParams, configId);
867
+ }
868
+ async refreshAsLockOwner(customParams, configId) {
869
+ try {
870
+ const response = await firstValueFrom(super.forceRefreshSession(customParams, configId));
871
+ await this.applyLoginResponse(response, configId);
872
+ this.publishRefreshResult('success', configId);
873
+ return response;
874
+ }
875
+ catch (error) {
876
+ this.publishRefreshResult('error', configId);
877
+ throw error;
878
+ }
879
+ }
880
+ async syncAuthState(configId) {
881
+ const response = await firstValueFrom(super.checkAuth(undefined, configId));
882
+ await this.applyLoginResponse(response, configId);
883
+ return response;
884
+ }
885
+ async applyLoginResponse(response, configId) {
886
+ this.loginResponse.next(response);
887
+ this.currentUser.next(response.userData);
888
+ const token = await firstValueFrom(super.getAccessToken(configId));
889
+ this.accessToken.next(token);
890
+ const payload = await firstValueFrom(this.getPayloadFromAccessToken());
891
+ this.payload.next(payload);
892
+ }
893
+ async isCurrentAccessTokenExpired() {
894
+ const payload = await firstValueFrom(this.getPayloadFromAccessToken());
895
+ return !payload?.exp || payload.exp < Math.floor(Date.now() / 1000);
896
+ }
897
+ tryAcquireRefreshLock(configId) {
898
+ const lockKey = this.getRefreshLockKey(configId);
899
+ const now = Date.now();
900
+ const currentLock = this.readRefreshLock(lockKey);
901
+ if (currentLock && currentLock.ownerId !== this.refreshTabId && currentLock.expiresAt > now) {
902
+ return false;
903
+ }
904
+ const nextLock = {
905
+ ownerId: this.refreshTabId,
906
+ expiresAt: now + this.refreshLockTtlMs
907
+ };
908
+ localStorage.setItem(lockKey, JSON.stringify(nextLock));
909
+ return this.readRefreshLock(lockKey)?.ownerId === this.refreshTabId;
910
+ }
911
+ releaseRefreshLock(configId) {
912
+ const lockKey = this.getRefreshLockKey(configId);
913
+ const currentLock = this.readRefreshLock(lockKey);
914
+ if (currentLock?.ownerId === this.refreshTabId) {
915
+ localStorage.removeItem(lockKey);
916
+ }
917
+ }
918
+ waitForRefreshResult(startedAt, configId) {
919
+ const resultKey = this.getRefreshResultKey(configId);
920
+ return new Promise((resolve) => {
921
+ const timeoutId = window.setTimeout(() => {
922
+ cleanup();
923
+ resolve('timeout');
924
+ }, this.refreshWaitTimeoutMs);
925
+ const intervalId = window.setInterval(() => {
926
+ const result = this.tryResolveRefreshResult(resultKey, startedAt, configId);
927
+ if (result) {
928
+ cleanup();
929
+ resolve(result);
930
+ }
931
+ }, 250);
932
+ const onStorage = (event) => {
933
+ if (event.key === resultKey) {
934
+ const result = this.tryResolveRefreshResult(resultKey, startedAt, configId);
935
+ if (result) {
936
+ cleanup();
937
+ resolve(result);
938
+ }
939
+ }
940
+ };
941
+ const cleanup = () => {
942
+ window.clearTimeout(timeoutId);
943
+ window.clearInterval(intervalId);
944
+ window.removeEventListener('storage', onStorage);
945
+ };
946
+ window.addEventListener('storage', onStorage);
947
+ const result = this.tryResolveRefreshResult(resultKey, startedAt, configId);
948
+ if (result) {
949
+ cleanup();
950
+ resolve(result);
951
+ }
952
+ });
953
+ }
954
+ tryResolveRefreshResult(resultKey, startedAt, configId) {
955
+ const result = this.readRefreshResult(resultKey);
956
+ if (!result || result.timestamp < startedAt || result.configId !== configId) {
957
+ return null;
958
+ }
959
+ return result.status;
960
+ }
961
+ publishRefreshResult(status, configId) {
962
+ const result = {
963
+ configId,
964
+ ownerId: this.refreshTabId,
965
+ status,
966
+ timestamp: Date.now()
967
+ };
968
+ localStorage.setItem(this.getRefreshResultKey(configId), JSON.stringify(result));
969
+ }
970
+ readRefreshLock(lockKey) {
971
+ try {
972
+ const value = localStorage.getItem(lockKey);
973
+ return value ? JSON.parse(value) : null;
974
+ }
975
+ catch {
976
+ return null;
977
+ }
978
+ }
979
+ readRefreshResult(resultKey) {
980
+ try {
981
+ const value = localStorage.getItem(resultKey);
982
+ return value ? JSON.parse(value) : null;
983
+ }
984
+ catch {
985
+ return null;
986
+ }
987
+ }
988
+ getRefreshLockKey(configId) {
989
+ return `${this.refreshLockKeyPrefix}:${configId ?? 'default'}`;
990
+ }
991
+ getRefreshResultKey(configId) {
992
+ return `${this.refreshResultKeyPrefix}:${configId ?? 'default'}`;
993
+ }
994
+ getWebLocks() {
995
+ return navigator.locks ?? null;
996
+ }
997
+ createRefreshTabId() {
998
+ return window.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
999
+ }
810
1000
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
811
1001
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService }); }
812
1002
  }
@@ -3002,9 +3192,18 @@ class MenuItemCreateDialogComponent {
3002
3192
  constructor() {
3003
3193
  this.menuService = inject(MenuService);
3004
3194
  this.menu = inject(MenuApi);
3195
+ this.msgService = inject(MsgService);
3005
3196
  this.visibleChange = new EventEmitter();
3006
3197
  this.modules = [];
3198
+ this.iconOptions = Object.values(PrimeIcons)
3199
+ .filter((icon) => typeof icon === 'string')
3200
+ .map((icon) => ({
3201
+ label: icon.replace('pi pi-', ''),
3202
+ value: icon
3203
+ }))
3204
+ .sort((left, right) => left.label.localeCompare(right.label));
3007
3205
  this.selectIcon = 'pi pi-box';
3206
+ this.saving = false;
3008
3207
  }
3009
3208
  async ngOnInit() {
3010
3209
  this.modules = await this.menu.getModules();
@@ -3014,15 +3213,27 @@ class MenuItemCreateDialogComponent {
3014
3213
  this.visibleChange.emit(this.visible);
3015
3214
  }
3016
3215
  async save() {
3216
+ if (this.saving) {
3217
+ return;
3218
+ }
3017
3219
  const item = {
3018
3220
  moduleId: this.selectModule,
3019
3221
  label: this.label,
3020
3222
  icon: this.selectIcon,
3021
3223
  parentId: this.menuService.contextMenuItem?.moduleInstanceId
3022
3224
  };
3023
- await this.menuService.addModuleInstance(item);
3024
- await this.menuService.loadMenu();
3025
- this.hide();
3225
+ this.saving = true;
3226
+ try {
3227
+ await this.menuService.addModuleInstance(item);
3228
+ await this.menuService.loadMenu();
3229
+ this.hide();
3230
+ }
3231
+ catch (error) {
3232
+ this.msgService.error(error);
3233
+ }
3234
+ finally {
3235
+ this.saving = false;
3236
+ }
3026
3237
  }
3027
3238
  hide() {
3028
3239
  this.visible = false;
@@ -3038,7 +3249,8 @@ class MenuItemCreateDialogComponent {
3038
3249
  header="{{ 'menuItemCreateDialogComponent.header' | translate }}"
3039
3250
  [modal]="true"
3040
3251
  [style]="{ width: '40rem' }"
3041
- [(visible)]="visible">
3252
+ [(visible)]="visible"
3253
+ (keydown.enter)="save()">
3042
3254
  @if (menuService.contextMenuItem) {
3043
3255
  <div class="flex items-center gap-4 mb-4 mt-1">
3044
3256
  <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-parent-input">
@@ -3077,24 +3289,47 @@ class MenuItemCreateDialogComponent {
3077
3289
  <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-icon">
3078
3290
  {{ 'menuItemCreateDialogComponent.icon' | translate }}
3079
3291
  </label>
3080
- <i class="{{ selectIcon }}"></i>
3081
- <input class="flex-auto" id="oip-menu-item-create-dialog-icon" pInputText [(ngModel)]="selectIcon" />
3292
+ <p-select
3293
+ appendTo="body"
3294
+ class="flex-auto"
3295
+ filterBy="label,value"
3296
+ id="oip-menu-item-create-dialog-icon"
3297
+ optionLabel="label"
3298
+ optionValue="value"
3299
+ scrollHeight="18rem"
3300
+ [filter]="true"
3301
+ [options]="iconOptions"
3302
+ [(ngModel)]="selectIcon">
3303
+ <ng-template let-icon pTemplate="selectedItem">
3304
+ <div class="flex items-center gap-2">
3305
+ <i [class]="icon.value"></i>
3306
+ <span>{{ icon.label }}</span>
3307
+ </div>
3308
+ </ng-template>
3309
+ <ng-template let-icon pTemplate="item">
3310
+ <div class="flex items-center gap-2">
3311
+ <i [class]="icon.value"></i>
3312
+ <span>{{ icon.label }}</span>
3313
+ </div>
3314
+ </ng-template>
3315
+ </p-select>
3082
3316
  </div>
3083
3317
  <div class="flex justify-end gap-2">
3084
3318
  <p-button
3085
3319
  id="oip-menu-item-create-cancel"
3086
3320
  label="{{ 'menuItemCreateDialogComponent.cancel' | translate }}"
3087
3321
  severity="secondary"
3088
- (click)="changeVisible()"
3089
- (keydown)="changeVisible()" />
3322
+ [disabled]="saving"
3323
+ (click)="changeVisible()" />
3090
3324
  <p-button
3091
3325
  id="oip-menu-item-create-save"
3092
3326
  label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
3093
- (click)="save()"
3094
- (keydown)="save()" />
3327
+ [disabled]="saving"
3328
+ [loading]="saving"
3329
+ (click)="save()" />
3095
3330
  </div>
3096
3331
  </p-dialog>
3097
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3332
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3098
3333
  }
3099
3334
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemCreateDialogComponent, decorators: [{
3100
3335
  type: Component,
@@ -3107,7 +3342,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3107
3342
  header="{{ 'menuItemCreateDialogComponent.header' | translate }}"
3108
3343
  [modal]="true"
3109
3344
  [style]="{ width: '40rem' }"
3110
- [(visible)]="visible">
3345
+ [(visible)]="visible"
3346
+ (keydown.enter)="save()">
3111
3347
  @if (menuService.contextMenuItem) {
3112
3348
  <div class="flex items-center gap-4 mb-4 mt-1">
3113
3349
  <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-parent-input">
@@ -3146,21 +3382,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3146
3382
  <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-icon">
3147
3383
  {{ 'menuItemCreateDialogComponent.icon' | translate }}
3148
3384
  </label>
3149
- <i class="{{ selectIcon }}"></i>
3150
- <input class="flex-auto" id="oip-menu-item-create-dialog-icon" pInputText [(ngModel)]="selectIcon" />
3385
+ <p-select
3386
+ appendTo="body"
3387
+ class="flex-auto"
3388
+ filterBy="label,value"
3389
+ id="oip-menu-item-create-dialog-icon"
3390
+ optionLabel="label"
3391
+ optionValue="value"
3392
+ scrollHeight="18rem"
3393
+ [filter]="true"
3394
+ [options]="iconOptions"
3395
+ [(ngModel)]="selectIcon">
3396
+ <ng-template let-icon pTemplate="selectedItem">
3397
+ <div class="flex items-center gap-2">
3398
+ <i [class]="icon.value"></i>
3399
+ <span>{{ icon.label }}</span>
3400
+ </div>
3401
+ </ng-template>
3402
+ <ng-template let-icon pTemplate="item">
3403
+ <div class="flex items-center gap-2">
3404
+ <i [class]="icon.value"></i>
3405
+ <span>{{ icon.label }}</span>
3406
+ </div>
3407
+ </ng-template>
3408
+ </p-select>
3151
3409
  </div>
3152
3410
  <div class="flex justify-end gap-2">
3153
3411
  <p-button
3154
3412
  id="oip-menu-item-create-cancel"
3155
3413
  label="{{ 'menuItemCreateDialogComponent.cancel' | translate }}"
3156
3414
  severity="secondary"
3157
- (click)="changeVisible()"
3158
- (keydown)="changeVisible()" />
3415
+ [disabled]="saving"
3416
+ (click)="changeVisible()" />
3159
3417
  <p-button
3160
3418
  id="oip-menu-item-create-save"
3161
3419
  label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
3162
- (click)="save()"
3163
- (keydown)="save()" />
3420
+ [disabled]="saving"
3421
+ [loading]="saving"
3422
+ (click)="save()" />
3164
3423
  </div>
3165
3424
  </p-dialog>
3166
3425
  `
@@ -3175,9 +3434,17 @@ class MenuItemEditDialogComponent {
3175
3434
  constructor() {
3176
3435
  this.menuService = inject(MenuService);
3177
3436
  this.securityDataService = inject(SecurityDataService);
3437
+ this.msgService = inject(MsgService);
3178
3438
  this.visibleChange = new EventEmitter();
3179
3439
  this.modules = [];
3180
3440
  this.roles = [];
3441
+ this.iconOptions = Object.values(PrimeIcons)
3442
+ .filter((icon) => typeof icon === 'string')
3443
+ .map((icon) => ({
3444
+ label: icon.replace('pi pi-', ''),
3445
+ value: icon
3446
+ }))
3447
+ .sort((left, right) => left.label.localeCompare(right.label));
3181
3448
  this.item = {
3182
3449
  icon: '',
3183
3450
  label: '',
@@ -3186,15 +3453,28 @@ class MenuItemEditDialogComponent {
3186
3453
  moduleInstanceId: 0,
3187
3454
  parentId: 0
3188
3455
  };
3456
+ this.saving = false;
3189
3457
  }
3190
3458
  changeVisible() {
3191
3459
  this.visible = !this.visible;
3192
3460
  this.visibleChange.emit(this.visible);
3193
3461
  }
3194
3462
  async save() {
3195
- await this.menuService.editModuleInstance(this.item);
3196
- await this.menuService.loadMenu();
3197
- this.hide();
3463
+ if (this.saving) {
3464
+ return;
3465
+ }
3466
+ this.saving = true;
3467
+ try {
3468
+ await this.menuService.editModuleInstance(this.item);
3469
+ await this.menuService.loadMenu();
3470
+ this.hide();
3471
+ }
3472
+ catch (error) {
3473
+ this.msgService.error(error);
3474
+ }
3475
+ finally {
3476
+ this.saving = false;
3477
+ }
3198
3478
  }
3199
3479
  hide() {
3200
3480
  this.visible = false;
@@ -3222,7 +3502,8 @@ class MenuItemEditDialogComponent {
3222
3502
  header="{{ 'menuItemEditDialogComponent.header' | translate }}"
3223
3503
  [modal]="true"
3224
3504
  [style]="{ width: '40rem' }"
3225
- [(visible)]="visible">
3505
+ [(visible)]="visible"
3506
+ (keydown.enter)="save()">
3226
3507
  <div class="flex items-center gap-4 mb-4 mt-1">
3227
3508
  <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-menu-input">
3228
3509
  {{ 'menuItemEditDialogComponent.label' | translate }}
@@ -3239,8 +3520,30 @@ class MenuItemEditDialogComponent {
3239
3520
  <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-icon">
3240
3521
  {{ 'menuItemEditDialogComponent.icon' | translate }}
3241
3522
  </label>
3242
- <i class="{{ item.icon }}"></i>
3243
- <input class="flex-auto" id="oip-menu-item-edit-dialog-icon" pInputText [(ngModel)]="item.icon" />
3523
+ <p-select
3524
+ appendTo="body"
3525
+ class="flex-auto"
3526
+ filterBy="label,value"
3527
+ id="oip-menu-item-edit-dialog-icon"
3528
+ optionLabel="label"
3529
+ optionValue="value"
3530
+ scrollHeight="18rem"
3531
+ [filter]="true"
3532
+ [options]="iconOptions"
3533
+ [(ngModel)]="item.icon">
3534
+ <ng-template let-icon pTemplate="selectedItem">
3535
+ <div class="flex items-center gap-2">
3536
+ <i [class]="icon.value"></i>
3537
+ <span>{{ icon.label }}</span>
3538
+ </div>
3539
+ </ng-template>
3540
+ <ng-template let-icon pTemplate="item">
3541
+ <div class="flex items-center gap-2">
3542
+ <i [class]="icon.value"></i>
3543
+ <span>{{ icon.label }}</span>
3544
+ </div>
3545
+ </ng-template>
3546
+ </p-select>
3244
3547
  </div>
3245
3548
 
3246
3549
  <div class="flex items-center gap-4 mb-4">
@@ -3262,21 +3565,22 @@ class MenuItemEditDialogComponent {
3262
3565
  id="oip-menu-item-edit-dialog-cancel-edit-button"
3263
3566
  label="{{ 'menuItemEditDialogComponent.cancel' | translate }}"
3264
3567
  severity="secondary"
3265
- (click)="changeVisible()"
3266
- (keydown)="changeVisible()" />
3568
+ [disabled]="saving"
3569
+ (click)="changeVisible()" />
3267
3570
  <p-button
3268
3571
  id="oip-menu-item-edit-dialog-save-edit-button"
3269
3572
  label="{{ 'menuItemEditDialogComponent.save' | translate }}"
3270
- (click)="save()"
3271
- (keydown)="save()" />
3573
+ [disabled]="saving"
3574
+ [loading]="saving"
3575
+ (click)="save()" />
3272
3576
  </div>
3273
3577
  </p-dialog>
3274
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i1.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3578
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i1.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3275
3579
  }
3276
3580
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemEditDialogComponent, decorators: [{
3277
3581
  type: Component,
3278
3582
  args: [{
3279
- imports: [ButtonModule, DialogModule, InputTextModule, FormsModule, TranslatePipe, MultiSelectModule],
3583
+ imports: [ButtonModule, DialogModule, InputTextModule, SelectModule, FormsModule, TranslatePipe, MultiSelectModule],
3280
3584
  selector: 'menu-item-edit-dialog',
3281
3585
  standalone: true,
3282
3586
  template: `
@@ -3284,7 +3588,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3284
3588
  header="{{ 'menuItemEditDialogComponent.header' | translate }}"
3285
3589
  [modal]="true"
3286
3590
  [style]="{ width: '40rem' }"
3287
- [(visible)]="visible">
3591
+ [(visible)]="visible"
3592
+ (keydown.enter)="save()">
3288
3593
  <div class="flex items-center gap-4 mb-4 mt-1">
3289
3594
  <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-menu-input">
3290
3595
  {{ 'menuItemEditDialogComponent.label' | translate }}
@@ -3301,8 +3606,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3301
3606
  <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-icon">
3302
3607
  {{ 'menuItemEditDialogComponent.icon' | translate }}
3303
3608
  </label>
3304
- <i class="{{ item.icon }}"></i>
3305
- <input class="flex-auto" id="oip-menu-item-edit-dialog-icon" pInputText [(ngModel)]="item.icon" />
3609
+ <p-select
3610
+ appendTo="body"
3611
+ class="flex-auto"
3612
+ filterBy="label,value"
3613
+ id="oip-menu-item-edit-dialog-icon"
3614
+ optionLabel="label"
3615
+ optionValue="value"
3616
+ scrollHeight="18rem"
3617
+ [filter]="true"
3618
+ [options]="iconOptions"
3619
+ [(ngModel)]="item.icon">
3620
+ <ng-template let-icon pTemplate="selectedItem">
3621
+ <div class="flex items-center gap-2">
3622
+ <i [class]="icon.value"></i>
3623
+ <span>{{ icon.label }}</span>
3624
+ </div>
3625
+ </ng-template>
3626
+ <ng-template let-icon pTemplate="item">
3627
+ <div class="flex items-center gap-2">
3628
+ <i [class]="icon.value"></i>
3629
+ <span>{{ icon.label }}</span>
3630
+ </div>
3631
+ </ng-template>
3632
+ </p-select>
3306
3633
  </div>
3307
3634
 
3308
3635
  <div class="flex items-center gap-4 mb-4">
@@ -3324,13 +3651,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3324
3651
  id="oip-menu-item-edit-dialog-cancel-edit-button"
3325
3652
  label="{{ 'menuItemEditDialogComponent.cancel' | translate }}"
3326
3653
  severity="secondary"
3327
- (click)="changeVisible()"
3328
- (keydown)="changeVisible()" />
3654
+ [disabled]="saving"
3655
+ (click)="changeVisible()" />
3329
3656
  <p-button
3330
3657
  id="oip-menu-item-edit-dialog-save-edit-button"
3331
3658
  label="{{ 'menuItemEditDialogComponent.save' | translate }}"
3332
- (click)="save()"
3333
- (keydown)="save()" />
3659
+ [disabled]="saving"
3660
+ [loading]="saving"
3661
+ (click)="save()" />
3334
3662
  </div>
3335
3663
  </p-dialog>
3336
3664
  `
@@ -4281,7 +4609,7 @@ class DbMigrationComponent extends BaseModuleComponent {
4281
4609
  } @else if (isSecurity) {
4282
4610
  <security [controller]="controller" [id]="id"/>
4283
4611
  }
4284
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$6.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$6.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i1$6.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i1$6.EditableRow, selector: "[pEditableRow]", inputs: ["pEditableRow", "pEditableRowDisabled"] }, { kind: "directive", type: i1$6.CancelEditableRow, selector: "[pCancelEditableRow]" }, { kind: "component", type: i1$6.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: TagModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: TextareaModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4612
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$6.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i1$6.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i1$6.EditableRow, selector: "[pEditableRow]", inputs: ["pEditableRow", "pEditableRowDisabled"] }, { kind: "directive", type: i1$6.CancelEditableRow, selector: "[pCancelEditableRow]" }, { kind: "component", type: i1$6.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: TagModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: TextareaModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4285
4613
  }
4286
4614
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DbMigrationComponent, decorators: [{
4287
4615
  type: Component,
@@ -4434,52 +4762,57 @@ class AppModulesComponent {
4434
4762
  this.msgService = inject(MsgService);
4435
4763
  this.confirmationService = inject(ConfirmationService);
4436
4764
  this.l10nService = inject(L10nService);
4437
- this.l10n = {};
4438
4765
  this.titleService = inject(AppTitleService);
4439
4766
  this.moduleService = inject(ModuleApi);
4767
+ this.translationsReady = firstValueFrom(this.l10nService.loadComponentTranslations('app-modules'));
4440
4768
  }
4441
4769
  async ngOnInit() {
4442
- this.l10nService.get('app-modules').subscribe((l10n) => {
4443
- this.l10n = l10n;
4444
- });
4445
- this.titleService.setTitle(this.l10n.title);
4770
+ await this.translationsReady;
4771
+ this.titleService.setTitle(this.t('app-modules.title'));
4446
4772
  await this.refreshAction();
4447
4773
  }
4448
4774
  async refreshAction() {
4449
4775
  this.modules = await this.moduleService.getModulesWithLoadStatus();
4450
4776
  }
4451
- deleteModule(module) {
4777
+ async deleteModule(module) {
4778
+ await this.translationsReady;
4452
4779
  this.confirmationService.confirm({
4453
- header: this.l10n.confirm.header,
4454
- message: this.l10n.confirm.message,
4780
+ header: this.t('app-modules.confirm.header'),
4781
+ message: this.t('app-modules.confirm.message'),
4455
4782
  icon: 'pi pi-trash',
4456
4783
  rejectButtonProps: {
4457
- label: this.l10n.confirm.cancel,
4784
+ label: this.t('app-modules.confirm.cancel'),
4458
4785
  severity: 'secondary',
4459
4786
  outlined: true
4460
4787
  },
4461
4788
  acceptButtonProps: {
4462
- label: this.l10n.confirm.delete,
4789
+ label: this.t('app-modules.confirm.delete'),
4463
4790
  severity: 'danger'
4464
4791
  },
4465
4792
  accept: async () => {
4466
- this.dataService
4467
- .sendRequest(`api/module/delete`, 'DELETE', {
4468
- moduleId: module.moduleId
4469
- })
4470
- .then(() => this.refreshAction())
4471
- .catch((error) => console.error(error));
4472
- this.msgService.success(this.l10n.messages.deleteSuccess);
4793
+ try {
4794
+ await this.dataService.sendRequest(`api/module/delete`, 'DELETE', {
4795
+ moduleId: module.moduleId
4796
+ });
4797
+ await this.refreshAction();
4798
+ this.msgService.success(this.t('app-modules.messages.deleteSuccess'));
4799
+ }
4800
+ catch (error) {
4801
+ this.msgService.error(error);
4802
+ }
4473
4803
  }
4474
4804
  });
4475
4805
  }
4806
+ t(key) {
4807
+ return this.l10nService.instant(key);
4808
+ }
4476
4809
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppModulesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4477
4810
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: AppModulesComponent, isStandalone: true, selector: "app-modules", providers: [ConfirmationService, ModuleApi], ngImport: i0, template: `
4478
4811
  <p-confirmDialog></p-confirmDialog>
4479
4812
  <div class="flex flex-col md:flex-row gap-4">
4480
4813
  <div class="card w-full">
4481
4814
  <div class="font-semibold text-xl mb-4">
4482
- {{ l10n.title }}
4815
+ {{ 'app-modules.title' | translate }}
4483
4816
  </div>
4484
4817
  <div class="mb-4">
4485
4818
  <p-toolbar>
@@ -4528,7 +4861,7 @@ class AppModulesComponent {
4528
4861
  </p-table>
4529
4862
  </div>
4530
4863
  </div>
4531
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$6.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$6.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i4$1.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4864
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$6.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i4$1.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4532
4865
  }
4533
4866
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppModulesComponent, decorators: [{
4534
4867
  type: Component,
@@ -4541,7 +4874,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4541
4874
  <div class="flex flex-col md:flex-row gap-4">
4542
4875
  <div class="card w-full">
4543
4876
  <div class="font-semibold text-xl mb-4">
4544
- {{ l10n.title }}
4877
+ {{ 'app-modules.title' | translate }}
4545
4878
  </div>
4546
4879
  <div class="mb-4">
4547
4880
  <p-toolbar>
@@ -4592,7 +4925,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4592
4925
  </div>
4593
4926
  `
4594
4927
  }]
4595
- }] });
4928
+ }], ctorParameters: () => [] });
4596
4929
 
4597
4930
  /* eslint-disable */
4598
4931
  /* tslint:disable */
@@ -5597,7 +5930,7 @@ class DiscussionComponent {
5597
5930
  </div>
5598
5931
  }
5599
5932
  </section>
5600
- `, isInline: true, styles: [":host{display:block}.file-trigger{position:relative;display:inline-flex}.file-trigger input{position:absolute;inset:0;opacity:0;cursor:pointer}.markdown-preview,.history-markdown{word-break:break-word}.markdown-preview :is(h1,h2,h3),.history-markdown :is(h1,h2,h3){margin:0 0 .75rem;font-weight:600}.markdown-preview a,.history-markdown a{color:#2563eb;text-decoration:underline;text-underline-offset:.18em}.emoji-popover{display:flex;flex-wrap:wrap;gap:.5rem;max-width:16rem}.emoji-option{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;font-size:1.25rem;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "directive", type: i2$6.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: DividerModule }, { kind: "ngmodule", type: PanelModule }, { kind: "component", type: i6.Panel, selector: "p-panel", inputs: ["id", "toggleable", "header", "collapsed", "styleClass", "iconPos", "showHeader", "toggler", "transitionOptions", "toggleButtonProps"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i7.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i8.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i9.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "pipe", type: i2$1.DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5933
+ `, isInline: true, styles: [":host{display:block}.file-trigger{position:relative;display:inline-flex}.file-trigger input{position:absolute;inset:0;opacity:0;cursor:pointer}.markdown-preview,.history-markdown{word-break:break-word}.markdown-preview :is(h1,h2,h3),.history-markdown :is(h1,h2,h3){margin:0 0 .75rem;font-weight:600}.markdown-preview a,.history-markdown a{color:#2563eb;text-decoration:underline;text-underline-offset:.18em}.emoji-popover{display:flex;flex-wrap:wrap;gap:.5rem;max-width:16rem}.emoji-option{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;font-size:1.25rem;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: DividerModule }, { kind: "ngmodule", type: PanelModule }, { kind: "component", type: i6.Panel, selector: "p-panel", inputs: ["id", "toggleable", "header", "collapsed", "styleClass", "iconPos", "showHeader", "toggler", "transitionOptions", "toggleButtonProps"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i7.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i8.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i9.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "pipe", type: i2$1.DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5601
5934
  }
5602
5935
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DiscussionComponent, decorators: [{
5603
5936
  type: Component,