oip-common 0.1.7 → 0.1.8

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,5 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, InjectionToken, signal, computed, effect, ChangeDetectorRef, Component, Input, PLATFORM_ID, HostBinding, EventEmitter, Output, ViewChild, Renderer2, SecurityContext, ChangeDetectionStrategy, makeEnvironmentProviders, Pipe } from '@angular/core';
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
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
4
  import * as i2$6 from 'primeng/api';
4
5
  import { MessageService, ConfirmationService, PrimeIcons, SharedModule } from 'primeng/api';
5
6
  import { HttpErrorResponse, HttpClient as HttpClient$1, HttpHeaders } from '@angular/common/http';
@@ -7,8 +8,11 @@ import * as i2$4 from '@ngx-translate/core';
7
8
  import { TranslateService, TranslatePipe, TranslateModule } from '@ngx-translate/core';
8
9
  import * as i1$3 from '@angular/router';
9
10
  import { ActivatedRoute, Router, RouterModule, NavigationEnd, RouterLinkActive, RouterLink } from '@angular/router';
10
- import { lastValueFrom, BehaviorSubject, Subject, ReplaySubject, merge, filter as filter$1, combineLatest, of, map as map$1, Observable } from 'rxjs';
11
+ import { lastValueFrom, BehaviorSubject, Subject, ReplaySubject, merge, from, filter as filter$1, combineLatest, of, map as map$1, Observable } from 'rxjs';
12
+ import { filter, distinctUntilChanged, map, switchMap, catchError } from 'rxjs/operators';
11
13
  import { Title, DomSanitizer } from '@angular/platform-browser';
14
+ import { PrimeNG } from 'primeng/config';
15
+ import { OidcSecurityService, PublicEventsService, EventTypes, StsConfigHttpLoader } from 'angular-auth-oidc-client';
12
16
  import * as i1 from 'primeng/multiselect';
13
17
  import { MultiSelectModule } from 'primeng/multiselect';
14
18
  import * as i2 from 'primeng/tooltip';
@@ -25,11 +29,8 @@ import { updatePreset, updateSurfacePalette, $t } from '@primeng/themes';
25
29
  import Aura from '@primeng/themes/aura';
26
30
  import Lara from '@primeng/themes/lara';
27
31
  import Nora from '@primeng/themes/nora';
28
- import { PrimeNG } from 'primeng/config';
29
32
  import * as i3 from 'primeng/selectbutton';
30
33
  import { SelectButtonModule } from 'primeng/selectbutton';
31
- import { OidcSecurityService, PublicEventsService, EventTypes, StsConfigHttpLoader } from 'angular-auth-oidc-client';
32
- import { filter, distinctUntilChanged, map, switchMap, catchError } from 'rxjs/operators';
33
34
  import { Tabs, TabList, Tab } from 'primeng/tabs';
34
35
  import * as i2$2 from 'primeng/avatar';
35
36
  import { AvatarModule } from 'primeng/avatar';
@@ -144,7 +145,11 @@ class MsgService {
144
145
  });
145
146
  }
146
147
  error(detail, summary = this.translate.instant('msgService.error'), life = this.lifetime) {
147
- if (detail instanceof HttpErrorResponse) {
148
+ const validationMessage = this.extractValidationMessage(detail);
149
+ if (validationMessage) {
150
+ detail = validationMessage;
151
+ }
152
+ else if (detail instanceof HttpErrorResponse) {
148
153
  summary = `Error: ${detail.status} ${detail.statusText}`;
149
154
  detail = `${detail.name} \r\n ${detail.message}`;
150
155
  }
@@ -156,6 +161,10 @@ class MsgService {
156
161
  });
157
162
  }
158
163
  extractErrorMessage(error, fallback) {
164
+ const validationMessage = this.extractValidationMessage(error);
165
+ if (validationMessage) {
166
+ return validationMessage;
167
+ }
159
168
  if (typeof error === 'object' &&
160
169
  error &&
161
170
  'error' in error &&
@@ -170,6 +179,35 @@ class MsgService {
170
179
  }
171
180
  return fallback;
172
181
  }
182
+ extractValidationMessage(error) {
183
+ const responseError = this.getObjectProperty(error, 'error');
184
+ const validationErrors = this.getObjectProperty(responseError, 'errors') ?? this.getObjectProperty(error, 'errors');
185
+ if (!validationErrors) {
186
+ return null;
187
+ }
188
+ const messages = Object.entries(validationErrors)
189
+ .reduce((result, [field, value]) => [...result, ...this.toValidationMessages(field, value)], [])
190
+ .filter((message) => message.length > 0);
191
+ return messages.length > 0 ? messages.join('\n') : null;
192
+ }
193
+ toValidationMessages(field, value) {
194
+ if (Array.isArray(value)) {
195
+ return value
196
+ .filter((message) => typeof message === 'string')
197
+ .map((message) => `${field}: ${message}`);
198
+ }
199
+ if (typeof value === 'string') {
200
+ return [`${field}: ${value}`];
201
+ }
202
+ return [];
203
+ }
204
+ getObjectProperty(source, property) {
205
+ if (typeof source !== 'object' || source === null || !(property in source)) {
206
+ return null;
207
+ }
208
+ const value = source[property];
209
+ return typeof value === 'object' && value !== null ? value : null;
210
+ }
173
211
  errorFromException(error, fallback, summary = fallback, life = this.lifetime) {
174
212
  this.error(this.extractErrorMessage(error, fallback), summary, life);
175
213
  }
@@ -567,7 +605,219 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
567
605
  args: [{ providedIn: 'root' }]
568
606
  }], ctorParameters: () => [] });
