oip-common 0.2.2 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,18 @@
1
1
  import * as i0 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';
2
+ import { Injectable, inject, signal, computed, effect, DestroyRef, ChangeDetectorRef, Component, Input, InjectionToken, PLATFORM_ID, ViewChild, HostBinding, EventEmitter, Output, Renderer2, SecurityContext, ChangeDetectionStrategy, makeEnvironmentProviders, importProvidersFrom } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import * as i2$3 from 'primeng/api';
5
5
  import { MessageService, ConfirmationService, PrimeIcons, SharedModule } from 'primeng/api';
6
- import { HttpErrorResponse, HttpClient as HttpClient$1, HttpHeaders } from '@angular/common/http';
6
+ import { HttpErrorResponse, HttpClient as HttpClient$1, provideHttpClient, withInterceptors, withFetch } from '@angular/common/http';
7
7
  import * as i2$4 from '@ngx-translate/core';
8
- import { TranslateService, TranslatePipe, TranslateModule } from '@ngx-translate/core';
9
- import * as i1$3 from '@angular/router';
8
+ import { TranslateService, TranslatePipe, TranslateModule, TranslateLoader } from '@ngx-translate/core';
9
+ import * as i1$4 from '@angular/router';
10
10
  import { ActivatedRoute, Router, RouterModule, NavigationEnd, RouterLinkActive, RouterLink } from '@angular/router';
11
- import { lastValueFrom, BehaviorSubject, Subject, of, tap, shareReplay, ReplaySubject, merge, from, finalize, firstValueFrom, filter as filter$1, combineLatest, map as map$1, Observable } from 'rxjs';
12
- import { filter, distinctUntilChanged, map, switchMap, catchError } from 'rxjs/operators';
11
+ import { BehaviorSubject, Subject, of, tap, shareReplay, ReplaySubject, firstValueFrom, merge, from, finalize, filter as filter$1 } from 'rxjs';
12
+ import { tap as tap$1, catchError, filter, distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
13
13
  import { Title, DomSanitizer } from '@angular/platform-browser';
14
14
  import { PrimeNG } from 'primeng/config';
15
- import { OidcSecurityService, PublicEventsService, EventTypes, StsConfigHttpLoader } from 'angular-auth-oidc-client';
15
+ import { OidcSecurityService, PublicEventsService, EventTypes } from 'angular-auth-oidc-client';
16
16
  import * as i1 from 'primeng/multiselect';
17
17
  import { MultiSelectModule } from 'primeng/multiselect';
18
18
  import * as i2 from 'primeng/tooltip';
@@ -22,8 +22,8 @@ import { ButtonModule, Button } from 'primeng/button';
22
22
  import * as i1$1 from '@angular/forms';
23
23
  import { FormsModule, ReactiveFormsModule } from '@angular/forms';
24
24
  import * as i2$1 from '@angular/common';
25
- import { isPlatformBrowser, CommonModule, NgComponentOutlet, NgClass, DatePipe } from '@angular/common';
26
- import * as i3$1 from 'primeng/styleclass';
25
+ import { isPlatformBrowser, CommonModule, NgComponentOutlet, NgClass, DatePipe, PathLocationStrategy, LocationStrategy } from '@angular/common';
26
+ import * as i3$2 from 'primeng/styleclass';
27
27
  import { StyleClassModule } from 'primeng/styleclass';
28
28
  import { updatePreset, updateSurfacePalette, $t } from '@primeng/themes';
29
29
  import Aura from '@primeng/themes/aura';
@@ -34,40 +34,44 @@ import { SelectButtonModule } from 'primeng/selectbutton';
34
34
  import { Tabs, TabList, Tab } from 'primeng/tabs';
35
35
  import * as i2$2 from 'primeng/avatar';
36
36
  import { AvatarModule } from 'primeng/avatar';
37
- import * as i1$4 from 'primeng/contextmenu';
37
+ import { ConfirmDialog } from 'primeng/confirmdialog';
38
+ import * as i1$3 from 'primeng/badge';
39
+ import { BadgeModule } from 'primeng/badge';
40
+ import * as i3$1 from 'primeng/paginator';
41
+ import { PaginatorModule } from 'primeng/paginator';
42
+ import * as i7 from 'primeng/popover';
43
+ import { Popover, PopoverModule } from 'primeng/popover';
44
+ import * as i4 from 'primeng/progressspinner';
45
+ import { ProgressSpinnerModule } from 'primeng/progressspinner';
46
+ import * as i9 from 'primeng/tag';
47
+ import { Tag, TagModule } from 'primeng/tag';
48
+ import * as signalR from '@microsoft/signalr';
49
+ import * as i1$5 from 'primeng/contextmenu';
38
50
  import { ContextMenuModule, ContextMenu } from 'primeng/contextmenu';
39
- import * as i3$3 from 'primeng/dialog';
51
+ import * as i3$4 from 'primeng/dialog';
40
52
  import { DialogModule } from 'primeng/dialog';
41
- import * as i4 from 'primeng/inputtext';
53
+ import * as i4$1 from 'primeng/inputtext';
42
54
  import { InputTextModule, InputText } from 'primeng/inputtext';
43
- import { trigger, state, transition, style, animate } from '@angular/animations';
44
- import * as i3$2 from 'primeng/ripple';
55
+ import * as i3$3 from 'primeng/ripple';
45
56
  import { RippleModule } from 'primeng/ripple';
46
- import { ConfirmDialog } from 'primeng/confirmdialog';
47
57
  import * as i5 from 'primeng/select';
48
58
  import { SelectModule, Select } from 'primeng/select';
49
- import * as i1$5 from 'primeng/fileupload';
59
+ import * as i1$6 from 'primeng/fileupload';
50
60
  import { FileUploadModule } from 'primeng/fileupload';
51
61
  import { ImageModule } from 'primeng/image';
52
- import * as i1$6 from 'primeng/table';
62
+ import * as i1$7 from 'primeng/table';
53
63
  import { TableModule } from 'primeng/table';
54
64
  import * as i2$5 from 'primeng/toggleswitch';
55
65
  import { ToggleSwitchModule } from 'primeng/toggleswitch';
56
- import * as i9 from 'primeng/tag';
57
- import { TagModule, Tag } from 'primeng/tag';
58
66
  import { TextareaModule, Textarea } from 'primeng/textarea';
59
- import * as i4$1 from 'primeng/toolbar';
67
+ import * as i4$2 from 'primeng/toolbar';
60
68
  import { ToolbarModule } from 'primeng/toolbar';
61
69
  import * as i5$1 from 'primeng/card';
62
70
  import { CardModule } from 'primeng/card';
63
71
  import { DividerModule } from 'primeng/divider';
64
72
  import * as i6 from 'primeng/panel';
65
73
  import { PanelModule } from 'primeng/panel';
66
- import * as i7 from 'primeng/popover';
67
- import { PopoverModule } from 'primeng/popover';
68
- import * as i8 from 'primeng/progressspinner';
69
- import { ProgressSpinnerModule } from 'primeng/progressspinner';
70
- import * as signalR from '@microsoft/signalr';
74
+ import { TranslateHttpLoader } from '@ngx-translate/http-loader';
71
75
 
72
76
  class TopBarService {
73
77
  get availableTopBarItems() {
@@ -235,94 +239,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
235
239
  args: [{ providedIn: 'root' }]
236
240
  }] });
237
241
 
238
- const DEFAULT_OIP_FRONTEND_CONFIG = {
239
- appMode: 'standalone',
240
- apiBaseUrl: '',
241
- notificationHubUrl: ''
242
- };
243
- const OIP_FRONTEND_CONFIG = new InjectionToken('OIP_FRONTEND_CONFIG', {
244
- factory: () => DEFAULT_OIP_FRONTEND_CONFIG
245
- });
246
-
247
- /**
248
- * BaseDataService provides a unified interface for sending HTTP requests
249
- * using Angular's HttpClient. It supports standard HTTP methods and automatic
250
- * credential handling.
251
- */
252
- class BaseDataService {
253
- constructor() {
254
- this.http = inject(HttpClient$1);
255
- this.frontendConfig = inject(OIP_FRONTEND_CONFIG);
256
- }
257
- /**
258
- * Gets the base URL of the application from the HTML <base> tag.
259
- */
260
- get baseUrl() {
261
- return this.normalizeBaseUrl(this.frontendConfig.apiBaseUrl || document.getElementsByTagName('base')[0].href);
262
- }
263
- /**
264
- * Builds a fully-qualified application URL based on frontend mode.
265
- */
266
- buildUrl(path) {
267
- const normalizedPath = path.startsWith('/') ? path.substring(1) : path;
268
- return `${this.baseUrl}${normalizedPath}`;
269
- }
270
- /**
271
- * Sends an HTTP request with the specified method and data.
272
- *
273
- * @template TResponse - Expected response type.
274
- * @param url - The target URL for the HTTP request.
275
- * @param method - The HTTP method to use (GET, PUT, POST, DELETE). Default is 'GET'.
276
- * @param data - An object containing request parameters or payload.
277
- * @returns A promise that resolves to the response of type TResponse.
278
- */
279
- sendRequest(url, method = 'GET', data = {}) {
280
- const httpOptions = { withCredentials: true };
281
- let result;
282
- switch (method) {
283
- case 'GET':
284
- result = this.http.get(url, { params: data });
285
- break;
286
- case 'PUT':
287
- result = this.http.put(url, data, httpOptions);
288
- break;
289
- case 'POST':
290
- result = this.http.post(url, data, httpOptions);
291
- break;
292
- case 'DELETE':
293
- result = this.http.request('DELETE', url, {
294
- body: data,
295
- headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
296
- withCredentials: true
297
- });
298
- break;
299
- }
300
- return lastValueFrom(result);
301
- }
302
- /**
303
- * Sends a GET request and retrieves a response as a Blob.
304
- *
305
- * @param url - The target URL for the GET request.
306
- * @returns A promise that resolves to a Object response.
307
- */
308
- getBlob(url) {
309
- const httpOptions = {
310
- responseType: 'blob',
311
- withCredentials: true
312
- };
313
- const result = this.http.get(url, httpOptions);
314
- return lastValueFrom(result);
315
- }
316
- normalizeBaseUrl(baseUrl) {
317
- return baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
318
- }
319
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
320
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseDataService }); }
321
- }
322
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseDataService, decorators: [{
323
- type: Injectable
324
- }] });
325
-
326
242
  /**
327
243
  * Service to manage the application title.
328
244
  */
@@ -693,25 +609,131 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
693
609
  args: [{ providedIn: 'root' }]
694
610
  }] });
695
611
 
696
- class SecurityDataService extends BaseDataService {
697
- getSecurity(controller, id) {
698
- return this.sendRequest(this.baseUrl + `api/${controller}/get-security?id=${id}`);
612
+ class SecurityService {
613
+ }
614
+ class BffSecurityService {
615
+ constructor() {
616
+ this.http = inject(HttpClient$1);
617
+ this.authenticated = new BehaviorSubject(null);
618
+ this.currentUser = new BehaviorSubject(null);
619
+ this.csrfToken = new ReplaySubject(1);
620
+ this.payload = new BehaviorSubject(null);
699
621
  }
700
- saveSecurity(controller, request) {
701
- return this.sendRequest(this.baseUrl + `api/${controller}/put-security`, 'PUT', request);
622
+ auth() {
623
+ this.http.get(this.buildUrl('api/security/get-current-auth-session'), {
624
+ withCredentials: true
625
+ }).pipe(tap$1((session) => this.applySession(session)), catchError(() => {
626
+ this.applyAnonymousSession();
627
+ return of(null);
628
+ })).subscribe();
629
+ }
630
+ logout() {
631
+ firstValueFrom(this.getCsrfToken()).then((csrfToken) => {
632
+ const form = this.createPostForm(this.buildUrl('api/security/delete-auth-session'));
633
+ if (csrfToken?.token) {
634
+ const tokenInput = document.createElement('input');
635
+ tokenInput.type = 'hidden';
636
+ tokenInput.name = '__RequestVerificationToken';
637
+ tokenInput.value = csrfToken.token;
638
+ form.appendChild(tokenInput);
639
+ }
640
+ document.body.appendChild(form);
641
+ form.submit();
642
+ });
702
643
  }
703
- getRealmRoles() {
704
- return this.sendRequest(this.baseUrl + `api/security/get-realm-roles`);
644
+ isAuthenticated() {
645
+ return this.authenticated.asObservable().pipe(filter((value) => value !== null), distinctUntilChanged());
646
+ }
647
+ getAccessToken() {
648
+ return of('');
649
+ }
650
+ isTokenExpired() {
651
+ return of(false);
705
652
  }
706
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
707
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService }); }
653
+ getCurrentUser() {
654
+ return this.currentUser.getValue();
655
+ }
656
+ getCurrentUser$() {
657
+ return this.currentUser.asObservable();
658
+ }
659
+ forceRefreshSession() {
660
+ this.auth();
661
+ return of({
662
+ isAuthenticated: this.authenticated.getValue() === true,
663
+ userData: this.currentUser.getValue()
664
+ });
665
+ }
666
+ getCsrfToken() {
667
+ this.http.get(this.buildUrl('api/security/get-auth-csrf-token'), {
668
+ withCredentials: true
669
+ }).pipe(catchError(() => of(null))).subscribe((token) => this.csrfToken.next(token));
670
+ return this.csrfToken.asObservable();
671
+ }
672
+ isAdmin() {
673
+ return this.payload.getValue()?.realm_access?.roles?.includes('admin') ?? false;
674
+ }
675
+ authorize() {
676
+ const form = this.createPostForm(this.buildUrl('api/security/create-auth-session'));
677
+ document.body.appendChild(form);
678
+ form.submit();
679
+ }
680
+ ngOnDestroy() {
681
+ this.authenticated.complete();
682
+ this.currentUser.complete();
683
+ this.payload.complete();
684
+ }
685
+ applySession(session) {
686
+ const roles = session.roles ?? [];
687
+ const user = this.createCurrentUser(session, roles);
688
+ this.authenticated.next(session.isAuthenticated);
689
+ this.currentUser.next(user);
690
+ this.payload.next({ realm_access: { roles }, ...user });
691
+ }
692
+ createCurrentUser(session, roles) {
693
+ const displayName = session.displayName || session.userName || session.email;
694
+ const nameParts = this.splitDisplayName(displayName);
695
+ return {
696
+ userName: session.userName,
697
+ displayName,
698
+ email: session.email,
699
+ roles,
700
+ preferred_username: session.userName,
701
+ name: displayName,
702
+ given_name: nameParts.givenName,
703
+ family_name: nameParts.familyName
704
+ };
705
+ }
706
+ splitDisplayName(displayName) {
707
+ const parts = displayName?.trim().split(/\s+/).filter(Boolean) ?? [];
708
+ return {
709
+ givenName: parts[0],
710
+ familyName: parts.length > 1 ? parts.slice(1).join(' ') : undefined
711
+ };
712
+ }
713
+ applyAnonymousSession() {
714
+ this.authenticated.next(false);
715
+ this.currentUser.next(null);
716
+ this.payload.next(null);
717
+ this.csrfToken.next(null);
718
+ }
719
+ createPostForm(action) {
720
+ const form = document.createElement('form');
721
+ form.method = 'post';
722
+ form.action = action;
723
+ form.style.display = 'none';
724
+ return form;
725
+ }
726
+ buildUrl(path) {
727
+ const baseUrl = document.getElementsByTagName('base')[0].href;
728
+ const normalizedBase = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
729
+ return `${normalizedBase}${path}`;
730
+ }
731
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BffSecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
732
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BffSecurityService }); }
708
733
  }
709
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityDataService, decorators: [{
734
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BffSecurityService, decorators: [{
710
735
  type: Injectable
711
736
  }] });
