oip-common 0.1.7 → 0.2.0
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.
- package/assets/i18n/en.json +2 -1
- package/assets/i18n/iframe-module.en.json +10 -0
- package/assets/i18n/iframe-module.ru.json +10 -0
- package/assets/i18n/ru.json +2 -1
- package/fesm2022/oip-common.mjs +811 -534
- package/fesm2022/oip-common.mjs.map +1 -1
- package/index.d.ts +205 -153
- package/package.json +1 -1
package/fesm2022/oip-common.mjs
CHANGED
|
@@ -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';
|
|
@@ -38,7 +39,7 @@ import { ContextMenuModule, ContextMenu } from 'primeng/contextmenu';
|
|
|
38
39
|
import * as i2$3 from 'primeng/dialog';
|
|
39
40
|
import { DialogModule } from 'primeng/dialog';
|
|
40
41
|
import * as i3$3 from 'primeng/inputtext';
|
|
41
|
-
import { InputTextModule } from 'primeng/inputtext';
|
|
42
|
+
import { InputTextModule, InputText } from 'primeng/inputtext';
|
|
42
43
|
import { trigger, state, transition, style, animate } from '@angular/animations';
|
|
43
44
|
import * as i3$2 from 'primeng/ripple';
|
|
44
45
|
import { RippleModule } from 'primeng/ripple';
|
|
@@ -144,7 +145,11 @@ class MsgService {
|
|
|
144
145
|
});
|
|
145
146
|
}
|
|
146
147
|
error(detail, summary = this.translate.instant('msgService.error'), life = this.lifetime) {
|
|
147
|
-
|
|
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
|
-
|
|
829
|
-
if (
|
|
830
|
-
this.
|
|
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
|
-
|
|
836
|
-
|
|
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,80 +1153,100 @@ class SecurityComponent {
|
|
|
850
1153
|
}
|
|
851
1154
|
saveKeyDown($event) {
|
|
852
1155
|
if ($event.key === 'Enter' || $event.key === 'Space') {
|
|
853
|
-
this.
|
|
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: `
|
|
858
|
-
<div class="flex flex-col md:flex-row gap-8">
|
|
859
|
-
<div class="md:w-1/2">
|
|
860
|
-
<div class="card flex flex-col gap-4">
|
|
861
|
-
<div class="font-semibold text-xl">
|
|
862
|
-
{{ 'securityComponent.security' | translate }}
|
|
863
|
-
</div>
|
|
864
|
-
@for (item of securityData; track item.name) {
|
|
865
|
-
<div class="flex flex-col gap-2">
|
|
866
|
-
<label htmlFor="oip-security-multiselect-{{ item.name }}">
|
|
867
|
-
{{ item.name }}
|
|
868
|
-
<span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
|
|
869
|
-
</label>
|
|
870
|
-
<p-multiSelect
|
|
871
|
-
id="oip-security-multiselect-{{ item.name }}"
|
|
872
|
-
placeholder="
|
|
873
|
-
[maxSelectedLabels]="10"
|
|
874
|
-
[options]="roles"
|
|
875
|
-
[(ngModel)]="item.roles" />
|
|
876
|
-
</div>
|
|
877
|
-
}
|
|
878
|
-
<div class="flex justify-content-end flex-wrap">
|
|
879
|
-
<p-button
|
|
880
|
-
icon="pi pi-save"
|
|
881
|
-
id="oip-security-save-button"
|
|
882
|
-
label="{{ 'securityComponent.save' | translate }}"
|
|
883
|
-
(click)="saveClick()"
|
|
884
|
-
(keydown)="saveKeyDown($event)" />
|
|
885
|
-
</div>
|
|
886
|
-
</div>
|
|
887
|
-
</div>
|
|
888
|
-
</div>
|
|
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: `
|
|
1181
|
+
<div class="flex flex-col md:flex-row gap-8">
|
|
1182
|
+
<div class="md:w-1/2">
|
|
1183
|
+
<div class="card flex flex-col gap-4">
|
|
1184
|
+
<div class="font-semibold text-xl">
|
|
1185
|
+
{{ 'securityComponent.security' | translate }}
|
|
1186
|
+
</div>
|
|
1187
|
+
@for (item of securityData; track item.name) {
|
|
1188
|
+
<div class="flex flex-col gap-2">
|
|
1189
|
+
<label htmlFor="oip-security-multiselect-{{ item.name }}">
|
|
1190
|
+
{{ item.name }}
|
|
1191
|
+
<span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
|
|
1192
|
+
</label>
|
|
1193
|
+
<p-multiSelect
|
|
1194
|
+
id="oip-security-multiselect-{{ item.name }}"
|
|
1195
|
+
placeholder="{{ 'securityComponent.selectRoles' | translate }}"
|
|
1196
|
+
[maxSelectedLabels]="10"
|
|
1197
|
+
[options]="roles"
|
|
1198
|
+
[(ngModel)]="item.roles" />
|
|
1199
|
+
</div>
|
|
1200
|
+
}
|
|
1201
|
+
<div class="flex justify-content-end flex-wrap">
|
|
1202
|
+
<p-button
|
|
1203
|
+
icon="pi pi-save"
|
|
1204
|
+
id="oip-security-save-button"
|
|
1205
|
+
label="{{ 'securityComponent.save' | translate }}"
|
|
1206
|
+
(click)="saveClick()"
|
|
1207
|
+
(keydown)="saveKeyDown($event)" />
|
|
1208
|
+
</div>
|
|
1209
|
+
</div>
|
|
1210
|
+
</div>
|
|
1211
|
+
</div>
|
|
889
1212
|
`, isInline: true, dependencies: [{ 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: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: FormsModule }, { 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: 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: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
890
1213
|
}
|
|
891
1214
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityComponent, decorators: [{
|
|
892
1215
|
type: Component,
|
|
893
1216
|
args: [{
|
|
894
1217
|
selector: 'security',
|
|
895
|
-
template: `
|
|
896
|
-
<div class="flex flex-col md:flex-row gap-8">
|
|
897
|
-
<div class="md:w-1/2">
|
|
898
|
-
<div class="card flex flex-col gap-4">
|
|
899
|
-
<div class="font-semibold text-xl">
|
|
900
|
-
{{ 'securityComponent.security' | translate }}
|
|
901
|
-
</div>
|
|
902
|
-
@for (item of securityData; track item.name) {
|
|
903
|
-
<div class="flex flex-col gap-2">
|
|
904
|
-
<label htmlFor="oip-security-multiselect-{{ item.name }}">
|
|
905
|
-
{{ item.name }}
|
|
906
|
-
<span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
|
|
907
|
-
</label>
|
|
908
|
-
<p-multiSelect
|
|
909
|
-
id="oip-security-multiselect-{{ item.name }}"
|
|
910
|
-
placeholder="
|
|
911
|
-
[maxSelectedLabels]="10"
|
|
912
|
-
[options]="roles"
|
|
913
|
-
[(ngModel)]="item.roles" />
|
|
914
|
-
</div>
|
|
915
|
-
}
|
|
916
|
-
<div class="flex justify-content-end flex-wrap">
|
|
917
|
-
<p-button
|
|
918
|
-
icon="pi pi-save"
|
|
919
|
-
id="oip-security-save-button"
|
|
920
|
-
label="{{ 'securityComponent.save' | translate }}"
|
|
921
|
-
(click)="saveClick()"
|
|
922
|
-
(keydown)="saveKeyDown($event)" />
|
|
923
|
-
</div>
|
|
924
|
-
</div>
|
|
925
|
-
</div>
|
|
926
|
-
</div>
|
|
1218
|
+
template: `
|
|
1219
|
+
<div class="flex flex-col md:flex-row gap-8">
|
|
1220
|
+
<div class="md:w-1/2">
|
|
1221
|
+
<div class="card flex flex-col gap-4">
|
|
1222
|
+
<div class="font-semibold text-xl">
|
|
1223
|
+
{{ 'securityComponent.security' | translate }}
|
|
1224
|
+
</div>
|
|
1225
|
+
@for (item of securityData; track item.name) {
|
|
1226
|
+
<div class="flex flex-col gap-2">
|
|
1227
|
+
<label htmlFor="oip-security-multiselect-{{ item.name }}">
|
|
1228
|
+
{{ item.name }}
|
|
1229
|
+
<span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
|
|
1230
|
+
</label>
|
|
1231
|
+
<p-multiSelect
|
|
1232
|
+
id="oip-security-multiselect-{{ item.name }}"
|
|
1233
|
+
placeholder="{{ 'securityComponent.selectRoles' | translate }}"
|
|
1234
|
+
[maxSelectedLabels]="10"
|
|
1235
|
+
[options]="roles"
|
|
1236
|
+
[(ngModel)]="item.roles" />
|
|
1237
|
+
</div>
|
|
1238
|
+
}
|
|
1239
|
+
<div class="flex justify-content-end flex-wrap">
|
|
1240
|
+
<p-button
|
|
1241
|
+
icon="pi pi-save"
|
|
1242
|
+
id="oip-security-save-button"
|
|
1243
|
+
label="{{ 'securityComponent.save' | translate }}"
|
|
1244
|
+
(click)="saveClick()"
|
|
1245
|
+
(keydown)="saveKeyDown($event)" />
|
|
1246
|
+
</div>
|
|
1247
|
+
</div>
|
|
1248
|
+
</div>
|
|
1249
|
+
</div>
|
|
927
1250
|
`,
|
|
928
1251
|
imports: [MultiSelectModule, TooltipModule, FormsModule, ButtonModule, TranslatePipe],
|
|
929
1252
|
standalone: true
|
|
@@ -1447,195 +1770,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1447
1770
|
args: [{
|
|
1448
1771
|
selector: 'app-configurator',
|
|
1449
1772
|
standalone: true,
|
|
1450
|
-
imports: [CommonModule, FormsModule, SelectButtonModule, TranslatePipe],
|
|
1451
|
-
template: `
|
|
1452
|
-
<div class="flex flex-col gap-4">
|
|
1453
|
-
<div>
|
|
1454
|
-
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.primary' | translate }}</span>
|
|
1455
|
-
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
1456
|
-
@for (primaryColor of primaryColors(); track primaryColor.name) {
|
|
1457
|
-
<button
|
|
1458
|
-
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
1459
|
-
id="oip-app-configurator-primary-color-{{ primaryColor.name }}"
|
|
1460
|
-
type="button"
|
|
1461
|
-
[ngClass]="{
|
|
1462
|
-
'outline-primary': primaryColor.name === selectedPrimaryColor()
|
|
1463
|
-
}"
|
|
1464
|
-
[style]="{
|
|
1465
|
-
'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
|
|
1466
|
-
}"
|
|
1467
|
-
[title]="primaryColor.name"
|
|
1468
|
-
(click)="updateColors($event, 'primary', primaryColor)"></button>
|
|
1469
|
-
}
|
|
1470
|
-
</div>
|
|
1471
|
-
</div>
|
|
1472
|
-
<div>
|
|
1473
|
-
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.surface' | translate }}</span>
|
|
1474
|
-
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
1475
|
-
@for (surface of surfaceColors(); track surface.name) {
|
|
1476
|
-
<button
|
|
1477
|
-
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
1478
|
-
id="oip-app-configurator-surface-color-{{ surface.name }}"
|
|
1479
|
-
type="button"
|
|
1480
|
-
[ngClass]="{
|
|
1481
|
-
'outline-primary': selectedSurfaceColor()
|
|
1482
|
-
? selectedSurfaceColor() === surface.name
|
|
1483
|
-
: layoutService.layoutConfig().darkTheme
|
|
1484
|
-
? surface.name === 'zinc'
|
|
1485
|
-
: surface.name === 'slate'
|
|
1486
|
-
}"
|
|
1487
|
-
[style]="{
|
|
1488
|
-
'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
|
|
1489
|
-
}"
|
|
1490
|
-
[title]="surface.name"
|
|
1491
|
-
(click)="updateColors($event, 'surface', surface)"></button>
|
|
1492
|
-
}
|
|
1493
|
-
</div>
|
|
1494
|
-
</div>
|
|
1495
|
-
<div class="flex flex-col gap-2">
|
|
1496
|
-
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.presets' | translate }}</span>
|
|
1497
|
-
<p-selectButton
|
|
1498
|
-
id="oip-app-configurator-preset-select-button"
|
|
1499
|
-
size="small"
|
|
1500
|
-
[allowEmpty]="false"
|
|
1501
|
-
[ngModel]="selectedPreset()"
|
|
1502
|
-
[options]="presets"
|
|
1503
|
-
optionLabel="label"
|
|
1504
|
-
optionValue="value"
|
|
1505
|
-
(ngModelChange)="onPresetChange($event)" />
|
|
1506
|
-
</div>
|
|
1507
|
-
@if (showMenuModeButton()) {
|
|
1508
|
-
<div class="flex flex-col gap-2">
|
|
1509
|
-
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.menuMode' | translate }}</span>
|
|
1510
|
-
<p-selectButton
|
|
1511
|
-
id="oip-app-configurator-menu-mode-select-button"
|
|
1512
|
-
size="small"
|
|
1513
|
-
[allowEmpty]="false"
|
|
1514
|
-
[ngModel]="menuMode()"
|
|
1515
|
-
[options]="menuModeOptions"
|
|
1516
|
-
(ngModelChange)="onMenuModeChange($event)" />
|
|
1517
|
-
</div>
|
|
1518
|
-
}
|
|
1519
|
-
</div>
|
|
1520
|
-
`,
|
|
1521
|
-
host: {
|
|
1522
|
-
class: 'hidden absolute top-[3.25rem] right-0 w-72 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]'
|
|
1523
|
-
}
|
|
1524
|
-
}]
|
|
1525
|
-
}] });
|
|
1526
|
-
|
|
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: () => [] });
|
|
1773
|
+
imports: [CommonModule, FormsModule, SelectButtonModule, TranslatePipe],
|
|
1774
|
+
template: `
|
|
1775
|
+
<div class="flex flex-col gap-4">
|
|
1776
|
+
<div>
|
|
1777
|
+
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.primary' | translate }}</span>
|
|
1778
|
+
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
1779
|
+
@for (primaryColor of primaryColors(); track primaryColor.name) {
|
|
1780
|
+
<button
|
|
1781
|
+
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
1782
|
+
id="oip-app-configurator-primary-color-{{ primaryColor.name }}"
|
|
1783
|
+
type="button"
|
|
1784
|
+
[ngClass]="{
|
|
1785
|
+
'outline-primary': primaryColor.name === selectedPrimaryColor()
|
|
1786
|
+
}"
|
|
1787
|
+
[style]="{
|
|
1788
|
+
'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
|
|
1789
|
+
}"
|
|
1790
|
+
[title]="primaryColor.name"
|
|
1791
|
+
(click)="updateColors($event, 'primary', primaryColor)"></button>
|
|
1792
|
+
}
|
|
1793
|
+
</div>
|
|
1794
|
+
</div>
|
|
1795
|
+
<div>
|
|
1796
|
+
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.surface' | translate }}</span>
|
|
1797
|
+
<div class="pt-2 flex gap-2 flex-wrap justify-start">
|
|
1798
|
+
@for (surface of surfaceColors(); track surface.name) {
|
|
1799
|
+
<button
|
|
1800
|
+
class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
|
|
1801
|
+
id="oip-app-configurator-surface-color-{{ surface.name }}"
|
|
1802
|
+
type="button"
|
|
1803
|
+
[ngClass]="{
|
|
1804
|
+
'outline-primary': selectedSurfaceColor()
|
|
1805
|
+
? selectedSurfaceColor() === surface.name
|
|
1806
|
+
: layoutService.layoutConfig().darkTheme
|
|
1807
|
+
? surface.name === 'zinc'
|
|
1808
|
+
: surface.name === 'slate'
|
|
1809
|
+
}"
|
|
1810
|
+
[style]="{
|
|
1811
|
+
'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
|
|
1812
|
+
}"
|
|
1813
|
+
[title]="surface.name"
|
|
1814
|
+
(click)="updateColors($event, 'surface', surface)"></button>
|
|
1815
|
+
}
|
|
1816
|
+
</div>
|
|
1817
|
+
</div>
|
|
1818
|
+
<div class="flex flex-col gap-2">
|
|
1819
|
+
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.presets' | translate }}</span>
|
|
1820
|
+
<p-selectButton
|
|
1821
|
+
id="oip-app-configurator-preset-select-button"
|
|
1822
|
+
size="small"
|
|
1823
|
+
[allowEmpty]="false"
|
|
1824
|
+
[ngModel]="selectedPreset()"
|
|
1825
|
+
[options]="presets"
|
|
1826
|
+
optionLabel="label"
|
|
1827
|
+
optionValue="value"
|
|
1828
|
+
(ngModelChange)="onPresetChange($event)" />
|
|
1829
|
+
</div>
|
|
1830
|
+
@if (showMenuModeButton()) {
|
|
1831
|
+
<div class="flex flex-col gap-2">
|
|
1832
|
+
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.menuMode' | translate }}</span>
|
|
1833
|
+
<p-selectButton
|
|
1834
|
+
id="oip-app-configurator-menu-mode-select-button"
|
|
1835
|
+
size="small"
|
|
1836
|
+
[allowEmpty]="false"
|
|
1837
|
+
[ngModel]="menuMode()"
|
|
1838
|
+
[options]="menuModeOptions"
|
|
1839
|
+
(ngModelChange)="onMenuModeChange($event)" />
|
|
1840
|
+
</div>
|
|
1841
|
+
}
|
|
1842
|
+
</div>
|
|
1843
|
+
`,
|
|
1844
|
+
host: {
|
|
1845
|
+
class: 'hidden absolute top-[3.25rem] right-0 w-72 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]'
|
|
1846
|
+
}
|
|
1847
|
+
}]
|
|
1848
|
+
}] });
|
|
1639
1849
|
|
|
1640
1850
|
/**
|
|
1641
1851
|
* UserService is responsible for retrieving and handling user-related data,
|
|
@@ -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
|
-
|
|
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
|
-
|
|
2099
|
-
|
|
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"
|
|
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"
|
|
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
|
}]
|
|
@@ -5954,6 +6081,152 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5954
6081
|
args: [{ required: true }]
|
|
5955
6082
|
}] } });
|
|
5956
6083
|
|
|
6084
|
+
class IframeModuleComponent extends BaseModuleComponent {
|
|
6085
|
+
constructor() {
|
|
6086
|
+
super();
|
|
6087
|
+
this.renderer = inject(Renderer2);
|
|
6088
|
+
this.translate = inject(TranslateService);
|
|
6089
|
+
this.iframeUrl = null;
|
|
6090
|
+
this.l10nService.loadComponentTranslations('iframe-module');
|
|
6091
|
+
}
|
|
6092
|
+
set iframeElement(element) {
|
|
6093
|
+
this.iframe = element;
|
|
6094
|
+
this.updateIframeSrc();
|
|
6095
|
+
}
|
|
6096
|
+
setIframeUrl(url) {
|
|
6097
|
+
const iframeUrl = url?.trim();
|
|
6098
|
+
if (!iframeUrl) {
|
|
6099
|
+
this.iframeUrl = null;
|
|
6100
|
+
this.updateIframeSrc();
|
|
6101
|
+
const message = this.translate.instant('iframe-module.iframeModule.emptyUrlMessage');
|
|
6102
|
+
this.msgService.warn(message);
|
|
6103
|
+
return;
|
|
6104
|
+
}
|
|
6105
|
+
if (!this.isAllowedIframeUrl(iframeUrl)) {
|
|
6106
|
+
this.iframeUrl = null;
|
|
6107
|
+
this.updateIframeSrc();
|
|
6108
|
+
const message = this.translate.instant('iframe-module.iframeModule.siteLoadingMessage');
|
|
6109
|
+
this.msgService.error(message);
|
|
6110
|
+
return;
|
|
6111
|
+
}
|
|
6112
|
+
this.iframeUrl = iframeUrl;
|
|
6113
|
+
this.updateIframeSrc();
|
|
6114
|
+
}
|
|
6115
|
+
isAllowedIframeUrl(url) {
|
|
6116
|
+
try {
|
|
6117
|
+
const parsedUrl = new URL(url, window.location.origin);
|
|
6118
|
+
return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
|
|
6119
|
+
}
|
|
6120
|
+
catch {
|
|
6121
|
+
return false;
|
|
6122
|
+
}
|
|
6123
|
+
}
|
|
6124
|
+
async onModuleInstanceChange() {
|
|
6125
|
+
this.setIframeUrl(this.settings.url);
|
|
6126
|
+
}
|
|
6127
|
+
updateIframeSrc() {
|
|
6128
|
+
if (!this.iframe) {
|
|
6129
|
+
return;
|
|
6130
|
+
}
|
|
6131
|
+
if (!this.iframeUrl) {
|
|
6132
|
+
this.renderer.removeAttribute(this.iframe.nativeElement, 'src');
|
|
6133
|
+
return;
|
|
6134
|
+
}
|
|
6135
|
+
this.renderer.setAttribute(this.iframe.nativeElement, 'src', this.iframeUrl);
|
|
6136
|
+
}
|
|
6137
|
+
onIframeError() {
|
|
6138
|
+
const errorMessage = this.translate.instant('iframe-module.iframeModule.siteLoadingMessage');
|
|
6139
|
+
this.msgService.error(errorMessage);
|
|
6140
|
+
}
|
|
6141
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6142
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: IframeModuleComponent, isStandalone: true, selector: "ng-component", viewQueries: [{ propertyName: "iframeElement", first: true, predicate: ["iframe"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
6143
|
+
@if (isContent) {
|
|
6144
|
+
<iframe
|
|
6145
|
+
#iframe
|
|
6146
|
+
class="w-full h-screen"
|
|
6147
|
+
style="background-color: var(--surface-ground)"
|
|
6148
|
+
title="Main iframe"
|
|
6149
|
+
(error)="onIframeError()">
|
|
6150
|
+
</iframe>
|
|
6151
|
+
} @else if (isSettings) {
|
|
6152
|
+
<div class="flex flex-col md:flex-row gap-8">
|
|
6153
|
+
<div class="md:w-1/2">
|
|
6154
|
+
<div class="card flex flex-col gap-4">
|
|
6155
|
+
<div class="font-semibold text-xl">{{ 'baseComponent.settings' | translate }}</div>
|
|
6156
|
+
<div class="col-span-30 md:col-span-10 w-full">
|
|
6157
|
+
<input
|
|
6158
|
+
class="w-full"
|
|
6159
|
+
pInputText
|
|
6160
|
+
placeholder="{{ 'iframe-module.iframeModule.urlPlaceholder' | translate }}"
|
|
6161
|
+
qa-id="iframe-module-settings-site-url-input"
|
|
6162
|
+
type="text"
|
|
6163
|
+
[(ngModel)]="settings.url"/>
|
|
6164
|
+
</div>
|
|
6165
|
+
<div class="flex justify-end">
|
|
6166
|
+
<p-button
|
|
6167
|
+
icon="pi pi-save"
|
|
6168
|
+
label="{{ 'iframe-module.iframeModule.settingSaveButtonLabel' | translate }}"
|
|
6169
|
+
qa-id="iframe-module-settings-save-button"
|
|
6170
|
+
(onClick)="saveSettings(settings)">
|
|
6171
|
+
</p-button>
|
|
6172
|
+
</div>
|
|
6173
|
+
</div>
|
|
6174
|
+
</div>
|
|
6175
|
+
</div>
|
|
6176
|
+
} @else if (isSecurity) {
|
|
6177
|
+
<security [controller]="controller" [id]="id"/>
|
|
6178
|
+
}
|
|
6179
|
+
`, isInline: true, dependencies: [{ kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "directive", type: 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: "component", type: 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: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
6180
|
+
}
|
|
6181
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleComponent, decorators: [{
|
|
6182
|
+
type: Component,
|
|
6183
|
+
args: [{
|
|
6184
|
+
standalone: true,
|
|
6185
|
+
imports: [SecurityComponent, TranslatePipe, InputText, FormsModule, Button],
|
|
6186
|
+
template: `
|
|
6187
|
+
@if (isContent) {
|
|
6188
|
+
<iframe
|
|
6189
|
+
#iframe
|
|
6190
|
+
class="w-full h-screen"
|
|
6191
|
+
style="background-color: var(--surface-ground)"
|
|
6192
|
+
title="Main iframe"
|
|
6193
|
+
(error)="onIframeError()">
|
|
6194
|
+
</iframe>
|
|
6195
|
+
} @else if (isSettings) {
|
|
6196
|
+
<div class="flex flex-col md:flex-row gap-8">
|
|
6197
|
+
<div class="md:w-1/2">
|
|
6198
|
+
<div class="card flex flex-col gap-4">
|
|
6199
|
+
<div class="font-semibold text-xl">{{ 'baseComponent.settings' | translate }}</div>
|
|
6200
|
+
<div class="col-span-30 md:col-span-10 w-full">
|
|
6201
|
+
<input
|
|
6202
|
+
class="w-full"
|
|
6203
|
+
pInputText
|
|
6204
|
+
placeholder="{{ 'iframe-module.iframeModule.urlPlaceholder' | translate }}"
|
|
6205
|
+
qa-id="iframe-module-settings-site-url-input"
|
|
6206
|
+
type="text"
|
|
6207
|
+
[(ngModel)]="settings.url"/>
|
|
6208
|
+
</div>
|
|
6209
|
+
<div class="flex justify-end">
|
|
6210
|
+
<p-button
|
|
6211
|
+
icon="pi pi-save"
|
|
6212
|
+
label="{{ 'iframe-module.iframeModule.settingSaveButtonLabel' | translate }}"
|
|
6213
|
+
qa-id="iframe-module-settings-save-button"
|
|
6214
|
+
(onClick)="saveSettings(settings)">
|
|
6215
|
+
</p-button>
|
|
6216
|
+
</div>
|
|
6217
|
+
</div>
|
|
6218
|
+
</div>
|
|
6219
|
+
</div>
|
|
6220
|
+
} @else if (isSecurity) {
|
|
6221
|
+
<security [controller]="controller" [id]="id"/>
|
|
6222
|
+
}
|
|
6223
|
+
`
|
|
6224
|
+
}]
|
|
6225
|
+
}], ctorParameters: () => [], propDecorators: { iframeElement: [{
|
|
6226
|
+
type: ViewChild,
|
|
6227
|
+
args: ['iframe']
|
|
6228
|
+
}] } });
|
|
6229
|
+
|
|
5957
6230
|
/**
|
|
5958
6231
|
* A route guard that ensures the user is authenticated and has a valid access token.
|
|
5959
6232
|
* If the access token is expired, it attempts to refresh the session.
|
|
@@ -6182,6 +6455,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6182
6455
|
}]
|
|
6183
6456
|
}] });
|
|
6184
6457
|
|
|
6458
|
+
const appendCurrentOriginSecureRoute = (secureRoutes) => {
|
|
6459
|
+
const currentOriginRoute = `${window.location.origin}/`;
|
|
6460
|
+
return Array.from(new Set([...(secureRoutes ?? []), currentOriginRoute]));
|
|
6461
|
+
};
|
|
6185
6462
|
/**
|
|
6186
6463
|
* Load keycloak settings from backend and save to sessionStorage
|
|
6187
6464
|
* @param httpClient
|
|
@@ -6208,7 +6485,7 @@ const httpLoaderAuthFactory = (httpClient) => {
|
|
|
6208
6485
|
useRefreshToken: config.useRefreshToken,
|
|
6209
6486
|
silentRenew: config.silentRenew,
|
|
6210
6487
|
logLevel: config.logLevel,
|
|
6211
|
-
secureRoutes: config.secureRoutes
|
|
6488
|
+
secureRoutes: appendCurrentOriginSecureRoute(config.secureRoutes)
|
|
6212
6489
|
};
|
|
6213
6490
|
sessionStorage.setItem(KEYCLOAK_SETTINGS_KEY, JSON.stringify(authConfig));
|
|
6214
6491
|
return authConfig;
|
|
@@ -6223,5 +6500,5 @@ const httpLoaderAuthFactory = (httpClient) => {
|
|
|
6223
6500
|
* Generated bundle index. Do not edit.
|
|
6224
6501
|
*/
|
|
6225
6502
|
|
|
6226
|
-
export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AuthGuardService, BaseDataService, BaseModuleComponent, ConfigComponent, ContentType, DEFAULT_OIP_FRONTEND_CONFIG, DbMigrationComponent, DiscussionComponent, ErrorComponent, FooterComponent, HttpClient, KeycloakSecurityService, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationService, OIP_FRONTEND_CONFIG, ProfileComponent, SecurePipe, SecurityComponent, SecurityDataService, SecurityService, SecurityStorageService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserService, httpLoaderAuthFactory, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, replaceDefaults };
|
|
6503
|
+
export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AuthGuardService, BaseDataService, BaseModuleComponent, ConfigComponent, ContentType, DEFAULT_OIP_FRONTEND_CONFIG, DbMigrationComponent, DiscussionComponent, ErrorComponent, FooterComponent, HttpClient, IframeModuleComponent, KeycloakSecurityService, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationService, OIP_FRONTEND_CONFIG, ProfileComponent, SecurePipe, SecurityComponent, SecurityDataService, SecurityService, SecurityStorageService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserService, httpLoaderAuthFactory, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, replaceDefaults };
|
|
6227
6504
|
//# sourceMappingURL=oip-common.mjs.map
|