569
607
 
608
+ /**
609
+ * Service for managing translation loading in the application
610
+ */
611
+ class L10nService {
612
+ constructor() {
613
+ this.loadedTranslations = new Set();
614
+ this.httpClient = inject(HttpClient$1);
615
+ this.translateService = inject(TranslateService);
616
+ this.primeNg = inject(PrimeNG);
617
+ this.layoutService = inject(LayoutService);
618
+ }
619
+ /**
620
+ * Loads translations for a specific component
621
+ * @param component - Name of the component to load translations for
622
+ */
623
+ loadComponentTranslations(component) {
624
+ const lang = this.translateService.currentLang;
625
+ this.loadTranslations(component, lang);
626
+ }
627
+ /**
628
+ * Gets the translated value of a key (or an array of keys)
629
+ * @returns the translated key, or an object of translated keys
630
+ */
631
+ get(key) {
632
+ this.loadComponentTranslations(key.split('.')[0]);
633
+ return this.translateService.get(key);
634
+ }
635
+ /**
636
+ * Internal method to load translations from JSON files
637
+ * @param component - Component or translation namespace
638
+ * @param lang - Language code to load translations for
639
+ */
640
+ loadTranslations(component, lang) {
641
+ const key = `${component}.${lang}`;
642
+ 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
+ });
651
+ }
652
+ catch (e) {
653
+ console.error(`No translations found for ${component}.${lang}.json`);
654
+ console.error(e);
655
+ }
656
+ }
657
+ /**
658
+ * Changes the lang currently used
659
+ */
660
+ use(selectedLanguage, key = null) {
661
+ if (key) {
662
+ this.get(key);
663
+ }
664
+ this.translateService.use(selectedLanguage);
665
+ }
666
+ init(languages) {
667
+ this.availableLanguages = languages;
668
+ this.translateService.addLangs(languages.map((x) => x.code));
669
+ const lang = this.layoutService.language() ? this.layoutService.language() : 'en';
670
+ this.translateService.setDefaultLang(lang);
671
+ this.translateService.use(lang).subscribe(() => {
672
+ this.loadComponentTranslations('app-info');
673
+ this.translateService.get('primeng').subscribe((res) => this.primeNg.setTranslation(res));
674
+ });
675
+ }
676
+ instant(key, interpolateParams) {
677
+ return this.translateService.instant(key, interpolateParams);
678
+ }
679
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: L10nService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
680
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: L10nService, providedIn: 'root' }); }
681
+ }
682
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: L10nService, decorators: [{
683
+ type: Injectable,
684
+ args: [{ providedIn: 'root' }]
685
+ }] });
686
+
687
+ class SecurityDataService extends BaseDataService {
688
+ getSecurity(controller, id) {
689
+ return this.sendRequest(this.baseUrl + `api/${controller}/get-security?id=${id}`);
690
+ }
691
+ saveSecurity(controller, request) {
692
+ return this.sendRequest(this.baseUrl + `api/${controller}/put-security`, 'PUT', request);
693
+ }
694
+ getRealmRoles() {
695
+ return this.sendRequest(this.baseUrl + `api/security/get-realm-roles`);
696
+ }
697
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
698
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService }); }
699
+ }
700
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService, decorators: [{
701
+ type: Injectable
702
+ }] });
703
+
704
+ class SecurityService {
705
+ }
706
+ /**
707
+ * SecurityService extends OidcSecurityService to manage authentication,
708
+ * token handling, and user role access in an Angular application.
709
+ *
710
+ * It provides helper methods for checking authentication, managing tokens,
711
+ * determining user roles, and performing logout and refresh operations.
712
+ */
713
+ class KeycloakSecurityService extends OidcSecurityService {
714
+ /**
715
+ * Initializes service and subscribes to authentication events.
716
+ * When a 'NewAuthenticationResult' event is received, the `auth` method is called.
717
+ */
718
+ constructor() {
719
+ super();
720
+ /**
721
+ * Handles angular OIDC events.
722
+ */
723
+ this.publicEventsService = inject(PublicEventsService);
724
+ /**
725
+ * Stores the latest login response from checkAuth().
726
+ */
727
+ this.loginResponse = new BehaviorSubject(null);
728
+ /**
729
+ * Stores the decoded access token payload.
730
+ */
731
+ this.payload = new BehaviorSubject(null);
732
+ /**
733
+ * Stores user-specific data from the login response.
734
+ */
735
+ this.currentUser = new BehaviorSubject(null);
736
+ /**
737
+ * Emits access token updates from initial auth check, manual refresh,
738
+ * and library authentication events.
739
+ */
740
+ this.accessToken = new ReplaySubject(1);
741
+ this.publicEventsService
742
+ .registerForEvents()
743
+ .pipe(filter((event) => event.type === EventTypes.NewAuthenticationResult))
744
+ .subscribe(() => {
745
+ super.getAccessToken().subscribe(token => { this.accessToken.next(token); });
746
+ this.auth();
747
+ });
748
+ }
749
+ getCurrentUser() {
750
+ return this.currentUser.getValue();
751
+ }
752
+ getCurrentUser$() {
753
+ return this.currentUser.asObservable();
754
+ }
755
+ /**
756
+ * Returns the ID token for the sign-in.
757
+ * @returns A string with the id token.
758
+ */
759
+ getAccessToken(configId) {
760
+ return merge(super.getAccessToken(configId), this.accessToken.asObservable()).pipe(distinctUntilChanged());
761
+ }
762
+ /**
763
+ * Indicates whether the current user has the 'admin' role.
764
+ *
765
+ * @returns {boolean} True if the user is an admin, false otherwise.
766
+ */
767
+ isAdmin() {
768
+ return this.payload.getValue()?.realm_access?.roles?.includes('admin');
769
+ }
770
+ /**
771
+ * Initiates authentication check and updates login response, user data,
772
+ * and decoded token payload if authenticated.
773
+ */
774
+ auth() {
775
+ super.checkAuth().subscribe((_response) => {
776
+ this.loginResponse.next(_response);
777
+ this.currentUser.next(_response.userData);
778
+ this.getPayloadFromAccessToken().subscribe((_token) => {
779
+ this.payload.next(_token);
780
+ });
781
+ });
782
+ }
783
+ /**
784
+ * Performs logout and clears the local token payload.
785
+ *
786
+ * @param {string} [configId] Optional configuration ID for logout.
787
+ * @param {LogoutAuthOptions} [logoutAuthOptions] Optional logout options.
788
+ */
789
+ logout(configId, logoutAuthOptions) {
790
+ this.logoff(configId, logoutAuthOptions).subscribe((x) => this.payload.next(x));
791
+ }
792
+ /**
793
+ * Completes the BehaviorSubjects when the service is destroyed to avoid memory leaks.
794
+ */
795
+ ngOnDestroy() {
796
+ this.loginResponse.complete();
797
+ this.payload.complete();
798
+ this.currentUser.complete();
799
+ }
800
+ /**
801
+ * Checks whether the current access token is expired based on the 'exp' claim.
802
+ *
803
+ * @returns {Observable<boolean>} Observable that emits true if the token is expired.
804
+ */
805
+ isTokenExpired() {
806
+ return this.getPayloadFromAccessToken().pipe(map((payload) => {
807
+ return payload.exp < Math.floor(Date.now() / 1000);
808
+ }));
809
+ }
810
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
811
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService }); }
812
+ }
813
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService, decorators: [{
814
+ type: Injectable
815
+ }], ctorParameters: () => [] });
816
+
570
817
  class BaseModuleComponent {
818
+ static { this.readRight = 'read'; }
819
+ static { this.editRight = 'edit'; }
820
+ static { this.deleteRight = 'delete'; }
571
821
  /**
572
822
  * Updates local settings and persists them to local storage.
573
823
  * @return {void}
@@ -615,12 +865,21 @@ class BaseModuleComponent {
615
865
  get isSecurity() {
616
866
  return this.topBarService.checkId('security');
617
867
  }
868
+ /**
869
+ * Gets an instant translation for a key or an array of keys.
870
+ */
871
+ t(key, interpolateParams) {
872
+ return this.translateService.instant(key, interpolateParams);
873
+ }
618
874
  /**
619
875
  * Initializes the component and subscribes to local settings updates.
620
876
  */
621
877
  constructor() {
622
878
  this.isInitialized = false;
623
879
  this.moduleInstanceReloadPromise = Promise.resolve();
880
+ this.destroyRef = inject(DestroyRef);
881
+ this.securityDataService = inject(SecurityDataService);
882
+ this.securityService = inject(SecurityService);
624
883
  /**
625
884
  * Provide access to app settings
626
885
  */
@@ -683,6 +942,11 @@ class BaseModuleComponent {
683
942
  * @type {Subject<TLocalStoreSettings>}
684
943
  */
685
944
  this.localSettingsUpdate = new Subject();
945
+ this.l10nService = inject(L10nService);
946
+ this.canRead = false;
947
+ this.canEdit = false;
948
+ this.canDelete = false;
949
+ this.securityRightsLoaded = false;
686
950
  /**
687
951
  * A unique numerical identifier for the module.
688
952
  * @type {number}
@@ -704,6 +968,7 @@ class BaseModuleComponent {
704
968
  });
705
969
  this.subscriptions.push(this.route.url.subscribe((url) => {
706
970
  this.controller = url[0].path;
971
+ this.l10n$ = this.l10nService.get(this.controller);
707
972
  }));
708
973
  this.subscriptions.push(this.route.paramMap.subscribe((params) => {
709
974
  const routeId = params.get('id');
@@ -725,6 +990,7 @@ class BaseModuleComponent {
725
990
  ngOnDestroy() {
726
991
  this.topBarService.setTopBarItems([]);
727
992
  this.topBarService.activeId = this.topBarItems[0].id;
993
+ this.rightsSubscription?.unsubscribe();
728
994
  this.subscriptions.forEach((s) => s.unsubscribe());
729
995
  }
730
996
  /**
@@ -782,10 +1048,58 @@ class BaseModuleComponent {
782
1048
  * Called whenever the module instance changes, including the first load.
783
1049
  * Derived components can override this to refresh module-specific data.
784
1050
  */
785
- async onModuleInstanceChange() { }
1051
+ async onModuleInstanceChange() {
1052
+ }
1053
+ /**
1054
+ * Called whenever current user rights for the active module instance are recalculated.
1055
+ */
1056
+ onSecurityRightsChange() {
1057
+ }
1058
+ /**
1059
+ * Starts watching current token roles and maps them to module instance security settings.
1060
+ */
1061
+ watchSecurityRights(controller = this.controller, id = this.id) {
1062
+ this.rightsSubscription?.unsubscribe();
1063
+ this.resetRightsState();
1064
+ if (!controller || id == null) {
1065
+ return;
1066
+ }
1067
+ this.rightsSubscription = this.securityService.payload
1068
+ .pipe(switchMap((payload) => from(this.securityDataService.getSecurity(controller, id)).pipe(map((securitySettings) => ({ payload, securitySettings })))), takeUntilDestroyed(this.destroyRef))
1069
+ .subscribe({
1070
+ next: ({ payload, securitySettings }) => {
1071
+ const roles = payload?.realm_access?.roles ?? [];
1072
+ this.updateRightsState(roles, securitySettings);
1073
+ },
1074
+ error: (error) => {
1075
+ this.securityRightsLoaded = true;
1076
+ console.error('Не удалось загрузить права', error);
1077
+ this.onSecurityRightsChange();
1078
+ }
1079
+ });
1080
+ }
1081
+ resetRightsState() {
1082
+ this.canRead = false;
1083
+ this.canEdit = false;
1084
+ this.canDelete = false;
1085
+ this.securityRightsLoaded = false;
1086
+ }
1087
+ updateRightsState(roles, securitySettings) {
1088
+ this.canRead = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.readRight);
1089
+ this.canEdit = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.editRight);
1090
+ this.canDelete = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.deleteRight);
1091
+ this.securityRightsLoaded = true;
1092
+ this.onSecurityRightsChange();
1093
+ }
1094
+ hasSecurityRight(roles, securitySettings, code) {
1095
+ return securitySettings
1096
+ .find((security) => security.code === code)
1097
+ ?.roles?.some((role) => roles.includes(role)) ?? false;
1098
+ }
786
1099
  async reloadModuleInstance() {
787
1100
  this.moduleInstanceReloadPromise = this.moduleInstanceReloadPromise.then(async () => {
788
1101
  await this.getSettings();
1102
+ this.watchSecurityRights();
789
1103
  await this.onModuleInstanceChange();
790
1104
  });
791
1105
  await this.moduleInstanceReloadPromise;
@@ -798,48 +1112,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
798
1112
  args: [{ standalone: true, template: '' }]
799
1113
  }], ctorParameters: () => [] });