712
-
713
- class SecurityService {
714
- }
715
737
  /**
716
738
  * SecurityService extends OidcSecurityService to manage authentication,
717
739
  * token handling, and user role access in an Angular application.
@@ -756,7 +778,9 @@ class KeycloakSecurityService extends OidcSecurityService {
756
778
  .registerForEvents()
757
779
  .pipe(filter((event) => event.type === EventTypes.NewAuthenticationResult))
758
780
  .subscribe(() => {
759
- super.getAccessToken().subscribe(token => { this.accessToken.next(token); });
781
+ super.getAccessToken().subscribe(token => {
782
+ this.accessToken.next(token);
783
+ });
760
784
  this.auth();
761
785
  });
762
786
  }
@@ -781,6 +805,9 @@ class KeycloakSecurityService extends OidcSecurityService {
781
805
  }
782
806
  return this.refreshSession$;
783
807
  }
808
+ getCsrfToken() {
809
+ return of(null);
810
+ }
784
811
  /**
785
812
  * Indicates whether the current user has the 'admin' role.
786
813
  *
@@ -1004,6 +1031,198 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1004
1031
  type: Injectable
1005
1032
  }], ctorParameters: () => [] });
1006
1033
 
1034
+ /* eslint-disable */
1035
+ /* tslint:disable */
1036
+ // @ts-nocheck
1037
+ var ContentType;
1038
+ (function (ContentType) {
1039
+ ContentType["Json"] = "application/json";
1040
+ ContentType["JsonApi"] = "application/vnd.api+json";
1041
+ ContentType["FormData"] = "multipart/form-data";
1042
+ ContentType["UrlEncoded"] = "application/x-www-form-urlencoded";
1043
+ ContentType["Text"] = "text/plain";
1044
+ })(ContentType || (ContentType = {}));
1045
+ class HttpClient {
1046
+ constructor() {
1047
+ this.securityService = inject(SecurityService);
1048
+ this.layoutService = inject(LayoutService);
1049
+ this.baseUrl = "";
1050
+ this.securityWorker = () => ({
1051
+ headers: {
1052
+ "Accept-language": this.layoutService.language()
1053
+ ? this.layoutService.language()
1054
+ : "en",
1055
+ "X-Timezone": this.layoutService.timeZone(),
1056
+ },
1057
+ });
1058
+ this.abortControllers = new Map();
1059
+ this.customFetch = (...fetchParams) => fetch(...fetchParams);
1060
+ this.baseApiParams = {
1061
+ credentials: "same-origin",
1062
+ headers: {},
1063
+ redirect: "follow",
1064
+ referrerPolicy: "no-referrer",
1065
+ };
1066
+ this.setSecurityData = (data) => { };
1067
+ this.contentFormatters = {
1068
+ [ContentType.Json]: (input) => input !== null && (typeof input === "object" || typeof input === "string")
1069
+ ? JSON.stringify(input)
1070
+ : input,
1071
+ [ContentType.JsonApi]: (input) => input !== null && (typeof input === "object" || typeof input === "string")
1072
+ ? JSON.stringify(input)
1073
+ : input,
1074
+ [ContentType.Text]: (input) => input !== null && typeof input !== "string"
1075
+ ? JSON.stringify(input)
1076
+ : input,
1077
+ [ContentType.FormData]: (input) => {
1078
+ if (input instanceof FormData) {
1079
+ return input;
1080
+ }
1081
+ return Object.keys(input || {}).reduce((formData, key) => {
1082
+ const property = input[key];
1083
+ formData.append(key, property instanceof Blob
1084
+ ? property
1085
+ : typeof property === "object" && property !== null
1086
+ ? JSON.stringify(property)
1087
+ : `${property}`);
1088
+ return formData;
1089
+ }, new FormData());
1090
+ },
1091
+ [ContentType.UrlEncoded]: (input) => this.toQueryString(input),
1092
+ };
1093
+ this.createAbortSignal = (cancelToken) => {
1094
+ if (this.abortControllers.has(cancelToken)) {
1095
+ const abortController = this.abortControllers.get(cancelToken);
1096
+ if (abortController) {
1097
+ return abortController.signal;
1098
+ }
1099
+ return void 0;
1100
+ }
1101
+ const abortController = new AbortController();
1102
+ this.abortControllers.set(cancelToken, abortController);
1103
+ return abortController.signal;
1104
+ };
1105
+ this.abortRequest = (cancelToken) => {
1106
+ const abortController = this.abortControllers.get(cancelToken);
1107
+ if (abortController) {
1108
+ abortController.abort();
1109
+ this.abortControllers.delete(cancelToken);
1110
+ }
1111
+ };
1112
+ this.request = async ({ body, secure, path, type, query, format, baseUrl, cancelToken, ...params }) => {
1113
+ const secureParams = ((typeof secure === "boolean" ? secure : this.baseApiParams.secure) &&
1114
+ this.securityWorker &&
1115
+ (await this.securityWorker(null))) ||
1116
+ {};
1117
+ const csrfParams = await this.getCsrfRequestParams(params.method, path);
1118
+ const requestParams = this.mergeRequestParams(this.mergeRequestParams(params, secureParams), csrfParams);
1119
+ const queryString = query && this.toQueryString(query);
1120
+ const payloadFormatter = this.contentFormatters[type || ContentType.Json];
1121
+ let responseFormat = format || requestParams.format;
1122
+ return this.customFetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, {
1123
+ ...requestParams,
1124
+ headers: {
1125
+ ...(requestParams.headers || {}),
1126
+ ...(type && type !== ContentType.FormData
1127
+ ? { "Content-Type": type }
1128
+ : {}),
1129
+ },
1130
+ signal: (cancelToken
1131
+ ? this.createAbortSignal(cancelToken)
1132
+ : requestParams.signal) || null,
1133
+ body: typeof body === "undefined" || body === null
1134
+ ? null
1135
+ : payloadFormatter(body),
1136
+ }).then(async (response) => {
1137
+ const r = response;
1138
+ r.data = null;
1139
+ r.error = null;
1140
+ if (typeof E !== undefined && responseFormat === undefined)
1141
+ responseFormat = "json";
1142
+ const responseToParse = responseFormat ? response.clone() : response;
1143
+ const data = !responseFormat
1144
+ ? r
1145
+ : await responseToParse[responseFormat]()
1146
+ .then((data) => {
1147
+ if (r.ok) {
1148
+ r.data = data;
1149
+ }
1150
+ else {
1151
+ r.error = data;
1152
+ }
1153
+ return r;
1154
+ })
1155
+ .catch((e) => {
1156
+ r.error = e;
1157
+ return r;
1158
+ });
1159
+ if (cancelToken) {
1160
+ this.abortControllers.delete(cancelToken);
1161
+ }
1162
+ if (!response.ok)
1163
+ throw data;
1164
+ return data.data;
1165
+ });
1166
+ };
1167
+ }
1168
+ encodeQueryParam(key, value) {
1169
+ const encodedKey = encodeURIComponent(key);
1170
+ return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
1171
+ }
1172
+ addQueryParam(query, key) {
1173
+ return this.encodeQueryParam(key, query[key]);
1174
+ }
1175
+ addArrayQueryParam(query, key) {
1176
+ const value = query[key];
1177
+ return value.map((v) => this.encodeQueryParam(key, v)).join("&");
1178
+ }
1179
+ toQueryString(rawQuery) {
1180
+ const query = rawQuery || {};
1181
+ const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
1182
+ return keys
1183
+ .map((key) => Array.isArray(query[key])
1184
+ ? this.addArrayQueryParam(query, key)
1185
+ : this.addQueryParam(query, key))
1186
+ .join("&");
1187
+ }
1188
+ addQueryParams(rawQuery) {
1189
+ const queryString = this.toQueryString(rawQuery);
1190
+ return queryString ? `?${queryString}` : "";
1191
+ }
1192
+ mergeRequestParams(params1, params2) {
1193
+ return {
1194
+ ...this.baseApiParams,
1195
+ ...params1,
1196
+ ...(params2 || {}),
1197
+ headers: {
1198
+ ...(this.baseApiParams.headers || {}),
1199
+ ...(params1.headers || {}),
1200
+ ...((params2 && params2.headers) || {}),
1201
+ },
1202
+ };
1203
+ }
1204
+ async getCsrfRequestParams(method, path) {
1205
+ if (!method ||
1206
+ !["POST", "PUT", "PATCH", "DELETE"].includes(method.toUpperCase())) {
1207
+ return {};
1208
+ }
1209
+ if (path.includes("/api/security/create-auth-session") ||
1210
+ path.includes("/api/security/get-auth-csrf-token")) {
1211
+ return {};
1212
+ }
1213
+ const csrfToken = await firstValueFrom(this.securityService.getCsrfToken());
1214
+ return csrfToken?.token
1215
+ ? { headers: { [csrfToken.headerName]: csrfToken.token } }
1216
+ : {};
1217
+ }
1218
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HttpClient, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1219
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HttpClient, providedIn: "root" }); }
1220
+ }
1221
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HttpClient, decorators: [{
1222
+ type: Injectable,
1223
+ args: [{ providedIn: "root" }]
1224
+ }] });
1225
+
1007
1226
  class BaseModuleComponent {
1008
1227
  static { this.readRight = 'read'; }
1009
1228
  static { this.editRight = 'edit'; }
@@ -1061,15 +1280,23 @@ class BaseModuleComponent {
1061
1280
  t(key, interpolateParams) {
1062
1281
  return this.translateService.instant(key, interpolateParams);
1063
1282
  }
1283
+ /**
1284
+ * Checks whether the current user has the specified security right.
1285
+ */
1286
+ hasRight(code) {
1287
+ return this.hasSecurityRight(this.securityRoles, this.securitySettings, code);
1288
+ }
1064
1289
  /**
1065
1290
  * Initializes the component and subscribes to local settings updates.
1066
1291
  */
1067
1292
  constructor() {
1068
1293
  this.isInitialized = false;
1069
1294
  this.moduleInstanceReloadPromise = Promise.resolve();
1295
+ this.securityRoles = [];
1296
+ this.securitySettings = [];
1070
1297
  this.destroyRef = inject(DestroyRef);
1071
- this.securityDataService = inject(SecurityDataService);
1072
1298
  this.securityService = inject(SecurityService);
1299
+ this.httpClient = inject(HttpClient);
1073
1300
  /**
1074
1301
  * Provide access to app settings
1075
1302
  */
@@ -1088,11 +1315,6 @@ class BaseModuleComponent {
1088
1315
  * Provides access to messaging services.
1089
1316
  */
1090
1317
  this.msgService = inject(MsgService);
1091
- /**
1092
- * Provides access to base data service functionality.
1093
- * @deprecated The method should not be used
1094
- */
1095
- this.baseDataService = inject(BaseDataService);
1096
1318
  /**
1097
1319
  * Provides access to translation functionality.
1098
1320
  */
@@ -1210,7 +1432,10 @@ class BaseModuleComponent {
1210
1432
  */
1211
1433
  async getSettings() {
1212
1434
  try {
1213
- this.settings = await this.baseDataService.sendRequest(`${this.baseDataService.baseUrl}api/${this.controller}/get-module-instance-settings?id=${this.id}`);
1435
+ if (this.id == null) {
1436
+ return;
1437
+ }
1438
+ this.settings = await this.getModuleInstanceSettings();
1214
1439
  }
1215
1440
  catch (error) {
1216
1441
  this.msgService.error(error);
@@ -1222,8 +1447,11 @@ class BaseModuleComponent {
1222
1447
  * @return {Promise<void>} A promise that resolves when the settings are saved. Reject if an error occurs.
1223
1448
  */
1224
1449
  async saveSettings(settings) {
1225
- await this.baseDataService
1226
- .sendRequest(`api/${this.controller}/put-module-instance-settings`, 'PUT', {
1450
+ if (this.id == null) {
1451
+ this.msgService.error('Module id not passed!');
1452
+ return;
1453
+ }
1454
+ await this.saveModuleInstanceSettings({
1227
1455
  id: this.id,
1228
1456
  settings: settings
1229
1457
  })
@@ -1255,7 +1483,7 @@ class BaseModuleComponent {
1255
1483
  return;
1256
1484
  }
1257
1485
  this.rightsSubscription = this.securityService.payload
1258
- .pipe(switchMap((payload) => from(this.securityDataService.getSecurity(controller, id)).pipe(map((securitySettings) => ({ payload, securitySettings })))), takeUntilDestroyed(this.destroyRef))
1486
+ .pipe(switchMap((payload) => from(this.getSecurity(controller, id)).pipe(map((securitySettings) => ({ payload, securitySettings })))), takeUntilDestroyed(this.destroyRef))
1259
1487
  .subscribe({
1260
1488
  next: ({ payload, securitySettings }) => {
1261
1489
  const roles = payload?.realm_access?.roles ?? [];
@@ -1267,46 +1495,161 @@ class BaseModuleComponent {
1267
1495
  this.onSecurityRightsChange();
1268
1496
  }
1269
1497
  });
1270
- }
1271
- resetRightsState() {
1272
- this.canRead = false;
1273
- this.canEdit = false;
1274
- this.canDelete = false;
1275
- this.securityRightsLoaded = false;
1276
- }
1277
- updateRightsState(roles, securitySettings) {
1278
- this.canRead = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.readRight);
1279
- this.canEdit = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.editRight);
1280
- this.canDelete = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.deleteRight);
1281
- this.securityRightsLoaded = true;
1282
- this.onSecurityRightsChange();
1283
- }
1284
- hasSecurityRight(roles, securitySettings, code) {
1285
- return securitySettings
1286
- .find((security) => security.code === code)
1287
- ?.roles?.some((role) => roles.includes(role)) ?? false;
1288
- }
1289
- async reloadModuleInstance() {
1290
- this.moduleInstanceReloadPromise = this.moduleInstanceReloadPromise.then(async () => {
1291
- await this.getSettings();
1292
- this.watchSecurityRights();
1293
- await this.onModuleInstanceChange();
1498
+ }
1499
+ resetRightsState() {
1500
+ this.canRead = false;
1501
+ this.canEdit = false;
1502
+ this.canDelete = false;
1503
+ this.securityRightsLoaded = false;
1504
+ this.securityRoles = [];
1505
+ this.securitySettings = [];
1506
+ }
1507
+ updateRightsState(roles, securitySettings) {
1508
+ this.securityRoles = roles;
1509
+ this.securitySettings = securitySettings;
1510
+ this.canRead = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.readRight);
1511
+ this.canEdit = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.editRight);
1512
+ this.canDelete = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.deleteRight);
1513
+ this.securityRightsLoaded = true;
1514
+ this.onSecurityRightsChange();
1515
+ }
1516
+ hasSecurityRight(roles, securitySettings, code) {
1517
+ return securitySettings
1518
+ .find((security) => security.code === code)
1519
+ ?.roles?.some((role) => roles.includes(role)) ?? false;
1520
+ }
1521
+ getSecurity(controller = this.controller, id = this.id) {
1522
+ if (!controller || id == null) {
1523
+ return Promise.resolve([]);
1524
+ }
1525
+ return this.httpClient.request({
1526
+ path: `/api/${controller}/get-security`,
1527
+ method: 'GET',
1528
+ query: { id },
1529
+ secure: true,
1530
+ format: 'json'
1531
+ });
1532
+ }
1533
+ saveSecurity(request, controller = this.controller) {
1534
+ return this.httpClient.request({
1535
+ path: `/api/${controller}/put-security`,
1536
+ method: 'PUT',
1537
+ body: request,
1538
+ secure: true,
1539
+ type: ContentType.Json
1540
+ });
1541
+ }
1542
+ getModuleInstanceSettings(controller = this.controller, id = this.id) {
1543
+ return this.httpClient.request({
1544
+ path: `/api/${controller}/get-module-instance-settings`,
1545
+ method: 'GET',
1546
+ query: { id },
1547
+ secure: true,
1548
+ format: 'json'
1549
+ });
1550
+ }
1551
+ saveModuleInstanceSettings(request, controller = this.controller) {
1552
+ return this.httpClient.request({
1553
+ path: `/api/${controller}/put-module-instance-settings`,
1554
+ method: 'PUT',
1555
+ body: request,
1556
+ secure: true,
1557
+ type: ContentType.Json
1558
+ });
1559
+ }
1560
+ getMigrations(controller = this.controller) {
1561
+ return this.httpClient.request({
1562
+ path: `/api/${controller}/get-migrations`,
1563
+ method: 'GET',
1564
+ secure: true,
1565
+ format: 'json'
1566
+ });
1567
+ }
1568
+ applyModuleMigration(request, controller = this.controller) {
1569
+ return this.httpClient.request({
1570
+ path: `/api/${controller}/apply-migration`,
1571
+ method: 'POST',
1572
+ body: request,
1573
+ secure: true,
1574
+ type: ContentType.Json
1575
+ });
1576
+ }
1577
+ async reloadModuleInstance() {
1578
+ this.moduleInstanceReloadPromise = this.moduleInstanceReloadPromise.then(async () => {
1579
+ await this.getSettings();
1580
+ this.watchSecurityRights();
1581
+ await this.onModuleInstanceChange();
1582
+ });
1583
+ await this.moduleInstanceReloadPromise;
1584
+ }
1585
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseModuleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1586
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BaseModuleComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '', isInline: true }); }
1587
+ }
1588
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseModuleComponent, decorators: [{
1589
+ type: Component,
1590
+ args: [{ standalone: true, template: '' }]
1591
+ }], ctorParameters: () => [] });
1592
+
1593
+ /* eslint-disable */
1594
+ /* tslint:disable */
1595
+ // @ts-nocheck
1596
+ class SecurityApi extends HttpClient {
1597
+ constructor() {
1598
+ super(...arguments);
1599
+ this.getCurrentAuthSession = (params = {}) => this.request({
1600
+ path: `/api/security/get-current-auth-session`,
1601
+ method: "GET",
1602
+ secure: true,
1603
+ format: "json",
1604
+ ...params,
1605
+ });
1606
+ this.createAuthSession = (params = {}) => this.request({
1607
+ path: `/api/security/create-auth-session`,
1608
+ method: "POST",
1609
+ secure: true,
1610
+ ...params,
1611
+ });
1612
+ this.deleteAuthSession = (params = {}) => this.request({
1613
+ path: `/api/security/delete-auth-session`,
1614
+ method: "POST",
1615
+ secure: true,
1616
+ ...params,
1617
+ });
1618
+ this.getAuthCsrfToken = (params = {}) => this.request({
1619
+ path: `/api/security/get-auth-csrf-token`,
1620
+ method: "GET",
1621
+ secure: true,
1622
+ format: "json",
1623
+ ...params,
1624
+ });
1625
+ this.getKeycloakClientSettings = (params = {}) => this.request({
1626
+ path: `/api/security/get-keycloak-client-settings`,
1627
+ method: "GET",
1628
+ secure: true,
1629
+ format: "json",
1630
+ ...params,
1631
+ });
1632
+ this.getRealmRoles = (params = {}) => this.request({
1633
+ path: `/api/security/get-realm-roles`,
1634
+ method: "GET",
1635
+ secure: true,
1636
+ format: "json",
1637
+ ...params,
1294
1638
  });
1295
- await this.moduleInstanceReloadPromise;
1296
1639
  }
1297
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseModuleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1298
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: BaseModuleComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '', isInline: true }); }
1640
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1641
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi }); }
1299
1642
  }
1300
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseModuleComponent, decorators: [{
1301
- type: Component,
1302
- args: [{ standalone: true, template: '' }]
1303
- }], ctorParameters: () => [] });
1643
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi, decorators: [{
1644
+ type: Injectable
1645
+ }] });
1304
1646
 
