oip-common 0.2.2 → 0.3.1

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
+ });
643
+ }
644
+ isAuthenticated() {
645
+ return this.authenticated.asObservable().pipe(filter((value) => value !== null), distinctUntilChanged());
646
+ }
647
+ getAccessToken() {
648
+ return of('');
702
649
  }
703
- getRealmRoles() {
704
- return this.sendRequest(this.baseUrl + `api/security/get-realm-roles`);
650
+ isTokenExpired() {
651
+ return of(false);
652
+ }
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();
705
671
  }
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 }); }
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'; }
@@ -1068,8 +1287,8 @@ class BaseModuleComponent {
1068
1287
  this.isInitialized = false;
1069
1288
  this.moduleInstanceReloadPromise = Promise.resolve();
1070
1289
  this.destroyRef = inject(DestroyRef);
1071
- this.securityDataService = inject(SecurityDataService);
1072
1290
  this.securityService = inject(SecurityService);
1291
+ this.httpClient = inject(HttpClient);
1073
1292
  /**
1074
1293
  * Provide access to app settings
1075
1294
  */
@@ -1088,11 +1307,6 @@ class BaseModuleComponent {
1088
1307
  * Provides access to messaging services.
1089
1308
  */
1090
1309
  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
1310
  /**
1097
1311
  * Provides access to translation functionality.
1098
1312
  */
@@ -1210,7 +1424,10 @@ class BaseModuleComponent {
1210
1424
  */
1211
1425
  async getSettings() {
1212
1426
  try {
1213
- this.settings = await this.baseDataService.sendRequest(`${this.baseDataService.baseUrl}api/${this.controller}/get-module-instance-settings?id=${this.id}`);
1427
+ if (this.id == null) {
1428
+ return;
1429
+ }
1430
+ this.settings = await this.getModuleInstanceSettings();
1214
1431
  }
1215
1432
  catch (error) {
1216
1433
  this.msgService.error(error);
@@ -1222,8 +1439,11 @@ class BaseModuleComponent {
1222
1439
  * @return {Promise<void>} A promise that resolves when the settings are saved. Reject if an error occurs.
1223
1440
  */
1224
1441
  async saveSettings(settings) {
1225
- await this.baseDataService
1226
- .sendRequest(`api/${this.controller}/put-module-instance-settings`, 'PUT', {
1442
+ if (this.id == null) {
1443
+ this.msgService.error('Module id not passed!');
1444
+ return;
1445
+ }
1446
+ await this.saveModuleInstanceSettings({
1227
1447
  id: this.id,
1228
1448
  settings: settings
1229
1449
  })
@@ -1255,7 +1475,7 @@ class BaseModuleComponent {
1255
1475
  return;
1256
1476
  }
1257
1477
  this.rightsSubscription = this.securityService.payload
1258
- .pipe(switchMap((payload) => from(this.securityDataService.getSecurity(controller, id)).pipe(map((securitySettings) => ({ payload, securitySettings })))), takeUntilDestroyed(this.destroyRef))
1478
+ .pipe(switchMap((payload) => from(this.getSecurity(controller, id)).pipe(map((securitySettings) => ({ payload, securitySettings })))), takeUntilDestroyed(this.destroyRef))
1259
1479
  .subscribe({
1260
1480
  next: ({ payload, securitySettings }) => {
1261
1481
  const roles = payload?.realm_access?.roles ?? [];
@@ -1267,46 +1487,157 @@ class BaseModuleComponent {
1267
1487
  this.onSecurityRightsChange();
1268
1488
  }
1269
1489
  });
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();
1490
+ }
1491
+ resetRightsState() {
1492
+ this.canRead = false;
1493
+ this.canEdit = false;
1494
+ this.canDelete = false;
1495
+ this.securityRightsLoaded = false;
1496
+ }
1497
+ updateRightsState(roles, securitySettings) {
1498
+ this.canRead = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.readRight);
1499
+ this.canEdit = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.editRight);
1500
+ this.canDelete = this.hasSecurityRight(roles, securitySettings, BaseModuleComponent.deleteRight);
1501
+ this.securityRightsLoaded = true;
1502
+ this.onSecurityRightsChange();
1503
+ }
1504
+ hasSecurityRight(roles, securitySettings, code) {
1505
+ return securitySettings
1506
+ .find((security) => security.code === code)
1507
+ ?.roles?.some((role) => roles.includes(role)) ?? false;
1508
+ }
1509
+ getSecurity(controller = this.controller, id = this.id) {
1510
+ if (!controller || id == null) {
1511
+ return Promise.resolve([]);
1512
+ }
1513
+ return this.httpClient.request({
1514
+ path: `/api/${controller}/get-security`,
1515
+ method: 'GET',
1516
+ query: { id },
1517
+ secure: true,
1518
+ format: 'json'
1519
+ });
1520
+ }
1521
+ saveSecurity(request, controller = this.controller) {
1522
+ return this.httpClient.request({
1523
+ path: `/api/${controller}/put-security`,
1524
+ method: 'PUT',
1525
+ body: request,
1526
+ secure: true,
1527
+ type: ContentType.Json
1528
+ });
1529
+ }
1530
+ getModuleInstanceSettings(controller = this.controller, id = this.id) {
1531
+ return this.httpClient.request({
1532
+ path: `/api/${controller}/get-module-instance-settings`,
1533
+ method: 'GET',
1534
+ query: { id },
1535
+ secure: true,
1536
+ format: 'json'
1537
+ });
1538
+ }
1539
+ saveModuleInstanceSettings(request, controller = this.controller) {
1540
+ return this.httpClient.request({
1541
+ path: `/api/${controller}/put-module-instance-settings`,
1542
+ method: 'PUT',
1543
+ body: request,
1544
+ secure: true,
1545
+ type: ContentType.Json
1546
+ });
1547
+ }
1548
+ getMigrations(controller = this.controller) {
1549
+ return this.httpClient.request({
1550
+ path: `/api/${controller}/get-migrations`,
1551
+ method: 'GET',
1552
+ secure: true,
1553
+ format: 'json'
1554
+ });
1555
+ }
1556
+ applyModuleMigration(request, controller = this.controller) {
1557
+ return this.httpClient.request({
1558
+ path: `/api/${controller}/apply-migration`,
1559
+ method: 'POST',
1560
+ body: request,
1561
+ secure: true,
1562
+ type: ContentType.Json
1563
+ });
1564
+ }
1565
+ async reloadModuleInstance() {
1566
+ this.moduleInstanceReloadPromise = this.moduleInstanceReloadPromise.then(async () => {
1567
+ await this.getSettings();
1568
+ this.watchSecurityRights();
1569
+ await this.onModuleInstanceChange();
1570
+ });
1571
+ await this.moduleInstanceReloadPromise;
1572
+ }
1573
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseModuleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1574
+ 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 }); }
1575
+ }
1576
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BaseModuleComponent, decorators: [{
1577
+ type: Component,
1578
+ args: [{ standalone: true, template: '' }]
1579
+ }], ctorParameters: () => [] });
1580
+
1581
+ /* eslint-disable */
1582
+ /* tslint:disable */
1583
+ // @ts-nocheck
1584
+ class SecurityApi extends HttpClient {
1585
+ constructor() {
1586
+ super(...arguments);
1587
+ this.getCurrentAuthSession = (params = {}) => this.request({
1588
+ path: `/api/security/get-current-auth-session`,
1589
+ method: "GET",
1590
+ secure: true,
1591
+ format: "json",
1592
+ ...params,
1593
+ });
1594
+ this.createAuthSession = (params = {}) => this.request({
1595
+ path: `/api/security/create-auth-session`,
1596
+ method: "POST",
1597
+ secure: true,
1598
+ ...params,
1599
+ });
1600
+ this.deleteAuthSession = (params = {}) => this.request({
1601
+ path: `/api/security/delete-auth-session`,
1602
+ method: "POST",
1603
+ secure: true,
1604
+ ...params,
1605
+ });
1606
+ this.getAuthCsrfToken = (params = {}) => this.request({
1607
+ path: `/api/security/get-auth-csrf-token`,
1608
+ method: "GET",
1609
+ secure: true,
1610
+ format: "json",
1611
+ ...params,
1612
+ });
1613
+ this.getKeycloakClientSettings = (params = {}) => this.request({
1614
+ path: `/api/security/get-keycloak-client-settings`,
1615
+ method: "GET",
1616
+ secure: true,
1617
+ format: "json",
1618
+ ...params,
1619
+ });
1620
+ this.getRealmRoles = (params = {}) => this.request({
1621
+ path: `/api/security/get-realm-roles`,
1622
+ method: "GET",
1623
+ secure: true,
1624
+ format: "json",
1625
+ ...params,
1294
1626
  });
1295
- await this.moduleInstanceReloadPromise;
1296
1627
  }
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 }); }
1628
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1629
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi }); }
1299
1630
  }
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: () => [] });
1631
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityApi, decorators: [{
1632
+ type: Injectable
1633
+ }] });
1304
1634
 