800
1114
 
801
- class SecurityDataService extends BaseDataService {
802
- getSecurity(controller, id) {
803
- return this.sendRequest(this.baseUrl + `api/${controller}/get-security?id=${id}`);
804
- }
805
- saveSecurity(controller, request) {
806
- return this.sendRequest(this.baseUrl + `api/${controller}/put-security`, 'PUT', request);
807
- }
808
- getRealmRoles() {
809
- return this.sendRequest(this.baseUrl + `api/security/get-realm-roles`);
810
- }
811
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
812
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService }); }
813
- }
814
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService, decorators: [{
815
- type: Injectable
816
- }] });
817
-
818
1115
  class SecurityComponent {
819
1116
  constructor() {
820
1117
  this.msgService = inject(MsgService);
821
1118
  this.dataService = inject(SecurityDataService);
822
1119
  this.translateService = inject(TranslateService);
1120
+ this.securityLoadToken = 0;
1121
+ this.securityData = [];
823
1122
  this.roles = [];
824
1123
  }
825
1124
  ngOnDestroy() {
826
1125
  // on destroy
827
1126
  }
828
- ngOnInit() {
829
- if (!this.id) {
830
- this.msgService.error('Module id not passed!');
831
- }
832
- if (!this.controller) {
833
- this.msgService.error('Controller not passed!');
1127
+ ngOnChanges(changes) {
1128
+ if (changes['id'] || changes['controller']) {
1129
+ void this.loadSecurity();
834
1130
  }
835
- this.dataService.getSecurity(this.controller, this.id).then((result) => {
836
- this.securityData = result;
837
- }, (error) => this.msgService.error(error));
1131
+ }
1132
+ ngOnInit() {
838
1133
  this.dataService.getRealmRoles().then((result) => {
839
1134
  this.roles = result;
840
1135
  }, (error) => this.msgService.error(error));
841
1136
  }
842
1137
  saveClick() {
1138
+ if (this.id == null) {
1139
+ this.msgService.error('Module id not passed!');
1140
+ return;
1141
+ }
1142
+ if (!this.controller) {
1143
+ this.msgService.error('Controller not passed!');
1144
+ return;
1145
+ }
843
1146
  const request = {
844
1147
  id: this.id,
845
1148
  securities: this.securityData
@@ -850,11 +1153,31 @@ class SecurityComponent {
850
1153
  }
851
1154
  saveKeyDown($event) {
852
1155
  if ($event.key === 'Enter' || $event.key === 'Space') {
853
- this.saveKeyDown(null);
1156
+ this.saveClick();
1157
+ }
1158
+ }
1159
+ async loadSecurity() {
1160
+ const loadToken = ++this.securityLoadToken;
1161
+ const controller = this.controller;
1162
+ const id = this.id;
1163
+ this.securityData = [];
1164
+ if (!controller || id == null) {
1165
+ return;
1166
+ }
1167
+ try {
1168
+ const result = await this.dataService.getSecurity(controller, id);
1169
+ if (loadToken === this.securityLoadToken) {
1170
+ this.securityData = result;
1171
+ }
1172
+ }
1173
+ catch (error) {
1174
+ if (loadToken === this.securityLoadToken) {
1175
+ this.msgService.error(error);
1176
+ }
854
1177
  }
855
1178
  }
856
1179
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
857
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: SecurityComponent, isStandalone: true, selector: "security", inputs: { id: "id", controller: "controller" }, ngImport: i0, template: `
1180
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: SecurityComponent, isStandalone: true, selector: "security", inputs: { id: "id", controller: "controller" }, usesOnChanges: true, ngImport: i0, template: `
858
1181
  <div class="flex flex-col md:flex-row gap-8">
859
1182
  <div class="md:w-1/2">
860
1183
  <div class="card flex flex-col gap-4">
@@ -869,7 +1192,7 @@ class SecurityComponent {
869
1192
  </label>
870
1193
  <p-multiSelect
871
1194
  id="oip-security-multiselect-{{ item.name }}"
872
- placeholder="Select roles"
1195
+ placeholder="{{ 'securityComponent.selectRoles' | translate }}"
873
1196
  [maxSelectedLabels]="10"
874
1197
  [options]="roles"
875
1198
  [(ngModel)]="item.roles" />
@@ -907,7 +1230,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
907
1230
  </label>
908
1231
  <p-multiSelect
909
1232
  id="oip-security-multiselect-{{ item.name }}"
910
- placeholder="Select roles"
1233
+ placeholder="{{ 'securityComponent.selectRoles' | translate }}"
911
1234
  [maxSelectedLabels]="10"
912
1235
  [options]="roles"
913
1236
  [(ngModel)]="item.roles" />
@@ -1524,119 +1847,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1524
1847
  }]
1525
1848
  }] });