1305
1647
  class SecurityComponent {
1306
1648
  constructor() {
1307
1649
  this.msgService = inject(MsgService);
1308
- this.dataService = inject(SecurityDataService);
1309
1650
  this.translateService = inject(TranslateService);
1651
+ this.httpClient = inject(HttpClient);
1652
+ this.securityApi = inject(SecurityApi);
1310
1653
  this.securityLoadToken = 0;
1311
1654
  this.securityData = [];
1312
1655
  this.roles = [];
@@ -1320,7 +1663,7 @@ class SecurityComponent {
1320
1663
  }
1321
1664
  }
1322
1665
  ngOnInit() {
1323
- this.dataService.getRealmRoles().then((result) => {
1666
+ this.securityApi.getRealmRoles().then((result) => {
1324
1667
  this.roles = result;
1325
1668
  }, (error) => this.msgService.error(error));
1326
1669
  }
@@ -1337,7 +1680,7 @@ class SecurityComponent {
1337
1680
  id: this.id,
1338
1681
  securities: this.securityData
1339
1682
  };
1340
- this.dataService.saveSecurity(this.controller, request).then((result) => {
1683
+ this.saveSecurity(this.controller, request).then((result) => {
1341
1684
  this.msgService.success(this.translateService.instant('securityComponent.savedSecurity'));
1342
1685
  }, (error) => this.msgService.error(error));
1343
1686
  }
@@ -1355,7 +1698,7 @@ class SecurityComponent {
1355
1698
  return;
1356
1699
  }
1357
1700
  try {
1358
- const result = await this.dataService.getSecurity(controller, id);
1701
+ const result = await this.getSecurity(controller, id);
1359
1702
  if (loadToken === this.securityLoadToken) {
1360
1703
  this.securityData = result;
1361
1704
  }
@@ -1366,6 +1709,24 @@ class SecurityComponent {
1366
1709
  }
1367
1710
  }
1368
1711
  }
1712
+ getSecurity(controller, id) {
1713
+ return this.httpClient.request({
1714
+ path: `/api/${controller}/get-security`,
1715
+ method: 'GET',
1716
+ query: { id },
1717
+ secure: true,
1718
+ format: 'json'
1719
+ });
1720
+ }
1721
+ saveSecurity(controller, request) {
1722
+ return this.httpClient.request({
1723
+ path: `/api/${controller}/put-security`,
1724
+ method: 'PUT',
1725
+ body: request,
1726
+ secure: true,
1727
+ type: ContentType.Json
1728
+ });
1729
+ }
1369
1730
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1370
1731
  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: `
1371
1732
  <div class="flex flex-col md:flex-row gap-8">
@@ -2037,6 +2398,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2037
2398
  }]
2038
2399
  }] });
2039
2400
 
2401
+ /* eslint-disable */
2402
+ /* tslint:disable */
2403
+ // @ts-nocheck
2404
+ class UserProfileApi extends HttpClient {
2405
+ constructor() {
2406
+ super(...arguments);
2407
+ this.getUserPhoto = (query, params = {}) => this.request({
2408
+ path: `/api/user-profile/get-user-photo`,
2409
+ method: "GET",
2410
+ query: query,
2411
+ secure: true,
2412
+ format: "blob",
2413
+ ...params,
2414
+ });
2415
+ this.postUserPhoto = (data, params = {}) => this.request({
2416
+ path: `/api/user-profile/post-user-photo`,
2417
+ method: "POST",
2418
+ body: data,
2419
+ secure: true,
2420
+ type: ContentType.FormData,
2421
+ ...params,
2422
+ });
2423
+ this.getSettings = (params = {}) => this.request({
2424
+ path: `/api/user-profile/get-settings`,
2425
+ method: "GET",
2426
+ secure: true,
2427
+ format: "json",
2428
+ ...params,
2429
+ });
2430
+ this.setSettings = (data, params = {}) => this.request({
2431
+ path: `/api/user-profile/set-settings`,
2432
+ method: "PUT",
2433
+ body: data,
2434
+ secure: true,
2435
+ type: ContentType.Json,
2436
+ ...params,
2437
+ });
2438
+ }
2439
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2440
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileApi }); }
2441
+ }
2442
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileApi, decorators: [{
2443
+ type: Injectable
2444
+ }] });
2445
+
2040
2446
  /**
2041
2447
  * UserService is responsible for retrieving and handling user-related data,
2042
2448
  * including the user's photo and short label for avatar display.
@@ -2044,7 +2450,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2044
2450
  class UserService {
2045
2451
  constructor() {
2046
2452
  this.securityService = inject(SecurityService);
2047
- this.baseDataService = inject(BaseDataService);
2453
+ this.userProfileApi = inject(UserProfileApi);
2048
2454
  this.requestedPhotoEmail = null;
2049
2455
  /**
2050
2456
  * Stores the user's photo as a data URL or binary blob, depending on how it's processed.
@@ -2069,11 +2475,18 @@ class UserService {
2069
2475
  const data = this.securityService.getCurrentUser();
2070
2476
  const givenNameInitial = data?.given_name?.trim()?.[0];
2071
2477
  const familyNameInitial = data?.family_name?.trim()?.[0];
2072
- return `${givenNameInitial ?? ''}${familyNameInitial ?? ''}`.toUpperCase();
2478
+ const displayNameInitials = this.getInitials(data?.displayName ?? data?.name ?? data?.userName ?? data?.preferred_username);
2479
+ return `${givenNameInitial ?? ''}${familyNameInitial ?? ''}`.toUpperCase() || displayNameInitials;
2073
2480
  }
2074
2481
  get userName() {
2075
2482
  const data = this.securityService.getCurrentUser();
2076
- return [data?.given_name, data?.family_name].filter(Boolean).join(' ');
2483
+ return [data?.given_name, data?.family_name].filter(Boolean).join(' ')
2484
+ || data?.displayName
2485
+ || data?.name
2486
+ || data?.userName
2487
+ || data?.preferred_username
2488
+ || data?.email
2489
+ || '';
2077
2490
  }
2078
2491
  /**
2079
2492
  * Initiates an HTTP request to fetch the user's photo based on their email,
@@ -2088,8 +2501,7 @@ class UserService {
2088
2501
  return;
2089
2502
  }
2090
2503
  this.requestedPhotoEmail = email;
2091
- const url = this.baseDataService.buildUrl(`api/user-profile/get-user-photo?email=${email}`);
2092
- this.baseDataService.getBlob(url).then((data) => {
2504
+ this.userProfileApi.getUserPhoto({ email }, { format: 'blob' }).then((data) => {
2093
2505
  this.createImageFromBlob(data);
2094
2506
  this.photoLoaded = true;
2095
2507
  }, (error) => {
@@ -2111,6 +2523,16 @@ class UserService {
2111
2523
  reader.readAsDataURL(image);
2112
2524
  }
2113
2525
  }
2526
+ getInitials(value) {
2527
+ return value
2528
+ ?.trim()
2529
+ .split(/\s+/)
2530
+ .filter(Boolean)
2531
+ .slice(0, 2)
2532
+ .map((part) => part[0])
2533
+ .join('')
2534
+ .toUpperCase() ?? '';
2535
+ }
2114
2536
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2115
2537
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserService }); }
2116
2538
  }
@@ -2177,28 +2599,395 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2177
2599
  type: Input
2178
2600
  }] } });
2179
2601
 
2180
- const LOGO_COMPONENT_TOKEN = new InjectionToken('LOGO_COMPONENT_TOKEN');
2181
- function provideLogoComponent(component) {
2182
- return {
2183
- provide: LOGO_COMPONENT_TOKEN,
2184
- useValue: component
2185
- };
2186
- }
2187
- class LogoService {
2188
- constructor() {
2189
- this.customLogoComponent = inject(LOGO_COMPONENT_TOKEN, { optional: true });
2190
- }
2191
- getLogoComponent() {
2192
- return this.customLogoComponent || LogoComponent;
2193
- }
2194
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2195
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, providedIn: 'root' }); }
2196
- }
2197
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, decorators: [{
2198
- type: Injectable,
2199
- args: [{ providedIn: 'root' }]
2200
- }] });
2201
-
2602
+ const LOGO_COMPONENT_TOKEN = new InjectionToken('LOGO_COMPONENT_TOKEN');
2603
+ function provideLogoComponent(component) {
2604
+ return {
2605
+ provide: LOGO_COMPONENT_TOKEN,
2606
+ useValue: component
2607
+ };
2608
+ }
2609
+ class LogoService {
2610
+ constructor() {
2611
+ this.customLogoComponent = inject(LOGO_COMPONENT_TOKEN, { optional: true });
2612
+ }
2613
+ getLogoComponent() {
2614
+ return this.customLogoComponent || LogoComponent;
2615
+ }
2616
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2617
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, providedIn: 'root' }); }
2618
+ }
2619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, decorators: [{
2620
+ type: Injectable,
2621
+ args: [{ providedIn: 'root' }]
2622
+ }] });
2623
+
2624
+ /* eslint-disable */
2625
+ /* tslint:disable */
2626
+ // @ts-nocheck
2627
+ class NotificationApi extends HttpClient {
2628
+ constructor() {
2629
+ super(...arguments);
2630
+ this.getNotificationByUser = (query, params = {}) => this.request({
2631
+ path: `/api/notification/get-notification-by-user`,
2632
+ method: "GET",
2633
+ query: query,
2634
+ secure: true,
2635
+ format: "json",
2636
+ ...params,
2637
+ });
2638
+ this.getNotificationCountByUser = (params = {}) => this.request({
2639
+ path: `/api/notification/get-notification-count-by-user`,
2640
+ method: "GET",
2641
+ secure: true,
2642
+ format: "json",
2643
+ ...params,
2644
+ });
2645
+ this.markNotificationAsRead = ({ id, ...query }, params = {}) => this.request({
2646
+ path: `/api/notification/mark-notification-as-read/${id}`,
2647
+ method: "POST",
2648
+ secure: true,
2649
+ ...params,
2650
+ });
2651
+ this.getNotificationById = (query, params = {}) => this.request({
2652
+ path: `/api/notification/get-notification-by-id`,
2653
+ method: "GET",
2654
+ query: query,
2655
+ secure: true,
2656
+ format: "json",
2657
+ ...params,
2658
+ });
2659
+ }
2660
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2661
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationApi }); }
2662
+ }
2663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationApi, decorators: [{
2664
+ type: Injectable
2665
+ }] });
2666
+
2667
+ class NotificationService {
2668
+ constructor() {
2669
+ this.securityService = inject(SecurityService);
2670
+ this.msgService = inject(MsgService);
2671
+ this.notificationApi = inject(NotificationApi);
2672
+ this.unreadNotificationCount = signal(undefined, ...(ngDevMode ? [{ debugName: "unreadNotificationCount" }] : []));
2673
+ this.connection = new signalR.HubConnectionBuilder()
2674
+ .withUrl('/hubs/notification', {
2675
+ withCredentials: true,
2676
+ skipNegotiation: true,
2677
+ transport: signalR.HttpTransportType.WebSockets
2678
+ })
2679
+ .configureLogging(signalR.LogLevel.Error)
2680
+ .build();
2681
+ this.connection.on('ReceiveNotification', (notification) => {
2682
+ const opt = {
2683
+ severity: notification.severity,
2684
+ summary: notification.subject,
2685
+ detail: notification.message,
2686
+ life: 0
2687
+ };
2688
+ this.msgService.add(opt);
2689
+ this.unreadNotificationCount.update((count) => (count ?? 0) + 1);
2690
+ });
2691
+ this.securityService.isAuthenticated().subscribe((authenticated) => {
2692
+ if (!authenticated) {
2693
+ this.unreadNotificationCount.set(undefined);
2694
+ if (this.connection.state !== signalR.HubConnectionState.Disconnected) {
2695
+ this.connection.stop();
2696
+ }
2697
+ return;
2698
+ }
2699
+ this.loadUnreadNotificationCount();
2700
+ if (this.connection.state === signalR.HubConnectionState.Disconnected) {
2701
+ this.connection.start().catch((error) => console.error('Failed to start notification connection', error));
2702
+ return;
2703
+ }
2704
+ this.connection.stop().then(() => {
2705
+ this.connection.start().catch((error) => console.error('Failed to restart notification connection', error));
2706
+ });
2707
+ });
2708
+ }
2709
+ loadUnreadNotificationCount() {
2710
+ this.notificationApi
2711
+ .getNotificationCountByUser()
2712
+ .then((response) => this.unreadNotificationCount.set(response.count ?? 0))
2713
+ .catch((error) => console.error('Failed to load notification count', error));
2714
+ }
2715
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2716
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, providedIn: 'root' }); }
2717
+ }
2718
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, decorators: [{
2719
+ type: Injectable,
2720
+ args: [{ providedIn: 'root' }]
2721
+ }], ctorParameters: () => [] });
2722
+
2723
+ class UserNotificationsComponent {
2724
+ constructor() {
2725
+ this.notifications = [];
2726
+ this.totalCount = 0;
2727
+ this.skip = 0;
2728
+ this.take = 5;
2729
+ this.loading = false;
2730
+ this.notificationApi = inject(NotificationApi);
2731
+ this.notificationService = inject(NotificationService);
2732
+ this.msgService = inject(MsgService);
2733
+ this.translateService = inject(TranslateService);
2734
+ this.unreadNotificationCount = computed(() => this.notificationService.unreadNotificationCount() ?? 0, ...(ngDevMode ? [{ debugName: "unreadNotificationCount" }] : []));
2735
+ this.unreadNotificationBadge = computed(() => {
2736
+ const count = this.unreadNotificationCount();
2737
+ return count > 99 ? '99+' : count.toString();
2738
+ }, ...(ngDevMode ? [{ debugName: "unreadNotificationBadge" }] : []));
2739
+ }
2740
+ async toggle(event) {
2741
+ this.popover?.toggle(event);
2742
+ await this.loadNotifications();
2743
+ }
2744
+ async loadNotifications() {
2745
+ this.loading = true;
2746
+ try {
2747
+ const response = await this.notificationApi.getNotificationByUser({
2748
+ skip: this.skip,
2749
+ take: this.take,
2750
+ unreadOnly: true
2751
+ });
2752
+ this.notifications = response.notifications ?? [];
2753
+ this.totalCount = response.totalCount ?? 0;
2754
+ }
2755
+ catch (error) {
2756
+ this.msgService.error(error);
2757
+ }
2758
+ finally {
2759
+ this.loading = false;
2760
+ }
2761
+ }
2762
+ async onPageChange(event) {
2763
+ this.skip = event.first ?? 0;
2764
+ this.take = event.rows ?? this.take;
2765
+ await this.loadNotifications();
2766
+ }
2767
+ async markAsRead(notification) {
2768
+ if (!notification.notificationUserId) {
2769
+ return;
2770
+ }
2771
+ this.readingNotificationId = notification.notificationUserId;
2772
+ try {
2773
+ await this.notificationApi.markNotificationAsRead({ id: notification.notificationUserId });
2774
+ this.msgService.success(this.translateService.instant('userNotifications.markedAsRead'));
2775
+ this.notificationService.loadUnreadNotificationCount();
2776
+ if (this.notifications.length === 1 && this.skip > 0) {
2777
+ this.skip = Math.max(this.skip - this.take, 0);
2778
+ }
2779
+ await this.loadNotifications();
2780
+ }
2781
+ catch (error) {
2782
+ this.msgService.error(error);
2783
+ }
2784
+ finally {
2785
+ this.readingNotificationId = undefined;
2786
+ }
2787
+ }
2788
+ getImportanceSeverity(importance) {
2789
+ switch (importance) {
2790
+ case 'Critical':
2791
+ case 'High':
2792
+ return 'danger';
2793
+ case 'Medium':
2794
+ return 'warn';
2795
+ case 'Low':
2796
+ return 'info';
2797
+ default:
2798
+ return 'secondary';
2799
+ }
2800
+ }
2801
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserNotificationsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2802
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: UserNotificationsComponent, isStandalone: true, selector: "app-user-notifications", viewQueries: [{ propertyName: "popover", first: true, predicate: ["popover"], descendants: true }], ngImport: i0, template: `
2803
+ <button
2804
+ class="layout-topbar-action relative"
2805
+ id="oip-app-topbar-notification-button"
2806
+ type="button"
2807
+ (click)="toggle($event)"
2808
+ [attr.aria-label]="'Notifications: ' + unreadNotificationCount()">
2809
+ <i class="pi pi-bell"></i>
2810
+ @if (unreadNotificationCount() > 0) {
2811
+ <p-badge
2812
+ class="absolute -top-1 -right-1"
2813
+ severity="danger"
2814
+ [badgeSize]="'small'"
2815
+ [value]="unreadNotificationBadge()" />
2816
+ }
2817
+ </button>
2818
+
2819
+ <p-popover #popover styleClass="w-[min(92vw,34rem)]">
2820
+ <div class="flex items-center justify-between gap-3 mb-4">
2821
+ <div class="font-semibold text-lg">
2822
+ {{ 'userNotifications.title' | translate }}
2823
+ </div>
2824
+ <p-button
2825
+ icon="pi pi-refresh"
2826
+ rounded="true"
2827
+ severity="secondary"
2828
+ text="true"
2829
+ tooltipPosition="bottom"
2830
+ [disabled]="loading"
2831
+ [pTooltip]="'userNotifications.refresh' | translate"
2832
+ (onClick)="loadNotifications()"></p-button>
2833
+ </div>
2834
+
2835
+ @if (loading && notifications.length === 0) {
2836
+ <div class="flex justify-center py-8">
2837
+ <p-progressSpinner style="w-8 h-8"></p-progressSpinner>
2838
+ </div>
2839
+ } @else if (notifications.length === 0) {
2840
+ <div class="text-center py-8 text-surface-500">
2841
+ {{ 'userNotifications.empty' | translate }}
2842
+ </div>
2843
+ } @else {
2844
+ <div class="flex flex-col gap-3 max-h-[26rem] overflow-y-auto pr-1">
2845
+ @for (notification of notifications; track notification.notificationUserId) {
2846
+ <div class="border border-surface-200 dark:border-surface-700 rounded-md p-3">
2847
+ <div class="flex items-start justify-between gap-3">
2848
+ <div class="min-w-0">
2849
+ <div class="font-medium leading-snug break-words">
2850
+ {{ notification.subject }}
2851
+ </div>
2852
+ <div class="text-xs text-surface-500 mt-1">
2853
+ {{ notification.createdAt | date: 'dd.MM.yyyy HH:mm' }}
2854
+ </div>
2855
+ </div>
2856
+ @if (notification.importance) {
2857
+ <p-tag
2858
+ class="shrink-0"
2859
+ [severity]="getImportanceSeverity(notification.importance)"
2860
+ [value]="notification.importance"></p-tag>
2861
+ }
2862
+ </div>
2863
+
2864
+ <div class="text-sm text-surface-700 dark:text-surface-200 mt-3 whitespace-pre-line break-words">
2865
+ {{ notification.message }}
2866
+ </div>
2867
+
2868
+ <div class="flex justify-end mt-3">
2869
+ <p-button
2870
+ icon="pi pi-check"
2871
+ size="small"
2872
+ [label]="'userNotifications.markAsRead' | translate"
2873
+ [loading]="readingNotificationId === notification.notificationUserId"
2874
+ (onClick)="markAsRead(notification)"></p-button>
2875
+ </div>
2876
+ </div>
2877
+ }
2878
+ </div>
2879
+
2880
+ <p-paginator
2881
+ styleClass="mt-3"
2882
+ [first]="skip"
2883
+ [rows]="take"
2884
+ [totalRecords]="totalCount"
2885
+ [rowsPerPageOptions]="[5, 10, 20]"
2886
+ (onPageChange)="onPageChange($event)"></p-paginator>
2887
+ }
2888
+ </p-popover>
2889
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i1$3.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { 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: PaginatorModule }, { kind: "component", type: i3$1.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first", "appendTo"], outputs: ["onPageChange"] }, { kind: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { 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: i2$1.DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
2890
+ }
2891
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserNotificationsComponent, decorators: [{
2892
+ type: Component,
2893
+ args: [{
2894
+ selector: 'app-user-notifications',
2895
+ standalone: true,
2896
+ imports: [CommonModule, BadgeModule, ButtonModule, PaginatorModule, Popover, ProgressSpinnerModule, Tag, Tooltip, TranslatePipe],
2897
+ template: `
2898
+ <button
2899
+ class="layout-topbar-action relative"
2900
+ id="oip-app-topbar-notification-button"
2901
+ type="button"
2902
+ (click)="toggle($event)"
2903
+ [attr.aria-label]="'Notifications: ' + unreadNotificationCount()">
2904
+ <i class="pi pi-bell"></i>
2905
+ @if (unreadNotificationCount() > 0) {
2906
+ <p-badge
2907
+ class="absolute -top-1 -right-1"
2908
+ severity="danger"
2909
+ [badgeSize]="'small'"
2910
+ [value]="unreadNotificationBadge()" />
2911
+ }
2912
+ </button>
2913
+
2914
+ <p-popover #popover styleClass="w-[min(92vw,34rem)]">
2915
+ <div class="flex items-center justify-between gap-3 mb-4">
2916
+ <div class="font-semibold text-lg">
2917
+ {{ 'userNotifications.title' | translate }}
2918
+ </div>
2919
+ <p-button
2920
+ icon="pi pi-refresh"
2921
+ rounded="true"
2922
+ severity="secondary"
2923
+ text="true"
2924
+ tooltipPosition="bottom"
2925
+ [disabled]="loading"
2926
+ [pTooltip]="'userNotifications.refresh' | translate"
2927
+ (onClick)="loadNotifications()"></p-button>
2928
+ </div>
2929
+
2930
+ @if (loading && notifications.length === 0) {
2931
+ <div class="flex justify-center py-8">
2932
+ <p-progressSpinner style="w-8 h-8"></p-progressSpinner>
2933
+ </div>
2934
+ } @else if (notifications.length === 0) {
2935
+ <div class="text-center py-8 text-surface-500">
2936
+ {{ 'userNotifications.empty' | translate }}
2937
+ </div>
2938
+ } @else {
2939
+ <div class="flex flex-col gap-3 max-h-[26rem] overflow-y-auto pr-1">
2940
+ @for (notification of notifications; track notification.notificationUserId) {
2941
+ <div class="border border-surface-200 dark:border-surface-700 rounded-md p-3">
2942
+ <div class="flex items-start justify-between gap-3">
2943
+ <div class="min-w-0">
2944
+ <div class="font-medium leading-snug break-words">
2945
+ {{ notification.subject }}
2946
+ </div>
2947
+ <div class="text-xs text-surface-500 mt-1">
2948
+ {{ notification.createdAt | date: 'dd.MM.yyyy HH:mm' }}
2949
+ </div>
2950
+ </div>
2951
+ @if (notification.importance) {
2952
+ <p-tag
2953
+ class="shrink-0"
2954
+ [severity]="getImportanceSeverity(notification.importance)"
2955
+ [value]="notification.importance"></p-tag>
2956
+ }
2957
+ </div>
2958
+
2959
+ <div class="text-sm text-surface-700 dark:text-surface-200 mt-3 whitespace-pre-line break-words">
2960
+ {{ notification.message }}
2961
+ </div>
2962
+
2963
+ <div class="flex justify-end mt-3">
2964
+ <p-button
2965
+ icon="pi pi-check"
2966
+ size="small"
2967
+ [label]="'userNotifications.markAsRead' | translate"
2968
+ [loading]="readingNotificationId === notification.notificationUserId"
2969
+ (onClick)="markAsRead(notification)"></p-button>
2970
+ </div>
2971
+ </div>
2972
+ }
2973
+ </div>
2974
+
2975
+ <p-paginator
2976
+ styleClass="mt-3"
2977
+ [first]="skip"
2978
+ [rows]="take"
2979
+ [totalRecords]="totalCount"
2980
+ [rowsPerPageOptions]="[5, 10, 20]"
2981
+ (onPageChange)="onPageChange($event)"></p-paginator>
2982
+ }
2983
+ </p-popover>
2984
+ `
2985
+ }]
2986
+ }], propDecorators: { popover: [{
2987
+ type: ViewChild,
2988
+ args: ['popover']
2989
+ }] } });
2990
+
2202
2991
  class AppTopbar {
2203
2992
  constructor() {
2204
2993
  this.securityService = inject(SecurityService);
@@ -2206,6 +2995,8 @@ class AppTopbar {
2206
2995
  this.userService = inject(UserService);
2207
2996
  this.layoutService = inject(LayoutService);
2208
2997
  this.logoService = inject(LogoService);
2998
+ this.confirmationService = inject(ConfirmationService);
2999
+ this.translateService = inject(TranslateService);
2209
3000
  }
2210
3001
  toggleDarkMode() {
2211
3002
  this.layoutService.layoutConfig.update((state) => ({
@@ -2215,11 +3006,32 @@ class AppTopbar {
2215
3006
  }
2216
3007
  logoutKeyDown($event) {
2217
3008
  if ($event.key === 'Enter') {
2218
- this.securityService.logout();
3009
+ $event.preventDefault();
3010
+ this.confirmLogout();
2219
3011
  }
2220
3012
  }
3013
+ confirmLogout() {
3014
+ this.confirmationService.confirm({
3015
+ header: this.translateService.instant('topbar.logoutConfirmHeader'),
3016
+ message: this.translateService.instant('topbar.logoutConfirmMessage'),
3017
+ icon: 'pi pi-sign-out',
3018
+ rejectButtonProps: {
3019
+ label: this.translateService.instant('topbar.logoutConfirmCancel'),
3020
+ severity: 'secondary',
3021
+ outlined: true
3022
+ },
3023
+ acceptButtonProps: {
3024
+ label: this.translateService.instant('topbar.logoutConfirmAccept'),
3025
+ severity: 'danger'
3026
+ },
3027
+ accept: () => {
3028
+ this.securityService.logout();
3029
+ }
3030
+ });
3031
+ }
2221
3032
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppTopbar, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2222
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AppTopbar, isStandalone: true, selector: "app-topbar", ngImport: i0, template: ` <div class="layout-topbar">
3033
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AppTopbar, isStandalone: true, selector: "app-topbar", providers: [ConfirmationService], ngImport: i0, template: ` <div class="layout-topbar">
3034
+ <p-confirmDialog appendTo="body" />
2223
3035
  <div class="layout-topbar-logo-container">
2224
3036
  <button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
2225
3037
  <i class="pi pi-bars"></i>
@@ -2245,6 +3057,7 @@ class AppTopbar {
2245
3057
  }
2246
3058
  <div class="layout-topbar-actions">
2247
3059
  <div class="layout-config-menu">
3060
+ <app-user-notifications />
2248
3061
  <p-button
2249
3062
  class="layout-topbar-action"
2250
3063
  id="oip-app-topbar-theme-button"
@@ -2295,7 +3108,7 @@ class AppTopbar {
2295
3108
  class="layout-topbar-action"
2296
3109
  id="oip-app-topbar-logout-button"
2297
3110
  type="button"
2298
- (click)="securityService.logout()"
3111
+ (click)="confirmLogout()"
2299
3112
  (keydown)="logoutKeyDown($event)">
2300
3113
  <i class="pi pi-sign-out"></i>
2301
3114
  <span>{{ 'topbar.logout' | translate }}</span>
@@ -2314,7 +3127,7 @@ class AppTopbar {
2314
3127
  </div>
2315
3128
  </div>
2316
3129
  </div>
2317
- </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i3$1.StyleClass, selector: "[pStyleClass]", inputs: ["pStyleClass", "enterFromClass", "enterActiveClass", "enterToClass", "leaveFromClass", "leaveActiveClass", "leaveToClass", "hideOnOutsideClick", "toggleClass", "hideOnEscape", "hideOnResize", "resizeSelector"] }, { kind: "component", type: AppConfiguratorComponent, selector: "app-configurator" }, { kind: "component", type: Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: TabList, selector: "p-tablist" }, { kind: "component", type: Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "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" }] }); }
3130
+ </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i3$2.StyleClass, selector: "[pStyleClass]", inputs: ["pStyleClass", "enterFromClass", "enterActiveClass", "enterToClass", "leaveFromClass", "leaveActiveClass", "leaveToClass", "hideOnOutsideClick", "toggleClass", "hideOnEscape", "hideOnResize", "resizeSelector"] }, { kind: "component", type: AppConfiguratorComponent, selector: "app-configurator" }, { kind: "component", type: Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: TabList, selector: "p-tablist" }, { kind: "component", type: Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "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: "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: UserNotificationsComponent, selector: "app-user-notifications" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
2318
3131
  }
2319
3132
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppTopbar, decorators: [{
2320
3133
  type: Component,
@@ -2331,9 +3144,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2331
3144
  Tab,
2332
3145
  AvatarModule,
2333
3146
  ButtonModule,
3147
+ ConfirmDialog,
3148
+ UserNotificationsComponent,
2334
3149
  TranslatePipe
2335
3150
  ],
2336
3151
  template: ` <div class="layout-topbar">
3152
+ <p-confirmDialog appendTo="body" />
2337
3153
  <div class="layout-topbar-logo-container">
2338
3154
  <button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
2339
3155
  <i class="pi pi-bars"></i>
@@ -2359,6 +3175,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2359
3175
  }
2360
3176
  <div class="layout-topbar-actions">
2361
3177
  <div class="layout-config-menu">
3178
+ <app-user-notifications />
2362
3179
  <p-button
2363
3180
  class="layout-topbar-action"
2364
3181
  id="oip-app-topbar-theme-button"
@@ -2409,7 +3226,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2409
3226
  class="layout-topbar-action"
2410
3227
  id="oip-app-topbar-logout-button"
2411
3228
  type="button"
2412
- (click)="securityService.logout()"
3229
+ (click)="confirmLogout()"
2413
3230
  (keydown)="logoutKeyDown($event)">
2414
3231
  <i class="pi pi-sign-out"></i>
2415
3232
  <span>{{ 'topbar.logout' | translate }}</span>
@@ -2428,7 +3245,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2428
3245
  </div>
2429
3246
  </div>
2430
3247
  </div>
2431
- </div>`
3248
+ </div>`,
3249
+ providers: [ConfirmationService]
2432
3250
  }]
2433
3251
  }] });
2434
3252
 
@@ -2471,190 +3289,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2471
3289
  }]
2472
3290
  }] });
2473
3291
 
2474
- /* eslint-disable */
2475
- /* tslint:disable */
2476
- // @ts-nocheck
2477
- var ContentType;
2478
- (function (ContentType) {
2479
- ContentType["Json"] = "application/json";
2480
- ContentType["JsonApi"] = "application/vnd.api+json";
2481
- ContentType["FormData"] = "multipart/form-data";
2482
- ContentType["UrlEncoded"] = "application/x-www-form-urlencoded";
2483
- ContentType["Text"] = "text/plain";
2484
- })(ContentType || (ContentType = {}));
2485
- class HttpClient {
2486
- constructor() {
2487
- this.securityService = inject(SecurityService);
2488
- this.layoutService = inject(LayoutService);
2489
- this.baseUrl = "";
2490
- this.securityData = null;
2491
- this.securityWorker = (securityData) => ({
2492
- headers: {
2493
- "Accept-language": this.layoutService.language()
2494
- ? this.layoutService.language()
2495
- : "en",
2496
- "X-Timezone": this.layoutService.timeZone(),
2497
- Authorization: `Bearer ${securityData}`,
2498
- },
2499
- });
2500
- this.abortControllers = new Map();
2501
- this.customFetch = (...fetchParams) => fetch(...fetchParams);
2502
- this.baseApiParams = {
2503
- credentials: "same-origin",
2504
- headers: {},
2505
- redirect: "follow",
2506
- referrerPolicy: "no-referrer",
2507
- };
2508
- this.setSecurityData = (data) => {
2509
- this.securityData = data;
2510
- };
2511
- this.contentFormatters = {
2512
- [ContentType.Json]: (input) => input !== null && (typeof input === "object" || typeof input === "string")
2513
- ? JSON.stringify(input)
2514
- : input,
2515
- [ContentType.JsonApi]: (input) => input !== null && (typeof input === "object" || typeof input === "string")
2516
- ? JSON.stringify(input)
2517
- : input,
2518
- [ContentType.Text]: (input) => input !== null && typeof input !== "string"
2519
- ? JSON.stringify(input)
2520
- : input,
2521
- [ContentType.FormData]: (input) => {
2522
- if (input instanceof FormData) {
2523
- return input;
2524
- }
2525
- return Object.keys(input || {}).reduce((formData, key) => {
2526
- const property = input[key];
2527
- formData.append(key, property instanceof Blob
2528
- ? property
2529
- : typeof property === "object" && property !== null
2530
- ? JSON.stringify(property)
2531
- : `${property}`);
2532
- return formData;
2533
- }, new FormData());
2534
- },
2535
- [ContentType.UrlEncoded]: (input) => this.toQueryString(input),
2536
- };
2537
- this.createAbortSignal = (cancelToken) => {
2538
- if (this.abortControllers.has(cancelToken)) {
2539
- const abortController = this.abortControllers.get(cancelToken);
2540
- if (abortController) {
2541
- return abortController.signal;
2542
- }
2543
- return void 0;
2544
- }
2545
- const abortController = new AbortController();
2546
- this.abortControllers.set(cancelToken, abortController);
2547
- return abortController.signal;
2548
- };
2549
- this.abortRequest = (cancelToken) => {
2550
- const abortController = this.abortControllers.get(cancelToken);
2551
- if (abortController) {
2552
- abortController.abort();
2553
- this.abortControllers.delete(cancelToken);
2554
- }
2555
- };
2556
- this.request = async ({ body, secure, path, type, query, format, baseUrl, cancelToken, ...params }) => {
2557
- const secureParams = ((typeof secure === "boolean" ? secure : this.baseApiParams.secure) &&
2558
- this.securityWorker &&
2559
- (await this.securityWorker(this.securityData))) ||
2560
- {};
2561
- const requestParams = this.mergeRequestParams(params, secureParams);
2562
- const queryString = query && this.toQueryString(query);
2563
- const payloadFormatter = this.contentFormatters[type || ContentType.Json];
2564
- let responseFormat = format || requestParams.format;
2565
- return this.customFetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, {
2566
- ...requestParams,
2567
- headers: {
2568
- ...(requestParams.headers || {}),
2569
- ...(type && type !== ContentType.FormData
2570
- ? { "Content-Type": type }
2571
- : {}),
2572
- },
2573
- signal: (cancelToken
2574
- ? this.createAbortSignal(cancelToken)
2575
- : requestParams.signal) || null,
2576
- body: typeof body === "undefined" || body === null
2577
- ? null
2578
- : payloadFormatter(body),
2579
- }).then(async (response) => {
2580
- const r = response;
2581
- r.data = null;
2582
- r.error = null;
2583
- if (typeof E !== undefined && responseFormat === undefined)
2584
- responseFormat = "json";
2585
- const responseToParse = responseFormat ? response.clone() : response;
2586
- const data = !responseFormat
2587
- ? r
2588
- : await responseToParse[responseFormat]()
2589
- .then((data) => {
2590
- if (r.ok) {
2591
- r.data = data;
2592
- }
2593
- else {
2594
- r.error = data;
2595
- }
2596
- return r;
2597
- })
2598
- .catch((e) => {
2599
- r.error = e;
2600
- return r;
2601
- });
2602
- if (cancelToken) {
2603
- this.abortControllers.delete(cancelToken);
2604
- }
2605
- if (!response.ok)
2606
- throw data;
2607
- return data.data;
2608
- });
2609
- };
2610
- this.securityService.getAccessToken().subscribe((token) => {
2611
- this.securityData = token;
2612
- });
2613
- }
2614
- encodeQueryParam(key, value) {
2615
- const encodedKey = encodeURIComponent(key);
2616
- return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
2617
- }
2618
- addQueryParam(query, key) {
2619
- return this.encodeQueryParam(key, query[key]);
2620
- }
2621
- addArrayQueryParam(query, key) {
2622
- const value = query[key];
2623
- return value.map((v) => this.encodeQueryParam(key, v)).join("&");
2624
- }
2625
- toQueryString(rawQuery) {
2626
- const query = rawQuery || {};
2627
- const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
2628
- return keys
2629
- .map((key) => Array.isArray(query[key])
2630
- ? this.addArrayQueryParam(query, key)
2631
- : this.addQueryParam(query, key))
2632
- .join("&");
2633
- }
2634
- addQueryParams(rawQuery) {
2635
- const queryString = this.toQueryString(rawQuery);
2636
- return queryString ? `?${queryString}` : "";
2637
- }
2638
- mergeRequestParams(params1, params2) {
2639
- return {
2640
- ...this.baseApiParams,
2641
- ...params1,
2642
- ...(params2 || {}),
2643
- headers: {
2644
- ...(this.baseApiParams.headers || {}),
2645
- ...(params1.headers || {}),
2646
- ...((params2 && params2.headers) || {}),
2647
- },
2648
- };
2649
- }
2650
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HttpClient, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2651
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HttpClient, providedIn: "root" }); }
2652
- }
2653
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: HttpClient, decorators: [{
2654
- type: Injectable,
2655
- args: [{ providedIn: "root" }]
2656
- }], ctorParameters: () => [] });
2657
-
2658
3292
  /* eslint-disable */
2659
3293
  /* tslint:disable */
2660
3294
  // @ts-nocheck
@@ -2720,9 +3354,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2720
3354
  type: Injectable
2721
3355
  }] });
2722
3356
 
2723
- class MenuService extends BaseDataService {
3357
+ class MenuService {
2724
3358
  constructor() {
2725
- super(...arguments);
2726
3359
  this.menuSource = new Subject();
2727
3360
  this.resetSource = new Subject();
2728
3361
  this.titleService = inject(AppTitleService);
@@ -2742,7 +3375,9 @@ class MenuService extends BaseDataService {
2742
3375
  */
2743
3376
  onMenuStateChange(event) {
2744
3377
  this.menuSource.next(event);
2745
- this.titleService.setTitle(event.item.label);
3378
+ if (!event.item.items?.length) {
3379
+ this.titleService.setTitle(event.item.label);
3380
+ }
2746
3381
  }
2747
3382
  reset() {
2748
3383
  this.resetSource.next(true);
@@ -2765,7 +3400,7 @@ class MenuService extends BaseDataService {
2765
3400
  editModuleInstance(item) {
2766
3401
  return this.menuDataService.editModuleInstance(item);
2767
3402
  }
2768
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
3403
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2769
3404
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService }); }
2770
3405
  }
2771
3406
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService, decorators: [{
@@ -2782,17 +3417,15 @@ class MenuItemComponent {
2782
3417
  this.confirmationService = inject(ConfirmationService);
2783
3418
  this.msgService = inject(MsgService);
2784
3419
  this.menuDataService = inject(MenuApi);
3420
+ this.securityService = inject(SecurityService);
2785
3421
  this.active = false;
2786
3422
  this.subscriptions = [];
2787
3423
  this.localization = {};
2788
3424
  this.key = '';
2789
3425
  this.subscriptions.push(this.menuService.menuSource$.subscribe((value) => {
2790
3426
  Promise.resolve(null).then(() => {
2791
- if (value.routeEvent) {
2792
- this.active = value.key === this.key || value.key.startsWith(this.key + '-');
2793
- }
2794
- else if (value.key !== this.key && !value.key.startsWith(this.key + '-')) {
2795
- this.active = false;
3427
+ if (value.routeEvent && (value.key === this.key || value.key.startsWith(this.key + '-'))) {
3428
+ this.active = true;
2796
3429
  }
2797
3430
  });
2798
3431
  }));
@@ -2845,8 +3478,8 @@ class MenuItemComponent {
2845
3478
  }
2846
3479
  this.menuService.onMenuStateChange({ key: this.key, item: this.item });
2847
3480
  }
2848
- get submenuAnimation() {
2849
- return this.root || this.active ? 'expanded' : 'collapsed';
3481
+ get isSubmenuExpanded() {
3482
+ return this.root || this.active;
2850
3483
  }
2851
3484
  get activeClass() {
2852
3485
  return this.active && !this.root;
@@ -2858,6 +3491,11 @@ class MenuItemComponent {
2858
3491
  this.menuItemCreateDialogComponent.showDialog();
2859
3492
  }
2860
3493
  onContextMenu($event, item) {
3494
+ if (!this.securityService.isAdmin()) {
3495
+ return;
3496
+ }
3497
+ $event.stopPropagation();
3498
+ $event.preventDefault();
2861
3499
  this.menuService.contextMenuItem = item;
2862
3500
  this.contextMenu.model = [
2863
3501
  {
@@ -2977,19 +3615,32 @@ class MenuItemComponent {
2977
3615
  hasVisiblePrev(currentItem) {
2978
3616
  const items = this.getItems(currentItem);
2979
3617
  const currentIndex = items.findIndex((item) => item.moduleInstanceId == currentItem.moduleInstanceId);
2980
- return currentIndex > 0;
3618
+ return this.findPrevVisibleItem(items, currentIndex) !== -1;
2981
3619
  }
2982
3620
  getItems(currentItem) {
2983
- return !currentItem.parentId
2984
- ? this.menuService.menu
2985
- : this.menuService.menu.find((m) => m.moduleInstanceId == currentItem.parentId).items;
3621
+ if (!currentItem.parentId) {
3622
+ return this.menuService.menu;
3623
+ }
3624
+ return this.findItemByModuleInstanceId(this.menuService.menu, currentItem.parentId)?.items ?? [];
3625
+ }
3626
+ findItemByModuleInstanceId(items, moduleInstanceId) {
3627
+ for (const item of items) {
3628
+ if (item.moduleInstanceId == moduleInstanceId) {
3629
+ return item;
3630
+ }
3631
+ const foundItem = this.findItemByModuleInstanceId(item.items ?? [], moduleInstanceId);
3632
+ if (foundItem) {
3633
+ return foundItem;
3634
+ }
3635
+ }
3636
+ return null;
2986
3637
  }
2987
3638
  hasVisibleNext(currentItem) {
2988
3639
  const items = this.getItems(currentItem);
2989
3640
  const currentIndex = items.findIndex((item) => item.moduleInstanceId == currentItem.moduleInstanceId);
2990
- return currentIndex < items.length - 1;
3641
+ return this.findNextVisibleIndex(items, currentIndex) !== -1;
2991
3642
  }
2992
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$3.Router }, { token: MenuService }], target: i0.ɵɵFactoryTarget.Component }); }
3643
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$4.Router }, { token: MenuService }], target: i0.ɵɵFactoryTarget.Component }); }
2993
3644
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: MenuItemComponent, isStandalone: true, selector: "[app-menuitem]", inputs: { item: "item", index: "index", root: "root", parentKey: "parentKey", menuItemCreateDialogComponent: "menuItemCreateDialogComponent", menuItemEditDialogComponent: "menuItemEditDialogComponent", contextMenu: "contextMenu" }, host: { properties: { "class.layout-root-menuitem": "this.root", "class.active-menuitem": "this.activeClass" } }, providers: [ConfirmationService], ngImport: i0, template: `
2994
3645
  <ng-container>
2995
3646
  <p-confirm-dialog />
@@ -3005,7 +3656,8 @@ class MenuItemComponent {
3005
3656
  [attr.href]="item.url"
3006
3657
  [attr.target]="item.target"
3007
3658
  [ngClass]="item.class"
3008
- (click)="itemClick($event)">
3659
+ (click)="itemClick($event)"
3660
+ (contextmenu)="onContextMenu($event, item)">
3009
3661
  <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
3010
3662
  <span class="layout-menuitem-text">{{ item.label }}</span>
3011
3663
  @if (item.items) {
@@ -3047,7 +3699,7 @@ class MenuItemComponent {
3047
3699
  }
3048
3700
 
3049
3701
  @if (item.items && item.visible !== false) {
3050
- <ul [@children]="submenuAnimation" (contextmenu)="onContextMenu($event, item)">
3702
+ <ul class="layout-submenu" [class.layout-submenu-expanded]="isSubmenuExpanded">
3051
3703
  @for (child of item.items; track child; let i = $index) {
3052
3704
  <li
3053
3705
  app-menuitem
@@ -3062,17 +3714,7 @@ class MenuItemComponent {
3062
3714
  </ul>
3063
3715
  }
3064
3716
  </ng-container>
3065
- `, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i3$2.Ripple, selector: "[pRipple]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: ContextMenuModule }, { 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"] }], animations: [
3066
- trigger('children', [
3067
- state('collapsed', style({
3068
- height: '0'
3069
- })),
3070
- state('expanded', style({
3071
- height: '*'
3072
- })),
3073
- transition('collapsed <=> expanded', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
3074
- ])
3075
- ] }); }
3717
+ `, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i3$3.Ripple, selector: "[pRipple]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: ContextMenuModule }, { 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"] }] }); }
3076
3718
  }
3077
3719
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemComponent, decorators: [{
3078
3720
  type: Component,
@@ -3094,7 +3736,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3094
3736
  [attr.href]="item.url"
3095
3737
  [attr.target]="item.target"
3096
3738
  [ngClass]="item.class"
3097
- (click)="itemClick($event)">
3739
+ (click)="itemClick($event)"
3740
+ (contextmenu)="onContextMenu($event, item)">
3098
3741
  <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
3099
3742
  <span class="layout-menuitem-text">{{ item.label }}</span>
3100
3743
  @if (item.items) {
@@ -3136,7 +3779,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3136
3779
  }
3137
3780
 
3138
3781
  @if (item.items && item.visible !== false) {
3139
- <ul [@children]="submenuAnimation" (contextmenu)="onContextMenu($event, item)">
3782
+ <ul class="layout-submenu" [class.layout-submenu-expanded]="isSubmenuExpanded">
3140
3783
  @for (child of item.items; track child; let i = $index) {
3141
3784
  <li
3142
3785
  app-menuitem
@@ -3152,21 +3795,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3152
3795
  }
3153
3796
  </ng-container>
3154
3797
  `,
3155
- animations: [
3156
- trigger('children', [
3157
- state('collapsed', style({
3158
- height: '0'
3159
- })),
3160
- state('expanded', style({
3161
- height: '*'
3162
- })),
3163
- transition('collapsed <=> expanded', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
3164
- ])
3165
- ],
3166
3798
  imports: [RippleModule, NgClass, RouterLinkActive, RouterLink, ContextMenuModule, ConfirmDialog],
3167
3799
  providers: [ConfirmationService]
3168
3800
  }]
3169
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$3.Router }, { type: MenuService }], propDecorators: { item: [{
3801
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$4.Router }, { type: MenuService }], propDecorators: { item: [{
3170
3802
  type: Input
3171
3803
  }], index: [{
3172
3804
  type: Input
@@ -3205,6 +3837,9 @@ class MenuItemCreateDialogComponent {
3205
3837
  this.selectIcon = 'pi pi-box';
3206
3838
  this.saving = false;
3207
3839
  }
3840
+ get canSave() {
3841
+ return !this.saving && !!this.selectModule;
3842
+ }
3208
3843
  async ngOnInit() {
3209
3844
  this.modules = await this.menu.getModules();
3210
3845
  }
@@ -3216,6 +3851,9 @@ class MenuItemCreateDialogComponent {
3216
3851
  if (this.saving) {
3217
3852
  return;
3218
3853
  }
3854
+ if (!this.selectModule) {
3855
+ return;
3856
+ }
3219
3857
  const item = {
3220
3858
  moduleId: this.selectModule,
3221
3859
  label: this.label,
@@ -3229,7 +3867,7 @@ class MenuItemCreateDialogComponent {
3229
3867
  this.hide();
3230
3868
  }
3231
3869
  catch (error) {
3232
- this.msgService.error(error);
3870
+ this.msgService.errorFromException(error, 'Unexpected error');
3233
3871
  }
3234
3872
  finally {
3235
3873
  this.saving = false;
@@ -3324,12 +3962,12 @@ class MenuItemCreateDialogComponent {
3324
3962
  <p-button
3325
3963
  id="oip-menu-item-create-save"
3326
3964
  label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
3327
- [disabled]="saving"
3965
+ [disabled]="!canSave"
3328
3966
  [loading]="saving"
3329
3967
  (click)="save()" />
3330
3968
  </div>
3331
3969
  </p-dialog>
3332
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3970
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3333
3971
  }
3334
3972
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemCreateDialogComponent, decorators: [{
3335
3973
  type: Component,
@@ -3417,7 +4055,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3417
4055
  <p-button
3418
4056
  id="oip-menu-item-create-save"
3419
4057
  label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
3420
- [disabled]="saving"
4058
+ [disabled]="!canSave"
3421
4059
  [loading]="saving"
3422
4060
  (click)="save()" />
3423
4061
  </div>
@@ -3433,7 +4071,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3433
4071
  class MenuItemEditDialogComponent {
3434
4072
  constructor() {
3435
4073
  this.menuService = inject(MenuService);
3436
- this.securityDataService = inject(SecurityDataService);
4074
+ this.securityApi = inject(SecurityApi);
3437
4075
  this.msgService = inject(MsgService);
3438
4076
  this.visibleChange = new EventEmitter();
3439
4077
  this.modules = [];
@@ -3489,7 +4127,7 @@ class MenuItemEditDialogComponent {
3489
4127
  icon: this.menuService.contextMenuItem?.icon,
3490
4128
  viewRoles: this.menuService.contextMenuItem?.securities
3491
4129
  };
3492
- this.roles = await this.securityDataService.getRealmRoles();
4130
+ this.roles = await this.securityApi.getRealmRoles();
3493
4131
  this.menuService.getModules().then((data) => {
3494
4132
  this.modules = data;
3495
4133
  });
@@ -3575,7 +4213,7 @@ class MenuItemEditDialogComponent {
3575
4213
  (click)="save()" />
3576
4214
  </div>
3577
4215
  </p-dialog>
3578
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i1.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4216
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i1.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3579
4217
  }
3580
4218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemEditDialogComponent, decorators: [{
3581
4219
  type: Component,
@@ -3682,6 +4320,9 @@ class MenuComponent {
3682
4320
  this.menuItemCreateDialogComponent.showDialog();
3683
4321
  }
3684
4322
  onContextMenu($event) {
4323
+ if (!this.securityService.isAdmin()) {
4324
+ return;
4325
+ }
3685
4326
  this.menuService.contextMenuItem = null;
3686
4327
  this.contextMenu.model = [
3687
4328
  {
@@ -3713,11 +4354,11 @@ class MenuComponent {
3713
4354
  }
3714
4355
  </ul>
3715
4356
  </div>
3716
- <p-contextMenu [target]="empty"/>
3717
4357
  @if (securityService.isAdmin()) {
4358
+ <p-contextMenu [target]="empty"/>
3718
4359
  <menu-item-create-dialog/>
3719
4360
  <menu-item-edit-dialog/>
3720
- }`, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i1$4.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "component", type: MenuItemCreateDialogComponent, selector: "menu-item-create-dialog", inputs: ["visible"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: MenuItemEditDialogComponent, selector: "menu-item-edit-dialog", inputs: ["visible"], outputs: ["visibleChange"] }] }); }
4361
+ }`, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i1$5.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "component", type: MenuItemCreateDialogComponent, selector: "menu-item-create-dialog", inputs: ["visible"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: MenuItemEditDialogComponent, selector: "menu-item-edit-dialog", inputs: ["visible"], outputs: ["visibleChange"] }] }); }
3721
4362
  }
3722
4363
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuComponent, decorators: [{
3723
4364
  type: Component,
@@ -3756,8 +4397,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3756
4397
  }
3757
4398
  </ul>
3758
4399
  </div>
3759
- <p-contextMenu [target]="empty"/>
3760
4400
  @if (securityService.isAdmin()) {
4401
+ <p-contextMenu [target]="empty"/>
3761
4402
  <menu-item-create-dialog/>
3762
4403
  <menu-item-edit-dialog/>
3763
4404
  }`