1305
1635
  class SecurityComponent {
1306
1636
  constructor() {
1307
1637
  this.msgService = inject(MsgService);
1308
- this.dataService = inject(SecurityDataService);
1309
1638
  this.translateService = inject(TranslateService);
1639
+ this.httpClient = inject(HttpClient);
1640
+ this.securityApi = inject(SecurityApi);
1310
1641
  this.securityLoadToken = 0;
1311
1642
  this.securityData = [];
1312
1643
  this.roles = [];
@@ -1320,7 +1651,7 @@ class SecurityComponent {
1320
1651
  }
1321
1652
  }
1322
1653
  ngOnInit() {
1323
- this.dataService.getRealmRoles().then((result) => {
1654
+ this.securityApi.getRealmRoles().then((result) => {
1324
1655
  this.roles = result;
1325
1656
  }, (error) => this.msgService.error(error));
1326
1657
  }
@@ -1337,7 +1668,7 @@ class SecurityComponent {
1337
1668
  id: this.id,
1338
1669
  securities: this.securityData
1339
1670
  };
1340
- this.dataService.saveSecurity(this.controller, request).then((result) => {
1671
+ this.saveSecurity(this.controller, request).then((result) => {
1341
1672
  this.msgService.success(this.translateService.instant('securityComponent.savedSecurity'));
1342
1673
  }, (error) => this.msgService.error(error));
1343
1674
  }
@@ -1355,7 +1686,7 @@ class SecurityComponent {
1355
1686
  return;
1356
1687
  }
1357
1688
  try {
1358
- const result = await this.dataService.getSecurity(controller, id);
1689
+ const result = await this.getSecurity(controller, id);
1359
1690
  if (loadToken === this.securityLoadToken) {
1360
1691
  this.securityData = result;
1361
1692
  }
@@ -1366,6 +1697,24 @@ class SecurityComponent {
1366
1697
  }
1367
1698
  }
1368
1699
  }
1700
+ getSecurity(controller, id) {
1701
+ return this.httpClient.request({
1702
+ path: `/api/${controller}/get-security`,
1703
+ method: 'GET',
1704
+ query: { id },
1705
+ secure: true,
1706
+ format: 'json'
1707
+ });
1708
+ }
1709
+ saveSecurity(controller, request) {
1710
+ return this.httpClient.request({
1711
+ path: `/api/${controller}/put-security`,
1712
+ method: 'PUT',
1713
+ body: request,
1714
+ secure: true,
1715
+ type: ContentType.Json
1716
+ });
1717
+ }
1369
1718
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SecurityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1370
1719
  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
1720
  <div class="flex flex-col md:flex-row gap-8">
@@ -2037,6 +2386,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2037
2386
  }]
2038
2387
  }] });
2039
2388
 