1526
1849
 
1527
- class SecurityService {
1528
- }
1529
- /**
1530
- * SecurityService extends OidcSecurityService to manage authentication,
1531
- * token handling, and user role access in an Angular application.
1532
- *
1533
- * It provides helper methods for checking authentication, managing tokens,
1534
- * determining user roles, and performing logout and refresh operations.
1535
- */
1536
- class KeycloakSecurityService extends OidcSecurityService {
1537
- /**
1538
- * Initializes service and subscribes to authentication events.
1539
- * When a 'NewAuthenticationResult' event is received, the `auth` method is called.
1540
- */
1541
- constructor() {
1542
- super();
1543
- /**
1544
- * Handles angular OIDC events.
1545
- */
1546
- this.publicEventsService = inject(PublicEventsService);
1547
- /**
1548
- * Stores the latest login response from checkAuth().
1549
- */
1550
- this.loginResponse = new BehaviorSubject(null);
1551
- /**
1552
- * Stores the decoded access token payload.
1553
- */
1554
- this.payload = new BehaviorSubject(null);
1555
- /**
1556
- * Stores user-specific data from the login response.
1557
- */
1558
- this.currentUser = new BehaviorSubject(null);
1559
- /**
1560
- * Emits access token updates from initial auth check, manual refresh,
1561
- * and library authentication events.
1562
- */
1563
- this.accessToken = new ReplaySubject(1);
1564
- this.publicEventsService
1565
- .registerForEvents()
1566
- .pipe(filter((event) => event.type === EventTypes.NewAuthenticationResult))
1567
- .subscribe(() => {
1568
- super.getAccessToken().subscribe(token => { this.accessToken.next(token); });
1569
- this.auth();
1570
- });
1571
- }
1572
- getCurrentUser() {
1573
- return this.currentUser.getValue();
1574
- }
1575
- getCurrentUser$() {
1576
- return this.currentUser.asObservable();
1577
- }
1578
- /**
1579
- * Returns the ID token for the sign-in.
1580
- * @returns A string with the id token.
1581
- */
1582
- getAccessToken(configId) {
1583
- return merge(super.getAccessToken(configId), this.accessToken.asObservable()).pipe(distinctUntilChanged());
1584
- }
1585
- /**
1586
- * Indicates whether the current user has the 'admin' role.
1587
- *
1588
- * @returns {boolean} True if the user is an admin, false otherwise.
1589
- */
1590
- isAdmin() {
1591
- return this.payload.getValue()?.realm_access?.roles?.includes('admin');
1592
- }
1593
- /**
1594
- * Initiates authentication check and updates login response, user data,
1595
- * and decoded token payload if authenticated.
1596
- */
1597
- auth() {
1598
- super.checkAuth().subscribe((_response) => {
1599
- this.loginResponse.next(_response);
1600
- this.currentUser.next(_response.userData);
1601
- this.getPayloadFromAccessToken().subscribe((_token) => {
1602
- this.payload.next(_token);
1603
- });
1604
- });
1605
- }
1606
- /**
1607
- * Performs logout and clears the local token payload.
1608
- *
1609
- * @param {string} [configId] Optional configuration ID for logout.
1610
- * @param {LogoutAuthOptions} [logoutAuthOptions] Optional logout options.
1611
- */
1612
- logout(configId, logoutAuthOptions) {
1613
- this.logoff(configId, logoutAuthOptions).subscribe((x) => this.payload.next(x));
1614
- }
1615
- /**
1616
- * Completes the BehaviorSubjects when the service is destroyed to avoid memory leaks.
1617
- */
1618
- ngOnDestroy() {
1619
- this.loginResponse.complete();
1620
- this.payload.complete();
1621
- this.currentUser.complete();
1622
- }
1623
- /**
1624
- * Checks whether the current access token is expired based on the 'exp' claim.
1625
- *
1626
- * @returns {Observable<boolean>} Observable that emits true if the token is expired.
1627
- */
1628
- isTokenExpired() {
1629
- return this.getPayloadFromAccessToken().pipe(map((payload) => {
1630
- return payload.exp < Math.floor(Date.now() / 1000);
1631
- }));
1632
- }
1633
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1634
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService }); }
1635
- }
1636
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: KeycloakSecurityService, decorators: [{
1637
- type: Injectable
1638
- }], ctorParameters: () => [] });
1639
-
1640
1850
  /**
1641
1851
  * UserService is responsible for retrieving and handling user-related data,
1642
1852
  * including the user's photo and short label for avatar display.
@@ -2088,18 +2298,15 @@ class HttpClient {
2088
2298
  this.layoutService = inject(LayoutService);
2089
2299
  this.baseUrl = "";
2090
2300
  this.securityData = null;
2091
- this.securityWorker = (securityData) => {
2092
- const headers = {
2301
+ this.securityWorker = (securityData) => ({
2302
+ headers: {
2093
2303
  "Accept-language": this.layoutService.language()
2094
2304
  ? this.layoutService.language()
2095
2305
  : "en",
2096
2306
  "X-Timezone": this.layoutService.timeZone(),
2097
- };
2098
- if (securityData) {
2099
- headers.Authorization = `Bearer ${securityData}`;
2100
- }
2101
- return { headers };
2102
- };
2307
+ Authorization: `Bearer ${securityData}`,
2308
+ },
2309
+ });
2103
2310
  this.abortControllers = new Map();
2104
2311
  this.customFetch = (...fetchParams) => fetch(...fetchParams);
2105
2312
  this.baseApiParams = {
@@ -3519,85 +3726,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3519
3726
  }]
3520
3727
  }] });
3521
3728
 
3522
- /**
3523
- * Service for managing translation loading in the application
3524
- */
3525
- class L10nService {
3526
- constructor() {
3527
- this.loadedTranslations = new Set();
3528
- this.httpClient = inject(HttpClient$1);
3529
- this.translateService = inject(TranslateService);
3530
- this.primeNg = inject(PrimeNG);
3531
- this.layoutService = inject(LayoutService);
3532
- }
3533
- /**
3534
- * Loads translations for a specific component
3535
- * @param component - Name of the component to load translations for
3536
- */
3537
- loadComponentTranslations(component) {
3538
- const lang = this.translateService.currentLang;
3539
- this.loadTranslations(component, lang);
3540
- }
3541
- /**
3542
- * Gets the translated value of a key (or an array of keys)
3543
- * @returns the translated key, or an object of translated keys
3544
- */
3545
- get(key) {
3546
- this.loadComponentTranslations(key.split('.')[0]);
3547
- return this.translateService.get(key);
3548
- }
3549
- /**
3550
- * Internal method to load translations from JSON files
3551
- * @param component - Component or translation namespace
3552
- * @param lang - Language code to load translations for
3553
- */
3554
- loadTranslations(component, lang) {
3555
- const key = `${component}.${lang}`;
3556
- if (this.loadedTranslations.has(key)) {
3557
- return;
3558
- }
3559
- try {
3560
- this.httpClient.get(`./assets/i18n/${component}.${lang}.json`).subscribe((translations) => {
3561
- const current = this.translateService.translations[lang] || {};
3562
- this.translateService.setTranslation(lang, { ...current, ...translations }, true);
3563
- this.loadedTranslations.add(key);
3564
- });
3565
- }
3566
- catch (e) {
3567
- console.error(`No translations found for ${component}.${lang}.json`);
3568
- console.error(e);
3569
- }
3570
- }
3571
- /**
3572
- * Changes the lang currently used
3573
- */
3574
- use(selectedLanguage, key = null) {
3575
- if (key) {
3576
- this.get(key);
3577
- }
3578
- this.translateService.use(selectedLanguage);
3579
- }
3580
- init(languages) {
3581
- this.availableLanguages = languages;
3582
- this.translateService.addLangs(languages.map((x) => x.code));
3583
- const lang = this.layoutService.language() ? this.layoutService.language() : 'en';
3584
- this.translateService.setDefaultLang(lang);
3585
- this.translateService.use(lang).subscribe(() => {
3586
- this.loadComponentTranslations('app-info');
3587
- this.translateService.get('primeng').subscribe((res) => this.primeNg.setTranslation(res));
3588
- });
3589
- }
3590
- instant(key, interpolateParams) {
3591
- return this.translateService.instant(key, interpolateParams);
3592
- }
3593
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: L10nService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3594
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: L10nService, providedIn: 'root' }); }
3595
- }
3596
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: L10nService, decorators: [{
3597
- type: Injectable,
3598
- args: [{ providedIn: 'root' }]
3599
- }] });
3600
-
3601
3729
  class NotfoundComponent {
3602
3730
  constructor(l10nService) {
3603
3731
  l10nService.get('notfound');
@@ -4125,7 +4253,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4125
4253
  class DbMigrationComponent extends BaseModuleComponent {
4126
4254
  constructor() {
4127
4255
  super();
4128
- this.l10nService = inject(L10nService);
4129
4256
  this.l10nService.loadComponentTranslations('db-migration');
4130
4257
  }
4131
4258
  async ngOnInit() {
@@ -4150,84 +4277,84 @@ class DbMigrationComponent extends BaseModuleComponent {
4150
4277
  return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
4151
4278
  }
4152
4279
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DbMigrationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4153
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DbMigrationComponent, isStandalone: true, selector: "db-migration", providers: [ConfirmationService], usesInheritance: true, ngImport: i0, template: `
4154
- @if (isContent) {
4155
- <div class="card" style="height: 100%">
4156
- <p-confirmDialog />
4157
- <div>
4158
- <h5>{{ 'db-migration.migrationManager' | translate }}</h5>
4159
- <div class="flex flex-row gap-2">
4160
- <p-button
4161
- icon="pi pi-refresh"
4162
- severity="secondary"
4163
- tooltipPosition="bottom"
4164
- [outlined]="true"
4165
- [pTooltip]="'db-migration.actions.refresh' | translate"
4166
- (click)="refreshAction()" />
4167
- <p-button
4168
- icon="pi pi-filter-slash"
4169
- severity="secondary"
4170
- tooltipPosition="bottom"
4171
- [outlined]="true"
4172
- [pTooltip]="'db-migration.actions.cleanFilter' | translate"
4173
- (click)="dt.clear()" />
4174
- </div>
4175
- <div>
4176
- <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
4177
- <ng-template let-columns pTemplate="header">
4178
- <tr>
4179
- <th pSortableColumn="name" scope="col">
4180
- {{ 'db-migration.columns.name' | translate }}
4181
- <p-columnFilter display="menu" field="name" type="text" />
4182
- </th>
4183
- <th scope="col">{{ 'db-migration.columns.applied' | translate }}</th>
4184
- <th scope="col">{{ 'db-migration.columns.exist' | translate }}</th>
4185
- <th scope="col">{{ 'db-migration.columns.pending' | translate }}</th>
4186
- <th scope="col"></th>
4187
- </tr>
4188
- </ng-template>
4189
-
4190
- <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
4191
- <tr [pEditableRow]="rowData">
4192
- <td>
4193
- {{ rowData.name }}
4194
- </td>
4195
- <td>
4196
- @if (rowData.applied) {
4197
- <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"> </p-button>
4198
- }
4199
- </td>
4200
- <td>
4201
- @if (rowData.exist) {
4202
- <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true" />
4203
- }
4204
- </td>
4205
- <td>
4206
- @if (rowData.pending) {
4207
- <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
4208
- }
4209
- </td>
4210
- <td>
4211
- <p-button
4212
- icon="pi pi-bolt"
4213
- pCancelEditableRow
4214
- pTooltip="{{ 'db-migration.actions.applyMigration' | translate }}"
4215
- severity="secondary"
4216
- tooltipPosition="left"
4217
- [rounded]="true"
4218
- [text]="true"
4219
- (click)="applyMigration(rowData)">
4220
- </p-button>
4221
- </td>
4222
- </tr>
4223
- </ng-template>
4224
- </p-table>
4225
- </div>
4226
- </div>
4227
- </div>
4228
- } @else if (isSecurity) {
4229
- <security [controller]="controller" [id]="id" />
4230
- }
4280
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DbMigrationComponent, isStandalone: true, selector: "db-migration", providers: [ConfirmationService], usesInheritance: true, ngImport: i0, template: `
4281
+ @if (isContent) {
4282
+ <div class="card" style="height: 100%">
4283
+ <p-confirmDialog/>
4284
+ <div>
4285
+ <h5>{{ 'db-migration.migrationManager' | translate }}</h5>
4286
+ <div class="flex flex-row gap-2">
4287
+ <p-button
4288
+ icon="pi pi-refresh"
4289
+ severity="secondary"
4290
+ tooltipPosition="bottom"
4291
+ [outlined]="true"
4292
+ [pTooltip]="'db-migration.actions.refresh' | translate"
4293
+ (click)="refreshAction()"/>
4294
+ <p-button
4295
+ icon="pi pi-filter-slash"
4296
+ severity="secondary"
4297
+ tooltipPosition="bottom"
4298
+ [outlined]="true"
4299
+ [pTooltip]="'db-migration.actions.cleanFilter' | translate"
4300
+ (click)="dt.clear()"/>
4301
+ </div>
4302
+ <div>
4303
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
4304
+ <ng-template let-columns pTemplate="header">
4305
+ <tr>
4306
+ <th pSortableColumn="name" scope="col">
4307
+ {{ 'db-migration.columns.name' | translate }}
4308
+ <p-columnFilter display="menu" field="name" type="text"/>
4309
+ </th>
4310
+ <th scope="col">{{ 'db-migration.columns.applied' | translate }}</th>
4311
+ <th scope="col">{{ 'db-migration.columns.exist' | translate }}</th>
4312
+ <th scope="col">{{ 'db-migration.columns.pending' | translate }}</th>
4313
+ <th scope="col"></th>
4314
+ </tr>
4315
+ </ng-template>
4316
+
4317
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
4318
+ <tr [pEditableRow]="rowData">
4319
+ <td>
4320
+ {{ rowData.name }}
4321
+ </td>
4322
+ <td>
4323
+ @if (rowData.applied) {
4324
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
4325
+ }
4326
+ </td>
4327
+ <td>
4328
+ @if (rowData.exist) {
4329
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"/>
4330
+ }
4331
+ </td>
4332
+ <td>
4333
+ @if (rowData.pending) {
4334
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
4335
+ }
4336
+ </td>
4337
+ <td>
4338
+ <p-button
4339
+ icon="pi pi-bolt"
4340
+ pCancelEditableRow
4341
+ pTooltip="{{ 'db-migration.actions.applyMigration' | translate }}"
4342
+ severity="secondary"
4343
+ tooltipPosition="left"
4344
+ [rounded]="true"
4345
+ [text]="true"
4346
+ (click)="applyMigration(rowData)">
4347
+ </p-button>
4348
+ </td>
4349
+ </tr>
4350
+ </ng-template>
4351
+ </p-table>
4352
+ </div>
4353
+ </div>
4354
+ </div>
4355
+ } @else if (isSecurity) {
4356
+ <security [controller]="controller" [id]="id"/>
4357
+ }
4231
4358
  `, 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" }] }); }
4232
4359
  }
4233
4360
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DbMigrationComponent, decorators: [{
@@ -4247,84 +4374,84 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4247
4374
  TranslatePipe
4248
4375
  ],
4249
4376
  selector: 'db-migration',
4250
- template: `
4251
- @if (isContent) {
4252
- <div class="card" style="height: 100%">
4253
- <p-confirmDialog />
4254
- <div>
4255
- <h5>{{ 'db-migration.migrationManager' | translate }}</h5>
4256
- <div class="flex flex-row gap-2">
4257
- <p-button
4258
- icon="pi pi-refresh"
4259
- severity="secondary"
4260
- tooltipPosition="bottom"
4261
- [outlined]="true"
4262
- [pTooltip]="'db-migration.actions.refresh' | translate"
4263
- (click)="refreshAction()" />
4264
- <p-button
4265
- icon="pi pi-filter-slash"
4266
- severity="secondary"
4267
- tooltipPosition="bottom"
4268
- [outlined]="true"
4269
- [pTooltip]="'db-migration.actions.cleanFilter' | translate"
4270
- (click)="dt.clear()" />
4271
- </div>
4272
- <div>
4273
- <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
4274
- <ng-template let-columns pTemplate="header">
4275
- <tr>
4276
- <th pSortableColumn="name" scope="col">
4277
- {{ 'db-migration.columns.name' | translate }}
4278
- <p-columnFilter display="menu" field="name" type="text" />
4279
- </th>
4280
- <th scope="col">{{ 'db-migration.columns.applied' | translate }}</th>
4281
- <th scope="col">{{ 'db-migration.columns.exist' | translate }}</th>
4282
- <th scope="col">{{ 'db-migration.columns.pending' | translate }}</th>
4283
- <th scope="col"></th>
4284
- </tr>
4285
- </ng-template>
4286
-
4287
- <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
4288
- <tr [pEditableRow]="rowData">
4289
- <td>
4290
- {{ rowData.name }}
4291
- </td>
4292
- <td>
4293
- @if (rowData.applied) {
4294
- <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"> </p-button>
4295
- }
4296
- </td>
4297
- <td>
4298
- @if (rowData.exist) {
4299
- <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true" />
4300
- }
4301
- </td>
4302
- <td>
4303
- @if (rowData.pending) {
4304
- <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
4305
- }
4306
- </td>
4307
- <td>
4308
- <p-button
4309
- icon="pi pi-bolt"
4310
- pCancelEditableRow
4311
- pTooltip="{{ 'db-migration.actions.applyMigration' | translate }}"
4312
- severity="secondary"
4313
- tooltipPosition="left"
4314
- [rounded]="true"
4315
- [text]="true"
4316
- (click)="applyMigration(rowData)">
4317
- </p-button>
4318
- </td>
4319
- </tr>
4320
- </ng-template>
4321
- </p-table>
4322
- </div>
4323
- </div>
4324
- </div>
4325
- } @else if (isSecurity) {
4326
- <security [controller]="controller" [id]="id" />
4327
- }
4377
+ template: `
4378
+ @if (isContent) {
4379
+ <div class="card" style="height: 100%">
4380
+ <p-confirmDialog/>
4381
+ <div>
4382
+ <h5>{{ 'db-migration.migrationManager' | translate }}</h5>
4383
+ <div class="flex flex-row gap-2">
4384
+ <p-button
4385
+ icon="pi pi-refresh"
4386
+ severity="secondary"
4387
+ tooltipPosition="bottom"
4388
+ [outlined]="true"
4389
+ [pTooltip]="'db-migration.actions.refresh' | translate"
4390
+ (click)="refreshAction()"/>
4391
+ <p-button
4392
+ icon="pi pi-filter-slash"
4393
+ severity="secondary"
4394
+ tooltipPosition="bottom"
4395
+ [outlined]="true"
4396
+ [pTooltip]="'db-migration.actions.cleanFilter' | translate"
4397
+ (click)="dt.clear()"/>
4398
+ </div>
4399
+ <div>
4400
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
4401
+ <ng-template let-columns pTemplate="header">
4402
+ <tr>
4403
+ <th pSortableColumn="name" scope="col">
4404
+ {{ 'db-migration.columns.name' | translate }}
4405
+ <p-columnFilter display="menu" field="name" type="text"/>
4406
+ </th>
4407
+ <th scope="col">{{ 'db-migration.columns.applied' | translate }}</th>
4408
+ <th scope="col">{{ 'db-migration.columns.exist' | translate }}</th>
4409
+ <th scope="col">{{ 'db-migration.columns.pending' | translate }}</th>
4410
+ <th scope="col"></th>
4411
+ </tr>
4412
+ </ng-template>
4413
+
4414
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
4415
+ <tr [pEditableRow]="rowData">
4416
+ <td>
4417
+ {{ rowData.name }}
4418
+ </td>
4419
+ <td>
4420
+ @if (rowData.applied) {
4421
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
4422
+ }
4423
+ </td>
4424
+ <td>
4425
+ @if (rowData.exist) {
4426
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"/>
4427
+ }
4428
+ </td>
4429
+ <td>
4430
+ @if (rowData.pending) {
4431
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
4432
+ }
4433
+ </td>
4434
+ <td>
4435
+ <p-button
4436
+ icon="pi pi-bolt"
4437
+ pCancelEditableRow
4438
+ pTooltip="{{ 'db-migration.actions.applyMigration' | translate }}"
4439
+ severity="secondary"
4440
+ tooltipPosition="left"
4441
+ [rounded]="true"
4442
+ [text]="true"
4443
+ (click)="applyMigration(rowData)">
4444
+ </p-button>
4445
+ </td>
4446
+ </tr>
4447
+ </ng-template>
4448
+ </p-table>
4449
+ </div>
4450
+ </div>
4451
+ </div>
4452
+ } @else if (isSecurity) {
4453
+ <security [controller]="controller" [id]="id"/>
4454
+ }
4328
4455
  `,
4329
4456
  providers: [ConfirmationService]
4330
4457
  }]