@@ -3878,7 +4519,7 @@ class AppLayoutComponent {
3878
4519
  </div>
3879
4520
  <div class="layout-mask animate-fadein"></div>
3880
4521
  </div>
3881
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AppTopbar, selector: "app-topbar" }, { kind: "component", type: SidebarComponent, selector: "app-sidebar" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$3.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: FooterComponent, selector: "app-footer" }] }); }
4522
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AppTopbar, selector: "app-topbar" }, { kind: "component", type: SidebarComponent, selector: "app-sidebar" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$4.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: FooterComponent, selector: "app-footer" }] }); }
3882
4523
  }
3883
4524
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppLayoutComponent, decorators: [{
3884
4525
  type: Component,
@@ -3945,7 +4586,7 @@ class AppFloatingConfiguratorComponent {
3945
4586
  <app-configurator />
3946
4587
  </div>
3947
4588
  </div>
3948
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i3$1.StyleClass, selector: "[pStyleClass]", inputs: ["pStyleClass", "enterFromClass", "enterActiveClass", "enterToClass", "leaveFromClass", "leaveActiveClass", "leaveToClass", "hideOnOutsideClick", "toggleClass", "hideOnEscape", "hideOnResize", "resizeSelector"] }, { kind: "component", type: AppConfiguratorComponent, selector: "app-configurator" }] }); }
4589
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i3$2.StyleClass, selector: "[pStyleClass]", inputs: ["pStyleClass", "enterFromClass", "enterActiveClass", "enterToClass", "leaveFromClass", "leaveActiveClass", "leaveToClass", "hideOnOutsideClick", "toggleClass", "hideOnEscape", "hideOnResize", "resizeSelector"] }, { kind: "component", type: AppConfiguratorComponent, selector: "app-configurator" }] }); }
3949
4590
  }