2389
+ /* eslint-disable */
2390
+ /* tslint:disable */
2391
+ // @ts-nocheck
2392
+ class UserProfileApi extends HttpClient {
2393
+ constructor() {
2394
+ super(...arguments);
2395
+ this.getUserPhoto = (query, params = {}) => this.request({
2396
+ path: `/api/user-profile/get-user-photo`,
2397
+ method: "GET",
2398
+ query: query,
2399
+ secure: true,
2400
+ format: "blob",
2401
+ ...params,
2402
+ });
2403
+ this.postUserPhoto = (data, params = {}) => this.request({
2404
+ path: `/api/user-profile/post-user-photo`,
2405
+ method: "POST",
2406
+ body: data,
2407
+ secure: true,
2408
+ type: ContentType.FormData,
2409
+ ...params,
2410
+ });
2411
+ this.getSettings = (params = {}) => this.request({
2412
+ path: `/api/user-profile/get-settings`,
2413
+ method: "GET",
2414
+ secure: true,
2415
+ format: "json",
2416
+ ...params,
2417
+ });
2418
+ this.setSettings = (data, params = {}) => this.request({
2419
+ path: `/api/user-profile/set-settings`,
2420
+ method: "PUT",
2421
+ body: data,
2422
+ secure: true,
2423
+ type: ContentType.Json,
2424
+ ...params,
2425
+ });
2426
+ }
2427
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2428
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileApi }); }
2429
+ }
2430
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserProfileApi, decorators: [{
2431
+ type: Injectable
2432
+ }] });
2433
+
2040
2434
  /**
2041
2435
  * UserService is responsible for retrieving and handling user-related data,
2042
2436
  * including the user's photo and short label for avatar display.
@@ -2044,7 +2438,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2044
2438
  class UserService {
2045
2439
  constructor() {
2046
2440
  this.securityService = inject(SecurityService);
2047
- this.baseDataService = inject(BaseDataService);
2441
+ this.userProfileApi = inject(UserProfileApi);
2048
2442
  this.requestedPhotoEmail = null;
2049
2443
  /**
2050
2444
  * Stores the user's photo as a data URL or binary blob, depending on how it's processed.
@@ -2069,11 +2463,18 @@ class UserService {
2069
2463
  const data = this.securityService.getCurrentUser();
2070
2464
  const givenNameInitial = data?.given_name?.trim()?.[0];
2071
2465
  const familyNameInitial = data?.family_name?.trim()?.[0];
2072
- return `${givenNameInitial ?? ''}${familyNameInitial ?? ''}`.toUpperCase();
2466
+ const displayNameInitials = this.getInitials(data?.displayName ?? data?.name ?? data?.userName ?? data?.preferred_username);
2467
+ return `${givenNameInitial ?? ''}${familyNameInitial ?? ''}`.toUpperCase() || displayNameInitials;
2073
2468
  }
2074
2469
  get userName() {
2075
2470
  const data = this.securityService.getCurrentUser();
2076
- return [data?.given_name, data?.family_name].filter(Boolean).join(' ');
2471
+ return [data?.given_name, data?.family_name].filter(Boolean).join(' ')
2472
+ || data?.displayName
2473
+ || data?.name
2474
+ || data?.userName
2475
+ || data?.preferred_username
2476
+ || data?.email
2477
+ || '';
2077
2478
  }
2078
2479
  /**
2079
2480
  * Initiates an HTTP request to fetch the user's photo based on their email,
@@ -2088,8 +2489,7 @@ class UserService {
2088
2489
  return;
2089
2490
  }
2090
2491
  this.requestedPhotoEmail = email;
2091
- const url = this.baseDataService.buildUrl(`api/user-profile/get-user-photo?email=${email}`);
2092
- this.baseDataService.getBlob(url).then((data) => {
2492
+ this.userProfileApi.getUserPhoto({ email }, { format: 'blob' }).then((data) => {
2093
2493
  this.createImageFromBlob(data);
2094
2494
  this.photoLoaded = true;
2095
2495
  }, (error) => {
@@ -2111,6 +2511,16 @@ class UserService {
2111
2511
  reader.readAsDataURL(image);
2112
2512
  }
2113
2513
  }
2514
+ getInitials(value) {
2515
+ return value
2516
+ ?.trim()
2517
+ .split(/\s+/)
2518
+ .filter(Boolean)
2519
+ .slice(0, 2)
2520
+ .map((part) => part[0])
2521
+ .join('')
2522
+ .toUpperCase() ?? '';
2523
+ }
2114
2524
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2115
2525
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserService }); }
2116
2526
  }
@@ -2177,28 +2587,395 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2177
2587
  type: Input
2178
2588
  }] } });
2179
2589
 
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
-
2590
+ const LOGO_COMPONENT_TOKEN = new InjectionToken('LOGO_COMPONENT_TOKEN');
2591
+ function provideLogoComponent(component) {
2592
+ return {
2593
+ provide: LOGO_COMPONENT_TOKEN,
2594
+ useValue: component
2595
+ };
2596
+ }
2597
+ class LogoService {
2598
+ constructor() {
2599
+ this.customLogoComponent = inject(LOGO_COMPONENT_TOKEN, { optional: true });
2600
+ }
2601
+ getLogoComponent() {
2602
+ return this.customLogoComponent || LogoComponent;
2603
+ }
2604
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2605
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, providedIn: 'root' }); }
2606
+ }
2607
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LogoService, decorators: [{
2608
+ type: Injectable,
2609
+ args: [{ providedIn: 'root' }]
2610
+ }] });
2611
+
2612
+ /* eslint-disable */
2613
+ /* tslint:disable */
2614
+ // @ts-nocheck
2615
+ class NotificationApi extends HttpClient {
2616
+ constructor() {
2617
+ super(...arguments);
2618
+ this.getNotificationByUser = (query, params = {}) => this.request({
2619
+ path: `/api/notification/get-notification-by-user`,
2620
+ method: "GET",
2621
+ query: query,
2622
+ secure: true,
2623
+ format: "json",
2624
+ ...params,
2625
+ });
2626
+ this.getNotificationCountByUser = (params = {}) => this.request({
2627
+ path: `/api/notification/get-notification-count-by-user`,
2628
+ method: "GET",
2629
+ secure: true,
2630
+ format: "json",
2631
+ ...params,
2632
+ });
2633
+ this.markNotificationAsRead = ({ id, ...query }, params = {}) => this.request({
2634
+ path: `/api/notification/mark-notification-as-read/${id}`,
2635
+ method: "POST",
2636
+ secure: true,
2637
+ ...params,
2638
+ });
2639
+ this.getNotificationById = (query, params = {}) => this.request({
2640
+ path: `/api/notification/get-notification-by-id`,
2641
+ method: "GET",
2642
+ query: query,
2643
+ secure: true,
2644
+ format: "json",
2645
+ ...params,
2646
+ });
2647
+ }
2648
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2649
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationApi }); }
2650
+ }
2651
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationApi, decorators: [{
2652
+ type: Injectable
2653
+ }] });
2654
+
2655
+ class NotificationService {
2656
+ constructor() {
2657
+ this.securityService = inject(SecurityService);
2658
+ this.msgService = inject(MsgService);
2659
+ this.notificationApi = inject(NotificationApi);
2660
+ this.unreadNotificationCount = signal(undefined, ...(ngDevMode ? [{ debugName: "unreadNotificationCount" }] : []));
2661
+ this.connection = new signalR.HubConnectionBuilder()
2662
+ .withUrl('/hubs/notification', {
2663
+ withCredentials: true,
2664
+ skipNegotiation: true,
2665
+ transport: signalR.HttpTransportType.WebSockets
2666
+ })
2667
+ .configureLogging(signalR.LogLevel.Error)
2668
+ .build();
2669
+ this.connection.on('ReceiveNotification', (notification) => {
2670
+ const opt = {
2671
+ severity: notification.severity,
2672
+ summary: notification.subject,
2673
+ detail: notification.message,
2674
+ life: 0
2675
+ };
2676
+ this.msgService.add(opt);
2677
+ this.unreadNotificationCount.update((count) => (count ?? 0) + 1);
2678
+ });
2679
+ this.securityService.isAuthenticated().subscribe((authenticated) => {
2680
+ if (!authenticated) {
2681
+ this.unreadNotificationCount.set(undefined);
2682
+ if (this.connection.state !== signalR.HubConnectionState.Disconnected) {
2683
+ this.connection.stop();
2684
+ }
2685
+ return;
2686
+ }
2687
+ this.loadUnreadNotificationCount();
2688
+ if (this.connection.state === signalR.HubConnectionState.Disconnected) {
2689
+ this.connection.start().catch((error) => console.error('Failed to start notification connection', error));
2690
+ return;
2691
+ }
2692
+ this.connection.stop().then(() => {
2693
+ this.connection.start().catch((error) => console.error('Failed to restart notification connection', error));
2694
+ });
2695
+ });
2696
+ }
2697
+ loadUnreadNotificationCount() {
2698
+ this.notificationApi
2699
+ .getNotificationCountByUser()
2700
+ .then((response) => this.unreadNotificationCount.set(response.count ?? 0))
2701
+ .catch((error) => console.error('Failed to load notification count', error));
2702
+ }
2703
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2704
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, providedIn: 'root' }); }
2705
+ }
2706
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NotificationService, decorators: [{
2707
+ type: Injectable,
2708
+ args: [{ providedIn: 'root' }]
2709
+ }], ctorParameters: () => [] });
2710
+
2711
+ class UserNotificationsComponent {
2712
+ constructor() {
2713
+ this.notifications = [];
2714
+ this.totalCount = 0;
2715
+ this.skip = 0;
2716
+ this.take = 5;
2717
+ this.loading = false;
2718
+ this.notificationApi = inject(NotificationApi);
2719
+ this.notificationService = inject(NotificationService);
2720
+ this.msgService = inject(MsgService);
2721
+ this.translateService = inject(TranslateService);
2722
+ this.unreadNotificationCount = computed(() => this.notificationService.unreadNotificationCount() ?? 0, ...(ngDevMode ? [{ debugName: "unreadNotificationCount" }] : []));
2723
+ this.unreadNotificationBadge = computed(() => {
2724
+ const count = this.unreadNotificationCount();
2725
+ return count > 99 ? '99+' : count.toString();
2726
+ }, ...(ngDevMode ? [{ debugName: "unreadNotificationBadge" }] : []));
2727
+ }
2728
+ async toggle(event) {
2729
+ this.popover?.toggle(event);
2730
+ await this.loadNotifications();
2731
+ }
2732
+ async loadNotifications() {
2733
+ this.loading = true;
2734
+ try {
2735
+ const response = await this.notificationApi.getNotificationByUser({
2736
+ skip: this.skip,
2737
+ take: this.take,
2738
+ unreadOnly: true
2739
+ });
2740
+ this.notifications = response.notifications ?? [];
2741
+ this.totalCount = response.totalCount ?? 0;
2742
+ }
2743
+ catch (error) {
2744
+ this.msgService.error(error);
2745
+ }
2746
+ finally {
2747
+ this.loading = false;
2748
+ }
2749
+ }
2750
+ async onPageChange(event) {
2751
+ this.skip = event.first ?? 0;
2752
+ this.take = event.rows ?? this.take;
2753
+ await this.loadNotifications();
2754
+ }
2755
+ async markAsRead(notification) {
2756
+ if (!notification.notificationUserId) {
2757
+ return;
2758
+ }
2759
+ this.readingNotificationId = notification.notificationUserId;
2760
+ try {
2761
+ await this.notificationApi.markNotificationAsRead({ id: notification.notificationUserId });
2762
+ this.msgService.success(this.translateService.instant('userNotifications.markedAsRead'));
2763
+ this.notificationService.loadUnreadNotificationCount();
2764
+ if (this.notifications.length === 1 && this.skip > 0) {
2765
+ this.skip = Math.max(this.skip - this.take, 0);
2766
+ }
2767
+ await this.loadNotifications();
2768
+ }
2769
+ catch (error) {
2770
+ this.msgService.error(error);
2771
+ }
2772
+ finally {
2773
+ this.readingNotificationId = undefined;
2774
+ }
2775
+ }
2776
+ getImportanceSeverity(importance) {
2777
+ switch (importance) {
2778
+ case 'Critical':
2779
+ case 'High':
2780
+ return 'danger';
2781
+ case 'Medium':
2782
+ return 'warn';
2783
+ case 'Low':
2784
+ return 'info';
2785
+ default:
2786
+ return 'secondary';
2787
+ }
2788
+ }
2789
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserNotificationsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2790
+ 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: `
2791
+ <button
2792
+ class="layout-topbar-action relative"
2793
+ id="oip-app-topbar-notification-button"
2794
+ type="button"
2795
+ (click)="toggle($event)"
2796
+ [attr.aria-label]="'Notifications: ' + unreadNotificationCount()">
2797
+ <i class="pi pi-bell"></i>
2798
+ @if (unreadNotificationCount() > 0) {
2799
+ <p-badge
2800
+ class="absolute -top-1 -right-1"
2801
+ severity="danger"
2802
+ [badgeSize]="'small'"
2803
+ [value]="unreadNotificationBadge()" />
2804
+ }
2805
+ </button>
2806
+
2807
+ <p-popover #popover styleClass="w-[min(92vw,34rem)]">
2808
+ <div class="flex items-center justify-between gap-3 mb-4">
2809
+ <div class="font-semibold text-lg">
2810
+ {{ 'userNotifications.title' | translate }}
2811
+ </div>
2812
+ <p-button
2813
+ icon="pi pi-refresh"
2814
+ rounded="true"
2815
+ severity="secondary"
2816
+ text="true"
2817
+ tooltipPosition="bottom"
2818
+ [disabled]="loading"
2819
+ [pTooltip]="'userNotifications.refresh' | translate"
2820
+ (onClick)="loadNotifications()"></p-button>
2821
+ </div>
2822
+
2823
+ @if (loading && notifications.length === 0) {
2824
+ <div class="flex justify-center py-8">
2825
+ <p-progressSpinner style="w-8 h-8"></p-progressSpinner>
2826
+ </div>
2827
+ } @else if (notifications.length === 0) {
2828
+ <div class="text-center py-8 text-surface-500">
2829
+ {{ 'userNotifications.empty' | translate }}
2830
+ </div>
2831
+ } @else {
2832
+ <div class="flex flex-col gap-3 max-h-[26rem] overflow-y-auto pr-1">
2833
+ @for (notification of notifications; track notification.notificationUserId) {
2834
+ <div class="border border-surface-200 dark:border-surface-700 rounded-md p-3">
2835
+ <div class="flex items-start justify-between gap-3">
2836
+ <div class="min-w-0">
2837
+ <div class="font-medium leading-snug break-words">
2838
+ {{ notification.subject }}
2839
+ </div>
2840
+ <div class="text-xs text-surface-500 mt-1">
2841
+ {{ notification.createdAt | date: 'dd.MM.yyyy HH:mm' }}
2842
+ </div>
2843
+ </div>
2844
+ @if (notification.importance) {
2845
+ <p-tag
2846
+ class="shrink-0"
2847
+ [severity]="getImportanceSeverity(notification.importance)"
2848
+ [value]="notification.importance"></p-tag>
2849
+ }
2850
+ </div>
2851
+
2852
+ <div class="text-sm text-surface-700 dark:text-surface-200 mt-3 whitespace-pre-line break-words">
2853
+ {{ notification.message }}
2854
+ </div>
2855
+
2856
+ <div class="flex justify-end mt-3">
2857
+ <p-button
2858
+ icon="pi pi-check"
2859
+ size="small"
2860
+ [label]="'userNotifications.markAsRead' | translate"
2861
+ [loading]="readingNotificationId === notification.notificationUserId"
2862
+ (onClick)="markAsRead(notification)"></p-button>
2863
+ </div>
2864
+ </div>
2865
+ }
2866
+ </div>
2867
+
2868
+ <p-paginator
2869
+ styleClass="mt-3"
2870
+ [first]="skip"
2871
+ [rows]="take"
2872
+ [totalRecords]="totalCount"
2873
+ [rowsPerPageOptions]="[5, 10, 20]"
2874
+ (onPageChange)="onPageChange($event)"></p-paginator>
2875
+ }
2876
+ </p-popover>
2877
+ `, 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" }] }); }
2878
+ }
2879
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UserNotificationsComponent, decorators: [{
2880
+ type: Component,
2881
+ args: [{
2882
+ selector: 'app-user-notifications',
2883
+ standalone: true,
2884
+ imports: [CommonModule, BadgeModule, ButtonModule, PaginatorModule, Popover, ProgressSpinnerModule, Tag, Tooltip, TranslatePipe],
2885
+ template: `
2886
+ <button
2887
+ class="layout-topbar-action relative"
2888
+ id="oip-app-topbar-notification-button"
2889
+ type="button"
2890
+ (click)="toggle($event)"
2891
+ [attr.aria-label]="'Notifications: ' + unreadNotificationCount()">
2892
+ <i class="pi pi-bell"></i>
2893
+ @if (unreadNotificationCount() > 0) {
2894
+ <p-badge
2895
+ class="absolute -top-1 -right-1"
2896
+ severity="danger"
2897
+ [badgeSize]="'small'"
2898
+ [value]="unreadNotificationBadge()" />
2899
+ }
2900
+ </button>
2901
+
2902
+ <p-popover #popover styleClass="w-[min(92vw,34rem)]">
2903
+ <div class="flex items-center justify-between gap-3 mb-4">
2904
+ <div class="font-semibold text-lg">
2905
+ {{ 'userNotifications.title' | translate }}
2906
+ </div>
2907
+ <p-button
2908
+ icon="pi pi-refresh"
2909
+ rounded="true"
2910
+ severity="secondary"
2911
+ text="true"
2912
+ tooltipPosition="bottom"
2913
+ [disabled]="loading"
2914
+ [pTooltip]="'userNotifications.refresh' | translate"
2915
+ (onClick)="loadNotifications()"></p-button>
2916
+ </div>
2917
+
2918
+ @if (loading && notifications.length === 0) {
2919
+ <div class="flex justify-center py-8">
2920
+ <p-progressSpinner style="w-8 h-8"></p-progressSpinner>
2921
+ </div>
2922
+ } @else if (notifications.length === 0) {
2923
+ <div class="text-center py-8 text-surface-500">
2924
+ {{ 'userNotifications.empty' | translate }}
2925
+ </div>
2926
+ } @else {
2927
+ <div class="flex flex-col gap-3 max-h-[26rem] overflow-y-auto pr-1">
2928
+ @for (notification of notifications; track notification.notificationUserId) {
2929
+ <div class="border border-surface-200 dark:border-surface-700 rounded-md p-3">
2930
+ <div class="flex items-start justify-between gap-3">
2931
+ <div class="min-w-0">
2932
+ <div class="font-medium leading-snug break-words">
2933
+ {{ notification.subject }}
2934
+ </div>
2935
+ <div class="text-xs text-surface-500 mt-1">
2936
+ {{ notification.createdAt | date: 'dd.MM.yyyy HH:mm' }}
2937
+ </div>
2938
+ </div>
2939
+ @if (notification.importance) {
2940
+ <p-tag
2941
+ class="shrink-0"
2942
+ [severity]="getImportanceSeverity(notification.importance)"
2943
+ [value]="notification.importance"></p-tag>
2944
+ }
2945
+ </div>
2946
+
2947
+ <div class="text-sm text-surface-700 dark:text-surface-200 mt-3 whitespace-pre-line break-words">
2948
+ {{ notification.message }}
2949
+ </div>
2950
+
2951
+ <div class="flex justify-end mt-3">
2952
+ <p-button
2953
+ icon="pi pi-check"
2954
+ size="small"
2955
+ [label]="'userNotifications.markAsRead' | translate"
2956
+ [loading]="readingNotificationId === notification.notificationUserId"
2957
+ (onClick)="markAsRead(notification)"></p-button>
2958
+ </div>
2959
+ </div>
2960
+ }
2961
+ </div>
2962
+
2963
+ <p-paginator
2964
+ styleClass="mt-3"
2965
+ [first]="skip"
2966
+ [rows]="take"
2967
+ [totalRecords]="totalCount"
2968
+ [rowsPerPageOptions]="[5, 10, 20]"
2969
+ (onPageChange)="onPageChange($event)"></p-paginator>
2970
+ }
2971
+ </p-popover>
2972
+ `
2973
+ }]
2974
+ }], propDecorators: { popover: [{
2975
+ type: ViewChild,
2976
+ args: ['popover']
2977
+ }] } });
2978
+
2202
2979
  class AppTopbar {
2203
2980
  constructor() {
2204
2981
  this.securityService = inject(SecurityService);
@@ -2206,6 +2983,8 @@ class AppTopbar {
2206
2983
  this.userService = inject(UserService);
2207
2984
  this.layoutService = inject(LayoutService);
2208
2985
  this.logoService = inject(LogoService);
2986
+ this.confirmationService = inject(ConfirmationService);
2987
+ this.translateService = inject(TranslateService);
2209
2988
  }
2210
2989
  toggleDarkMode() {
2211
2990
  this.layoutService.layoutConfig.update((state) => ({
@@ -2215,11 +2994,32 @@ class AppTopbar {
2215
2994
  }
2216
2995
  logoutKeyDown($event) {
2217
2996
  if ($event.key === 'Enter') {
2218
- this.securityService.logout();
2997
+ $event.preventDefault();
2998
+ this.confirmLogout();
2219
2999
  }
2220
3000
  }
3001
+ confirmLogout() {
3002
+ this.confirmationService.confirm({
3003
+ header: this.translateService.instant('topbar.logoutConfirmHeader'),
3004
+ message: this.translateService.instant('topbar.logoutConfirmMessage'),
3005
+ icon: 'pi pi-sign-out',
3006
+ rejectButtonProps: {
3007
+ label: this.translateService.instant('topbar.logoutConfirmCancel'),
3008
+ severity: 'secondary',
3009
+ outlined: true
3010
+ },
3011
+ acceptButtonProps: {
3012
+ label: this.translateService.instant('topbar.logoutConfirmAccept'),
3013
+ severity: 'danger'
3014
+ },
3015
+ accept: () => {
3016
+ this.securityService.logout();
3017
+ }
3018
+ });
3019
+ }
2221
3020
  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">
3021
+ 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">
3022
+ <p-confirmDialog appendTo="body" />
2223
3023
  <div class="layout-topbar-logo-container">
2224
3024
  <button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
2225
3025
  <i class="pi pi-bars"></i>
@@ -2245,6 +3045,7 @@ class AppTopbar {
2245
3045
  }
2246
3046
  <div class="layout-topbar-actions">
2247
3047
  <div class="layout-config-menu">
3048
+ <app-user-notifications />
2248
3049
  <p-button
2249
3050
  class="layout-topbar-action"
2250
3051
  id="oip-app-topbar-theme-button"
@@ -2295,7 +3096,7 @@ class AppTopbar {
2295
3096
  class="layout-topbar-action"
2296
3097
  id="oip-app-topbar-logout-button"
2297
3098
  type="button"
2298
- (click)="securityService.logout()"
3099
+ (click)="confirmLogout()"
2299
3100
  (keydown)="logoutKeyDown($event)">
2300
3101
  <i class="pi pi-sign-out"></i>
2301
3102
  <span>{{ 'topbar.logout' | translate }}</span>
@@ -2314,7 +3115,7 @@ class AppTopbar {
2314
3115
  </div>
2315
3116
  </div>
2316
3117
  </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" }] }); }
3118
+ </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
3119
  }
2319
3120
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppTopbar, decorators: [{
2320
3121
  type: Component,
@@ -2331,9 +3132,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2331
3132
  Tab,
2332
3133
  AvatarModule,
2333
3134
  ButtonModule,
3135
+ ConfirmDialog,
3136
+ UserNotificationsComponent,
2334
3137
  TranslatePipe
2335
3138
  ],
2336
3139
  template: ` <div class="layout-topbar">
3140
+ <p-confirmDialog appendTo="body" />
2337
3141
  <div class="layout-topbar-logo-container">
2338
3142
  <button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
2339
3143
  <i class="pi pi-bars"></i>
@@ -2359,6 +3163,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2359
3163
  }
2360
3164
  <div class="layout-topbar-actions">
2361
3165
  <div class="layout-config-menu">
3166
+ <app-user-notifications />
2362
3167
  <p-button
2363
3168
  class="layout-topbar-action"
2364
3169
  id="oip-app-topbar-theme-button"
@@ -2409,7 +3214,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2409
3214
  class="layout-topbar-action"
2410
3215
  id="oip-app-topbar-logout-button"
2411
3216
  type="button"
2412
- (click)="securityService.logout()"
3217
+ (click)="confirmLogout()"
2413
3218
  (keydown)="logoutKeyDown($event)">
2414
3219
  <i class="pi pi-sign-out"></i>
2415
3220
  <span>{{ 'topbar.logout' | translate }}</span>
@@ -2428,7 +3233,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2428
3233
  </div>
2429
3234
  </div>
2430
3235
  </div>
2431
- </div>`
3236
+ </div>`,
3237
+ providers: [ConfirmationService]
2432
3238
  }]
2433
3239
  }] });
2434
3240
 
@@ -2471,190 +3277,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2471
3277
  }]
2472
3278
  }] });
2473
3279
 
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
3280
  /* eslint-disable */
2659
3281
  /* tslint:disable */
2660
3282
  // @ts-nocheck
@@ -2720,9 +3342,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2720
3342
  type: Injectable
2721
3343
  }] });
2722
3344
 
2723
- class MenuService extends BaseDataService {
3345
+ class MenuService {
2724
3346
  constructor() {
2725
- super(...arguments);
2726
3347
  this.menuSource = new Subject();
2727
3348
  this.resetSource = new Subject();
2728
3349
  this.titleService = inject(AppTitleService);
@@ -2742,7 +3363,9 @@ class MenuService extends BaseDataService {
2742
3363
  */
2743
3364
  onMenuStateChange(event) {
2744
3365
  this.menuSource.next(event);
2745
- this.titleService.setTitle(event.item.label);
3366
+ if (!event.item.items?.length) {
3367
+ this.titleService.setTitle(event.item.label);
3368
+ }
2746
3369
  }
2747
3370
  reset() {
2748
3371
  this.resetSource.next(true);
@@ -2765,7 +3388,7 @@ class MenuService extends BaseDataService {
2765
3388
  editModuleInstance(item) {
2766
3389
  return this.menuDataService.editModuleInstance(item);
2767
3390
  }
2768
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
3391
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2769
3392
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService }); }
2770
3393
  }
2771
3394
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuService, decorators: [{
@@ -2782,17 +3405,15 @@ class MenuItemComponent {
2782
3405
  this.confirmationService = inject(ConfirmationService);
2783
3406
  this.msgService = inject(MsgService);
2784
3407
  this.menuDataService = inject(MenuApi);
3408
+ this.securityService = inject(SecurityService);
2785
3409
  this.active = false;
2786
3410
  this.subscriptions = [];
2787
3411
  this.localization = {};
2788
3412
  this.key = '';
2789
3413
  this.subscriptions.push(this.menuService.menuSource$.subscribe((value) => {
2790
3414
  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;
3415
+ if (value.routeEvent && (value.key === this.key || value.key.startsWith(this.key + '-'))) {
3416
+ this.active = true;
2796
3417
  }
2797
3418
  });
2798
3419
  }));
@@ -2845,8 +3466,8 @@ class MenuItemComponent {
2845
3466
  }
2846
3467
  this.menuService.onMenuStateChange({ key: this.key, item: this.item });
2847
3468
  }
2848
- get submenuAnimation() {
2849
- return this.root || this.active ? 'expanded' : 'collapsed';
3469
+ get isSubmenuExpanded() {
3470
+ return this.root || this.active;
2850
3471
  }
2851
3472
  get activeClass() {
2852
3473
  return this.active && !this.root;
@@ -2858,6 +3479,11 @@ class MenuItemComponent {
2858
3479
  this.menuItemCreateDialogComponent.showDialog();
2859
3480
  }
2860
3481
  onContextMenu($event, item) {
3482
+ if (!this.securityService.isAdmin()) {
3483
+ return;
3484
+ }
3485
+ $event.stopPropagation();
3486
+ $event.preventDefault();
2861
3487
  this.menuService.contextMenuItem = item;
2862
3488
  this.contextMenu.model = [
2863
3489
  {
@@ -2977,19 +3603,32 @@ class MenuItemComponent {
2977
3603
  hasVisiblePrev(currentItem) {
2978
3604
  const items = this.getItems(currentItem);
2979
3605
  const currentIndex = items.findIndex((item) => item.moduleInstanceId == currentItem.moduleInstanceId);
2980
- return currentIndex > 0;
3606
+ return this.findPrevVisibleItem(items, currentIndex) !== -1;
2981
3607
  }
2982
3608
  getItems(currentItem) {
2983
- return !currentItem.parentId
2984
- ? this.menuService.menu
2985
- : this.menuService.menu.find((m) => m.moduleInstanceId == currentItem.parentId).items;
3609
+ if (!currentItem.parentId) {
3610
+ return this.menuService.menu;
3611
+ }
3612
+ return this.findItemByModuleInstanceId(this.menuService.menu, currentItem.parentId)?.items ?? [];
3613
+ }
3614
+ findItemByModuleInstanceId(items, moduleInstanceId) {
3615
+ for (const item of items) {
3616
+ if (item.moduleInstanceId == moduleInstanceId) {
3617
+ return item;
3618
+ }
3619
+ const foundItem = this.findItemByModuleInstanceId(item.items ?? [], moduleInstanceId);
3620
+ if (foundItem) {
3621
+ return foundItem;
3622
+ }
3623
+ }
3624
+ return null;
2986
3625
  }
2987
3626
  hasVisibleNext(currentItem) {
2988
3627
  const items = this.getItems(currentItem);
2989
3628
  const currentIndex = items.findIndex((item) => item.moduleInstanceId == currentItem.moduleInstanceId);
2990
- return currentIndex < items.length - 1;
3629
+ return this.findNextVisibleIndex(items, currentIndex) !== -1;
2991
3630
  }
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 }); }
3631
+ 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
3632
  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
3633
  <ng-container>
2995
3634
  <p-confirm-dialog />
@@ -3005,7 +3644,8 @@ class MenuItemComponent {
3005
3644
  [attr.href]="item.url"
3006
3645
  [attr.target]="item.target"
3007
3646
  [ngClass]="item.class"
3008
- (click)="itemClick($event)">
3647
+ (click)="itemClick($event)"
3648
+ (contextmenu)="onContextMenu($event, item)">
3009
3649
  <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
3010
3650
  <span class="layout-menuitem-text">{{ item.label }}</span>
3011
3651
  @if (item.items) {
@@ -3047,7 +3687,7 @@ class MenuItemComponent {
3047
3687
  }
3048
3688
 
3049
3689
  @if (item.items && item.visible !== false) {
3050
- <ul [@children]="submenuAnimation" (contextmenu)="onContextMenu($event, item)">
3690
+ <ul class="layout-submenu" [class.layout-submenu-expanded]="isSubmenuExpanded">
3051
3691
  @for (child of item.items; track child; let i = $index) {
3052
3692
  <li
3053
3693
  app-menuitem
@@ -3062,17 +3702,7 @@ class MenuItemComponent {
3062
3702
  </ul>
3063
3703
  }
3064
3704
  </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
- ] }); }
3705
+ `, 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
3706
  }
3077
3707
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemComponent, decorators: [{
3078
3708
  type: Component,
@@ -3094,7 +3724,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3094
3724
  [attr.href]="item.url"
3095
3725
  [attr.target]="item.target"
3096
3726
  [ngClass]="item.class"
3097
- (click)="itemClick($event)">
3727
+ (click)="itemClick($event)"
3728
+ (contextmenu)="onContextMenu($event, item)">
3098
3729
  <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
3099
3730
  <span class="layout-menuitem-text">{{ item.label }}</span>
3100
3731
  @if (item.items) {
@@ -3136,7 +3767,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3136
3767
  }
3137
3768
 
3138
3769
  @if (item.items && item.visible !== false) {
3139
- <ul [@children]="submenuAnimation" (contextmenu)="onContextMenu($event, item)">
3770
+ <ul class="layout-submenu" [class.layout-submenu-expanded]="isSubmenuExpanded">
3140
3771
  @for (child of item.items; track child; let i = $index) {
3141
3772
  <li
3142
3773
  app-menuitem
@@ -3152,21 +3783,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3152
3783
  }
3153
3784
  </ng-container>
3154
3785
  `,
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
3786
  imports: [RippleModule, NgClass, RouterLinkActive, RouterLink, ContextMenuModule, ConfirmDialog],
3167
3787
  providers: [ConfirmationService]
3168
3788
  }]
3169
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$3.Router }, { type: MenuService }], propDecorators: { item: [{
3789
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$4.Router }, { type: MenuService }], propDecorators: { item: [{
3170
3790
  type: Input
3171
3791
  }], index: [{
3172
3792
  type: Input
@@ -3205,6 +3825,9 @@ class MenuItemCreateDialogComponent {
3205
3825
  this.selectIcon = 'pi pi-box';
3206
3826
  this.saving = false;
3207
3827
  }
3828
+ get canSave() {
3829
+ return !this.saving && !!this.selectModule;
3830
+ }
3208
3831
  async ngOnInit() {
3209
3832
  this.modules = await this.menu.getModules();
3210
3833
  }
@@ -3216,6 +3839,9 @@ class MenuItemCreateDialogComponent {
3216
3839
  if (this.saving) {
3217
3840
  return;
3218
3841
  }
3842
+ if (!this.selectModule) {
3843
+ return;
3844
+ }
3219
3845
  const item = {
3220
3846
  moduleId: this.selectModule,
3221
3847
  label: this.label,
@@ -3229,7 +3855,7 @@ class MenuItemCreateDialogComponent {
3229
3855
  this.hide();
3230
3856
  }
3231
3857
  catch (error) {
3232
- this.msgService.error(error);
3858
+ this.msgService.errorFromException(error, 'Unexpected error');
3233
3859
  }
3234
3860
  finally {
3235
3861
  this.saving = false;
@@ -3324,12 +3950,12 @@ class MenuItemCreateDialogComponent {
3324
3950
  <p-button
3325
3951
  id="oip-menu-item-create-save"
3326
3952
  label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
3327
- [disabled]="saving"
3953
+ [disabled]="!canSave"
3328
3954
  [loading]="saving"
3329
3955
  (click)="save()" />
3330
3956
  </div>
3331
3957
  </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" }] }); }
3958
+ `, 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
3959
  }
3334
3960
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemCreateDialogComponent, decorators: [{
3335
3961
  type: Component,
@@ -3417,7 +4043,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3417
4043
  <p-button
3418
4044
  id="oip-menu-item-create-save"
3419
4045
  label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
3420
- [disabled]="saving"
4046
+ [disabled]="!canSave"
3421
4047
  [loading]="saving"
3422
4048
  (click)="save()" />
3423
4049
  </div>
@@ -3433,7 +4059,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3433
4059
  class MenuItemEditDialogComponent {
3434
4060
  constructor() {
3435
4061
  this.menuService = inject(MenuService);
3436
- this.securityDataService = inject(SecurityDataService);
4062
+ this.securityApi = inject(SecurityApi);
3437
4063
  this.msgService = inject(MsgService);
3438
4064
  this.visibleChange = new EventEmitter();
3439
4065
  this.modules = [];
@@ -3489,7 +4115,7 @@ class MenuItemEditDialogComponent {
3489
4115
  icon: this.menuService.contextMenuItem?.icon,
3490
4116
  viewRoles: this.menuService.contextMenuItem?.securities
3491
4117
  };
3492
- this.roles = await this.securityDataService.getRealmRoles();
4118
+ this.roles = await this.securityApi.getRealmRoles();
3493
4119
  this.menuService.getModules().then((data) => {
3494
4120
  this.modules = data;
3495
4121
  });
@@ -3575,7 +4201,7 @@ class MenuItemEditDialogComponent {
3575
4201
  (click)="save()" />
3576
4202
  </div>
3577
4203
  </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" }] }); }
4204
+ `, 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
4205
  }
3580
4206
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuItemEditDialogComponent, decorators: [{
3581
4207
  type: Component,
@@ -3682,6 +4308,9 @@ class MenuComponent {
3682
4308
  this.menuItemCreateDialogComponent.showDialog();
3683
4309
  }
3684
4310
  onContextMenu($event) {
4311
+ if (!this.securityService.isAdmin()) {
4312
+ return;
4313
+ }
3685
4314
  this.menuService.contextMenuItem = null;
3686
4315
  this.contextMenu.model = [
3687
4316
  {
@@ -3713,11 +4342,11 @@ class MenuComponent {
3713
4342
  }
3714
4343
  </ul>
3715
4344
  </div>
3716
- <p-contextMenu [target]="empty"/>
3717
4345
  @if (securityService.isAdmin()) {
4346
+ <p-contextMenu [target]="empty"/>
3718
4347
  <menu-item-create-dialog/>
3719
4348
  <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"] }] }); }
4349
+ }`, 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
4350
  }
3722
4351
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MenuComponent, decorators: [{
3723
4352
  type: Component,
@@ -3756,8 +4385,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3756
4385
  }
3757
4386
  </ul>
3758
4387
  </div>
3759
- <p-contextMenu [target]="empty"/>
3760
4388
  @if (securityService.isAdmin()) {
4389
+ <p-contextMenu [target]="empty"/>
3761
4390
  <menu-item-create-dialog/>
3762
4391
  <menu-item-edit-dialog/>
3763
4392
  }`
@@ -3878,7 +4507,7 @@ class AppLayoutComponent {
3878
4507
  </div>
3879
4508
  <div class="layout-mask animate-fadein"></div>
3880
4509
  </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" }] }); }
4510
+ `, 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
4511
  }
3883
4512
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppLayoutComponent, decorators: [{
3884
4513
  type: Component,
@@ -3945,7 +4574,7 @@ class AppFloatingConfiguratorComponent {
3945
4574
  <app-configurator />
3946
4575
  </div>
3947
4576
  </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" }] }); }
4577
+ `, 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
4578
  }
3950
4579
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppFloatingConfiguratorComponent, decorators: [{
3951
4580
  type: Component,
@@ -4036,73 +4665,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4036
4665
  standalone: true
4037
4666
  }]
4038
4667
  }], 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>
4668
+
4669
+ class UnauthorizedComponent {
4670
+ constructor() {
4671
+ this.securityService = inject(SecurityService);
4672
+ this.route = inject(ActivatedRoute);
4673
+ this.router = inject(Router);
4674
+ }
4675
+ signIn() {
4676
+ const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl') || '/';
4677
+ this.router.navigate(['/unauthorized'], {
4678
+ queryParams: { returnUrl },
4679
+ replaceUrl: true
4680
+ }).then(() => this.securityService.authorize());
4681
+ }
4682
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UnauthorizedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4683
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: UnauthorizedComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
4684
+ <app-floating-configurator />
4685
+ <div
4686
+ class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
4687
+ <div class="flex flex-col items-center justify-center">
4688
+ <div
4689
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
4690
+ <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
4691
+ <div class="flex flex-col items-center justify-center">
4692
+ <logo [height]="96" [width]="96" />
4693
+ </div>
4694
+ <div class="text-center mb-8">
4695
+ <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
4696
+ {{ 'unauthorized.welcomeToOip' | translate }}
4697
+ </div>
4698
+ <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
4699
+ </div>
4700
+ <div>
4701
+ <p-button
4702
+ id="oip-unauthorized-error-sign-in-button"
4703
+ label="{{ 'unauthorized.signIn' | translate }}"
4704
+ styleClass="w-full"
4705
+ (click)="signIn()"></p-button>
4706
+ </div>
4707
+ </div>
4708
+ </div>
4709
+ </div>
4710
+ </div>
4073
4711
  `, 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
4712
  }
4075
4713
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: UnauthorizedComponent, decorators: [{
4076
4714
  type: Component,
4077
4715
  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>
4716
+ template: `
4717
+ <app-floating-configurator />
4718
+ <div
4719
+ class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
4720
+ <div class="flex flex-col items-center justify-center">
4721
+ <div
4722
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
4723
+ <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
4724
+ <div class="flex flex-col items-center justify-center">
4725
+ <logo [height]="96" [width]="96" />
4726
+ </div>
4727
+ <div class="text-center mb-8">
4728
+ <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
4729
+ {{ 'unauthorized.welcomeToOip' | translate }}
4730
+ </div>
4731
+ <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
4732
+ </div>
4733
+ <div>
4734
+ <p-button
4735
+ id="oip-unauthorized-error-sign-in-button"
4736
+ label="{{ 'unauthorized.signIn' | translate }}"
4737
+ styleClass="w-full"
4738
+ (click)="signIn()"></p-button>
4739
+ </div>
4740
+ </div>
4741
+ </div>
4742
+ </div>
4743
+ </div>
4106
4744
  `,
4107
4745
  imports: [
4108
4746
  ButtonModule,
@@ -4147,7 +4785,7 @@ class ErrorComponent {
4147
4785
  </div>
4148
4786
  </div>
4149
4787
  </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"] }] }); }
4788
+ </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
4789
  }
4152
4790
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ErrorComponent, decorators: [{
4153
4791
  type: Component,
@@ -4220,7 +4858,7 @@ class ProfileComponent {
4220
4858
  [auto]="true"
4221
4859
  (onUpload)="onBasicUploadAuto($event)" />
4222
4860
  </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" }] }); }
4861
+ `, 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
4862
  }
4225
4863
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ProfileComponent, decorators: [{
4226
4864
  type: Component,
@@ -4260,7 +4898,6 @@ class ConfigComponent {
4260
4898
  this.userService = inject(UserService);
4261
4899
  this.securityService = inject(SecurityService);
4262
4900
  this.menuService = inject(MenuService);
4263
- this.l10n = {};
4264
4901
  this.dateFormats = ['dd.MM.yyyy', 'dd.MM.yy', 'yyyy-MM-dd', 'dd.MMM.yyyy'];
4265
4902
  this.timeFormats = ['HH:mm:ss', 'HH:mm'];
4266
4903
  // @ts-ignore
@@ -4291,204 +4928,204 @@ class ConfigComponent {
4291
4928
  await this.menuService.loadMenu();
4292
4929
  }
4293
4930
  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>
4931
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ConfigComponent, isStandalone: true, selector: "app-config", ngImport: i0, template: `
4932
+ <div class="flex flex-col md:flex-row gap-4">
4933
+ <div class="md:w-1/2">
4934
+ <div class="card flex flex-col gap-4">
4935
+ <div class="font-semibold text-xl">{{ 'config.profile' | translate }}</div>
4936
+ <div class="flex justify-content-end flex-wrap">
4937
+ {{ userService.userName }}
4938
+ </div>
4939
+ <label>
4940
+ {{ 'config.photo' | translate }}
4941
+ <span
4942
+ class="pi pi-question-circle"
4943
+ pTooltip="{{ 'config.usePhoto256x256Pixel' | translate }}"
4944
+ tooltipPosition="right"></span>
4945
+ </label>
4946
+ <div class="flex justify-content-end flex-wrap">
4947
+ <user-profile></user-profile>
4948
+ </div>
4949
+ </div>
4950
+ </div>
4951
+ <div class="md:w-1/2">
4952
+ <div class="card flex flex-col gap-4">
4953
+ <div class="font-semibold text-xl">{{ 'config.localization' | translate }}</div>
4954
+ <label> {{ 'config.selectLanguage' | translate }} </label>
4955
+ <div class="flex justify-content-end flex-wrap">
4956
+ <p-select
4957
+ class="w-full md:w-56"
4958
+ optionLabel="name"
4959
+ optionValue="code"
4960
+ qa-id="oip-app-config-language-select"
4961
+ [options]="l10nService.availableLanguages"
4962
+ [(ngModel)]="selectedLanguage"
4963
+ (onChange)="changeLanguage()">
4964
+ <ng-template #selectedItem let-selectedOption>
4965
+ <div class="flex items-center gap-2">
4966
+ <span [class]="selectedOption.icon"></span>
4967
+ <div>{{ selectedOption.name }}</div>
4968
+ </div>
4969
+ </ng-template>
4970
+ <ng-template #item let-languages>
4971
+ <div class="flex items-center gap-2">
4972
+ <span [class]="languages.icon"></span>
4973
+ <div>{{ languages.name }}</div>
4974
+ </div>
4975
+ </ng-template>
4976
+ </p-select>
4977
+ </div>
4978
+ <div class="flex flex-col gap-5">
4979
+ <div class="mt-5">{{ 'config.dateTimeFormat' | translate }}</div>
4980
+ <p-select
4981
+ class="w-full md:w-56"
4982
+ qa-id="oip-app-config-date-format-select"
4983
+ [options]="dateFormats"
4984
+ [placeholder]="'config.dateFormat' | translate"
4985
+ [(ngModel)]="selectedDateFormat"
4986
+ (onChange)="changeDateFormat()" />
4987
+ <p-select
4988
+ class="w-full md:w-56"
4989
+ qa-id="oip-app-config-time-format-select"
4990
+ [options]="timeFormats"
4991
+ [placeholder]="'config.timeFormat' | translate"
4992
+ [(ngModel)]="selectedTimeFormat"
4993
+ (onChange)="changeTimeFormat()" />
4994
+ <div class="mt-5">{{ 'config.timeZone' | translate }}</div>
4995
+ <p-select
4996
+ class="w-full md:w-56"
4997
+ qa-id="oip-app-config-timezone-select"
4998
+ [filter]="true"
4999
+ [options]="allTimeZones"
5000
+ [placeholder]="'config.timeZone' | translate"
5001
+ [virtualScroll]="true"
5002
+ [virtualScrollItemSize]="34"
5003
+ [(ngModel)]="selectedTimeZone"
5004
+ (onChange)="changeTimeZone()" />
5005
+ </div>
5006
+ </div>
5007
+ </div>
5008
+ @if (securityService.isAdmin()) {
5009
+ <div class="md:w-1/2">
5010
+ <div class="card flex flex-col gap-4">
5011
+ <div class="font-semibold text-xl">{{ 'config.menu' | translate }}</div>
5012
+ <div class="flex items-center gap-2">
5013
+ <label for="oip-app-config-admin-mode">{{ 'config.all' | translate }}</label>
5014
+ <p-toggle-switch
5015
+ id="oip-app-config-admin-mode"
5016
+ [(ngModel)]="menuService.adminMode"
5017
+ (onChange)="onSwitchChange()"></p-toggle-switch>
5018
+ </div>
5019
+ <div class="flex items-center gap-2">
5020
+ <label for="oip-app-config-admin-mode">{{ 'config.moduleManagement' | translate }}</label>
5021
+ <p-button icon="pi pi-cog" label="{{ 'config.goTo' | translate }}" routerLink="/modules" />
5022
+ </div>
5023
+ </div>
5024
+ </div>
5025
+ }
5026
+ </div>
4390
5027
  `, 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
5028
  }
4392
5029
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ConfigComponent, decorators: [{
4393
5030
  type: Component,
4394
5031
  args: [{
4395
5032
  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>
5033
+ template: `
5034
+ <div class="flex flex-col md:flex-row gap-4">
5035
+ <div class="md:w-1/2">
5036
+ <div class="card flex flex-col gap-4">
5037
+ <div class="font-semibold text-xl">{{ 'config.profile' | translate }}</div>
5038
+ <div class="flex justify-content-end flex-wrap">
5039
+ {{ userService.userName }}
5040
+ </div>
5041
+ <label>
5042
+ {{ 'config.photo' | translate }}
5043
+ <span
5044
+ class="pi pi-question-circle"
5045
+ pTooltip="{{ 'config.usePhoto256x256Pixel' | translate }}"
5046
+ tooltipPosition="right"></span>
5047
+ </label>
5048
+ <div class="flex justify-content-end flex-wrap">
5049
+ <user-profile></user-profile>
5050
+ </div>
5051
+ </div>
5052
+ </div>
5053
+ <div class="md:w-1/2">
5054
+ <div class="card flex flex-col gap-4">
5055
+ <div class="font-semibold text-xl">{{ 'config.localization' | translate }}</div>
5056
+ <label> {{ 'config.selectLanguage' | translate }} </label>
5057
+ <div class="flex justify-content-end flex-wrap">
5058
+ <p-select
5059
+ class="w-full md:w-56"
5060
+ optionLabel="name"
5061
+ optionValue="code"
5062
+ qa-id="oip-app-config-language-select"
5063
+ [options]="l10nService.availableLanguages"
5064
+ [(ngModel)]="selectedLanguage"
5065
+ (onChange)="changeLanguage()">
5066
+ <ng-template #selectedItem let-selectedOption>
5067
+ <div class="flex items-center gap-2">
5068
+ <span [class]="selectedOption.icon"></span>
5069
+ <div>{{ selectedOption.name }}</div>
5070
+ </div>
5071
+ </ng-template>
5072
+ <ng-template #item let-languages>
5073
+ <div class="flex items-center gap-2">
5074
+ <span [class]="languages.icon"></span>
5075
+ <div>{{ languages.name }}</div>
5076
+ </div>
5077
+ </ng-template>
5078
+ </p-select>
5079
+ </div>
5080
+ <div class="flex flex-col gap-5">
5081
+ <div class="mt-5">{{ 'config.dateTimeFormat' | translate }}</div>
5082
+ <p-select
5083
+ class="w-full md:w-56"
5084
+ qa-id="oip-app-config-date-format-select"
5085
+ [options]="dateFormats"
5086
+ [placeholder]="'config.dateFormat' | translate"
5087
+ [(ngModel)]="selectedDateFormat"
5088
+ (onChange)="changeDateFormat()" />
5089
+ <p-select
5090
+ class="w-full md:w-56"
5091
+ qa-id="oip-app-config-time-format-select"
5092
+ [options]="timeFormats"
5093
+ [placeholder]="'config.timeFormat' | translate"
5094
+ [(ngModel)]="selectedTimeFormat"
5095
+ (onChange)="changeTimeFormat()" />
5096
+ <div class="mt-5">{{ 'config.timeZone' | translate }}</div>
5097
+ <p-select
5098
+ class="w-full md:w-56"
5099
+ qa-id="oip-app-config-timezone-select"
5100
+ [filter]="true"
5101
+ [options]="allTimeZones"
5102
+ [placeholder]="'config.timeZone' | translate"
5103
+ [virtualScroll]="true"
5104
+ [virtualScrollItemSize]="34"
5105
+ [(ngModel)]="selectedTimeZone"
5106
+ (onChange)="changeTimeZone()" />
5107
+ </div>
5108
+ </div>
5109
+ </div>
5110
+ @if (securityService.isAdmin()) {
5111
+ <div class="md:w-1/2">
5112
+ <div class="card flex flex-col gap-4">
5113
+ <div class="font-semibold text-xl">{{ 'config.menu' | translate }}</div>
5114
+ <div class="flex items-center gap-2">
5115
+ <label for="oip-app-config-admin-mode">{{ 'config.all' | translate }}</label>
5116
+ <p-toggle-switch
5117
+ id="oip-app-config-admin-mode"
5118
+ [(ngModel)]="menuService.adminMode"
5119
+ (onChange)="onSwitchChange()"></p-toggle-switch>
5120
+ </div>
5121
+ <div class="flex items-center gap-2">
5122
+ <label for="oip-app-config-admin-mode">{{ 'config.moduleManagement' | translate }}</label>
5123
+ <p-button icon="pi pi-cog" label="{{ 'config.goTo' | translate }}" routerLink="/modules" />
5124
+ </div>
5125
+ </div>
5126
+ </div>
5127
+ }
5128
+ </div>
4492
5129
  `,
4493
5130
  imports: [
4494
5131
  ProfileComponent,
@@ -4524,11 +5161,11 @@ class DbMigrationComponent extends BaseModuleComponent {
4524
5161
  });
4525
5162
  }
4526
5163
  async getData() {
4527
- return this.baseDataService.sendRequest(`api/${this.controller}/get-migrations`, 'GET');
5164
+ return this.getMigrations();
4528
5165
  }
4529
5166
  async applyMigration(rowData) {
4530
5167
  const request = { name: rowData.name };
4531
- return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
5168
+ return this.applyModuleMigration(request);
4532
5169
  }
4533
5170
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DbMigrationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4534
5171
  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 +5246,7 @@ class DbMigrationComponent extends BaseModuleComponent {
4609
5246
  } @else if (isSecurity) {
4610
5247
  <security [controller]="controller" [id]="id"/>
4611
5248
  }
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" }] }); }
5249
+ `, 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
5250
  }
4614
5251
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DbMigrationComponent, decorators: [{
4615
5252
  type: Component,
@@ -4757,7 +5394,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4757
5394
 
4758
5395
  class AppModulesComponent {
4759
5396
  constructor() {
4760
- this.dataService = inject(BaseDataService);
4761
5397
  this.modules = [];
4762
5398
  this.msgService = inject(MsgService);
4763
5399
  this.confirmationService = inject(ConfirmationService);
@@ -4791,7 +5427,7 @@ class AppModulesComponent {
4791
5427
  },
4792
5428
  accept: async () => {
4793
5429
  try {
4794
- await this.dataService.sendRequest(`api/module/delete`, 'DELETE', {
5430
+ await this.moduleService.delete({
4795
5431
  moduleId: module.moduleId
4796
5432
  });
4797
5433
  await this.refreshAction();
@@ -4861,7 +5497,7 @@ class AppModulesComponent {
4861
5497
  </p-table>
4862
5498
  </div>
4863
5499
  </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" }] }); }
5500
+ `, 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
5501
  }
4866
5502
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AppModulesComponent, decorators: [{
4867
5503
  type: Component,
@@ -4933,17 +5569,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4933
5569
  class DiscussionApi extends HttpClient {
4934
5570
  constructor() {
4935
5571
  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
5572
  this.getByObject = (query, params = {}) => this.request({
4948
5573
  path: `/api/discussion/get-by-object`,
4949
5574
  method: "GET",
@@ -4952,18 +5577,6 @@ class DiscussionApi extends HttpClient {
4952
5577
  format: "json",
4953
5578
  ...params,
4954
5579
  });
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
5580
  this.getById = (query, params = {}) => this.request({
4968
5581
  path: `/api/discussion/get-by-id`,
4969
5582
  method: "GET",
@@ -4972,18 +5585,6 @@ class DiscussionApi extends HttpClient {
4972
5585
  format: "json",
4973
5586
  ...params,
4974
5587
  });
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
5588
  this.create = (data, params = {}) => this.request({
4988
5589
  path: `/api/discussion/create`,
4989
5590
  method: "POST",
@@ -4993,20 +5594,6 @@ class DiscussionApi extends HttpClient {
4993
5594
  format: "json",
4994
5595
  ...params,
4995
5596
  });
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
5597
  this.update = ({ id, ...query }, data, params = {}) => this.request({
5011
5598
  path: `/api/discussion/update/${id}`,
5012
5599
  method: "PUT",
@@ -5016,37 +5603,12 @@ class DiscussionApi extends HttpClient {
5016
5603
  format: "json",
5017
5604
  ...params,
5018
5605
  });
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
5606
  this.delete = ({ id, ...query }, params = {}) => this.request({
5033
5607
  path: `/api/discussion/delete/${id}`,
5034
5608
  method: "DELETE",
5035
5609
  secure: true,
5036
5610
  ...params,
5037
5611
  });
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
5612
  this.getHistory = ({ id, ...query }, params = {}) => this.request({
5051
5613
  path: `/api/discussion/get-history/${id}`,
5052
5614
  method: "GET",
@@ -5054,20 +5616,6 @@ class DiscussionApi extends HttpClient {
5054
5616
  format: "json",
5055
5617
  ...params,
5056
5618
  });
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
5619
  this.uploadAttachment = (data, params = {}) => this.request({
5072
5620
  path: `/api/discussion/upload-attachment`,
5073
5621
  method: "POST",
@@ -5077,56 +5625,18 @@ class DiscussionApi extends HttpClient {
5077
5625
  format: "json",
5078
5626
  ...params,
5079
5627
  });
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
5628
  this.deleteAttachment = ({ id, ...query }, params = {}) => this.request({
5094
5629
  path: `/api/discussion/delete-attachment/${id}`,
5095
5630
  method: "DELETE",
5096
5631
  secure: true,
5097
5632
  ...params,
5098
5633
  });
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
5634
  this.getAttachmentContent = ({ id, ...query }, params = {}) => this.request({
5112
5635
  path: `/api/discussion/get-attachment-content/${id}`,
5113
5636
  method: "GET",
5114
5637
  secure: true,
5115
5638
  ...params,
5116
5639
  });
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
5640
  this.addReaction = (data, params = {}) => this.request({
5131
5641
  path: `/api/discussion/add-reaction`,
5132
5642
  method: "POST",
@@ -5136,18 +5646,6 @@ class DiscussionApi extends HttpClient {
5136
5646
  format: "json",
5137
5647
  ...params,
5138
5648
  });
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
5649
  this.removeReaction = (query, params = {}) => this.request({
5152
5650
  path: `/api/discussion/remove-reaction`,
5153
5651
  method: "DELETE",
@@ -5156,18 +5654,6 @@ class DiscussionApi extends HttpClient {
5156
5654
  format: "json",
5157
5655
  ...params,
5158
5656
  });
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
5657
  this.searchMentionUsers = (query, params = {}) => this.request({
5172
5658
  path: `/api/discussion/search-mention-users`,
5173
5659
  method: "GET",
@@ -5930,7 +6416,7 @@ class DiscussionComponent {
5930
6416
  </div>
5931
6417
  }
5932
6418
  </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 }); }
6419
+ `, 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
6420
  }
5935
6421
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DiscussionComponent, decorators: [{
5936
6422
  type: Component,
@@ -6456,31 +6942,14 @@ class AuthGuardService {
6456
6942
  *
6457
6943
  * @returns {Observable<boolean | UrlTree>} A stream resolving to true (allow), or UrlTree (redirect).
6458
6944
  */
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
- }));
6945
+ canActivate(returnUrl = '/') {
6946
+ this.oidcSecurityService.auth();
6947
+ return this.oidcSecurityService.isAuthenticated().pipe(map((authenticated) => authenticated
6948
+ ? true
6949
+ : this.router.createUrlTree(['/unauthorized'], { queryParams: { returnUrl: this.getReturnUrl(returnUrl) } })));
6470
6950
  }
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
- }));
6951
+ getReturnUrl(returnUrl) {
6952
+ return returnUrl.startsWith('/unauthorized') ? '/' : returnUrl;
6484
6953
  }
6485
6954
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthGuardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6486
6955
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthGuardService }); }
@@ -6489,80 +6958,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6489
6958
  type: Injectable
6490
6959
  }] });
6491
6960
 
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
6961
  /**
6567
6962
  * Prime-ng table filter service
6568
6963
  */
@@ -6637,73 +7032,96 @@ function replaceDefaults(themes) {
6637
7032
 
6638
7033
  const langIntercept = (req, next) => {
6639
7034
  const layoutService = inject(LayoutService);
7035
+ const securityService = inject(SecurityService);
6640
7036
  const lang = layoutService.language() ? layoutService.language() : 'en';
6641
- const httpHeaders = req.headers.set('Accept-language', lang);
6642
- const authReq = req.clone({
6643
- headers: httpHeaders
7037
+ const headers = req.headers
7038
+ .set('Accept-language', lang)
7039
+ .set('X-Timezone', layoutService.timeZone());
7040
+ const reqWithCredentials = req.clone({
7041
+ headers,
7042
+ withCredentials: true
6644
7043
  });
6645
- return next(authReq);
7044
+ if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method.toUpperCase())) {
7045
+ return next(reqWithCredentials);
7046
+ }
7047
+ if (req.url.includes('/api/security/create-auth-session') || req.url.includes('/api/security/get-auth-csrf-token')) {
7048
+ return next(reqWithCredentials);
7049
+ }
7050
+ return securityService.getCsrfToken().pipe(take(1), switchMap((csrfToken) => next(csrfToken?.token
7051
+ ? reqWithCredentials.clone({
7052
+ headers: reqWithCredentials.headers.set(csrfToken.headerName, csrfToken.token)
7053
+ })
7054
+ : reqWithCredentials)));
6646
7055
  };
6647
7056
 
6648
- class SecurePipe {
7057
+ const httpLoaderFactory = (http) => new TranslateHttpLoader(http);
7058
+ function provideOip() {
7059
+ return makeEnvironmentProviders([
7060
+ provideHttpClient(withInterceptors([langIntercept]), withFetch()),
7061
+ { provide: LocationStrategy, useClass: PathLocationStrategy },
7062
+ { provide: SecurityService, useClass: BffSecurityService },
7063
+ AuthGuardService,
7064
+ MessageService,
7065
+ UserService,
7066
+ NotificationService,
7067
+ UserProfileApi,
7068
+ SecurityApi,
7069
+ NotificationApi,
7070
+ importProvidersFrom([
7071
+ TranslateModule.forRoot({
7072
+ loader: {
7073
+ provide: TranslateLoader,
7074
+ useFactory: httpLoaderFactory,
7075
+ deps: [HttpClient$1]
7076
+ }
7077
+ })
7078
+ ])
7079
+ ]);
7080
+ }
7081
+
7082
+ /* eslint-disable */
7083
+ /* tslint:disable */
7084
+ // @ts-nocheck
7085
+ class FolderModuleApi extends HttpClient {
6649
7086
  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))));
7087
+ super(...arguments);
7088
+ this.getModuleInstanceSettings = (query, params = {}) => this.request({
7089
+ path: `/api/folder-module/get-module-instance-settings`,
7090
+ method: "GET",
7091
+ query: query,
7092
+ secure: true,
7093
+ format: "json",
7094
+ ...params,
7095
+ });
6657
7096
  }
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" }); }
7097
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FolderModuleApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
7098
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FolderModuleApi }); }
6660
7099
  }
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
- }]
7100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FolderModuleApi, decorators: [{
7101
+ type: Injectable
6667
7102
  }] });
6668
7103
 
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));
7104
+ /* eslint-disable */
7105
+ /* tslint:disable */
7106
+ // @ts-nocheck
7107
+ class IframeModuleApi extends HttpClient {
7108
+ constructor() {
7109
+ super(...arguments);
7110
+ this.getModuleInstanceSettings = (query, params = {}) => this.request({
7111
+ path: `/api/iframe-module/get-module-instance-settings`,
7112
+ method: "GET",
7113
+ query: query,
7114
+ secure: true,
7115
+ format: "json",
7116
+ ...params,
6684
7117
  });
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
7118
  }
6706
- };
7119
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
7120
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleApi }); }
7121
+ }
7122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: IframeModuleApi, decorators: [{
7123
+ type: Injectable
7124
+ }] });
6707
7125
 
6708
7126
  // Components
6709
7127
 
@@ -6711,5 +7129,5 @@ const httpLoaderAuthFactory = (httpClient) => {
6711
7129
  * Generated bundle index. Do not edit.
6712
7130
  */
6713
7131
 
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 };
7132
+ 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
7133
  //# sourceMappingURL=oip-common.mjs.map