3950
4591
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppFloatingConfiguratorComponent, decorators: [{
3951
4592
  type: Component,
@@ -4036,73 +4677,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4036
4677
  standalone: true
4037
4678
  }]
4038
4679
  }], ctorParameters: () => [{ type: L10nService }] });
4039
-
4040
- class UnauthorizedComponent {
4041
- constructor() {
4042
- this.securityService = inject(SecurityService);
4043
- }
4044
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UnauthorizedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4045
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: UnauthorizedComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
4046
- <app-floating-configurator />
4047
- <div
4048
- class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
4049
- <div class="flex flex-col items-center justify-center">
4050
- <div
4051
- style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
4052
- <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
4053
- <div class="flex flex-col items-center justify-center">
4054
- <logo [height]="96" [width]="96" />
4055
- </div>
4056
- <div class="text-center mb-8">
4057
- <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
4058
- {{ 'unauthorized.welcomeToOip' | translate }}
4059
- </div>
4060
- <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
4061
- </div>
4062
- <div>
4063
- <p-button
4064
- id="oip-unauthorized-error-sign-in-button"
4065
- label="{{ 'unauthorized.signIn' | translate }}"
4066
- styleClass="w-full"
4067
- (click)="securityService.authorize()"></p-button>
4068
- </div>
4069
- </div>
4070
- </div>
4071
- </div>
4072
- </div>
4680
+
4681
+ class UnauthorizedComponent {
4682
+ constructor() {
4683
+ this.securityService = inject(SecurityService);
4684
+ this.route = inject(ActivatedRoute);
4685
+ this.router = inject(Router);
4686
+ }
4687
+ signIn() {
4688
+ const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl') || '/';
4689
+ this.router.navigate(['/unauthorized'], {
4690
+ queryParams: { returnUrl },
4691
+ replaceUrl: true
4692
+ }).then(() => this.securityService.authorize());
4693
+ }
4694
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UnauthorizedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4695
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: UnauthorizedComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
4696
+ <app-floating-configurator />
4697
+ <div
4698
+ class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
4699
+ <div class="flex flex-col items-center justify-center">
4700
+ <div
4701
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
4702
+ <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
4703
+ <div class="flex flex-col items-center justify-center">
4704
+ <logo [height]="96" [width]="96" />
4705
+ </div>
4706
+ <div class="text-center mb-8">
4707
+ <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
4708
+ {{ 'unauthorized.welcomeToOip' | translate }}
4709
+ </div>
4710
+ <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
4711
+ </div>
4712
+ <div>
4713
+ <p-button
4714
+ id="oip-unauthorized-error-sign-in-button"
4715
+ label="{{ 'unauthorized.signIn' | translate }}"
4716
+ styleClass="w-full"
4717
+ (click)="signIn()"></p-button>
4718
+ </div>
4719
+ </div>
4720
+ </div>
4721
+ </div>
4722
+ </div>
4073
4723
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: RippleModule }, { kind: "component", type: LogoComponent, selector: "logo", inputs: ["width", "height"] }, { kind: "component", type: AppFloatingConfiguratorComponent, selector: "app-floating-configurator" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4074
4724
  }
4075
4725
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UnauthorizedComponent, decorators: [{
4076
4726
  type: Component,
4077
4727
  args: [{
4078
- template: `
4079
- <app-floating-configurator />
4080
- <div
4081
- class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
4082
- <div class="flex flex-col items-center justify-center">
4083
- <div
4084
- style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
4085
- <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
4086
- <div class="flex flex-col items-center justify-center">
4087
- <logo [height]="96" [width]="96" />
4088
- </div>
4089
- <div class="text-center mb-8">
4090
- <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
4091
- {{ 'unauthorized.welcomeToOip' | translate }}
4092
- </div>
4093
- <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
4094
- </div>
4095
- <div>
4096
- <p-button
4097
- id="oip-unauthorized-error-sign-in-button"
4098
- label="{{ 'unauthorized.signIn' | translate }}"
4099
- styleClass="w-full"
4100
- (click)="securityService.authorize()"></p-button>
4101
- </div>
4102
- </div>
4103
- </div>
4104
- </div>
4105
- </div>
4728
+ template: `
4729
+ <app-floating-configurator />
4730
+ <div
4731
+ class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
4732
+ <div class="flex flex-col items-center justify-center">
4733
+ <div
4734
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
4735
+ <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
4736
+ <div class="flex flex-col items-center justify-center">
4737
+ <logo [height]="96" [width]="96" />
4738
+ </div>
4739
+ <div class="text-center mb-8">
4740
+ <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
4741
+ {{ 'unauthorized.welcomeToOip' | translate }}
4742
+ </div>
4743
+ <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
4744
+ </div>
4745
+ <div>
4746
+ <p-button
4747
+ id="oip-unauthorized-error-sign-in-button"
4748
+ label="{{ 'unauthorized.signIn' | translate }}"
4749
+ styleClass="w-full"
4750
+ (click)="signIn()"></p-button>
4751
+ </div>
4752
+ </div>
4753
+ </div>
4754
+ </div>
4755
+ </div>
4106
4756
  `,
4107
4757
  imports: [
4108
4758
  ButtonModule,
@@ -4147,7 +4797,7 @@ class ErrorComponent {
4147
4797
  </div>
4148
4798
  </div>
4149
4799
  </div>
4150
- </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i3$2.Ripple, selector: "[pRipple]" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
4800
+ </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i3$3.Ripple, selector: "[pRipple]" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
4151
4801
  }
4152
4802
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ErrorComponent, decorators: [{
4153
4803
  type: Component,
@@ -4220,7 +4870,7 @@ class ProfileComponent {
4220
4870
  [auto]="true"
4221
4871
  (onUpload)="onBasicUploadAuto($event)" />
4222
4872
  </div>
4223
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i1$5.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: ImageModule }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4873
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i1$6.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: ImageModule }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4224
4874
  }
4225
4875
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ProfileComponent, decorators: [{
4226
4876
  type: Component,
@@ -4260,7 +4910,6 @@ class ConfigComponent {
4260
4910
  this.userService = inject(UserService);
4261
4911
  this.securityService = inject(SecurityService);
4262
4912
  this.menuService = inject(MenuService);
4263
- this.l10n = {};
4264
4913
  this.dateFormats = ['dd.MM.yyyy', 'dd.MM.yy', 'yyyy-MM-dd', 'dd.MMM.yyyy'];
4265
4914
  this.timeFormats = ['HH:mm:ss', 'HH:mm'];
4266
4915
  // @ts-ignore
@@ -4291,204 +4940,204 @@ class ConfigComponent {
4291
4940
  await this.menuService.loadMenu();
4292
4941
  }
4293
4942
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4294
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ConfigComponent, isStandalone: true, selector: "app-config", ngImport: i0, template: `
4295
- <div class="flex flex-col md:flex-row gap-4">
4296
- <div class="md:w-1/2">
4297
- <div class="card flex flex-col gap-4">
4298
- <div class="font-semibold text-xl">{{ 'config.profile' | translate }}</div>
4299
- <div class="flex justify-content-end flex-wrap">
4300
- {{ userService.userName }}
4301
- </div>
4302
- <label>
4303
- {{ 'config.photo' | translate }}
4304
- <span
4305
- class="pi pi-question-circle"
4306
- pTooltip="{{ 'config.usePhoto256x256Pixel' | translate }}"
4307
- tooltipPosition="right"></span>
4308
- </label>
4309
- <div class="flex justify-content-end flex-wrap">
4310
- <user-profile></user-profile>
4311
- </div>
4312
- </div>
4313
- </div>
4314
- <div class="md:w-1/2">
4315
- <div class="card flex flex-col gap-4">
4316
- <div class="font-semibold text-xl">{{ 'config.localization' | translate }}</div>
4317
- <label> {{ 'config.selectLanguage' | translate }} </label>
4318
- <div class="flex justify-content-end flex-wrap">
4319
- <p-select
4320
- class="w-full md:w-56"
4321
- optionLabel="name"
4322
- optionValue="code"
4323
- qa-id="oip-app-config-language-select"
4324
- [options]="l10nService.availableLanguages"
4325
- [(ngModel)]="selectedLanguage"
4326
- (onChange)="changeLanguage()">
4327
- <ng-template #selectedItem let-selectedOption>
4328
- <div class="flex items-center gap-2">
4329
- <span [class]="selectedOption.icon"></span>
4330
- <div>{{ selectedOption.name }}</div>
4331
- </div>
4332
- </ng-template>
4333
- <ng-template #item let-languages>
4334
- <div class="flex items-center gap-2">
4335
- <span [class]="languages.icon"></span>
4336
- <div>{{ languages.name }}</div>
4337
- </div>
4338
- </ng-template>
4339
- </p-select>
4340
- </div>
4341
- <div class="flex flex-col gap-5">
4342
- <div class="mt-5">{{ 'config.dateTimeFormat' | translate }}</div>
4343
- <p-select
4344
- class="w-full md:w-56"
4345
- qa-id="oip-app-config-date-format-select"
4346
- [options]="dateFormats"
4347
- [placeholder]="'config.dateFormat' | translate"
4348
- [(ngModel)]="selectedDateFormat"
4349
- (onChange)="changeDateFormat()" />
4350
- <p-select
4351
- class="w-full md:w-56"
4352
- qa-id="oip-app-config-time-format-select"
4353
- [options]="timeFormats"
4354
- [placeholder]="'config.timeFormat' | translate"
4355
- [(ngModel)]="selectedTimeFormat"
4356
- (onChange)="changeTimeFormat()" />
4357
- <div class="mt-5">{{ 'config.timeZone' | translate }}</div>
4358
- <p-select
4359
- class="w-full md:w-56"
4360
- qa-id="oip-app-config-timezone-select"
4361
- [filter]="true"
4362
- [options]="allTimeZones"
4363
- [placeholder]="'config.timeZone' | translate"
4364
- [virtualScroll]="true"
4365
- [virtualScrollItemSize]="34"
4366
- [(ngModel)]="selectedTimeZone"
4367
- (onChange)="changeTimeZone()" />
4368
- </div>
4369
- </div>
4370
- </div>
4371
- @if (securityService.isAdmin()) {
4372
- <div class="md:w-1/2">
4373
- <div class="card flex flex-col gap-4">
4374
- <div class="font-semibold text-xl">{{ 'config.menu' | translate }}</div>
4375
- <div class="flex items-center gap-2">
4376
- <label for="oip-app-config-admin-mode">{{ 'config.all' | translate }}</label>
4377
- <p-toggle-switch
4378
- id="oip-app-config-admin-mode"
4379
- [(ngModel)]="menuService.adminMode"
4380
- (onChange)="onSwitchChange()"></p-toggle-switch>
4381
- </div>
4382
- <div class="flex items-center gap-2">
4383
- <label for="oip-app-config-admin-mode">{{ 'config.moduleManagement' | translate }}</label>
4384
- <p-button icon="pi pi-cog" label="{{ 'config.goTo' | translate }}" routerLink="/modules" />
4385
- </div>
4386
- </div>
4387
- </div>
4388
- }
4389
- </div>
4943
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ConfigComponent, isStandalone: true, selector: "app-config", ngImport: i0, template: `
4944
+ <div class="flex flex-col md:flex-row gap-4">
4945
+ <div class="md:w-1/2">
4946
+ <div class="card flex flex-col gap-4">
4947
+ <div class="font-semibold text-xl">{{ 'config.profile' | translate }}</div>
4948
+ <div class="flex justify-content-end flex-wrap">
4949
+ {{ userService.userName }}
4950
+ </div>
4951
+ <label>
4952
+ {{ 'config.photo' | translate }}
4953
+ <span
4954
+ class="pi pi-question-circle"
4955
+ pTooltip="{{ 'config.usePhoto256x256Pixel' | translate }}"
4956
+ tooltipPosition="right"></span>
4957
+ </label>
4958
+ <div class="flex justify-content-end flex-wrap">
4959
+ <user-profile></user-profile>
4960
+ </div>
4961
+ </div>
4962
+ </div>
4963
+ <div class="md:w-1/2">
4964
+ <div class="card flex flex-col gap-4">
4965
+ <div class="font-semibold text-xl">{{ 'config.localization' | translate }}</div>
4966
+ <label> {{ 'config.selectLanguage' | translate }} </label>
4967
+ <div class="flex justify-content-end flex-wrap">
4968
+ <p-select
4969
+ class="w-full md:w-56"
4970
+ optionLabel="name"
4971
+ optionValue="code"
4972
+ qa-id="oip-app-config-language-select"
4973
+ [options]="l10nService.availableLanguages"
4974
+ [(ngModel)]="selectedLanguage"
4975
+ (onChange)="changeLanguage()">
4976
+ <ng-template #selectedItem let-selectedOption>
4977
+ <div class="flex items-center gap-2">
4978
+ <span [class]="selectedOption.icon"></span>
4979
+ <div>{{ selectedOption.name }}</div>
4980
+ </div>
4981
+ </ng-template>
4982
+ <ng-template #item let-languages>
4983
+ <div class="flex items-center gap-2">
4984
+ <span [class]="languages.icon"></span>
4985
+ <div>{{ languages.name }}</div>
4986
+ </div>
4987
+ </ng-template>
4988
+ </p-select>
4989
+ </div>
4990
+ <div class="flex flex-col gap-5">
4991
+ <div class="mt-5">{{ 'config.dateTimeFormat' | translate }}</div>
4992
+ <p-select
4993
+ class="w-full md:w-56"
4994
+ qa-id="oip-app-config-date-format-select"
4995
+ [options]="dateFormats"
4996
+ [placeholder]="'config.dateFormat' | translate"
4997
+ [(ngModel)]="selectedDateFormat"
4998
+ (onChange)="changeDateFormat()" />
4999
+ <p-select
5000
+ class="w-full md:w-56"
5001
+ qa-id="oip-app-config-time-format-select"
5002
+ [options]="timeFormats"
5003
+ [placeholder]="'config.timeFormat' | translate"
5004
+ [(ngModel)]="selectedTimeFormat"
5005
+ (onChange)="changeTimeFormat()" />
5006
+ <div class="mt-5">{{ 'config.timeZone' | translate }}</div>
5007
+ <p-select
5008
+ class="w-full md:w-56"
5009
+ qa-id="oip-app-config-timezone-select"
5010
+ [filter]="true"
5011
+ [options]="allTimeZones"
5012
+ [placeholder]="'config.timeZone' | translate"
5013
+ [virtualScroll]="true"
5014
+ [virtualScrollItemSize]="34"
5015
+ [(ngModel)]="selectedTimeZone"
5016
+ (onChange)="changeTimeZone()" />
5017
+ </div>
5018
+ </div>
5019
+ </div>
5020
+ @if (securityService.isAdmin()) {
5021
+ <div class="md:w-1/2">
5022
+ <div class="card flex flex-col gap-4">
5023
+ <div class="font-semibold text-xl">{{ 'config.menu' | translate }}</div>
5024
+ <div class="flex items-center gap-2">
5025
+ <label for="oip-app-config-admin-mode">{{ 'config.all' | translate }}</label>
5026
+ <p-toggle-switch
5027
+ id="oip-app-config-admin-mode"
5028
+ [(ngModel)]="menuService.adminMode"
5029
+ (onChange)="onSwitchChange()"></p-toggle-switch>
5030
+ </div>
5031
+ <div class="flex items-center gap-2">
5032
+ <label for="oip-app-config-admin-mode">{{ 'config.moduleManagement' | translate }}</label>
5033
+ <p-button icon="pi pi-cog" label="{{ 'config.goTo' | translate }}" routerLink="/modules" />
5034
+ </div>
5035
+ </div>
5036
+ </div>
5037
+ }
5038
+ </div>
4390
5039
  `, isInline: true, dependencies: [{ kind: "component", type: ProfileComponent, selector: "user-profile" }, { 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: "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: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: TableModule }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i2$5.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { 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: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4391
5040
  }
4392
5041
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ConfigComponent, decorators: [{
4393
5042
  type: Component,
4394
5043
  args: [{
4395
5044
  selector: 'app-config',
4396
- template: `
4397
- <div class="flex flex-col md:flex-row gap-4">
4398
- <div class="md:w-1/2">
4399
- <div class="card flex flex-col gap-4">
4400
- <div class="font-semibold text-xl">{{ 'config.profile' | translate }}</div>
4401
- <div class="flex justify-content-end flex-wrap">
4402
- {{ userService.userName }}
4403
- </div>
4404
- <label>
4405
- {{ 'config.photo' | translate }}
4406
- <span
4407
- class="pi pi-question-circle"
4408
- pTooltip="{{ 'config.usePhoto256x256Pixel' | translate }}"
4409
- tooltipPosition="right"></span>
4410
- </label>
4411
- <div class="flex justify-content-end flex-wrap">
4412
- <user-profile></user-profile>
4413
- </div>
4414
- </div>
4415
- </div>
4416
- <div class="md:w-1/2">
4417
- <div class="card flex flex-col gap-4">
4418
- <div class="font-semibold text-xl">{{ 'config.localization' | translate }}</div>
4419
- <label> {{ 'config.selectLanguage' | translate }} </label>
4420
- <div class="flex justify-content-end flex-wrap">
4421
- <p-select
4422
- class="w-full md:w-56"
4423
- optionLabel="name"
4424
- optionValue="code"
4425
- qa-id="oip-app-config-language-select"
4426
- [options]="l10nService.availableLanguages"
4427
- [(ngModel)]="selectedLanguage"
4428
- (onChange)="changeLanguage()">
4429
- <ng-template #selectedItem let-selectedOption>
4430
- <div class="flex items-center gap-2">
4431
- <span [class]="selectedOption.icon"></span>
4432
- <div>{{ selectedOption.name }}</div>
4433
- </div>
4434
- </ng-template>
4435
- <ng-template #item let-languages>
4436
- <div class="flex items-center gap-2">
4437
- <span [class]="languages.icon"></span>
4438
- <div>{{ languages.name }}</div>
4439
- </div>
4440
- </ng-template>
4441
- </p-select>
4442
- </div>
4443
- <div class="flex flex-col gap-5">
4444
- <div class="mt-5">{{ 'config.dateTimeFormat' | translate }}</div>
4445
- <p-select
4446
- class="w-full md:w-56"
4447
- qa-id="oip-app-config-date-format-select"
4448
- [options]="dateFormats"
4449
- [placeholder]="'config.dateFormat' | translate"
4450
- [(ngModel)]="selectedDateFormat"
4451
- (onChange)="changeDateFormat()" />
4452
- <p-select
4453
- class="w-full md:w-56"
4454
- qa-id="oip-app-config-time-format-select"
4455
- [options]="timeFormats"
4456
- [placeholder]="'config.timeFormat' | translate"
4457
- [(ngModel)]="selectedTimeFormat"
4458
- (onChange)="changeTimeFormat()" />
4459
- <div class="mt-5">{{ 'config.timeZone' | translate }}</div>
4460
- <p-select
4461
- class="w-full md:w-56"
4462
- qa-id="oip-app-config-timezone-select"
4463
- [filter]="true"
4464
- [options]="allTimeZones"
4465
- [placeholder]="'config.timeZone' | translate"
4466
- [virtualScroll]="true"
4467
- [virtualScrollItemSize]="34"
4468
- [(ngModel)]="selectedTimeZone"
4469
- (onChange)="changeTimeZone()" />
4470
- </div>
4471
- </div>
4472
- </div>
4473
- @if (securityService.isAdmin()) {
4474
- <div class="md:w-1/2">
4475
- <div class="card flex flex-col gap-4">
4476
- <div class="font-semibold text-xl">{{ 'config.menu' | translate }}</div>
4477
- <div class="flex items-center gap-2">
4478
- <label for="oip-app-config-admin-mode">{{ 'config.all' | translate }}</label>
4479
- <p-toggle-switch
4480
- id="oip-app-config-admin-mode"
4481
- [(ngModel)]="menuService.adminMode"
4482
- (onChange)="onSwitchChange()"></p-toggle-switch>
4483
- </div>
4484
- <div class="flex items-center gap-2">
4485
- <label for="oip-app-config-admin-mode">{{ 'config.moduleManagement' | translate }}</label>
4486
- <p-button icon="pi pi-cog" label="{{ 'config.goTo' | translate }}" routerLink="/modules" />
4487
- </div>
4488
- </div>
4489
- </div>
4490
- }
4491
- </div>
5045
+ template: `
5046
+ <div class="flex flex-col md:flex-row gap-4">
5047
+ <div class="md:w-1/2">
5048
+ <div class="card flex flex-col gap-4">
5049
+ <div class="font-semibold text-xl">{{ 'config.profile' | translate }}</div>
5050
+ <div class="flex justify-content-end flex-wrap">
5051
+ {{ userService.userName }}
5052
+ </div>
5053
+ <label>
5054
+ {{ 'config.photo' | translate }}
5055
+ <span
5056
+ class="pi pi-question-circle"
5057
+ pTooltip="{{ 'config.usePhoto256x256Pixel' | translate }}"
5058
+ tooltipPosition="right"></span>
5059
+ </label>
5060
+ <div class="flex justify-content-end flex-wrap">
5061
+ <user-profile></user-profile>
5062
+ </div>
5063
+ </div>
5064
+ </div>
5065
+ <div class="md:w-1/2">
5066
+ <div class="card flex flex-col gap-4">
5067
+ <div class="font-semibold text-xl">{{ 'config.localization' | translate }}</div>
5068
+ <label> {{ 'config.selectLanguage' | translate }} </label>
5069
+ <div class="flex justify-content-end flex-wrap">
5070
+ <p-select
5071
+ class="w-full md:w-56"
5072
+ optionLabel="name"
5073
+ optionValue="code"
5074
+ qa-id="oip-app-config-language-select"
5075
+ [options]="l10nService.availableLanguages"
5076
+ [(ngModel)]="selectedLanguage"
5077
+ (onChange)="changeLanguage()">
5078
+ <ng-template #selectedItem let-selectedOption>
5079
+ <div class="flex items-center gap-2">
5080
+ <span [class]="selectedOption.icon"></span>
5081
+ <div>{{ selectedOption.name }}</div>
5082
+ </div>
5083
+ </ng-template>
5084
+ <ng-template #item let-languages>
5085
+ <div class="flex items-center gap-2">
5086
+ <span [class]="languages.icon"></span>
5087
+ <div>{{ languages.name }}</div>
5088
+ </div>
5089
+ </ng-template>
5090
+ </p-select>
5091
+ </div>
5092
+ <div class="flex flex-col gap-5">
5093
+ <div class="mt-5">{{ 'config.dateTimeFormat' | translate }}</div>
5094
+ <p-select
5095
+ class="w-full md:w-56"
5096
+ qa-id="oip-app-config-date-format-select"
5097
+ [options]="dateFormats"
5098
+ [placeholder]="'config.dateFormat' | translate"
5099
+ [(ngModel)]="selectedDateFormat"
5100
+ (onChange)="changeDateFormat()" />
5101
+ <p-select
5102
+ class="w-full md:w-56"
5103
+ qa-id="oip-app-config-time-format-select"
5104
+ [options]="timeFormats"
5105
+ [placeholder]="'config.timeFormat' | translate"
5106
+ [(ngModel)]="selectedTimeFormat"
5107
+ (onChange)="changeTimeFormat()" />
5108
+ <div class="mt-5">{{ 'config.timeZone' | translate }}</div>
5109
+ <p-select
5110
+ class="w-full md:w-56"
5111
+ qa-id="oip-app-config-timezone-select"
5112
+ [filter]="true"
5113
+ [options]="allTimeZones"
5114
+ [placeholder]="'config.timeZone' | translate"
5115
+ [virtualScroll]="true"
5116
+ [virtualScrollItemSize]="34"
5117
+ [(ngModel)]="selectedTimeZone"
5118
+ (onChange)="changeTimeZone()" />
5119
+ </div>
5120
+ </div>
5121
+ </div>
5122
+ @if (securityService.isAdmin()) {
5123
+ <div class="md:w-1/2">
5124
+ <div class="card flex flex-col gap-4">
5125
+ <div class="font-semibold text-xl">{{ 'config.menu' | translate }}</div>
5126
+ <div class="flex items-center gap-2">
5127
+ <label for="oip-app-config-admin-mode">{{ 'config.all' | translate }}</label>
5128
+ <p-toggle-switch
5129
+ id="oip-app-config-admin-mode"
5130
+ [(ngModel)]="menuService.adminMode"
5131
+ (onChange)="onSwitchChange()"></p-toggle-switch>
5132
+ </div>
5133
+ <div class="flex items-center gap-2">
5134
+ <label for="oip-app-config-admin-mode">{{ 'config.moduleManagement' | translate }}</label>
5135
+ <p-button icon="pi pi-cog" label="{{ 'config.goTo' | translate }}" routerLink="/modules" />
5136
+ </div>
5137
+ </div>
5138
+ </div>
5139
+ }
5140
+ </div>
4492
5141
  `,
4493
5142
  imports: [
4494
5143
  ProfileComponent,
@@ -4524,11 +5173,11 @@ class DbMigrationComponent extends BaseModuleComponent {
4524
5173
  });
4525
5174
  }
4526
5175
  async getData() {
4527
- return this.baseDataService.sendRequest(`api/${this.controller}/get-migrations`, 'GET');
5176
+ return this.getMigrations();
4528
5177
  }
4529
5178
  async applyMigration(rowData) {
4530
5179
  const request = { name: rowData.name };
4531
- return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
5180
+ return this.applyModuleMigration(request);
4532
5181
  }
4533
5182
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DbMigrationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4534
5183
  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: `
@@ -4609,7 +5258,7 @@ class DbMigrationComponent extends BaseModuleComponent {
4609
5258
  } @else if (isSecurity) {
4610
5259
  <security [controller]="controller" [id]="id"/>
4611
5260
  }
4612
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$6.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i1$6.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i1$6.EditableRow, selector: "[pEditableRow]", inputs: ["pEditableRow", "pEditableRowDisabled"] }, { kind: "directive", type: i1$6.CancelEditableRow, selector: "[pCancelEditableRow]" }, { kind: "component", type: i1$6.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: TagModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: TextareaModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5261
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$7.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i1$7.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i1$7.EditableRow, selector: "[pEditableRow]", inputs: ["pEditableRow", "pEditableRowDisabled"] }, { kind: "directive", type: i1$7.CancelEditableRow, selector: "[pCancelEditableRow]" }, { kind: "component", type: i1$7.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" }] }); }
4613
5262
  }
4614
5263
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DbMigrationComponent, decorators: [{
4615
5264
  type: Component,
@@ -4757,7 +5406,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4757
5406
 
4758
5407
  class AppModulesComponent {
4759
5408
  constructor() {
4760
- this.dataService = inject(BaseDataService);
4761
5409
  this.modules = [];
4762
5410
  this.msgService = inject(MsgService);
4763
5411
  this.confirmationService = inject(ConfirmationService);
@@ -4791,7 +5439,7 @@ class AppModulesComponent {
4791
5439
  },
4792
5440
  accept: async () => {
4793
5441
  try {
4794
- await this.dataService.sendRequest(`api/module/delete`, 'DELETE', {
5442
+ await this.moduleService.delete({
4795
5443
  moduleId: module.moduleId
4796
5444
  });
4797
5445
  await this.refreshAction();
@@ -4861,7 +5509,7 @@ class AppModulesComponent {
4861
5509
  </p-table>
4862
5510
  </div>
4863
5511
  </div>
4864
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$6.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i4$1.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5512
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$7.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i4$2.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4865
5513
  }
4866
5514
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppModulesComponent, decorators: [{
4867
5515
  type: Component,
@@ -4933,17 +5581,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4933
5581
  class DiscussionApi extends HttpClient {
4934
5582
  constructor() {
4935
5583
  super(...arguments);
4936
- /**
4937
- * @description Gets comments by object type and object identifier.
4938
- *
4939
- * @tags Discussion
4940
- * @name getByObject
4941
- * @summary Gets comments by object type and object identifier.
4942
- * @request GET:/api/discussion/get-by-object
4943
- * @secure
4944
- * @response `200` `(CommentDto)[]` OK
4945
- * @response `401` `ApiExceptionResponse` Unauthorized
4946
- */
4947
5584
  this.getByObject = (query, params = {}) => this.request({
4948
5585
  path: `/api/discussion/get-by-object`,
4949
5586
  method: "GET",
@@ -4952,18 +5589,6 @@ class DiscussionApi extends HttpClient {
4952
5589
  format: "json",
4953
5590
  ...params,
4954
5591
  });
4955
- /**
4956
- * @description Gets a comment by identifier.
4957
- *
4958
- * @tags Discussion
4959
- * @name getById
4960
- * @summary Gets a comment by identifier.
4961
- * @request GET:/api/discussion/get-by-id
4962
- * @secure
4963
- * @response `200` `CommentDto` OK
4964
- * @response `401` `ApiExceptionResponse` Unauthorized
4965
- * @response `404` `ApiExceptionResponse` Not Found
4966
- */
4967
5592
  this.getById = (query, params = {}) => this.request({
4968
5593
  path: `/api/discussion/get-by-id`,
4969
5594
  method: "GET",
@@ -4972,18 +5597,6 @@ class DiscussionApi extends HttpClient {
4972
5597
  format: "json",
4973
5598
  ...params,
4974
5599
  });
4975
- /**
4976
- * @description Creates a new comment
4977
- *
4978
- * @tags Discussion
4979
- * @name create
4980
- * @summary Creates a new comment
4981
- * @request POST:/api/discussion/create
4982
- * @secure
4983
- * @response `200` `CommentDto` OK
4984
- * @response `400` `ApiExceptionResponse` Bad Request
4985
- * @response `401` `ApiExceptionResponse` Unauthorized
4986
- */
4987
5600
  this.create = (data, params = {}) => this.request({
4988
5601
  path: `/api/discussion/create`,
4989
5602
  method: "POST",
@@ -4993,20 +5606,6 @@ class DiscussionApi extends HttpClient {
4993
5606
  format: "json",
4994
5607
  ...params,
4995
5608
  });
4996
- /**
4997
- * @description Updates an existing comment.
4998
- *
4999
- * @tags Discussion
5000
- * @name update
5001
- * @summary Updates an existing comment.
5002
- * @request PUT:/api/discussion/update/{id}
5003
- * @secure
5004
- * @response `200` `CommentDto` OK
5005
- * @response `400` `ApiExceptionResponse` Bad Request
5006
- * @response `401` `ApiExceptionResponse` Unauthorized
5007
- * @response `403` `ApiExceptionResponse` Forbidden
5008
- * @response `404` `ApiExceptionResponse` Not Found
5009
- */
5010
5609
  this.update = ({ id, ...query }, data, params = {}) => this.request({
5011
5610
  path: `/api/discussion/update/${id}`,
5012
5611
  method: "PUT",
@@ -5016,37 +5615,12 @@ class DiscussionApi extends HttpClient {
5016
5615
  format: "json",
5017
5616
  ...params,
5018
5617
  });
5019
- /**
5020
- * @description Soft deletes a comment.
5021
- *
5022
- * @tags Discussion
5023
- * @name delete
5024
- * @summary Soft deletes a comment.
5025
- * @request DELETE:/api/discussion/delete/{id}
5026
- * @secure
5027
- * @response `204` `void` No Content
5028
- * @response `401` `ApiExceptionResponse` Unauthorized
5029
- * @response `403` `ApiExceptionResponse` Forbidden
5030
- * @response `404` `ApiExceptionResponse` Not Found
5031
- */
5032
5618
  this.delete = ({ id, ...query }, params = {}) => this.request({
5033
5619
  path: `/api/discussion/delete/${id}`,
5034
5620
  method: "DELETE",
5035
5621
  secure: true,
5036
5622
  ...params,
5037
5623
  });
5038
- /**
5039
- * @description Gets edit history for a comment.
5040
- *
5041
- * @tags Discussion
5042
- * @name getHistory
5043
- * @summary Gets edit history for a comment.
5044
- * @request GET:/api/discussion/get-history/{id}
5045
- * @secure
5046
- * @response `200` `(CommentHistoryDto)[]` OK
5047
- * @response `401` `ApiExceptionResponse` Unauthorized
5048
- * @response `404` `ApiExceptionResponse` Not Found
5049
- */
5050
5624
  this.getHistory = ({ id, ...query }, params = {}) => this.request({
5051
5625
  path: `/api/discussion/get-history/${id}`,
5052
5626
  method: "GET",
@@ -5054,20 +5628,6 @@ class DiscussionApi extends HttpClient {
5054
5628
  format: "json",
5055
5629
  ...params,
5056
5630
  });
5057
- /**
5058
- * @description Uploads an attachment for a comment.
5059
- *
5060
- * @tags Discussion
5061
- * @name uploadAttachment
5062
- * @summary Uploads an attachment for a comment.
5063
- * @request POST:/api/discussion/upload-attachment
5064
- * @secure
5065
- * @response `200` `AttachmentDto` OK
5066
- * @response `400` `ApiExceptionResponse` Bad Request
5067
- * @response `401` `ApiExceptionResponse` Unauthorized
5068
- * @response `403` `ApiExceptionResponse` Forbidden
5069
- * @response `404` `ApiExceptionResponse` Not Found
5070
- */
5071
5631
  this.uploadAttachment = (data, params = {}) => this.request({
5072
5632
  path: `/api/discussion/upload-attachment`,
5073
5633
  method: "POST",
@@ -5077,56 +5637,18 @@ class DiscussionApi extends HttpClient {
5077
5637
  format: "json",
5078
5638
  ...params,
5079
5639
  });
5080
- /**
5081
- * @description Deletes an attachment.
5082
- *
5083
- * @tags Discussion
5084
- * @name deleteAttachment
5085
- * @summary Deletes an attachment.
5086
- * @request DELETE:/api/discussion/delete-attachment/{id}
5087
- * @secure
5088
- * @response `204` `void` No Content
5089
- * @response `401` `ApiExceptionResponse` Unauthorized
5090
- * @response `403` `ApiExceptionResponse` Forbidden
5091
- * @response `404` `ApiExceptionResponse` Not Found
5092
- */
5093
5640
  this.deleteAttachment = ({ id, ...query }, params = {}) => this.request({
5094
5641
  path: `/api/discussion/delete-attachment/${id}`,
5095
5642
  method: "DELETE",
5096
5643
  secure: true,
5097
5644
  ...params,
5098
5645
  });
5099
- /**
5100
- * @description Downloads attachment content.
5101
- *
5102
- * @tags Discussion
5103
- * @name getAttachmentContent
5104
- * @summary Downloads attachment content.
5105
- * @request GET:/api/discussion/get-attachment-content/{id}
5106
- * @secure
5107
- * @response `200` `void` OK
5108
- * @response `401` `ApiExceptionResponse` Unauthorized
5109
- * @response `404` `ApiExceptionResponse` Not Found
5110
- */
5111
5646
  this.getAttachmentContent = ({ id, ...query }, params = {}) => this.request({
5112
5647
  path: `/api/discussion/get-attachment-content/${id}`,
5113
5648
  method: "GET",
5114
5649
  secure: true,
5115
5650
  ...params,
5116
5651
  });
5117
- /**
5118
- * @description Adds or toggles a reaction for a comment.
5119
- *
5120
- * @tags Discussion
5121
- * @name addReaction
5122
- * @summary Adds or toggles a reaction for a comment.
5123
- * @request POST:/api/discussion/add-reaction
5124
- * @secure
5125
- * @response `200` `(CommentReactionDto)[]` OK
5126
- * @response `400` `ApiExceptionResponse` Bad Request
5127
- * @response `401` `ApiExceptionResponse` Unauthorized
5128
- * @response `404` `ApiExceptionResponse` Not Found
5129
- */
5130
5652
  this.addReaction = (data, params = {}) => this.request({
5131
5653
  path: `/api/discussion/add-reaction`,
5132
5654
  method: "POST",
@@ -5136,18 +5658,6 @@ class DiscussionApi extends HttpClient {
5136
5658
  format: "json",
5137
5659
  ...params,
5138
5660
  });
5139
- /**
5140
- * @description Removes a reaction from a comment.
5141
- *
5142
- * @tags Discussion
5143
- * @name removeReaction
5144
- * @summary Removes a reaction from a comment.
5145
- * @request DELETE:/api/discussion/remove-reaction
5146
- * @secure
5147
- * @response `200` `(CommentReactionDto)[]` OK
5148
- * @response `401` `ApiExceptionResponse` Unauthorized
5149
- * @response `404` `ApiExceptionResponse` Not Found
5150
- */
5151
5661
  this.removeReaction = (query, params = {}) => this.request({
5152
5662
  path: `/api/discussion/remove-reaction`,
5153
5663
  method: "DELETE",
@@ -5156,18 +5666,6 @@ class DiscussionApi extends HttpClient {
5156
5666
  format: "json",
5157
5667
  ...params,
5158
5668
  });
5159
- /**
5160
- * @description Searches users that can be mentioned in a comment.
5161
- *
5162
- * @tags Discussion
5163
- * @name searchMentionUsers
5164
- * @summary Searches users that can be mentioned in a comment.
5165
- * @request GET:/api/discussion/search-mention-users
5166
- * @secure
5167
- * @response `200` `(MentionUserDto)[]` OK
5168
- * @response `400` `ApiExceptionResponse` Bad Request
5169
- * @response `401` `ApiExceptionResponse` Unauthorized
5170
- */
5171
5669
  this.searchMentionUsers = (query, params = {}) => this.request({
5172
5670
  path: `/api/discussion/search-mention-users`,
5173
5671
  method: "GET",
@@ -5930,7 +6428,7 @@ class DiscussionComponent {
5930
6428
  </div>
5931
6429
  }
5932
6430
  </section>
5933
- `, isInline: true, styles: [":host{display:block}.file-trigger{position:relative;display:inline-flex}.file-trigger input{position:absolute;inset:0;opacity:0;cursor:pointer}.markdown-preview,.history-markdown{word-break:break-word}.markdown-preview :is(h1,h2,h3),.history-markdown :is(h1,h2,h3){margin:0 0 .75rem;font-weight:600}.markdown-preview a,.history-markdown a{color:#2563eb;text-decoration:underline;text-underline-offset:.18em}.emoji-popover{display:flex;flex-wrap:wrap;gap:.5rem;max-width:16rem}.emoji-option{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;font-size:1.25rem;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: DividerModule }, { kind: "ngmodule", type: PanelModule }, { kind: "component", type: i6.Panel, selector: "p-panel", inputs: ["id", "toggleable", "header", "collapsed", "styleClass", "iconPos", "showHeader", "toggler", "transitionOptions", "toggleButtonProps"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i7.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i8.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i9.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "pipe", type: i2$1.DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6431
+ `, isInline: true, styles: [":host{display:block}.file-trigger{position:relative;display:inline-flex}.file-trigger input{position:absolute;inset:0;opacity:0;cursor:pointer}.markdown-preview,.history-markdown{word-break:break-word}.markdown-preview :is(h1,h2,h3),.history-markdown :is(h1,h2,h3){margin:0 0 .75rem;font-weight:600}.markdown-preview a,.history-markdown a{color:#2563eb;text-decoration:underline;text-underline-offset:.18em}.emoji-popover{display:flex;flex-wrap:wrap;gap:.5rem;max-width:16rem}.emoji-option{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;font-size:1.25rem;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: DividerModule }, { kind: "ngmodule", type: PanelModule }, { kind: "component", type: i6.Panel, selector: "p-panel", inputs: ["id", "toggleable", "header", "collapsed", "styleClass", "iconPos", "showHeader", "toggler", "transitionOptions", "toggleButtonProps"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i7.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i9.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "pipe", type: i2$1.DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5934
6432
  }
5935
6433
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DiscussionComponent, decorators: [{
5936
6434
  type: Component,
@@ -6456,31 +6954,14 @@ class AuthGuardService {
6456
6954
  *
6457
6955
  * @returns {Observable<boolean | UrlTree>} A stream resolving to true (allow), or UrlTree (redirect).
6458
6956
  */
6459
- canActivate() {
6460
- return combineLatest([this.oidcSecurityService.isAuthenticated(), this.oidcSecurityService.isTokenExpired()]).pipe(switchMap(([authenticated, tokenExpired]) => {
6461
- if (!authenticated) {
6462
- return of(this.router.parseUrl('/unauthorized'));
6463
- }
6464
- if (!tokenExpired) {
6465
- return of(true);
6466
- }
6467
- // Token is expired; attempt to refresh
6468
- return this.tryRefreshToken();
6469
- }));
6957
+ canActivate(returnUrl = '/') {
6958
+ this.oidcSecurityService.auth();
6959
+ return this.oidcSecurityService.isAuthenticated().pipe(map((authenticated) => authenticated
6960
+ ? true
6961
+ : this.router.createUrlTree(['/unauthorized'], { queryParams: { returnUrl: this.getReturnUrl(returnUrl) } })));
6470
6962
  }
6471
- /**
6472
- * Attempts to refresh the session using the refresh token.
6473
- * If successful, allows route activation; otherwise, redirects to `/unauthorized`.
6474
- *
6475
- * @returns {boolean | UrlTree} A stream resolving to true or redirect UrlTree.
6476
- */
6477
- tryRefreshToken() {
6478
- return this.oidcSecurityService.forceRefreshSession().pipe(map((refreshSuccess) => {
6479
- return refreshSuccess ? true : this.router.parseUrl('/unauthorized');
6480
- }), catchError((err) => {
6481
- console.warn(err);
6482
- return of(this.router.parseUrl('/unauthorized'));
6483
- }));
6963
+ getReturnUrl(returnUrl) {
6964
+ return returnUrl.startsWith('/unauthorized') ? '/' : returnUrl;
6484
6965
  }
6485
6966
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthGuardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6486
6967
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthGuardService }); }
@@ -6489,80 +6970,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6489
6970
  type: Injectable
6490
6971
  }] });
6491
6972
 
6492
- class SecurityStorageService {
6493
- read(key) {
6494
- return localStorage.getItem(key);
6495
- }
6496
- write(key, value) {
6497
- localStorage.setItem(key, value);
6498
- }
6499
- remove(key) {
6500
- localStorage.removeItem(key);
6501
- }
6502
- clear() {
6503
- localStorage.clear();
6504
- }
6505
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6506
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityStorageService }); }
6507
- }
6508
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityStorageService, decorators: [{
6509
- type: Injectable
6510
- }] });
6511
-
6512
- class NotificationService {
6513
- constructor() {
6514
- this.securityService = inject(SecurityService);
6515
- this.msgService = inject(MsgService);
6516
- this.frontendConfig = inject(OIP_FRONTEND_CONFIG);
6517
- this.securityData = null;
6518
- this.connection = new signalR.HubConnectionBuilder()
6519
- .withUrl(this.resolveHubUrl(), {
6520
- accessTokenFactory: () => this.securityData ?? '',
6521
- skipNegotiation: true,
6522
- transport: signalR.HttpTransportType.WebSockets
6523
- })
6524
- .configureLogging(signalR.LogLevel.Error)
6525
- .build();
6526
- this.connection.on('ReceiveNotification', (notification) => {
6527
- const opt = {
6528
- severity: notification.severity,
6529
- summary: notification.subject,
6530
- detail: notification.message,
6531
- life: 0
6532
- };
6533
- this.msgService.add(opt);
6534
- });
6535
- this.securityService.getAccessToken().subscribe((token) => {
6536
- this.securityData = token;
6537
- if (!token) {
6538
- return;
6539
- }
6540
- if (this.connection.state === signalR.HubConnectionState.Disconnected) {
6541
- this.connection.start().catch((error) => console.error('Failed to start notification connection', error));
6542
- return;
6543
- }
6544
- this.connection.stop().then(() => {
6545
- this.connection.start().catch((error) => console.error('Failed to restart notification connection', error));
6546
- });
6547
- });
6548
- }
6549
- resolveHubUrl() {
6550
- if (this.frontendConfig.notificationHubUrl) {
6551
- return this.frontendConfig.notificationHubUrl;
6552
- }
6553
- if (this.frontendConfig.apiBaseUrl) {
6554
- return `${this.frontendConfig.apiBaseUrl.replace(/\/$/, '')}/hubs/notification`;
6555
- }
6556
- return '/hubs/notification';
6557
- }
6558
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6559
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, providedIn: 'root' }); }
6560
- }
6561
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, decorators: [{
6562
- type: Injectable,
6563
- args: [{ providedIn: 'root' }]
6564
- }], ctorParameters: () => [] });
6565
-
6566
6973
  /**
6567
6974
  * Prime-ng table filter service
6568
6975
  */
@@ -6637,73 +7044,96 @@ function replaceDefaults(themes) {
6637
7044
 
6638
7045
  const langIntercept = (req, next) => {
6639
7046
  const layoutService = inject(LayoutService);
7047
+ const securityService = inject(SecurityService);
6640
7048
  const lang = layoutService.language() ? layoutService.language() : 'en';
6641
- const httpHeaders = req.headers.set('Accept-language', lang);
6642
- const authReq = req.clone({
6643
- headers: httpHeaders
7049
+ const headers = req.headers
7050
+ .set('Accept-language', lang)
7051
+ .set('X-Timezone', layoutService.timeZone());
7052
+ const reqWithCredentials = req.clone({
7053
+ headers,
7054
+ withCredentials: true
6644
7055
  });
6645
- return next(authReq);
7056
+ if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method.toUpperCase())) {
7057
+ return next(reqWithCredentials);
7058
+ }
7059
+ if (req.url.includes('/api/security/create-auth-session') || req.url.includes('/api/security/get-auth-csrf-token')) {
7060
+ return next(reqWithCredentials);
7061
+ }
7062
+ return securityService.getCsrfToken().pipe(take(1), switchMap((csrfToken) => next(csrfToken?.token
7063
+ ? reqWithCredentials.clone({
7064
+ headers: reqWithCredentials.headers.set(csrfToken.headerName, csrfToken.token)
7065
+ })
7066
+ : reqWithCredentials)));
6646
7067
  };
6647
7068
 
6648
- class SecurePipe {
7069
+ const httpLoaderFactory = (http) => new TranslateHttpLoader(http);
7070
+ function provideOip() {
7071
+ return makeEnvironmentProviders([
7072
+ provideHttpClient(withInterceptors([langIntercept]), withFetch()),
7073
+ { provide: LocationStrategy, useClass: PathLocationStrategy },
7074
+ { provide: SecurityService, useClass: BffSecurityService },
7075
+ AuthGuardService,
7076
+ MessageService,
7077
+ UserService,
7078
+ NotificationService,
7079
+ UserProfileApi,
7080
+ SecurityApi,
7081
+ NotificationApi,
7082
+ importProvidersFrom([
7083
+ TranslateModule.forRoot({
7084
+ loader: {
7085
+ provide: TranslateLoader,
7086
+ useFactory: httpLoaderFactory,
7087
+ deps: [HttpClient$1]
7088
+ }
7089
+ })
7090
+ ])
7091
+ ]);
7092
+ }
7093
+
7094
+ /* eslint-disable */
7095
+ /* tslint:disable */
7096
+ // @ts-nocheck
7097
+ class FolderModuleApi extends HttpClient {
6649
7098
  constructor() {
6650
- this.http = inject(HttpClient$1);
6651
- this.sanitizer = inject(DomSanitizer);
6652
- }
6653
- transform(url) {
6654
- return this.http
6655
- .get(url, { responseType: 'blob' })
6656
- .pipe(map$1((val) => this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(val))));
7099
+ super(...arguments);
7100
+ this.getModuleInstanceSettings = (query, params = {}) => this.request({
7101
+ path: `/api/folder-module/get-module-instance-settings`,
7102
+ method: "GET",
7103
+ query: query,
7104
+ secure: true,
7105
+ format: "json",
7106
+ ...params,
7107
+ });
6657
7108
  }
6658
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6659
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: SecurePipe, isStandalone: true, name: "secure" }); }
7109
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FolderModuleApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
7110
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FolderModuleApi }); }
6660
7111
  }
6661
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurePipe, decorators: [{
6662
- type: Pipe,
6663
- args: [{
6664
- standalone: true,
6665
- name: 'secure'
6666
- }]
7112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FolderModuleApi, decorators: [{
7113
+ type: Injectable
6667
7114
  }] });
6668
7115
 
6669
- const appendCurrentOriginSecureRoute = (secureRoutes) => {
6670
- const currentOriginRoute = `${window.location.origin}/`;
6671
- return Array.from(new Set([...(secureRoutes ?? []), currentOriginRoute]));
6672
- };
6673
- /**
6674
- * Load keycloak settings from backend and save to sessionStorage
6675
- * @param httpClient
6676
- * @returns StsConfigHttpLoader
6677
- */
6678
- const httpLoaderAuthFactory = (httpClient) => {
6679
- const KEYCLOAK_SETTINGS_KEY = 'keycloak-client-settings';
6680
- const settingsStings = sessionStorage.getItem(KEYCLOAK_SETTINGS_KEY);
6681
- if (settingsStings) {
6682
- const config$ = new Observable((subscribe) => {
6683
- subscribe.next(JSON.parse(settingsStings));
7116
+ /* eslint-disable */
7117
+ /* tslint:disable */
7118
+ // @ts-nocheck
7119
+ class IframeModuleApi extends HttpClient {
7120
+ constructor() {
7121
+ super(...arguments);
7122
+ this.getModuleInstanceSettings = (query, params = {}) => this.request({
7123
+ path: `/api/iframe-module/get-module-instance-settings`,
7124
+ method: "GET",
7125
+ query: query,
7126
+ secure: true,
7127
+ format: "json",
7128
+ ...params,
6684
7129
  });
6685
- return new StsConfigHttpLoader(config$);
6686
- }
6687
- else {
6688
- const config$ = httpClient.get(`api/security/get-keycloak-client-settings`).pipe(map$1((config) => {
6689
- const authConfig = {
6690
- authority: config.authority,
6691
- redirectUrl: window.location.origin,
6692
- postLogoutRedirectUri: window.location.origin,
6693
- clientId: config.clientId,
6694
- scope: config.scope,
6695
- responseType: config.responseType,
6696
- useRefreshToken: config.useRefreshToken,
6697
- silentRenew: config.silentRenew,
6698
- logLevel: config.logLevel,
6699
- secureRoutes: appendCurrentOriginSecureRoute(config.secureRoutes)
6700
- };
6701
- sessionStorage.setItem(KEYCLOAK_SETTINGS_KEY, JSON.stringify(authConfig));
6702
- return authConfig;
6703
- }));
6704
- return new StsConfigHttpLoader(config$);
6705
7130
  }
6706
- };
7131
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
7132
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleApi }); }
7133
+ }
7134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleApi, decorators: [{
7135
+ type: Injectable
7136
+ }] });
6707
7137
 
6708
7138
  // Components
6709
7139
 
@@ -6711,5 +7141,5 @@ const httpLoaderAuthFactory = (httpClient) => {
6711
7141
  * Generated bundle index. Do not edit.
6712
7142
  */
6713
7143
 
6714
- 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 };
7144
+ export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AuthGuardService, BaseModuleComponent, BffSecurityService, ConfigComponent, ContentType, DbMigrationComponent, DiscussionComponent, ErrorComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, KeycloakSecurityService, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationApi, NotificationService, ProfileComponent, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserService, convertToPrimeNgDateFormat, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, provideOip, replaceDefaults };
6715
7145
  //# sourceMappingURL=oip-common.mjs.map