oip-common 0.0.3 → 0.0.5

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.
Files changed (95) hide show
  1. package/fesm2022/oip-common.mjs +4267 -0
  2. package/fesm2022/oip-common.mjs.map +1 -0
  3. package/index.d.ts +1028 -0
  4. package/package.json +17 -5
  5. package/ng-package.json +0 -19
  6. package/src/api/FolderModule.ts +0 -124
  7. package/src/api/Menu.ts +0 -134
  8. package/src/api/Module.ts +0 -92
  9. package/src/api/Security.ts +0 -40
  10. package/src/api/Service.ts +0 -57
  11. package/src/api/data-contracts.ts +0 -186
  12. package/src/api/http-client.ts +0 -276
  13. package/src/components/app-configurator.component.ts +0 -491
  14. package/src/components/app-floating-configurator.component.ts +0 -47
  15. package/src/components/app-modules.component.ts +0 -144
  16. package/src/components/app.layout.component.ts +0 -130
  17. package/src/components/auth/access/access.component.ts +0 -42
  18. package/src/components/auth/error/error.component.ts +0 -42
  19. package/src/components/auth/login/login.component.ts +0 -120
  20. package/src/components/auth/unauthorized/unauthorized.component.ts +0 -51
  21. package/src/components/base-module.component.ts +0 -258
  22. package/src/components/config.component.ts +0 -131
  23. package/src/components/db-migration/db-migration.component.ts +0 -162
  24. package/src/components/db-migration.component.ts +0 -154
  25. package/src/components/footer.component.ts +0 -17
  26. package/src/components/logo.component.ts +0 -34
  27. package/src/components/menu/menu-item-create-dialog.component.ts +0 -119
  28. package/src/components/menu/menu-item-edit-dialog.component.ts +0 -123
  29. package/src/components/menu/menu-item.component.ts +0 -295
  30. package/src/components/menu/menu.component.ts +0 -85
  31. package/src/components/notfound.component.ts +0 -31
  32. package/src/components/profile.component.ts +0 -43
  33. package/src/components/security.component.ts +0 -102
  34. package/src/components/sidebar.component.ts +0 -12
  35. package/src/components/top-bar.component.ts +0 -147
  36. package/src/dtos/context-menu-item.dto.ts +0 -23
  37. package/src/dtos/edit-module-instance.dto.ts +0 -8
  38. package/src/dtos/no-settings.dto.ts +0 -4
  39. package/src/dtos/put-security.dto.ts +0 -6
  40. package/src/dtos/security.dto.ts +0 -6
  41. package/src/dtos/top-bar.dto.ts +0 -13
  42. package/src/events/menu-change.event.ts +0 -23
  43. package/src/helpers/date.helper.ts +0 -94
  44. package/src/intercepts/i18n-intercept.service.ts +0 -13
  45. package/src/modules/http-loader.factory.ts +0 -40
  46. package/src/modules/secure.pipe.ts +0 -19
  47. package/src/public-api.ts +0 -42
  48. package/src/services/app-title.service.ts +0 -22
  49. package/src/services/app.layout.service.ts +0 -236
  50. package/src/services/app.menu.service.ts +0 -64
  51. package/src/services/auth.service.ts +0 -58
  52. package/src/services/base-data.service.ts +0 -74
  53. package/src/services/l10n.service.ts +0 -71
  54. package/src/services/msg.service.ts +0 -76
  55. package/src/services/security-data.service.ts +0 -19
  56. package/src/services/security-storage.service.ts +0 -21
  57. package/src/services/security.service.ts +0 -116
  58. package/src/services/top-bar.service.ts +0 -44
  59. package/src/services/user.service.ts +0 -77
  60. package/src/test.ts +0 -11
  61. package/src/user-api/UserProfile.ts +0 -85
  62. package/src/user-api/data-contracts.ts +0 -42
  63. package/src/user-api/http-client.ts +0 -251
  64. package/tsconfig.lib.json +0 -12
  65. package/tsconfig.lib.prod.json +0 -10
  66. package/tsconfig.spec.json +0 -9
  67. /package/{src/assets → assets}/demo/code.scss +0 -0
  68. /package/{src/assets → assets}/demo/demo.scss +0 -0
  69. /package/{src/assets → assets}/demo/flags/flags.scss +0 -0
  70. /package/{src/assets → assets}/demo/flags/flags_responsive.png +0 -0
  71. /package/{src/assets → assets}/demo/images/access/asset-access.svg +0 -0
  72. /package/{src/assets → assets}/demo/images/error/asset-error.svg +0 -0
  73. /package/{src/assets → assets}/demo/images/flag/flag_placeholder.png +0 -0
  74. /package/{src/assets → assets}/favicon.svg +0 -0
  75. /package/{src/assets → assets}/i18n/app-modules.en.json +0 -0
  76. /package/{src/assets → assets}/i18n/app-modules.ru.json +0 -0
  77. /package/{src/assets → assets}/i18n/config.en.json +0 -0
  78. /package/{src/assets → assets}/i18n/config.ru.json +0 -0
  79. /package/{src/assets → assets}/layout/_core.scss +0 -0
  80. /package/{src/assets → assets}/layout/_footer.scss +0 -0
  81. /package/{src/assets → assets}/layout/_logo.scss +0 -0
  82. /package/{src/assets → assets}/layout/_main.scss +0 -0
  83. /package/{src/assets → assets}/layout/_menu.scss +0 -0
  84. /package/{src/assets → assets}/layout/_mixins.scss +0 -0
  85. /package/{src/assets → assets}/layout/_preloading.scss +0 -0
  86. /package/{src/assets → assets}/layout/_responsive.scss +0 -0
  87. /package/{src/assets → assets}/layout/_topbar.scss +0 -0
  88. /package/{src/assets → assets}/layout/_typography.scss +0 -0
  89. /package/{src/assets → assets}/layout/_utils.scss +0 -0
  90. /package/{src/assets → assets}/layout/layout.scss +0 -0
  91. /package/{src/assets → assets}/layout/variables/_common.scss +0 -0
  92. /package/{src/assets → assets}/layout/variables/_dark.scss +0 -0
  93. /package/{src/assets → assets}/layout/variables/_light.scss +0 -0
  94. /package/{src/assets → assets}/oip-common.scss +0 -0
  95. /package/{src/assets → assets}/tailwind.css +0 -0
@@ -0,0 +1,4267 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, ChangeDetectorRef, signal, effect, Component, Input, computed, PLATFORM_ID, HostBinding, EventEmitter, Output, ViewChild, Renderer2, Pipe } from '@angular/core';
3
+ import * as i2$3 from 'primeng/api';
4
+ import { MessageService, ConfirmationService, PrimeIcons, SharedModule } from 'primeng/api';
5
+ import { HttpErrorResponse, HttpClient as HttpClient$1, HttpHeaders } from '@angular/common/http';
6
+ import { TranslateService, TranslatePipe } from '@ngx-translate/core';
7
+ import * as i1$3 from '@angular/router';
8
+ import { ActivatedRoute, Router, RouterModule, NavigationEnd, RouterLinkActive, RouterLink } from '@angular/router';
9
+ import { lastValueFrom, BehaviorSubject, Subject, filter as filter$1, combineLatest, of, map as map$1, Observable } from 'rxjs';
10
+ import { Title, DomSanitizer } from '@angular/platform-browser';
11
+ import * as i1 from 'primeng/multiselect';
12
+ import { MultiSelectModule } from 'primeng/multiselect';
13
+ import * as i2 from 'primeng/tooltip';
14
+ import { TooltipModule, Tooltip } from 'primeng/tooltip';
15
+ import * as i1$1 from 'primeng/button';
16
+ import { ButtonModule, Button } from 'primeng/button';
17
+ import * as i5 from '@angular/forms';
18
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
19
+ import * as i1$2 from '@angular/common';
20
+ import { isPlatformBrowser, CommonModule, NgIf, NgClass, NgFor } from '@angular/common';
21
+ import * as i4 from 'primeng/styleclass';
22
+ import { StyleClassModule } from 'primeng/styleclass';
23
+ import { updatePreset, updateSurfacePalette, $t } from '@primeng/themes';
24
+ import Aura from '@primeng/themes/aura';
25
+ import Lara from '@primeng/themes/lara';
26
+ import Nora from '@primeng/themes/nora';
27
+ import { PrimeNG } from 'primeng/config';
28
+ import * as i3 from 'primeng/selectbutton';
29
+ import { SelectButtonModule } from 'primeng/selectbutton';
30
+ import { OidcSecurityService, PublicEventsService, EventTypes, StsConfigHttpLoader } from 'angular-auth-oidc-client';
31
+ import { filter, map, switchMap, catchError } from 'rxjs/operators';
32
+ import { Tabs, TabList, Tab } from 'primeng/tabs';
33
+ import * as i5$1 from 'primeng/avatar';
34
+ import { AvatarModule } from 'primeng/avatar';
35
+ import * as i1$4 from 'primeng/contextmenu';
36
+ import { ContextMenuModule, ContextMenu } from 'primeng/contextmenu';
37
+ import * as i2$1 from 'primeng/dialog';
38
+ import { DialogModule } from 'primeng/dialog';
39
+ import * as i3$2 from 'primeng/inputtext';
40
+ import { InputTextModule } from 'primeng/inputtext';
41
+ import { trigger, state, transition, style, animate } from '@angular/animations';
42
+ import * as i3$1 from 'primeng/ripple';
43
+ import { RippleModule } from 'primeng/ripple';
44
+ import { ConfirmDialog } from 'primeng/confirmdialog';
45
+ import * as i4$1 from 'primeng/select';
46
+ import { SelectModule, Select } from 'primeng/select';
47
+ import * as i1$5 from 'primeng/fileupload';
48
+ import { FileUploadModule } from 'primeng/fileupload';
49
+ import { ImageModule } from 'primeng/image';
50
+ import { Fluid } from 'primeng/fluid';
51
+ import * as i1$6 from 'primeng/table';
52
+ import { TableModule } from 'primeng/table';
53
+ import * as i2$2 from 'primeng/toggleswitch';
54
+ import { ToggleSwitchModule } from 'primeng/toggleswitch';
55
+ import { TagModule, Tag } from 'primeng/tag';
56
+ import { TextareaModule } from 'primeng/textarea';
57
+ import * as i4$2 from 'primeng/toolbar';
58
+ import { ToolbarModule } from 'primeng/toolbar';
59
+
60
+ class TopBarService {
61
+ get availableTopBarItems() {
62
+ return this.topBarItems;
63
+ }
64
+ get activeTopBarItem() {
65
+ if (this._activeId === undefined) {
66
+ return undefined;
67
+ }
68
+ return this.topBarItems.find((topBarItem) => topBarItem.id === this._activeId);
69
+ }
70
+ get activeId() {
71
+ return this._activeId;
72
+ }
73
+ set activeId(value) {
74
+ this._activeId = value;
75
+ if (this.activeTopBarItem?.click)
76
+ this.activeTopBarItem.click();
77
+ }
78
+ constructor() {
79
+ this.topBarItems = [];
80
+ }
81
+ // Set tob bar items
82
+ setTopBarItems(items) {
83
+ this.topBarItems = items;
84
+ }
85
+ checkId(id) {
86
+ if (this.activeTopBarItem === undefined && id === 'content')
87
+ return true;
88
+ if (this.activeTopBarItem === undefined)
89
+ return false;
90
+ return this.activeTopBarItem.id == id;
91
+ }
92
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: TopBarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
93
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: TopBarService, providedIn: 'root' }); }
94
+ }
95
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: TopBarService, decorators: [{
96
+ type: Injectable,
97
+ args: [{
98
+ providedIn: 'root'
99
+ }]
100
+ }], ctorParameters: () => [] });
101
+
102
+ class MsgService {
103
+ constructor() {
104
+ this.messageService = inject(MessageService);
105
+ this.translate = inject(TranslateService);
106
+ this.lifetime = 2000;
107
+ }
108
+ add(msg) {
109
+ this.messageService.add(msg);
110
+ }
111
+ success(detail, summary = this.translate.instant('msgService.success'), life = this.lifetime) {
112
+ this.messageService.add({
113
+ severity: 'success',
114
+ summary: summary,
115
+ detail: detail,
116
+ life: life
117
+ });
118
+ }
119
+ info(detail, summary = this.translate.instant('msgService.info'), life = this.lifetime) {
120
+ this.messageService.add({
121
+ severity: 'info',
122
+ summary: summary,
123
+ detail: detail,
124
+ life: life
125
+ });
126
+ }
127
+ warn(detail, summary = this.translate.instant('msgService.warn'), life = this.lifetime) {
128
+ this.messageService.add({
129
+ severity: 'warn',
130
+ summary: summary,
131
+ detail: detail,
132
+ life: life
133
+ });
134
+ }
135
+ error(detail, summary = this.translate.instant('msgService.error'), life = this.lifetime) {
136
+ if (detail instanceof HttpErrorResponse) {
137
+ summary = `Error: ${detail.status} ${detail.statusText}`;
138
+ detail = `${detail.name} \r\n ${detail.message}`;
139
+ }
140
+ this.messageService.add({
141
+ severity: 'error',
142
+ summary: summary,
143
+ detail: detail.toString(),
144
+ life: life
145
+ });
146
+ }
147
+ contrast(detail, summary = this.translate.instant('msgService.error'), life = this.lifetime) {
148
+ this.messageService.add({
149
+ severity: 'contrast',
150
+ summary: summary,
151
+ detail: detail,
152
+ life: life
153
+ });
154
+ }
155
+ secondary(detail, summary = this.translate.instant('msgService.secondary'), life = this.lifetime) {
156
+ this.messageService.add({
157
+ severity: 'secondary',
158
+ summary: summary,
159
+ detail: detail,
160
+ life: life
161
+ });
162
+ }
163
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MsgService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
164
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MsgService, providedIn: 'root' }); }
165
+ }
166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MsgService, decorators: [{
167
+ type: Injectable,
168
+ args: [{
169
+ providedIn: 'root'
170
+ }]
171
+ }] });
172
+
173
+ /**
174
+ * BaseDataService provides a unified interface for sending HTTP requests
175
+ * using Angular's HttpClient. It supports standard HTTP methods and automatic
176
+ * credential handling.
177
+ */
178
+ class BaseDataService {
179
+ constructor() {
180
+ this.http = inject(HttpClient$1);
181
+ }
182
+ /**
183
+ * Gets the base URL of the application from the HTML <base> tag.
184
+ */
185
+ get baseUrl() {
186
+ return document.getElementsByTagName('base')[0].href;
187
+ }
188
+ /**
189
+ * Sends an HTTP request with the specified method and data.
190
+ *
191
+ * @template TResponse - Expected response type.
192
+ * @param url - The target URL for the HTTP request.
193
+ * @param method - The HTTP method to use (GET, PUT, POST, DELETE). Default is 'GET'.
194
+ * @param data - An object containing request parameters or payload.
195
+ * @returns A promise that resolves to the response of type TResponse.
196
+ */
197
+ sendRequest(url, method = 'GET', data = {}) {
198
+ const httpOptions = { withCredentials: true };
199
+ let result;
200
+ switch (method) {
201
+ case 'GET':
202
+ result = this.http.get(url, { params: data });
203
+ break;
204
+ case 'PUT':
205
+ result = this.http.put(url, data, httpOptions);
206
+ break;
207
+ case 'POST':
208
+ result = this.http.post(url, data, httpOptions);
209
+ break;
210
+ case 'DELETE':
211
+ result = this.http.request('DELETE', url, {
212
+ body: data,
213
+ headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
214
+ withCredentials: true
215
+ });
216
+ break;
217
+ }
218
+ return lastValueFrom(result);
219
+ }
220
+ /**
221
+ * Sends a GET request and retrieves a response as a Blob.
222
+ *
223
+ * @param url - The target URL for the GET request.
224
+ * @returns A promise that resolves to a Object response.
225
+ */
226
+ getBlob(url) {
227
+ const httpOptions = {
228
+ responseType: 'blob',
229
+ withCredentials: true
230
+ };
231
+ const result = this.http.get(url, httpOptions);
232
+ return lastValueFrom(result);
233
+ }
234
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: BaseDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
235
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: BaseDataService }); }
236
+ }
237
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: BaseDataService, decorators: [{
238
+ type: Injectable
239
+ }] });
240
+
241
+ /**
242
+ * Service to manage the application title.
243
+ */
244
+ class AppTitleService {
245
+ constructor() {
246
+ this.title = inject(Title);
247
+ this.titleSubject = new BehaviorSubject('');
248
+ this.title$ = this.titleSubject.asObservable();
249
+ }
250
+ /**
251
+ * Set the title of the current HTML document.
252
+ * @param newTitle
253
+ */
254
+ setTitle(newTitle) {
255
+ this.title.setTitle(newTitle);
256
+ this.titleSubject.next(newTitle);
257
+ }
258
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppTitleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
259
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppTitleService, providedIn: 'root' }); }
260
+ }
261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppTitleService, decorators: [{
262
+ type: Injectable,
263
+ args: [{ providedIn: 'root' }]
264
+ }] });
265
+
266
+ class BaseModuleComponent {
267
+ /**
268
+ * Updates local settings and persists them to local storage.
269
+ * @return {void}
270
+ */
271
+ onConfigUpdate() {
272
+ if (Object.keys(this.localSettings()).length > 0) {
273
+ this._localSettings = { ...this.localSettings() };
274
+ this.localSettingsUpdate.next(this._localSettings);
275
+ localStorage.setItem(`Instance_${this.id}`, JSON.stringify(this._localSettings));
276
+ }
277
+ }
278
+ getLocalStorageSettings() {
279
+ try {
280
+ const localStorageSettingsString = localStorage.getItem(`Instance_${this.id}`);
281
+ if (localStorageSettingsString != null) {
282
+ this.localSettings.set(JSON.parse(localStorageSettingsString));
283
+ }
284
+ }
285
+ catch (error) {
286
+ this.msgService.error(error, 'Error parsing layoutConfig:');
287
+ this.localSettings.set({});
288
+ }
289
+ }
290
+ /**
291
+ * Checks if the content ID is present.
292
+ * @returns {boolean} True if the content ID is present, false otherwise.
293
+ */
294
+ get isContent() {
295
+ return this.topBarService.checkId('content');
296
+ }
297
+ /**
298
+ * Checks if the settings ID is present.
299
+ * @returns {boolean} True if the settings ID is present, false otherwise.
300
+ */
301
+ get isSettings() {
302
+ return this.topBarService.checkId('settings');
303
+ }
304
+ /**
305
+ * Checks if the security ID is present.
306
+ * @returns {boolean} True if the security ID is present, false otherwise.
307
+ */
308
+ get isSecurity() {
309
+ return this.topBarService.checkId('security');
310
+ }
311
+ /**
312
+ * Initializes the component and subscribes to local settings updates.
313
+ */
314
+ constructor() {
315
+ /**
316
+ * Provides access to topbar related functionality, such as managing visibility and content.
317
+ * @type {TopBarService}
318
+ */
319
+ this.topBarService = inject(TopBarService);
320
+ /**
321
+ * Provides access to information about the current route.
322
+ * This includes route parameters, data, and the route's path.
323
+ */
324
+ this.route = inject(ActivatedRoute);
325
+ /**
326
+ * Provides access to messaging services.
327
+ */
328
+ this.msgService = inject(MsgService);
329
+ /**
330
+ * Provides access to base data service functionality.
331
+ * @deprecated The method should not be used
332
+ */
333
+ this.baseDataService = inject(BaseDataService);
334
+ /**
335
+ * Provides access to translation functionality.
336
+ */
337
+ this.translateService = inject(TranslateService);
338
+ /**
339
+ * Provides access to the application's title service.
340
+ */
341
+ this.appTitleService = inject(AppTitleService);
342
+ /**
343
+ * Reference to the ChangeDetector. Used to trigger change detection manually.
344
+ */
345
+ this.changeDetectorRef = inject(ChangeDetectorRef);
346
+ /**
347
+ * Represents a subscription to an observable.
348
+ * Manages the lifecycle of receiving data from the observable and allows unsubscribing to stop receiving data.
349
+ * @type {Subscription}
350
+ */
351
+ this.subscriptions = [];
352
+ /**
353
+ * Configuration object for backend storage
354
+ * @type {TBackendStoreSettings}
355
+ */
356
+ this.settings = {};
357
+ /**
358
+ * Configuration object for local storage.
359
+ * @type {TLocalStoreSettings}
360
+ */
361
+ this._localSettings = {};
362
+ /**
363
+ * A signal representing the local application settings. Changes to this signal
364
+ * propagate updates to the underlying local store settings.
365
+ * @type {WritableSignal<TLocalStoreSettings>}
366
+ */
367
+ this.localSettings = signal(this._localSettings, ...(ngDevMode ? [{ debugName: "localSettings" }] : []));
368
+ /**
369
+ * A Subject emitting updates to local store settings. Observables can subscribe to this Subject to react to changes in local settings.
370
+ * @type {Subject<TLocalStoreSettings>}
371
+ */
372
+ this.localSettingsUpdate = new Subject();
373
+ /**
374
+ * A unique numerical identifier for the module.
375
+ * @type {number}
376
+ */
377
+ this.id = undefined;
378
+ /**
379
+ * Defines the top bar items.
380
+ */
381
+ this.topBarItems = [
382
+ { id: 'content', icon: 'pi-box', caption: '' },
383
+ { id: 'settings', icon: 'pi-cog', caption: '' },
384
+ { id: 'security', icon: 'pi-lock', caption: '' }
385
+ ];
386
+ effect(() => {
387
+ const config = this.localSettings();
388
+ if (config) {
389
+ this.onConfigUpdate();
390
+ }
391
+ });
392
+ this.subscriptions.push(this.route.url.subscribe((url) => {
393
+ this.controller = url[0].path;
394
+ }));
395
+ this.subscriptions.push(this.route.paramMap.subscribe((params) => {
396
+ this.id = +params.get('id');
397
+ this.getLocalStorageSettings();
398
+ }));
399
+ }
400
+ /**
401
+ * Lifecycle hook that is called when a component is destroyed.
402
+ * Unsubscribes from all subscriptions to prevent memory leaks,
403
+ * resets the top bar items to an empty array, and sets the active ID
404
+ * to the ID of the first top bar item (if available).
405
+ */
406
+ ngOnDestroy() {
407
+ this.topBarService.setTopBarItems([]);
408
+ this.topBarService.activeId = this.topBarItems[0].id;
409
+ this.subscriptions.forEach((s) => s.unsubscribe());
410
+ }
411
+ /**
412
+ * Initializes the component. Subscribes to translation service to set captions for top bar items,
413
+ * sets the top bar items via the top bar service, sets the active ID,
414
+ * subscribes to route parameters to get the ID, and retrieves settings.
415
+ * @return {Promise<void>} A promise that resolves when the initialization is complete.
416
+ */
417
+ async ngOnInit() {
418
+ this.subscriptions.push(this.translateService.get('baseComponent').subscribe((value) => {
419
+ this.topBarItems[0].caption = value.content;
420
+ this.topBarItems[1].caption = value.settings;
421
+ this.topBarItems[2].caption = value.security;
422
+ }));
423
+ this.topBarService.setTopBarItems(this.topBarItems);
424
+ this.topBarService.activeId = this.topBarItems[0].id;
425
+ await this.getSettings();
426
+ this.subscriptions.push(this.appTitleService.title$.subscribe((title) => {
427
+ this.title = title;
428
+ this.changeDetectorRef.detectChanges();
429
+ }));
430
+ }
431
+ /**
432
+ * Retrieves module instance settings.
433
+ * @return {Promise<void>} A promise that resolves when settings are retrieved.
434
+ */
435
+ async getSettings() {
436
+ try {
437
+ this.settings = await this.baseDataService.sendRequest(`${this.baseDataService.baseUrl}api/${this.controller}/get-module-instance-settings?id=${this.id}`);
438
+ }
439
+ catch (error) {
440
+ this.msgService.error(error);
441
+ }
442
+ }
443
+ /**
444
+ * Saves the provided settings to the backend.
445
+ * @param {TLocalStoreSettings} settings - The settings object to save.
446
+ * @return {Promise<void>} A promise that resolves when the settings are saved. Reject if an error occurs.
447
+ */
448
+ async saveSettings(settings) {
449
+ await this.baseDataService
450
+ .sendRequest(`api/${this.controller}/put-module-instance-settings`, 'PUT', {
451
+ id: this.id,
452
+ settings: settings
453
+ })
454
+ .then(() => {
455
+ this.msgService.success(this.translateService.instant('baseComponent.success'));
456
+ })
457
+ .catch((error) => {
458
+ this.msgService.error(error);
459
+ });
460
+ }
461
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: BaseModuleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
462
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: BaseModuleComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '', isInline: true }); }
463
+ }
464
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: BaseModuleComponent, decorators: [{
465
+ type: Component,
466
+ args: [{ standalone: true, template: '' }]
467
+ }], ctorParameters: () => [] });
468
+
469
+ class SecurityDataService extends BaseDataService {
470
+ getSecurity(controller, id) {
471
+ return this.sendRequest(this.baseUrl + `api/${controller}/get-security?id=${id}`);
472
+ }
473
+ saveSecurity(controller, request) {
474
+ return this.sendRequest(this.baseUrl + `api/${controller}/put-security`, 'PUT', request);
475
+ }
476
+ getRealmRoles() {
477
+ return this.sendRequest(this.baseUrl + `api/security/get-realm-roles`);
478
+ }
479
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityDataService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
480
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityDataService }); }
481
+ }
482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityDataService, decorators: [{
483
+ type: Injectable
484
+ }] });
485
+
486
+ class SecurityComponent {
487
+ constructor() {
488
+ this.msgService = inject(MsgService);
489
+ this.dataService = inject(SecurityDataService);
490
+ this.translateService = inject(TranslateService);
491
+ this.roles = [];
492
+ }
493
+ ngOnDestroy() {
494
+ // on destroy
495
+ }
496
+ ngOnInit() {
497
+ if (!this.id) {
498
+ this.msgService.error('Module id not passed!');
499
+ }
500
+ if (!this.controller) {
501
+ this.msgService.error('Controller not passed!');
502
+ }
503
+ this.dataService.getSecurity(this.controller, this.id).then((result) => {
504
+ this.securityData = result;
505
+ }, (error) => this.msgService.error(error));
506
+ this.dataService.getRealmRoles().then((result) => {
507
+ this.roles = result;
508
+ }, (error) => this.msgService.error(error));
509
+ }
510
+ saveClick() {
511
+ const request = {
512
+ id: this.id,
513
+ securities: this.securityData
514
+ };
515
+ this.dataService.saveSecurity(this.controller, request).then((result) => {
516
+ this.msgService.success(this.translateService.instant('securityComponent.savedSecurity'));
517
+ }, (error) => this.msgService.error(error));
518
+ }
519
+ saveKeyDown($event) {
520
+ if ($event.key === 'Enter' || $event.key === 'Space') {
521
+ this.saveKeyDown(null);
522
+ }
523
+ }
524
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
525
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: SecurityComponent, isStandalone: true, selector: "security", inputs: { id: "id", controller: "controller" }, ngImport: i0, template: `
526
+ <div class="flex flex-col md:flex-row gap-8">
527
+ <div class="md:w-1/2">
528
+ <div class="card flex flex-col gap-4">
529
+ <div class="font-semibold text-xl">
530
+ {{ 'securityComponent.security' | translate }}
531
+ </div>
532
+ @for (item of securityData; track item.name) {
533
+ <div class="flex flex-col gap-2">
534
+ <label htmlFor="oip-security-multiselect-{{ item.name }}">
535
+ {{ item.name }}
536
+ <span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
537
+ </label>
538
+ <p-multiSelect
539
+ id="oip-security-multiselect-{{ item.name }}"
540
+ placeholder="Select roles"
541
+ [maxSelectedLabels]="10"
542
+ [options]="roles"
543
+ [(ngModel)]="item.roles" />
544
+ </div>
545
+ }
546
+ <div class="flex justify-content-end flex-wrap">
547
+ <p-button
548
+ icon="pi pi-save"
549
+ id="oip-security-save-button"
550
+ label="{{ 'securityComponent.save' | translate }}"
551
+ (click)="saveClick()"
552
+ (keydown)="saveKeyDown($event)" />
553
+ </div>
554
+ </div>
555
+ </div>
556
+ </div>
557
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i1.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
558
+ }
559
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityComponent, decorators: [{
560
+ type: Component,
561
+ args: [{
562
+ selector: 'security',
563
+ template: `
564
+ <div class="flex flex-col md:flex-row gap-8">
565
+ <div class="md:w-1/2">
566
+ <div class="card flex flex-col gap-4">
567
+ <div class="font-semibold text-xl">
568
+ {{ 'securityComponent.security' | translate }}
569
+ </div>
570
+ @for (item of securityData; track item.name) {
571
+ <div class="flex flex-col gap-2">
572
+ <label htmlFor="oip-security-multiselect-{{ item.name }}">
573
+ {{ item.name }}
574
+ <span class="pi pi-question-circle" pTooltip="{{ item.description }}" tooltipPosition="right"></span>
575
+ </label>
576
+ <p-multiSelect
577
+ id="oip-security-multiselect-{{ item.name }}"
578
+ placeholder="Select roles"
579
+ [maxSelectedLabels]="10"
580
+ [options]="roles"
581
+ [(ngModel)]="item.roles" />
582
+ </div>
583
+ }
584
+ <div class="flex justify-content-end flex-wrap">
585
+ <p-button
586
+ icon="pi pi-save"
587
+ id="oip-security-save-button"
588
+ label="{{ 'securityComponent.save' | translate }}"
589
+ (click)="saveClick()"
590
+ (keydown)="saveKeyDown($event)" />
591
+ </div>
592
+ </div>
593
+ </div>
594
+ </div>
595
+ `,
596
+ imports: [MultiSelectModule, TooltipModule, FormsModule, ButtonModule, TranslatePipe],
597
+ standalone: true
598
+ }]
599
+ }], propDecorators: { id: [{
600
+ type: Input
601
+ }], controller: [{
602
+ type: Input
603
+ }] } });
604
+
605
+ /**
606
+ * Convert Date to string in format 2022-02-22
607
+ * @param date
608
+ */
609
+ function dateToString(date) {
610
+ const year = date.getFullYear();
611
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
612
+ const day = date.getDate().toString().padStart(2, '0');
613
+ return `${year}-${month}-${day}`;
614
+ }
615
+ /**
616
+ * Convert string in format 2022-02-22 to Date
617
+ * @param date
618
+ */
619
+ function stringToDate(date) {
620
+ const dateParts = date.split('-');
621
+ const day = parseInt(dateParts[2], 10);
622
+ const month = parseInt(dateParts[1], 10) - 1;
623
+ const year = parseInt(dateParts[0], 10);
624
+ return new Date(year, month, day);
625
+ }
626
+ /**
627
+ * Add days to date
628
+ * @param date
629
+ * @param days
630
+ */
631
+ function addDays(date, days) {
632
+ const clonedDate = structuredClone(date);
633
+ clonedDate.setDate(clonedDate.getDate() + days);
634
+ return clonedDate;
635
+ }
636
+ /**
637
+ * Get today's date
638
+ * @param date
639
+ */
640
+ function getTodayDate() {
641
+ const date = new Date();
642
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
643
+ }
644
+ /* Convert dateformat from DatePipe to PrimeNG*/
645
+ function convertToPrimeNgDateFormat(dateformat) {
646
+ switch (dateformat) {
647
+ case 'dd.MM.yyyy':
648
+ return 'dd.mm.yy';
649
+ case 'dd.MM.yy':
650
+ return 'dd.mm.y';
651
+ case 'yyyy-MM-dd':
652
+ return 'yy-mm-dd';
653
+ case 'dd.MMM.yyyy':
654
+ return 'dd.M.yy';
655
+ default:
656
+ console.error(`Failed to convert format: ${dateformat}`);
657
+ }
658
+ }
659
+ /**
660
+ * Convert all properties of an object with string dates to Date objects
661
+ * @param obj
662
+ */
663
+ function restoreDates(obj) {
664
+ if (obj === null || typeof obj !== 'object')
665
+ return obj;
666
+ if (Array.isArray(obj)) {
667
+ return obj.map((item) => restoreDates(item));
668
+ }
669
+ const result = {};
670
+ for (const key in obj) {
671
+ const value = obj[key];
672
+ if (typeof value === 'string' && isIsoDate(value)) {
673
+ result[key] = new Date(value);
674
+ }
675
+ else if (typeof value === 'object' && value !== null && !(value instanceof Date)) {
676
+ result[key] = restoreDates(value);
677
+ }
678
+ else {
679
+ result[key] = value;
680
+ }
681
+ }
682
+ return result;
683
+ }
684
+ /**
685
+ * Check if a string is a date in ISO format
686
+ * @param str
687
+ */
688
+ function isIsoDate(str) {
689
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/.test(str);
690
+ }
691
+
692
+ class LayoutService {
693
+ constructor() {
694
+ this._config = this.getAppConfigFromStorage();
695
+ this._state = {
696
+ staticMenuDesktopInactive: false,
697
+ overlayMenuActive: false,
698
+ configSidebarVisible: false,
699
+ staticMenuMobileActive: false,
700
+ menuHoverActive: false
701
+ };
702
+ this.layoutConfig = signal(this._config, ...(ngDevMode ? [{ debugName: "layoutConfig" }] : []));
703
+ this.layoutState = signal(this._state, ...(ngDevMode ? [{ debugName: "layoutState" }] : []));
704
+ this.configUpdate = new Subject();
705
+ this.overlayOpen = new Subject();
706
+ this.menuSource = new Subject();
707
+ this.resetSource = new Subject();
708
+ this.menuSource$ = this.menuSource.asObservable();
709
+ this.resetSource$ = this.resetSource.asObservable();
710
+ this.configUpdate$ = this.configUpdate.asObservable();
711
+ this.overlayOpen$ = this.overlayOpen.asObservable();
712
+ this.theme = computed(() => (this.layoutConfig()?.darkTheme ? 'light' : 'dark'), ...(ngDevMode ? [{ debugName: "theme" }] : []));
713
+ this.isSidebarActive = computed(() => this.layoutState().overlayMenuActive || this.layoutState().staticMenuMobileActive, ...(ngDevMode ? [{ debugName: "isSidebarActive" }] : []));
714
+ this.isDarkTheme = computed(() => this.layoutConfig().darkTheme, ...(ngDevMode ? [{ debugName: "isDarkTheme" }] : []));
715
+ this.getPrimary = computed(() => this.layoutConfig().primary, ...(ngDevMode ? [{ debugName: "getPrimary" }] : []));
716
+ this.getSurface = computed(() => this.layoutConfig().surface, ...(ngDevMode ? [{ debugName: "getSurface" }] : []));
717
+ this.isOverlay = computed(() => this.layoutConfig().menuMode === 'overlay', ...(ngDevMode ? [{ debugName: "isOverlay" }] : []));
718
+ this.language = computed(() => this.layoutConfig().language, ...(ngDevMode ? [{ debugName: "language" }] : []));
719
+ this.dateFormat = computed(() => this.layoutConfig().dateFormat, ...(ngDevMode ? [{ debugName: "dateFormat" }] : []));
720
+ this.primeNgDateFormat = computed(() => convertToPrimeNgDateFormat(this.layoutConfig().dateFormat), ...(ngDevMode ? [{ debugName: "primeNgDateFormat" }] : []));
721
+ this.timeFormat = computed(() => this.layoutConfig().timeFormat, ...(ngDevMode ? [{ debugName: "timeFormat" }] : []));
722
+ this.dateTimeFormat = computed(() => `${this.layoutConfig().dateFormat} ${this.layoutConfig().timeFormat}`, ...(ngDevMode ? [{ debugName: "dateTimeFormat" }] : []));
723
+ this.monthFormat = computed(() => {
724
+ const reDay = /d+/i;
725
+ const reDelimeter = /^[^\w]|[^\w]$|([^\w])\1+/;
726
+ const ngDateFormat = convertToPrimeNgDateFormat(this.layoutConfig().dateFormat);
727
+ const ngDate = ngDateFormat.replace(reDay, '');
728
+ const dateGroups = ngDate.match(reDelimeter);
729
+ if (Array.isArray(dateGroups) && dateGroups.length > 1) {
730
+ return dateGroups[1] !== undefined
731
+ ? ngDate.replace(dateGroups[0], '')
732
+ : ngDate.startsWith(dateGroups[0])
733
+ ? ngDate.substring(1)
734
+ : ngDate.substring(0, ngDate.length - 1);
735
+ }
736
+ return ngDateFormat;
737
+ }, ...(ngDevMode ? [{ debugName: "monthFormat" }] : []));
738
+ this.timeZone = computed(() => this.layoutConfig().timeZone, ...(ngDevMode ? [{ debugName: "timeZone" }] : []));
739
+ this.transitionComplete = signal(false, ...(ngDevMode ? [{ debugName: "transitionComplete" }] : []));
740
+ this.initialized = false;
741
+ effect(() => {
742
+ const config = this.layoutConfig();
743
+ if (config) {
744
+ this.onConfigUpdate();
745
+ }
746
+ });
747
+ effect(() => {
748
+ const config = this.layoutConfig();
749
+ if (!this.initialized || !config) {
750
+ this.initialized = true;
751
+ return;
752
+ }
753
+ this.handleDarkModeTransition(config);
754
+ });
755
+ }
756
+ /**
757
+ * Get application settings from browser storage
758
+ * @returns AppConfig
759
+ */
760
+ getAppConfigFromStorage() {
761
+ const appConfigUiString = localStorage.getItem('layoutConfig');
762
+ if (appConfigUiString != null) {
763
+ const config = JSON.parse(appConfigUiString);
764
+ config.timeZone ??= Intl.DateTimeFormat().resolvedOptions().timeZone;
765
+ return config;
766
+ }
767
+ return {
768
+ preset: 'Aura',
769
+ primary: 'emerald',
770
+ surface: null,
771
+ darkTheme: false,
772
+ menuMode: 'static',
773
+ language: 'ru',
774
+ dateFormat: 'yyyy-MM-dd',
775
+ timeFormat: 'HH:mm:ss',
776
+ dateTimeFormat: 'yyyy-MM-dd HH:mm:ss',
777
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
778
+ };
779
+ }
780
+ handleDarkModeTransition(config) {
781
+ if (document.startViewTransition) {
782
+ this.startViewTransition(config);
783
+ }
784
+ else {
785
+ this.toggleDarkMode(config);
786
+ this.onTransitionEnd();
787
+ }
788
+ }
789
+ startViewTransition(config) {
790
+ const transition = document.startViewTransition(() => {
791
+ this.toggleDarkMode(config);
792
+ });
793
+ transition.ready
794
+ .then(() => {
795
+ this.onTransitionEnd();
796
+ })
797
+ .catch(() => { });
798
+ }
799
+ toggleDarkMode(config) {
800
+ const _config = config || this.layoutConfig();
801
+ if (_config.darkTheme) {
802
+ document.documentElement.classList.add('app-dark');
803
+ }
804
+ else {
805
+ document.documentElement.classList.remove('app-dark');
806
+ }
807
+ }
808
+ onTransitionEnd() {
809
+ this.transitionComplete.set(true);
810
+ setTimeout(() => {
811
+ this.transitionComplete.set(false);
812
+ });
813
+ }
814
+ onMenuToggle() {
815
+ if (this.isOverlay()) {
816
+ this.layoutState.update((prev) => ({ ...prev, overlayMenuActive: !this.layoutState().overlayMenuActive }));
817
+ if (this.layoutState().overlayMenuActive) {
818
+ this.overlayOpen.next(null);
819
+ }
820
+ }
821
+ if (this.isDesktop()) {
822
+ this.layoutState.update((prev) => ({
823
+ ...prev,
824
+ staticMenuDesktopInactive: !this.layoutState().staticMenuDesktopInactive
825
+ }));
826
+ }
827
+ else {
828
+ this.layoutState.update((prev) => ({
829
+ ...prev,
830
+ staticMenuMobileActive: !this.layoutState().staticMenuMobileActive
831
+ }));
832
+ if (this.layoutState().staticMenuMobileActive) {
833
+ this.overlayOpen.next(null);
834
+ }
835
+ }
836
+ }
837
+ isDesktop() {
838
+ return window.innerWidth > 991;
839
+ }
840
+ isMobile() {
841
+ return !this.isDesktop();
842
+ }
843
+ onConfigUpdate() {
844
+ this._config = { ...this.layoutConfig() };
845
+ this.configUpdate.next(this.layoutConfig());
846
+ localStorage.setItem('layoutConfig', JSON.stringify(this.layoutConfig()));
847
+ }
848
+ onMenuStateChange(event) {
849
+ this.menuSource.next(event);
850
+ }
851
+ reset() {
852
+ this.resetSource.next(true);
853
+ }
854
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
855
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LayoutService, providedIn: 'root' }); }
856
+ }
857
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LayoutService, decorators: [{
858
+ type: Injectable,
859
+ args: [{ providedIn: 'root' }]
860
+ }], ctorParameters: () => [] });
861
+
862
+ const presets = {
863
+ Aura,
864
+ Lara,
865
+ Nora
866
+ };
867
+ class AppConfiguratorComponent {
868
+ constructor() {
869
+ this.router = inject(Router);
870
+ this.config = inject(PrimeNG);
871
+ this.layoutService = inject(LayoutService);
872
+ this.platformId = inject(PLATFORM_ID);
873
+ this.primeng = inject(PrimeNG);
874
+ this.presets = Object.keys(presets);
875
+ this.showMenuModeButton = signal(!this.router.url.includes('auth'), ...(ngDevMode ? [{ debugName: "showMenuModeButton" }] : []));
876
+ this.menuModeOptions = [
877
+ { label: 'Static', value: 'static' },
878
+ { label: 'Overlay', value: 'overlay' }
879
+ ];
880
+ this.surfaces = [
881
+ {
882
+ name: 'slate',
883
+ palette: {
884
+ 0: '#ffffff',
885
+ 50: '#f8fafc',
886
+ 100: '#f1f5f9',
887
+ 200: '#e2e8f0',
888
+ 300: '#cbd5e1',
889
+ 400: '#94a3b8',
890
+ 500: '#64748b',
891
+ 600: '#475569',
892
+ 700: '#334155',
893
+ 800: '#1e293b',
894
+ 900: '#0f172a',
895
+ 950: '#020617'
896
+ }
897
+ },
898
+ {
899
+ name: 'gray',
900
+ palette: {
901
+ 0: '#ffffff',
902
+ 50: '#f9fafb',
903
+ 100: '#f3f4f6',
904
+ 200: '#e5e7eb',
905
+ 300: '#d1d5db',
906
+ 400: '#9ca3af',
907
+ 500: '#6b7280',
908
+ 600: '#4b5563',
909
+ 700: '#374151',
910
+ 800: '#1f2937',
911
+ 900: '#111827',
912
+ 950: '#030712'
913
+ }
914
+ },
915
+ {
916
+ name: 'zinc',
917
+ palette: {
918
+ 0: '#ffffff',
919
+ 50: '#fafafa',
920
+ 100: '#f4f4f5',
921
+ 200: '#e4e4e7',
922
+ 300: '#d4d4d8',
923
+ 400: '#a1a1aa',
924
+ 500: '#71717a',
925
+ 600: '#52525b',
926
+ 700: '#3f3f46',
927
+ 800: '#27272a',
928
+ 900: '#18181b',
929
+ 950: '#09090b'
930
+ }
931
+ },
932
+ {
933
+ name: 'neutral',
934
+ palette: {
935
+ 0: '#ffffff',
936
+ 50: '#fafafa',
937
+ 100: '#f5f5f5',
938
+ 200: '#e5e5e5',
939
+ 300: '#d4d4d4',
940
+ 400: '#a3a3a3',
941
+ 500: '#737373',
942
+ 600: '#525252',
943
+ 700: '#404040',
944
+ 800: '#262626',
945
+ 900: '#171717',
946
+ 950: '#0a0a0a'
947
+ }
948
+ },
949
+ {
950
+ name: 'stone',
951
+ palette: {
952
+ 0: '#ffffff',
953
+ 50: '#fafaf9',
954
+ 100: '#f5f5f4',
955
+ 200: '#e7e5e4',
956
+ 300: '#d6d3d1',
957
+ 400: '#a8a29e',
958
+ 500: '#78716c',
959
+ 600: '#57534e',
960
+ 700: '#44403c',
961
+ 800: '#292524',
962
+ 900: '#1c1917',
963
+ 950: '#0c0a09'
964
+ }
965
+ },
966
+ {
967
+ name: 'soho',
968
+ palette: {
969
+ 0: '#ffffff',
970
+ 50: '#ececec',
971
+ 100: '#dedfdf',
972
+ 200: '#c4c4c6',
973
+ 300: '#adaeb0',
974
+ 400: '#97979b',
975
+ 500: '#7f8084',
976
+ 600: '#6a6b70',
977
+ 700: '#55565b',
978
+ 800: '#3f4046',
979
+ 900: '#2c2c34',
980
+ 950: '#16161d'
981
+ }
982
+ },
983
+ {
984
+ name: 'viva',
985
+ palette: {
986
+ 0: '#ffffff',
987
+ 50: '#f3f3f3',
988
+ 100: '#e7e7e8',
989
+ 200: '#cfd0d0',
990
+ 300: '#b7b8b9',
991
+ 400: '#9fa1a1',
992
+ 500: '#87898a',
993
+ 600: '#6e7173',
994
+ 700: '#565a5b',
995
+ 800: '#3e4244',
996
+ 900: '#262b2c',
997
+ 950: '#0e1315'
998
+ }
999
+ },
1000
+ {
1001
+ name: 'ocean',
1002
+ palette: {
1003
+ 0: '#ffffff',
1004
+ 50: '#fbfcfc',
1005
+ 100: '#F7F9F8',
1006
+ 200: '#EFF3F2',
1007
+ 300: '#DADEDD',
1008
+ 400: '#B1B7B6',
1009
+ 500: '#828787',
1010
+ 600: '#5F7274',
1011
+ 700: '#415B61',
1012
+ 800: '#29444E',
1013
+ 900: '#183240',
1014
+ 950: '#0c1920'
1015
+ }
1016
+ }
1017
+ ];
1018
+ this.selectedPrimaryColor = computed(() => {
1019
+ return this.layoutService.layoutConfig().primary;
1020
+ }, ...(ngDevMode ? [{ debugName: "selectedPrimaryColor" }] : []));
1021
+ this.selectedSurfaceColor = computed(() => this.layoutService.layoutConfig().surface, ...(ngDevMode ? [{ debugName: "selectedSurfaceColor" }] : []));
1022
+ this.selectedPreset = computed(() => this.layoutService.layoutConfig().preset, ...(ngDevMode ? [{ debugName: "selectedPreset" }] : []));
1023
+ this.menuMode = computed(() => this.layoutService.layoutConfig().menuMode, ...(ngDevMode ? [{ debugName: "menuMode" }] : []));
1024
+ this.primaryColors = computed(() => {
1025
+ const presetPalette = presets[this.layoutService.layoutConfig().preset].primitive;
1026
+ const colors = [
1027
+ 'emerald',
1028
+ 'green',
1029
+ 'lime',
1030
+ 'orange',
1031
+ 'amber',
1032
+ 'yellow',
1033
+ 'teal',
1034
+ 'cyan',
1035
+ 'sky',
1036
+ 'blue',
1037
+ 'indigo',
1038
+ 'violet',
1039
+ 'purple',
1040
+ 'fuchsia',
1041
+ 'pink',
1042
+ 'rose'
1043
+ ];
1044
+ const palettes = [{ name: 'noir', palette: {} }];
1045
+ colors.forEach((color) => {
1046
+ palettes.push({
1047
+ name: color,
1048
+ palette: presetPalette?.[color]
1049
+ });
1050
+ });
1051
+ return palettes;
1052
+ }, ...(ngDevMode ? [{ debugName: "primaryColors" }] : []));
1053
+ }
1054
+ ngOnInit() {
1055
+ if (isPlatformBrowser(this.platformId)) {
1056
+ this.onPresetChange(this.layoutService.layoutConfig().preset);
1057
+ }
1058
+ }
1059
+ getPresetExt() {
1060
+ const color = this.primaryColors().find((c) => c.name === this.selectedPrimaryColor()) || {};
1061
+ const preset = this.layoutService.layoutConfig().preset;
1062
+ if (color.name === 'noir') {
1063
+ return {
1064
+ semantic: {
1065
+ primary: {
1066
+ 50: '{surface.50}',
1067
+ 100: '{surface.100}',
1068
+ 200: '{surface.200}',
1069
+ 300: '{surface.300}',
1070
+ 400: '{surface.400}',
1071
+ 500: '{surface.500}',
1072
+ 600: '{surface.600}',
1073
+ 700: '{surface.700}',
1074
+ 800: '{surface.800}',
1075
+ 900: '{surface.900}',
1076
+ 950: '{surface.950}'
1077
+ },
1078
+ colorScheme: {
1079
+ light: {
1080
+ primary: {
1081
+ color: '{primary.950}',
1082
+ contrastColor: '#ffffff',
1083
+ hoverColor: '{primary.800}',
1084
+ activeColor: '{primary.700}'
1085
+ },
1086
+ highlight: {
1087
+ background: '{primary.950}',
1088
+ focusBackground: '{primary.700}',
1089
+ color: '#ffffff',
1090
+ focusColor: '#ffffff'
1091
+ }
1092
+ },
1093
+ dark: {
1094
+ primary: {
1095
+ color: '{primary.50}',
1096
+ contrastColor: '{primary.950}',
1097
+ hoverColor: '{primary.200}',
1098
+ activeColor: '{primary.300}'
1099
+ },
1100
+ highlight: {
1101
+ background: '{primary.50}',
1102
+ focusBackground: '{primary.300}',
1103
+ color: '{primary.950}',
1104
+ focusColor: '{primary.950}'
1105
+ }
1106
+ }
1107
+ }
1108
+ }
1109
+ };
1110
+ }
1111
+ else if (preset === 'Nora') {
1112
+ return {
1113
+ semantic: {
1114
+ primary: color.palette,
1115
+ colorScheme: {
1116
+ light: {
1117
+ primary: {
1118
+ color: '{primary.600}',
1119
+ contrastColor: '#ffffff',
1120
+ hoverColor: '{primary.700}',
1121
+ activeColor: '{primary.800}'
1122
+ },
1123
+ highlight: {
1124
+ background: '{primary.600}',
1125
+ focusBackground: '{primary.700}',
1126
+ color: '#ffffff',
1127
+ focusColor: '#ffffff'
1128
+ }
1129
+ },
1130
+ dark: {
1131
+ primary: {
1132
+ color: '{primary.500}',
1133
+ contrastColor: '{surface.900}',
1134
+ hoverColor: '{primary.400}',
1135
+ activeColor: '{primary.300}'
1136
+ },
1137
+ highlight: {
1138
+ background: '{primary.500}',
1139
+ focusBackground: '{primary.400}',
1140
+ color: '{surface.900}',
1141
+ focusColor: '{surface.900}'
1142
+ }
1143
+ }
1144
+ }
1145
+ }
1146
+ };
1147
+ }
1148
+ else {
1149
+ return {
1150
+ semantic: {
1151
+ primary: color.palette,
1152
+ colorScheme: {
1153
+ light: {
1154
+ primary: {
1155
+ color: '{primary.500}',
1156
+ contrastColor: '#ffffff',
1157
+ hoverColor: '{primary.600}',
1158
+ activeColor: '{primary.700}'
1159
+ },
1160
+ highlight: {
1161
+ background: '{primary.50}',
1162
+ focusBackground: '{primary.100}',
1163
+ color: '{primary.700}',
1164
+ focusColor: '{primary.800}'
1165
+ }
1166
+ },
1167
+ dark: {
1168
+ primary: {
1169
+ color: '{primary.400}',
1170
+ contrastColor: '{surface.900}',
1171
+ hoverColor: '{primary.300}',
1172
+ activeColor: '{primary.200}'
1173
+ },
1174
+ highlight: {
1175
+ background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
1176
+ focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
1177
+ color: 'rgba(255,255,255,.87)',
1178
+ focusColor: 'rgba(255,255,255,.87)'
1179
+ }
1180
+ }
1181
+ }
1182
+ }
1183
+ };
1184
+ }
1185
+ }
1186
+ updateColors(event, type, color) {
1187
+ if (type === 'primary') {
1188
+ this.layoutService.layoutConfig.update((state) => ({
1189
+ ...state,
1190
+ primary: color.name
1191
+ }));
1192
+ }
1193
+ else if (type === 'surface') {
1194
+ this.layoutService.layoutConfig.update((state) => ({
1195
+ ...state,
1196
+ surface: color.name
1197
+ }));
1198
+ }
1199
+ this.applyTheme(type, color);
1200
+ event.stopPropagation();
1201
+ }
1202
+ applyTheme(type, color) {
1203
+ if (type === 'primary') {
1204
+ updatePreset(this.getPresetExt());
1205
+ }
1206
+ else if (type === 'surface') {
1207
+ updateSurfacePalette(color.palette);
1208
+ }
1209
+ }
1210
+ onPresetChange(event) {
1211
+ this.layoutService.layoutConfig.update((state) => ({
1212
+ ...state,
1213
+ preset: event
1214
+ }));
1215
+ const preset = presets[event];
1216
+ const surfacePalette = this.surfaces.find((s) => s.name === this.selectedSurfaceColor())?.palette;
1217
+ $t().preset(preset).preset(this.getPresetExt()).surfacePalette(surfacePalette).use({ useDefaultOptions: true });
1218
+ }
1219
+ onMenuModeChange(event) {
1220
+ this.layoutService.layoutConfig.update((prev) => ({
1221
+ ...prev,
1222
+ menuMode: event
1223
+ }));
1224
+ }
1225
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppConfiguratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1226
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: AppConfiguratorComponent, isStandalone: true, selector: "app-configurator", host: { classAttribute: "hidden absolute top-[3.25rem] right-0 w-72 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]" }, ngImport: i0, template: `
1227
+ <div class="flex flex-col gap-4">
1228
+ <div>
1229
+ <span class="text-sm text-muted-color font-semibold">Primary</span>
1230
+ <div class="pt-2 flex gap-2 flex-wrap justify-start">
1231
+ @for (primaryColor of primaryColors(); track primaryColor.name) {
1232
+ <button
1233
+ class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
1234
+ id="oip-app-configurator-primary-color-{{ primaryColor.name }}"
1235
+ type="button"
1236
+ [ngClass]="{
1237
+ 'outline-primary': primaryColor.name === selectedPrimaryColor()
1238
+ }"
1239
+ [style]="{
1240
+ 'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
1241
+ }"
1242
+ [title]="primaryColor.name"
1243
+ (click)="updateColors($event, 'primary', primaryColor)"></button>
1244
+ }
1245
+ </div>
1246
+ </div>
1247
+ <div>
1248
+ <span class="text-sm text-muted-color font-semibold">Surface</span>
1249
+ <div class="pt-2 flex gap-2 flex-wrap justify-start">
1250
+ @for (surface of surfaces; track surface.name) {
1251
+ <button
1252
+ class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
1253
+ id="oip-app-configurator-surface-color-{{ surface.name }}"
1254
+ type="button"
1255
+ [ngClass]="{
1256
+ 'outline-primary': selectedSurfaceColor()
1257
+ ? selectedSurfaceColor() === surface.name
1258
+ : layoutService.layoutConfig().darkTheme
1259
+ ? surface.name === 'zinc'
1260
+ : surface.name === 'slate'
1261
+ }"
1262
+ [style]="{
1263
+ 'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
1264
+ }"
1265
+ [title]="surface.name"
1266
+ (click)="updateColors($event, 'surface', surface)"></button>
1267
+ }
1268
+ </div>
1269
+ </div>
1270
+ <div class="flex flex-col gap-2">
1271
+ <span class="text-sm text-muted-color font-semibold">Presets</span>
1272
+ <p-selectButton
1273
+ id="oip-app-configurator-preset-select-button"
1274
+ size="small"
1275
+ [allowEmpty]="false"
1276
+ [ngModel]="selectedPreset()"
1277
+ [options]="presets"
1278
+ (ngModelChange)="onPresetChange($event)" />
1279
+ </div>
1280
+ @if (showMenuModeButton()) {
1281
+ <div class="flex flex-col gap-2">
1282
+ <span class="text-sm text-muted-color font-semibold">Menu Mode</span>
1283
+ <p-selectButton
1284
+ id="oip-app-configurator-menu-mode-select-button"
1285
+ size="small"
1286
+ [allowEmpty]="false"
1287
+ [ngModel]="menuMode()"
1288
+ [options]="menuModeOptions"
1289
+ (ngModelChange)="onMenuModeChange($event)" />
1290
+ </div>
1291
+ }
1292
+ </div>
1293
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i3.SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }] }); }
1294
+ }
1295
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppConfiguratorComponent, decorators: [{
1296
+ type: Component,
1297
+ args: [{
1298
+ selector: 'app-configurator',
1299
+ standalone: true,
1300
+ imports: [CommonModule, FormsModule, SelectButtonModule],
1301
+ template: `
1302
+ <div class="flex flex-col gap-4">
1303
+ <div>
1304
+ <span class="text-sm text-muted-color font-semibold">Primary</span>
1305
+ <div class="pt-2 flex gap-2 flex-wrap justify-start">
1306
+ @for (primaryColor of primaryColors(); track primaryColor.name) {
1307
+ <button
1308
+ class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
1309
+ id="oip-app-configurator-primary-color-{{ primaryColor.name }}"
1310
+ type="button"
1311
+ [ngClass]="{
1312
+ 'outline-primary': primaryColor.name === selectedPrimaryColor()
1313
+ }"
1314
+ [style]="{
1315
+ 'background-color': primaryColor?.name === 'noir' ? 'var(--text-color)' : primaryColor?.palette?.['500']
1316
+ }"
1317
+ [title]="primaryColor.name"
1318
+ (click)="updateColors($event, 'primary', primaryColor)"></button>
1319
+ }
1320
+ </div>
1321
+ </div>
1322
+ <div>
1323
+ <span class="text-sm text-muted-color font-semibold">Surface</span>
1324
+ <div class="pt-2 flex gap-2 flex-wrap justify-start">
1325
+ @for (surface of surfaces; track surface.name) {
1326
+ <button
1327
+ class="border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1"
1328
+ id="oip-app-configurator-surface-color-{{ surface.name }}"
1329
+ type="button"
1330
+ [ngClass]="{
1331
+ 'outline-primary': selectedSurfaceColor()
1332
+ ? selectedSurfaceColor() === surface.name
1333
+ : layoutService.layoutConfig().darkTheme
1334
+ ? surface.name === 'zinc'
1335
+ : surface.name === 'slate'
1336
+ }"
1337
+ [style]="{
1338
+ 'background-color': surface?.name === 'noir' ? 'var(--text-color)' : surface?.palette?.['500']
1339
+ }"
1340
+ [title]="surface.name"
1341
+ (click)="updateColors($event, 'surface', surface)"></button>
1342
+ }
1343
+ </div>
1344
+ </div>
1345
+ <div class="flex flex-col gap-2">
1346
+ <span class="text-sm text-muted-color font-semibold">Presets</span>
1347
+ <p-selectButton
1348
+ id="oip-app-configurator-preset-select-button"
1349
+ size="small"
1350
+ [allowEmpty]="false"
1351
+ [ngModel]="selectedPreset()"
1352
+ [options]="presets"
1353
+ (ngModelChange)="onPresetChange($event)" />
1354
+ </div>
1355
+ @if (showMenuModeButton()) {
1356
+ <div class="flex flex-col gap-2">
1357
+ <span class="text-sm text-muted-color font-semibold">Menu Mode</span>
1358
+ <p-selectButton
1359
+ id="oip-app-configurator-menu-mode-select-button"
1360
+ size="small"
1361
+ [allowEmpty]="false"
1362
+ [ngModel]="menuMode()"
1363
+ [options]="menuModeOptions"
1364
+ (ngModelChange)="onMenuModeChange($event)" />
1365
+ </div>
1366
+ }
1367
+ </div>
1368
+ `,
1369
+ host: {
1370
+ class: 'hidden absolute top-[3.25rem] right-0 w-72 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]'
1371
+ }
1372
+ }]
1373
+ }] });
1374
+
1375
+ class LogoComponent {
1376
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1377
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: LogoComponent, isStandalone: true, selector: "logo", inputs: { width: "width", height: "height" }, ngImport: i0, template: `
1378
+ <svg
1379
+ viewBox="0.8516 1.7159 60.0074 64.7142"
1380
+ xmlns="http://www.w3.org/2000/svg"
1381
+ [attr.height]="height + 'px'"
1382
+ [attr.width]="width + 'px'">
1383
+ <path
1384
+ class="primary-logo-color"
1385
+ d="M -130.45 -104.78 C -130.45 -105.9 -130.43 -107.01 -130.45 -108.13 C -130.49 -108.52 -130.28 -108.9 -129.92 -109.07 C -125.87 -111.4 -121.82 -113.74 -117.77 -116.08 C -115.7 -117.26 -113.63 -118.45 -111.58 -119.67 C -111.26 -119.89 -110.83 -119.89 -110.51 -119.67 C -101.66 -114.53 -92.787 -109.41 -83.915 -104.29 C -83.752 -104.2 -83.479 -104.16 -83.475 -103.94 C -83.472 -103.72 -83.766 -103.65 -83.947 -103.54 C -86.326 -102.16 -88.716 -100.79 -91.092 -99.39 C -91.377 -99.18 -91.761 -99.18 -92.046 -99.39 C -98.211 -102.98 -104.38 -106.55 -110.56 -110.12 C -110.85 -110.33 -111.23 -110.33 -111.52 -110.12 C -114.88 -108.16 -118.25 -106.22 -121.63 -104.28 C -122.01 -104.11 -122.24 -103.71 -122.2 -103.3 C -122.18 -101.11 -122.2 -98.922 -122.2 -96.736 C -122.19 -95.98 -122.21 -95.98 -122.84 -96.335 C -125.2 -97.7 -127.57 -99.07 -129.93 -100.42 C -130.27 -100.57 -130.49 -100.92 -130.46 -101.3 C -130.43 -102.46 -130.45 -103.62 -130.45 -104.78 Z"
1386
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1387
+ <path
1388
+ class="primary-logo-color"
1389
+ d="M -70.504 -100.94 L -70.504 -90.438 C -70.447 -89.98 -70.692 -89.537 -71.11 -89.342 C -78.942 -84.839 -86.769 -80.325 -94.592 -75.8 C -95.635 -75.2 -96.684 -74.612 -97.713 -73.988 C -98.17 -73.708 -98.255 -73.846 -98.255 -74.314 L -98.255 -82.785 C -98.268 -83.116 -98.07 -83.419 -97.762 -83.541 C -92.003 -86.86 -86.269 -90.236 -80.468 -93.47 C -79.181 -94.179 -78.667 -94.934 -78.731 -96.441 C -78.869 -99.76 -78.791 -103.09 -78.755 -106.42 C -78.694 -107 -79.02 -107.56 -79.56 -107.8 C -81.436 -108.83 -83.28 -109.93 -85.138 -110.99 C -85.734 -111.34 -85.734 -111.34 -85.113 -111.7 C -82.748 -113.07 -80.379 -114.43 -78.021 -115.82 C -77.707 -116.05 -77.283 -116.06 -76.957 -115.84 C -74.962 -114.66 -72.953 -113.5 -70.929 -112.37 C -70.62 -112.19 -70.456 -111.84 -70.521 -111.49 C -70.514 -107.99 -70.508 -104.48 -70.504 -100.94 Z"
1390
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1391
+ <path
1392
+ class="primary-logo-color"
1393
+ d="M -108.68 -85.743 L -108.68 -75.169 C -108.72 -74.754 -108.5 -74.358 -108.12 -74.179 C -104.77 -72.267 -101.44 -70.339 -98.117 -68.396 C -97.762 -68.141 -97.284 -68.141 -96.929 -68.396 C -95.028 -69.527 -93.096 -70.598 -91.195 -71.725 C -90.667 -72.041 -90.581 -71.892 -90.581 -71.371 C -90.596 -68.591 -90.596 -65.811 -90.581 -63.03 C -90.551 -62.7 -90.729 -62.386 -91.028 -62.243 C -93.083 -61.073 -95.13 -59.891 -97.17 -58.697 C -97.436 -58.537 -97.775 -58.569 -98.007 -58.775 C -102.74 -61.517 -107.47 -64.254 -112.22 -66.984 C -113.63 -67.796 -115.01 -68.615 -116.42 -69.406 C -116.77 -69.561 -116.97 -69.913 -116.94 -70.286 C -116.93 -80.555 -116.93 -90.823 -116.94 -101.09 C -116.94 -101.63 -116.86 -101.75 -116.35 -101.44 C -113.98 -100.05 -111.59 -98.667 -109.19 -97.303 C -108.84 -97.135 -108.62 -96.76 -108.66 -96.367 C -108.68 -92.833 -108.69 -89.291 -108.68 -85.743 Z"
1394
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1395
+ <path
1396
+ class="secondary-logo-color"
1397
+ d="M -122.18 -85.807 L -122.18 -82.129 C -122.18 -81.637 -122.34 -81.615 -122.72 -81.839 C -125.16 -83.257 -127.6 -84.667 -130.05 -86.069 C -130.35 -86.219 -130.53 -86.535 -130.5 -86.867 L -130.5 -94.09 C -130.5 -94.64 -130.34 -94.679 -129.89 -94.417 C -127.49 -92.998 -125.09 -91.607 -122.67 -90.243 C -122.35 -90.103 -122.15 -89.772 -122.18 -89.42 C -122.21 -88.214 -122.18 -87.012 -122.18 -85.807 Z M -82.688 -119.15 C -83.954 -118.41 -85.17 -117.7 -86.365 -117.02 C -87.748 -116.22 -89.138 -115.44 -90.514 -114.63 C -90.761 -114.45 -91.093 -114.45 -91.34 -114.63 C -93.432 -115.86 -95.535 -117.07 -97.649 -118.27 C -98.053 -118.5 -98.191 -118.63 -97.67 -118.93 C -95.216 -120.32 -92.776 -121.74 -90.337 -123.15 C -90.134 -123.33 -89.845 -123.36 -89.61 -123.23 L -82.918 -119.33 C -82.862 -119.28 -82.812 -119.24 -82.688 -119.15 Z M -85.365 -65.616 L -85.365 -72.062 L -85.365 -74.622 C -85.403 -74.928 -85.24 -75.223 -84.961 -75.353 C -82.886 -76.534 -80.83 -77.736 -78.77 -78.931 C -78.174 -79.286 -78.135 -79.257 -78.135 -78.576 L -78.135 -70.303 C -78.135 -69.991 -78.135 -69.711 -78.468 -69.52 C -80.656 -68.275 -82.833 -67.013 -85.014 -65.761 C -85.127 -65.704 -85.245 -65.655 -85.365 -65.616 Z"
1398
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1399
+ </svg>
1400
+ `, isInline: true }); }
1401
+ }
1402
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LogoComponent, decorators: [{
1403
+ type: Component,
1404
+ args: [{
1405
+ selector: 'logo',
1406
+ standalone: true,
1407
+ template: `
1408
+ <svg
1409
+ viewBox="0.8516 1.7159 60.0074 64.7142"
1410
+ xmlns="http://www.w3.org/2000/svg"
1411
+ [attr.height]="height + 'px'"
1412
+ [attr.width]="width + 'px'">
1413
+ <path
1414
+ class="primary-logo-color"
1415
+ d="M -130.45 -104.78 C -130.45 -105.9 -130.43 -107.01 -130.45 -108.13 C -130.49 -108.52 -130.28 -108.9 -129.92 -109.07 C -125.87 -111.4 -121.82 -113.74 -117.77 -116.08 C -115.7 -117.26 -113.63 -118.45 -111.58 -119.67 C -111.26 -119.89 -110.83 -119.89 -110.51 -119.67 C -101.66 -114.53 -92.787 -109.41 -83.915 -104.29 C -83.752 -104.2 -83.479 -104.16 -83.475 -103.94 C -83.472 -103.72 -83.766 -103.65 -83.947 -103.54 C -86.326 -102.16 -88.716 -100.79 -91.092 -99.39 C -91.377 -99.18 -91.761 -99.18 -92.046 -99.39 C -98.211 -102.98 -104.38 -106.55 -110.56 -110.12 C -110.85 -110.33 -111.23 -110.33 -111.52 -110.12 C -114.88 -108.16 -118.25 -106.22 -121.63 -104.28 C -122.01 -104.11 -122.24 -103.71 -122.2 -103.3 C -122.18 -101.11 -122.2 -98.922 -122.2 -96.736 C -122.19 -95.98 -122.21 -95.98 -122.84 -96.335 C -125.2 -97.7 -127.57 -99.07 -129.93 -100.42 C -130.27 -100.57 -130.49 -100.92 -130.46 -101.3 C -130.43 -102.46 -130.45 -103.62 -130.45 -104.78 Z"
1416
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1417
+ <path
1418
+ class="primary-logo-color"
1419
+ d="M -70.504 -100.94 L -70.504 -90.438 C -70.447 -89.98 -70.692 -89.537 -71.11 -89.342 C -78.942 -84.839 -86.769 -80.325 -94.592 -75.8 C -95.635 -75.2 -96.684 -74.612 -97.713 -73.988 C -98.17 -73.708 -98.255 -73.846 -98.255 -74.314 L -98.255 -82.785 C -98.268 -83.116 -98.07 -83.419 -97.762 -83.541 C -92.003 -86.86 -86.269 -90.236 -80.468 -93.47 C -79.181 -94.179 -78.667 -94.934 -78.731 -96.441 C -78.869 -99.76 -78.791 -103.09 -78.755 -106.42 C -78.694 -107 -79.02 -107.56 -79.56 -107.8 C -81.436 -108.83 -83.28 -109.93 -85.138 -110.99 C -85.734 -111.34 -85.734 -111.34 -85.113 -111.7 C -82.748 -113.07 -80.379 -114.43 -78.021 -115.82 C -77.707 -116.05 -77.283 -116.06 -76.957 -115.84 C -74.962 -114.66 -72.953 -113.5 -70.929 -112.37 C -70.62 -112.19 -70.456 -111.84 -70.521 -111.49 C -70.514 -107.99 -70.508 -104.48 -70.504 -100.94 Z"
1420
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1421
+ <path
1422
+ class="primary-logo-color"
1423
+ d="M -108.68 -85.743 L -108.68 -75.169 C -108.72 -74.754 -108.5 -74.358 -108.12 -74.179 C -104.77 -72.267 -101.44 -70.339 -98.117 -68.396 C -97.762 -68.141 -97.284 -68.141 -96.929 -68.396 C -95.028 -69.527 -93.096 -70.598 -91.195 -71.725 C -90.667 -72.041 -90.581 -71.892 -90.581 -71.371 C -90.596 -68.591 -90.596 -65.811 -90.581 -63.03 C -90.551 -62.7 -90.729 -62.386 -91.028 -62.243 C -93.083 -61.073 -95.13 -59.891 -97.17 -58.697 C -97.436 -58.537 -97.775 -58.569 -98.007 -58.775 C -102.74 -61.517 -107.47 -64.254 -112.22 -66.984 C -113.63 -67.796 -115.01 -68.615 -116.42 -69.406 C -116.77 -69.561 -116.97 -69.913 -116.94 -70.286 C -116.93 -80.555 -116.93 -90.823 -116.94 -101.09 C -116.94 -101.63 -116.86 -101.75 -116.35 -101.44 C -113.98 -100.05 -111.59 -98.667 -109.19 -97.303 C -108.84 -97.135 -108.62 -96.76 -108.66 -96.367 C -108.68 -92.833 -108.69 -89.291 -108.68 -85.743 Z"
1424
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1425
+ <path
1426
+ class="secondary-logo-color"
1427
+ d="M -122.18 -85.807 L -122.18 -82.129 C -122.18 -81.637 -122.34 -81.615 -122.72 -81.839 C -125.16 -83.257 -127.6 -84.667 -130.05 -86.069 C -130.35 -86.219 -130.53 -86.535 -130.5 -86.867 L -130.5 -94.09 C -130.5 -94.64 -130.34 -94.679 -129.89 -94.417 C -127.49 -92.998 -125.09 -91.607 -122.67 -90.243 C -122.35 -90.103 -122.15 -89.772 -122.18 -89.42 C -122.21 -88.214 -122.18 -87.012 -122.18 -85.807 Z M -82.688 -119.15 C -83.954 -118.41 -85.17 -117.7 -86.365 -117.02 C -87.748 -116.22 -89.138 -115.44 -90.514 -114.63 C -90.761 -114.45 -91.093 -114.45 -91.34 -114.63 C -93.432 -115.86 -95.535 -117.07 -97.649 -118.27 C -98.053 -118.5 -98.191 -118.63 -97.67 -118.93 C -95.216 -120.32 -92.776 -121.74 -90.337 -123.15 C -90.134 -123.33 -89.845 -123.36 -89.61 -123.23 L -82.918 -119.33 C -82.862 -119.28 -82.812 -119.24 -82.688 -119.15 Z M -85.365 -65.616 L -85.365 -72.062 L -85.365 -74.622 C -85.403 -74.928 -85.24 -75.223 -84.961 -75.353 C -82.886 -76.534 -80.83 -77.736 -78.77 -78.931 C -78.174 -79.286 -78.135 -79.257 -78.135 -78.576 L -78.135 -70.303 C -78.135 -69.991 -78.135 -69.711 -78.468 -69.52 C -80.656 -68.275 -82.833 -67.013 -85.014 -65.761 C -85.127 -65.704 -85.245 -65.655 -85.365 -65.616 Z"
1428
+ transform="matrix(1, 0, 0, 1, 131.35482788085938, 125.0257797241211)" />
1429
+ </svg>
1430
+ `
1431
+ }]
1432
+ }], propDecorators: { width: [{
1433
+ type: Input
1434
+ }], height: [{
1435
+ type: Input
1436
+ }] } });
1437
+
1438
+ /**
1439
+ * SecurityService extends OidcSecurityService to manage authentication,
1440
+ * token handling, and user role access in an Angular application.
1441
+ *
1442
+ * It provides helper methods for checking authentication, managing tokens,
1443
+ * determining user roles, and performing logout and refresh operations.
1444
+ */
1445
+ class SecurityService extends OidcSecurityService {
1446
+ /**
1447
+ * Initializes service and subscribes to authentication events.
1448
+ * When a 'NewAuthenticationResult' event is received, the `auth` method is called.
1449
+ */
1450
+ constructor() {
1451
+ super();
1452
+ /**
1453
+ * Handles angular OIDC events.
1454
+ */
1455
+ this.publicEventsService = inject(PublicEventsService);
1456
+ /**
1457
+ * Stores the latest login response from checkAuth().
1458
+ */
1459
+ this.loginResponse = new BehaviorSubject(null);
1460
+ /**
1461
+ * Stores the decoded access token payload.
1462
+ */
1463
+ this.payload = new BehaviorSubject(null);
1464
+ this.publicEventsService
1465
+ .registerForEvents()
1466
+ .pipe(filter((event) => event.type === EventTypes.NewAuthenticationResult))
1467
+ .subscribe(() => {
1468
+ this.auth();
1469
+ });
1470
+ }
1471
+ /**
1472
+ * Returns the ID token for the sign-in.
1473
+ * @returns A string with the id token.
1474
+ */
1475
+ getAccessToken() {
1476
+ return this.loginResponse.pipe(map((data) => data?.accessToken));
1477
+ }
1478
+ /**
1479
+ * Indicates whether the current user has the 'admin' role.
1480
+ *
1481
+ * @returns {boolean} True if the user is an admin, false otherwise.
1482
+ */
1483
+ get isAdmin() {
1484
+ return this.payload.getValue()?.realm_access?.roles?.includes('admin');
1485
+ }
1486
+ /**
1487
+ * Initiates authentication check and updates login response, user data,
1488
+ * and decoded token payload if authenticated.
1489
+ */
1490
+ auth() {
1491
+ super.checkAuth().subscribe((_response) => {
1492
+ this.loginResponse.next(_response);
1493
+ this.userData = _response.userData;
1494
+ this.getPayloadFromAccessToken().subscribe((_token) => {
1495
+ this.payload.next(_token);
1496
+ });
1497
+ });
1498
+ }
1499
+ /**
1500
+ * Performs logout and clears the local token payload.
1501
+ *
1502
+ * @param {string} [configId] Optional configuration ID for logout.
1503
+ * @param {LogoutAuthOptions} [logoutAuthOptions] Optional logout options.
1504
+ */
1505
+ logout(configId, logoutAuthOptions) {
1506
+ this.logoff(configId, logoutAuthOptions).subscribe((x) => this.payload.next(x));
1507
+ }
1508
+ /**
1509
+ * Completes the BehaviorSubjects when the service is destroyed to avoid memory leaks.
1510
+ */
1511
+ ngOnDestroy() {
1512
+ this.loginResponse.complete();
1513
+ this.payload.complete();
1514
+ }
1515
+ /**
1516
+ * Checks whether the current access token is expired based on the 'exp' claim.
1517
+ *
1518
+ * @returns {Observable<boolean>} Observable that emits true if the token is expired.
1519
+ */
1520
+ isTokenExpired() {
1521
+ return this.getPayloadFromAccessToken().pipe(map((payload) => {
1522
+ return payload.exp < Math.floor(Date.now() / 1000);
1523
+ }));
1524
+ }
1525
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1526
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityService, providedIn: 'root' }); }
1527
+ }
1528
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityService, decorators: [{
1529
+ type: Injectable,
1530
+ args: [{ providedIn: 'root' }]
1531
+ }], ctorParameters: () => [] });
1532
+
1533
+ /**
1534
+ * UserService is responsible for retrieving and handling user-related data,
1535
+ * including the user's photo and short label for avatar display.
1536
+ */
1537
+ class UserService {
1538
+ constructor() {
1539
+ this.securityService = inject(SecurityService);
1540
+ this.baseDataService = inject(BaseDataService);
1541
+ /**
1542
+ * Stores the user's photo as a data URL or binary blob, depending on how it's processed.
1543
+ */
1544
+ this.photo = null;
1545
+ /**
1546
+ * Indicates whether the user photo has finished loading.
1547
+ */
1548
+ this.photoLoaded = false;
1549
+ this.getUserPhoto();
1550
+ }
1551
+ /**
1552
+ * Returns a short label composed of the user's initials.
1553
+ * Typically used for avatar display when a photo is unavailable.
1554
+ */
1555
+ get shortLabel() {
1556
+ const data = this.securityService.userData;
1557
+ return data.given_name[0] + data.family_name[0];
1558
+ }
1559
+ get userName() {
1560
+ const data = this.securityService.userData;
1561
+ return `${data.given_name} ${data.family_name}`;
1562
+ }
1563
+ /**
1564
+ * Initiates an HTTP request to fetch the user's photo based on their email,
1565
+ * and updates the `photo` and `photoLoaded` properties accordingly.
1566
+ */
1567
+ getUserPhoto() {
1568
+ const url = `${this.baseDataService.baseUrl}api/user-profile/get-user-photo?email=${this.securityService.userData.email}`;
1569
+ this.baseDataService.getBlob(url).then((data) => {
1570
+ this.createImageFromBlob(data);
1571
+ this.photoLoaded = true;
1572
+ }, (error) => {
1573
+ console.log(error);
1574
+ });
1575
+ }
1576
+ /**
1577
+ * Converts a Blob image into a Base64 data URL and stores it in the `photo` property.
1578
+ *
1579
+ * @param image - The image Blob to be converted.
1580
+ */
1581
+ createImageFromBlob(image) {
1582
+ const reader = new FileReader();
1583
+ reader.addEventListener('load', () => {
1584
+ this.photo = reader.result;
1585
+ }, false);
1586
+ if (image) {
1587
+ reader.readAsDataURL(image);
1588
+ }
1589
+ }
1590
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1591
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: UserService }); }
1592
+ }
1593
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: UserService, decorators: [{
1594
+ type: Injectable
1595
+ }], ctorParameters: () => [] });
1596
+
1597
+ class AppTopbar {
1598
+ constructor(layoutService) {
1599
+ this.layoutService = layoutService;
1600
+ this.securityService = inject(SecurityService);
1601
+ this.topBarService = inject(TopBarService);
1602
+ this.userService = inject(UserService);
1603
+ }
1604
+ toggleDarkMode() {
1605
+ this.layoutService.layoutConfig.update((state) => ({
1606
+ ...state,
1607
+ darkTheme: !state.darkTheme
1608
+ }));
1609
+ }
1610
+ logoutKeyDown($event) {
1611
+ if ($event.key === 'Enter') {
1612
+ this.securityService.logout();
1613
+ }
1614
+ }
1615
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppTopbar, deps: [{ token: LayoutService }], target: i0.ɵɵFactoryTarget.Component }); }
1616
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: AppTopbar, isStandalone: true, selector: "app-topbar", ngImport: i0, template: ` <div class="layout-topbar">
1617
+ <div class="layout-topbar-logo-container">
1618
+ <button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
1619
+ <i class="pi pi-bars"></i>
1620
+ </button>
1621
+ <a class="layout-topbar-logo" id="oip-app-topbar-logo-link" routerLink="">
1622
+ <logo [height]="36" [width]="36"></logo>
1623
+ <span>OIP</span>
1624
+ </a>
1625
+ </div>
1626
+
1627
+ @if (securityService.isAdmin && topBarService.topBarItems.length > 0) {
1628
+ <p-tabs class="layout-topbar-tabs ml-2" [(value)]="topBarService.activeId">
1629
+ <p-tablist>
1630
+ @for (tab of topBarService.availableTopBarItems; track tab.id) {
1631
+ <p-tab id="oip-app-topbar-tab-{{ tab.id }}" [value]="tab.id">
1632
+ <i class="pi {{ tab.icon }}"></i>
1633
+ <span class="ml-2">{{ tab.caption }}</span>
1634
+ </p-tab>
1635
+ }
1636
+ </p-tablist>
1637
+ </p-tabs>
1638
+ }
1639
+ <div class="layout-topbar-actions">
1640
+ <div class="layout-config-menu">
1641
+ <p-button
1642
+ class="layout-topbar-action"
1643
+ id="oip-app-topbar-theme-button"
1644
+ severity="secondary"
1645
+ type="button"
1646
+ [rounded]="true"
1647
+ [text]="true"
1648
+ (click)="toggleDarkMode()">
1649
+ <i
1650
+ class="pi"
1651
+ [ngClass]="{
1652
+ 'pi-moon': layoutService.isDarkTheme(),
1653
+ 'pi-sun': !layoutService.isDarkTheme()
1654
+ }"></i>
1655
+ </p-button>
1656
+ <div class="relative">
1657
+ <p-button
1658
+ class="layout-topbar-action layout-topbar-action-highlight"
1659
+ enterActiveClass="animate-scalein"
1660
+ enterFromClass="hidden"
1661
+ id="oip-app-topbar-palette-button"
1662
+ leaveActiveClass="animate-fadeout"
1663
+ leaveToClass="hidden"
1664
+ pStyleClass="@next"
1665
+ [hideOnOutsideClick]="true"
1666
+ [rounded]="true">
1667
+ <i class="pi pi-palette"></i>
1668
+ </p-button>
1669
+ <app-configurator />
1670
+ </div>
1671
+ </div>
1672
+
1673
+ <button
1674
+ class="layout-topbar-menu-button layout-topbar-action"
1675
+ enterActiveClass="animate-scalein"
1676
+ enterFromClass="hidden"
1677
+ id="oip-app-topbar-menu-expand-button"
1678
+ leaveActiveClass="animate-fadeout"
1679
+ leaveToClass="hidden"
1680
+ pStyleClass="@next"
1681
+ [hideOnOutsideClick]="true">
1682
+ <i class="pi pi-ellipsis-v"></i>
1683
+ </button>
1684
+
1685
+ <div class="layout-topbar-menu hidden lg:block">
1686
+ <div class="layout-topbar-menu-content">
1687
+ <button
1688
+ class="layout-topbar-action"
1689
+ id="oip-app-topbar-logout-button"
1690
+ type="button"
1691
+ (click)="securityService.logout()"
1692
+ (keydown)="logoutKeyDown($event)">
1693
+ <i class="pi pi-sign-out"></i>
1694
+ <span>Logout</span>
1695
+ </button>
1696
+ <button class="layout-topbar-action" routerLink="config">
1697
+ <p-avatar
1698
+ class="p-link flex align-items-center"
1699
+ id="oip-app-topbar-user-avatar"
1700
+ shape="circle"
1701
+ size="normal"
1702
+ [image]="userService.photoLoaded ? userService.photo : null"
1703
+ >{{ !userService.photoLoaded ? userService.shortLabel : null }}
1704
+ </p-avatar>
1705
+ <span class="ml-2">Profile</span>
1706
+ </button>
1707
+ </div>
1708
+ </div>
1709
+ </div>
1710
+ </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: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i4.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: LogoComponent, selector: "logo", inputs: ["width", "height"] }, { 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: i5$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }] }); }
1711
+ }
1712
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppTopbar, decorators: [{
1713
+ type: Component,
1714
+ args: [{
1715
+ selector: 'app-topbar',
1716
+ standalone: true,
1717
+ imports: [
1718
+ RouterModule,
1719
+ CommonModule,
1720
+ StyleClassModule,
1721
+ AppConfiguratorComponent,
1722
+ LogoComponent,
1723
+ Tabs,
1724
+ TabList,
1725
+ Tab,
1726
+ AvatarModule,
1727
+ ButtonModule
1728
+ ],
1729
+ template: ` <div class="layout-topbar">
1730
+ <div class="layout-topbar-logo-container">
1731
+ <button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
1732
+ <i class="pi pi-bars"></i>
1733
+ </button>
1734
+ <a class="layout-topbar-logo" id="oip-app-topbar-logo-link" routerLink="">
1735
+ <logo [height]="36" [width]="36"></logo>
1736
+ <span>OIP</span>
1737
+ </a>
1738
+ </div>
1739
+
1740
+ @if (securityService.isAdmin && topBarService.topBarItems.length > 0) {
1741
+ <p-tabs class="layout-topbar-tabs ml-2" [(value)]="topBarService.activeId">
1742
+ <p-tablist>
1743
+ @for (tab of topBarService.availableTopBarItems; track tab.id) {
1744
+ <p-tab id="oip-app-topbar-tab-{{ tab.id }}" [value]="tab.id">
1745
+ <i class="pi {{ tab.icon }}"></i>
1746
+ <span class="ml-2">{{ tab.caption }}</span>
1747
+ </p-tab>
1748
+ }
1749
+ </p-tablist>
1750
+ </p-tabs>
1751
+ }
1752
+ <div class="layout-topbar-actions">
1753
+ <div class="layout-config-menu">
1754
+ <p-button
1755
+ class="layout-topbar-action"
1756
+ id="oip-app-topbar-theme-button"
1757
+ severity="secondary"
1758
+ type="button"
1759
+ [rounded]="true"
1760
+ [text]="true"
1761
+ (click)="toggleDarkMode()">
1762
+ <i
1763
+ class="pi"
1764
+ [ngClass]="{
1765
+ 'pi-moon': layoutService.isDarkTheme(),
1766
+ 'pi-sun': !layoutService.isDarkTheme()
1767
+ }"></i>
1768
+ </p-button>
1769
+ <div class="relative">
1770
+ <p-button
1771
+ class="layout-topbar-action layout-topbar-action-highlight"
1772
+ enterActiveClass="animate-scalein"
1773
+ enterFromClass="hidden"
1774
+ id="oip-app-topbar-palette-button"
1775
+ leaveActiveClass="animate-fadeout"
1776
+ leaveToClass="hidden"
1777
+ pStyleClass="@next"
1778
+ [hideOnOutsideClick]="true"
1779
+ [rounded]="true">
1780
+ <i class="pi pi-palette"></i>
1781
+ </p-button>
1782
+ <app-configurator />
1783
+ </div>
1784
+ </div>
1785
+
1786
+ <button
1787
+ class="layout-topbar-menu-button layout-topbar-action"
1788
+ enterActiveClass="animate-scalein"
1789
+ enterFromClass="hidden"
1790
+ id="oip-app-topbar-menu-expand-button"
1791
+ leaveActiveClass="animate-fadeout"
1792
+ leaveToClass="hidden"
1793
+ pStyleClass="@next"
1794
+ [hideOnOutsideClick]="true">
1795
+ <i class="pi pi-ellipsis-v"></i>
1796
+ </button>
1797
+
1798
+ <div class="layout-topbar-menu hidden lg:block">
1799
+ <div class="layout-topbar-menu-content">
1800
+ <button
1801
+ class="layout-topbar-action"
1802
+ id="oip-app-topbar-logout-button"
1803
+ type="button"
1804
+ (click)="securityService.logout()"
1805
+ (keydown)="logoutKeyDown($event)">
1806
+ <i class="pi pi-sign-out"></i>
1807
+ <span>Logout</span>
1808
+ </button>
1809
+ <button class="layout-topbar-action" routerLink="config">
1810
+ <p-avatar
1811
+ class="p-link flex align-items-center"
1812
+ id="oip-app-topbar-user-avatar"
1813
+ shape="circle"
1814
+ size="normal"
1815
+ [image]="userService.photoLoaded ? userService.photo : null"
1816
+ >{{ !userService.photoLoaded ? userService.shortLabel : null }}
1817
+ </p-avatar>
1818
+ <span class="ml-2">Profile</span>
1819
+ </button>
1820
+ </div>
1821
+ </div>
1822
+ </div>
1823
+ </div>`
1824
+ }]
1825
+ }], ctorParameters: () => [{ type: LayoutService }] });
1826
+
1827
+ class FooterComponent {
1828
+ constructor() { }
1829
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1830
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: FooterComponent, isStandalone: true, selector: "app-footer", ngImport: i0, template: `
1831
+ <div class="layout-footer">
1832
+ <logo class="mr-2" height="18" width="18"></logo>
1833
+ <span class="font-medium">OIP</span>
1834
+ </div>
1835
+ `, isInline: true, dependencies: [{ kind: "component", type: LogoComponent, selector: "logo", inputs: ["width", "height"] }] }); }
1836
+ }
1837
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FooterComponent, decorators: [{
1838
+ type: Component,
1839
+ args: [{
1840
+ selector: 'app-footer',
1841
+ template: `
1842
+ <div class="layout-footer">
1843
+ <logo class="mr-2" height="18" width="18"></logo>
1844
+ <span class="font-medium">OIP</span>
1845
+ </div>
1846
+ `,
1847
+ standalone: true,
1848
+ imports: [LogoComponent]
1849
+ }]
1850
+ }], ctorParameters: () => [] });
1851
+
1852
+ /* eslint-disable */
1853
+ /* tslint:disable */
1854
+ // @ts-nocheck
1855
+ /*
1856
+ * ---------------------------------------------------------------
1857
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
1858
+ * ## ##
1859
+ * ## AUTHOR: acacode ##
1860
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
1861
+ * ---------------------------------------------------------------
1862
+ */
1863
+ var ContentType;
1864
+ (function (ContentType) {
1865
+ ContentType["Json"] = "application/json";
1866
+ ContentType["FormData"] = "multipart/form-data";
1867
+ ContentType["UrlEncoded"] = "application/x-www-form-urlencoded";
1868
+ ContentType["Text"] = "text/plain";
1869
+ })(ContentType || (ContentType = {}));
1870
+ class HttpClient {
1871
+ constructor() {
1872
+ this.securityService = inject(SecurityService);
1873
+ this.layoutService = inject(LayoutService);
1874
+ this.baseUrl = "";
1875
+ this.securityData = null;
1876
+ this.securityWorker = (securityData) => ({
1877
+ headers: {
1878
+ "Accept-language": this.layoutService.language()
1879
+ ? this.layoutService.language()
1880
+ : "en",
1881
+ "X-Timezone": this.layoutService.timeZone(),
1882
+ Authorization: `Bearer ${securityData}`,
1883
+ },
1884
+ });
1885
+ this.abortControllers = new Map();
1886
+ this.customFetch = (...fetchParams) => fetch(...fetchParams);
1887
+ this.baseApiParams = {
1888
+ credentials: "same-origin",
1889
+ headers: {},
1890
+ redirect: "follow",
1891
+ referrerPolicy: "no-referrer",
1892
+ };
1893
+ this.setSecurityData = (data) => {
1894
+ this.securityData = data;
1895
+ };
1896
+ this.contentFormatters = {
1897
+ [ContentType.Json]: (input) => input !== null && (typeof input === "object" || typeof input === "string")
1898
+ ? JSON.stringify(input)
1899
+ : input,
1900
+ [ContentType.Text]: (input) => input !== null && typeof input !== "string"
1901
+ ? JSON.stringify(input)
1902
+ : input,
1903
+ [ContentType.FormData]: (input) => Object.keys(input || {}).reduce((formData, key) => {
1904
+ const property = input[key];
1905
+ formData.append(key, property instanceof Blob
1906
+ ? property
1907
+ : typeof property === "object" && property !== null
1908
+ ? JSON.stringify(property)
1909
+ : `${property}`);
1910
+ return formData;
1911
+ }, new FormData()),
1912
+ [ContentType.UrlEncoded]: (input) => this.toQueryString(input),
1913
+ };
1914
+ this.createAbortSignal = (cancelToken) => {
1915
+ if (this.abortControllers.has(cancelToken)) {
1916
+ const abortController = this.abortControllers.get(cancelToken);
1917
+ if (abortController) {
1918
+ return abortController.signal;
1919
+ }
1920
+ return void 0;
1921
+ }
1922
+ const abortController = new AbortController();
1923
+ this.abortControllers.set(cancelToken, abortController);
1924
+ return abortController.signal;
1925
+ };
1926
+ this.abortRequest = (cancelToken) => {
1927
+ const abortController = this.abortControllers.get(cancelToken);
1928
+ if (abortController) {
1929
+ abortController.abort();
1930
+ this.abortControllers.delete(cancelToken);
1931
+ }
1932
+ };
1933
+ this.request = async ({ body, secure, path, type, query, format, baseUrl, cancelToken, ...params }) => {
1934
+ const secureParams = ((typeof secure === "boolean" ? secure : this.baseApiParams.secure) &&
1935
+ this.securityWorker &&
1936
+ (await this.securityWorker(this.securityData))) ||
1937
+ {};
1938
+ const requestParams = this.mergeRequestParams(params, secureParams);
1939
+ const queryString = query && this.toQueryString(query);
1940
+ const payloadFormatter = this.contentFormatters[type || ContentType.Json];
1941
+ let responseFormat = format || requestParams.format;
1942
+ return this.customFetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, {
1943
+ ...requestParams,
1944
+ headers: {
1945
+ ...(requestParams.headers || {}),
1946
+ ...(type && type !== ContentType.FormData
1947
+ ? { "Content-Type": type }
1948
+ : {}),
1949
+ },
1950
+ signal: (cancelToken
1951
+ ? this.createAbortSignal(cancelToken)
1952
+ : requestParams.signal) || null,
1953
+ body: typeof body === "undefined" || body === null
1954
+ ? null
1955
+ : payloadFormatter(body),
1956
+ }).then(async (response) => {
1957
+ const r = response.clone();
1958
+ r.data = null;
1959
+ r.error = null;
1960
+ if (typeof E !== undefined && responseFormat === undefined)
1961
+ responseFormat = "json";
1962
+ const data = !responseFormat
1963
+ ? r
1964
+ : await response[responseFormat]()
1965
+ .then((data) => {
1966
+ if (r.ok) {
1967
+ r.data = data;
1968
+ }
1969
+ else {
1970
+ r.error = data;
1971
+ }
1972
+ return r;
1973
+ })
1974
+ .catch((e) => {
1975
+ r.error = e;
1976
+ return r;
1977
+ });
1978
+ if (cancelToken) {
1979
+ this.abortControllers.delete(cancelToken);
1980
+ }
1981
+ if (!response.ok)
1982
+ throw data;
1983
+ return data.data;
1984
+ });
1985
+ };
1986
+ this.securityService.getAccessToken().subscribe((token) => {
1987
+ this.securityData = token;
1988
+ });
1989
+ }
1990
+ encodeQueryParam(key, value) {
1991
+ const encodedKey = encodeURIComponent(key);
1992
+ return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
1993
+ }
1994
+ addQueryParam(query, key) {
1995
+ return this.encodeQueryParam(key, query[key]);
1996
+ }
1997
+ addArrayQueryParam(query, key) {
1998
+ const value = query[key];
1999
+ return value.map((v) => this.encodeQueryParam(key, v)).join("&");
2000
+ }
2001
+ toQueryString(rawQuery) {
2002
+ const query = rawQuery || {};
2003
+ const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
2004
+ return keys
2005
+ .map((key) => Array.isArray(query[key])
2006
+ ? this.addArrayQueryParam(query, key)
2007
+ : this.addQueryParam(query, key))
2008
+ .join("&");
2009
+ }
2010
+ addQueryParams(rawQuery) {
2011
+ const queryString = this.toQueryString(rawQuery);
2012
+ return queryString ? `?${queryString}` : "";
2013
+ }
2014
+ mergeRequestParams(params1, params2) {
2015
+ return {
2016
+ ...this.baseApiParams,
2017
+ ...params1,
2018
+ ...(params2 || {}),
2019
+ headers: {
2020
+ ...(this.baseApiParams.headers || {}),
2021
+ ...(params1.headers || {}),
2022
+ ...((params2 && params2.headers) || {}),
2023
+ },
2024
+ };
2025
+ }
2026
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: HttpClient, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2027
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: HttpClient, providedIn: "root" }); }
2028
+ }
2029
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: HttpClient, decorators: [{
2030
+ type: Injectable,
2031
+ args: [{ providedIn: "root" }]
2032
+ }], ctorParameters: () => [] });
2033
+
2034
+ /* eslint-disable */
2035
+ /* tslint:disable */
2036
+ // @ts-nocheck
2037
+ /*
2038
+ * ---------------------------------------------------------------
2039
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
2040
+ * ## ##
2041
+ * ## AUTHOR: acacode ##
2042
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
2043
+ * ---------------------------------------------------------------
2044
+ */
2045
+ class Menu extends HttpClient {
2046
+ constructor() {
2047
+ super(...arguments);
2048
+ /**
2049
+ * @description Retrieves the menu available to the current authenticated user.
2050
+ *
2051
+ * @tags Menu
2052
+ * @name menuGet
2053
+ * @request GET:/api/menu/get
2054
+ * @secure
2055
+ */
2056
+ this.menuGet = (params = {}) => this.request({
2057
+ path: `/api/menu/get`,
2058
+ method: "GET",
2059
+ secure: true,
2060
+ format: "json",
2061
+ ...params,
2062
+ });
2063
+ /**
2064
+ * @description Retrieves the admin-specific menu.
2065
+ *
2066
+ * @tags Menu
2067
+ * @name menuGetAdminMenu
2068
+ * @request GET:/api/menu/get-admin-menu
2069
+ * @secure
2070
+ */
2071
+ this.menuGetAdminMenu = (params = {}) => this.request({
2072
+ path: `/api/menu/get-admin-menu`,
2073
+ method: "GET",
2074
+ secure: true,
2075
+ format: "json",
2076
+ ...params,
2077
+ });
2078
+ /**
2079
+ * @description Retrieves all available modules in the system.
2080
+ *
2081
+ * @tags Menu
2082
+ * @name menuGetModules
2083
+ * @request GET:/api/menu/get-modules
2084
+ * @secure
2085
+ */
2086
+ this.menuGetModules = (params = {}) => this.request({
2087
+ path: `/api/menu/get-modules`,
2088
+ method: "GET",
2089
+ secure: true,
2090
+ format: "json",
2091
+ ...params,
2092
+ });
2093
+ /**
2094
+ * @description Adds a new module instance to the system.
2095
+ *
2096
+ * @tags Menu
2097
+ * @name menuAddModuleInstance
2098
+ * @request POST:/api/menu/add-module-instance
2099
+ * @secure
2100
+ */
2101
+ this.menuAddModuleInstance = (data, params = {}) => this.request({
2102
+ path: `/api/menu/add-module-instance`,
2103
+ method: "POST",
2104
+ body: data,
2105
+ secure: true,
2106
+ type: ContentType.Json,
2107
+ ...params,
2108
+ });
2109
+ /**
2110
+ * @description Edits an existing module instance.
2111
+ *
2112
+ * @tags Menu
2113
+ * @name menuEditModuleInstance
2114
+ * @request POST:/api/menu/edit-module-instance
2115
+ * @secure
2116
+ */
2117
+ this.menuEditModuleInstance = (data, params = {}) => this.request({
2118
+ path: `/api/menu/edit-module-instance`,
2119
+ method: "POST",
2120
+ body: data,
2121
+ secure: true,
2122
+ type: ContentType.Json,
2123
+ ...params,
2124
+ });
2125
+ /**
2126
+ * @description Deletes a module instance by its identifier.
2127
+ *
2128
+ * @tags Menu
2129
+ * @name menuDeleteModuleInstance
2130
+ * @request DELETE:/api/menu/delete-module-instance
2131
+ * @secure
2132
+ */
2133
+ this.menuDeleteModuleInstance = (query, params = {}) => this.request({
2134
+ path: `/api/menu/delete-module-instance`,
2135
+ method: "DELETE",
2136
+ query: query,
2137
+ secure: true,
2138
+ ...params,
2139
+ });
2140
+ }
2141
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Menu, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2142
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Menu }); }
2143
+ }
2144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Menu, decorators: [{
2145
+ type: Injectable
2146
+ }] });
2147
+
2148
+ class MenuService extends BaseDataService {
2149
+ constructor() {
2150
+ super(...arguments);
2151
+ this.menuSource = new Subject();
2152
+ this.resetSource = new Subject();
2153
+ this.titleService = inject(AppTitleService);
2154
+ this.menuDataService = inject(Menu);
2155
+ this.menuSource$ = this.menuSource.asObservable();
2156
+ this.resetSource$ = this.resetSource.asObservable();
2157
+ this.menu = [];
2158
+ this.adminMode = false;
2159
+ }
2160
+ async loadMenu() {
2161
+ this.menu = this.adminMode ? await this.getAdminMenu() : await this.getMenu();
2162
+ }
2163
+ /**
2164
+ * Handles changes in the menu state.
2165
+ * @param {MenuChangeEvent} event - The event containing information about the menu state change.
2166
+ * @return {void}
2167
+ */
2168
+ onMenuStateChange(event) {
2169
+ this.menuSource.next(event);
2170
+ this.titleService.setTitle(event.item.label);
2171
+ }
2172
+ reset() {
2173
+ this.resetSource.next(true);
2174
+ }
2175
+ getMenu() {
2176
+ return this.menuDataService.menuGet();
2177
+ }
2178
+ getAdminMenu() {
2179
+ return this.menuDataService.menuGetAdminMenu();
2180
+ }
2181
+ getModules() {
2182
+ return this.menuDataService.menuGetModules();
2183
+ }
2184
+ addModuleInstance(addModuleInstance) {
2185
+ return this.menuDataService.menuAddModuleInstance(addModuleInstance);
2186
+ }
2187
+ deleteItem(moduleInstanceId) {
2188
+ return this.sendRequest(this.baseUrl + 'api/menu/delete-module-instance?id=' + moduleInstanceId, 'DELETE');
2189
+ }
2190
+ editModuleInstance(item) {
2191
+ return this.sendRequest(this.baseUrl + 'api/menu/edit-module-instance', 'POST', item);
2192
+ }
2193
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
2194
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuService }); }
2195
+ }
2196
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuService, decorators: [{
2197
+ type: Injectable
2198
+ }] });
2199
+
2200
+ class MenuItemComponent {
2201
+ constructor(cd, router, menuService) {
2202
+ this.cd = cd;
2203
+ this.router = router;
2204
+ this.menuService = menuService;
2205
+ this.layoutService = inject(LayoutService);
2206
+ this.translateService = inject(TranslateService);
2207
+ this.confirmationService = inject(ConfirmationService);
2208
+ this.msgService = inject(MsgService);
2209
+ this.menuDataService = inject(Menu);
2210
+ this.active = false;
2211
+ this.subscriptions = [];
2212
+ this.localization = {};
2213
+ this.key = '';
2214
+ this.subscriptions.push(this.menuService.menuSource$.subscribe((value) => {
2215
+ Promise.resolve(null).then(() => {
2216
+ if (value.routeEvent) {
2217
+ this.active = value.key === this.key || value.key.startsWith(this.key + '-');
2218
+ }
2219
+ else if (value.key !== this.key && !value.key.startsWith(this.key + '-')) {
2220
+ this.active = false;
2221
+ }
2222
+ });
2223
+ }));
2224
+ this.subscriptions.push(this.menuService.resetSource$.subscribe(() => {
2225
+ this.active = false;
2226
+ }));
2227
+ this.subscriptions.push(this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe((params) => {
2228
+ if (this.item.routerLink) {
2229
+ this.updateActiveStateFromRoute();
2230
+ }
2231
+ }));
2232
+ this.subscriptions.push(this.translateService.get('menuItemComponent').subscribe((value) => {
2233
+ this.localization = value;
2234
+ }));
2235
+ }
2236
+ ngOnInit() {
2237
+ this.key = this.parentKey ? this.parentKey + '-' + this.index : String(this.index);
2238
+ if (this.item.routerLink) {
2239
+ this.updateActiveStateFromRoute();
2240
+ }
2241
+ }
2242
+ updateActiveStateFromRoute() {
2243
+ const activeRoute = this.router.isActive(this.item.routerLink[0], {
2244
+ paths: 'exact',
2245
+ queryParams: 'ignored',
2246
+ matrixParams: 'ignored',
2247
+ fragment: 'ignored'
2248
+ });
2249
+ if (activeRoute) {
2250
+ this.menuService.onMenuStateChange({
2251
+ key: this.key,
2252
+ item: this.item,
2253
+ routeEvent: true
2254
+ });
2255
+ }
2256
+ }
2257
+ itemClick(event) {
2258
+ // avoid processing disabled items
2259
+ if (this.item.disabled) {
2260
+ event.preventDefault();
2261
+ return;
2262
+ }
2263
+ // execute command
2264
+ if (this.item.command) {
2265
+ this.item.command({ originalEvent: event, item: this.item });
2266
+ }
2267
+ // toggle active state
2268
+ if (this.item.items) {
2269
+ this.active = !this.active;
2270
+ }
2271
+ this.menuService.onMenuStateChange({ key: this.key, item: this.item });
2272
+ }
2273
+ get submenuAnimation() {
2274
+ return this.root || this.active ? 'expanded' : 'collapsed';
2275
+ }
2276
+ get activeClass() {
2277
+ return this.active && !this.root;
2278
+ }
2279
+ ngOnDestroy() {
2280
+ this.subscriptions.map((s) => s.unsubscribe());
2281
+ }
2282
+ newClick(e) {
2283
+ this.menuItemCreateDialogComponent.showDialog();
2284
+ }
2285
+ onContextMenu($event, item) {
2286
+ this.menuService.contextMenuItem = item;
2287
+ this.contextMenu.model = [
2288
+ {
2289
+ label: this.localization.new,
2290
+ icon: PrimeIcons.PLUS,
2291
+ command: (event) => this.newClick(event)
2292
+ },
2293
+ {
2294
+ label: this.localization.edit,
2295
+ icon: PrimeIcons.FILE_EDIT,
2296
+ command: (event) => this.editClick(event)
2297
+ },
2298
+ { separator: true },
2299
+ {
2300
+ label: this.localization.delete,
2301
+ icon: PrimeIcons.TRASH,
2302
+ command: (event) => this.deleteItem(event)
2303
+ }
2304
+ ];
2305
+ this.contextMenu.show($event);
2306
+ }
2307
+ deleteItem(event) {
2308
+ this.confirmationService.confirm({
2309
+ header: this.localization.deleteItemConfirmHeader,
2310
+ message: this.localization.deleteItemConfirmMessage,
2311
+ icon: PrimeIcons.TRASH,
2312
+ rejectButtonProps: {
2313
+ label: this.localization.deleteItemConfirmRejectButtonPropsLabel,
2314
+ severity: 'secondary',
2315
+ outlined: true
2316
+ },
2317
+ acceptButtonProps: {
2318
+ label: this.localization.deleteItemConfirmAcceptButtonPropsLabel,
2319
+ severity: 'danger'
2320
+ },
2321
+ accept: async () => {
2322
+ await this.menuDataService.menuDeleteModuleInstance({
2323
+ id: this.menuService.contextMenuItem?.moduleInstanceId
2324
+ });
2325
+ this.msgService.success(this.localization.deleteItemSuccessMessage);
2326
+ await this.menuService.loadMenu();
2327
+ }
2328
+ });
2329
+ }
2330
+ editClick(event) {
2331
+ this.menuItemEditDialogComponent.showDialog();
2332
+ }
2333
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuItemComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$3.Router }, { token: MenuService }], target: i0.ɵɵFactoryTarget.Component }); }
2334
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", 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: `
2335
+ <ng-container>
2336
+ <p-confirm-dialog />
2337
+ <div
2338
+ *ngIf="root && item.visible !== false"
2339
+ class="layout-menuitem-root-text"
2340
+ (contextmenu)="onContextMenu($event, item)">
2341
+ {{ item.label }}
2342
+ </div>
2343
+ <a
2344
+ *ngIf="(!item.routerLink || item.items) && item.visible !== false"
2345
+ pRipple
2346
+ tabindex="0"
2347
+ [attr.href]="item.url"
2348
+ [attr.target]="item.target"
2349
+ [ngClass]="item.class"
2350
+ (click)="itemClick($event)">
2351
+ <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
2352
+ <span class="layout-menuitem-text">{{ item.label }}</span>
2353
+ <i *ngIf="item.items" class="pi pi-fw pi-angle-down layout-submenu-toggler"></i>
2354
+ </a>
2355
+ <a
2356
+ *ngIf="item.routerLink && !item.items && item.visible !== false"
2357
+ pRipple
2358
+ routerLinkActive="active-route"
2359
+ tabindex="0"
2360
+ [attr.target]="item.target"
2361
+ [fragment]="item.fragment"
2362
+ [ngClass]="item.class"
2363
+ [preserveFragment]="item.preserveFragment"
2364
+ [queryParams]="item.queryParams"
2365
+ [queryParamsHandling]="item.queryParamsHandling"
2366
+ [replaceUrl]="item.replaceUrl"
2367
+ [routerLink]="item.routerLink"
2368
+ [routerLinkActiveOptions]="
2369
+ item.routerLinkActiveOptions || {
2370
+ paths: 'exact',
2371
+ queryParams: 'ignored',
2372
+ matrixParams: 'ignored',
2373
+ fragment: 'ignored'
2374
+ }
2375
+ "
2376
+ [skipLocationChange]="item.skipLocationChange"
2377
+ [state]="item.state"
2378
+ (click)="itemClick($event)"
2379
+ (contextmenu)="onContextMenu($event, item)">
2380
+ <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
2381
+ <span class="layout-menuitem-text">{{ item.label }}</span>
2382
+ <i *ngIf="item.items" class="pi pi-fw pi-angle-down layout-submenu-toggler"></i>
2383
+ </a>
2384
+
2385
+ <ul
2386
+ *ngIf="item.items && item.visible !== false"
2387
+ [@children]="submenuAnimation"
2388
+ (contextmenu)="onContextMenu($event, item)">
2389
+ <ng-template let-child let-i="index" ngFor [ngForOf]="item.items">
2390
+ <li
2391
+ app-menuitem
2392
+ [class]="child.badgeClass"
2393
+ [contextMenu]="contextMenu"
2394
+ [index]="i"
2395
+ [item]="child"
2396
+ [menuItemCreateDialogComponent]="menuItemCreateDialogComponent"
2397
+ [menuItemEditDialogComponent]="menuItemEditDialogComponent"
2398
+ [parentKey]="key"></li>
2399
+ </ng-template>
2400
+ </ul>
2401
+ </ng-container>
2402
+ `, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i3$1.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: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { 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", "visible", "position", "draggable"], outputs: ["onHide"] }], animations: [
2403
+ trigger('children', [
2404
+ state('collapsed', style({
2405
+ height: '0'
2406
+ })),
2407
+ state('expanded', style({
2408
+ height: '*'
2409
+ })),
2410
+ transition('collapsed <=> expanded', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
2411
+ ])
2412
+ ] }); }
2413
+ }
2414
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuItemComponent, decorators: [{
2415
+ type: Component,
2416
+ args: [{
2417
+ // eslint-disable-next-line @angular-eslint/component-selector
2418
+ selector: '[app-menuitem]',
2419
+ template: `
2420
+ <ng-container>
2421
+ <p-confirm-dialog />
2422
+ <div
2423
+ *ngIf="root && item.visible !== false"
2424
+ class="layout-menuitem-root-text"
2425
+ (contextmenu)="onContextMenu($event, item)">
2426
+ {{ item.label }}
2427
+ </div>
2428
+ <a
2429
+ *ngIf="(!item.routerLink || item.items) && item.visible !== false"
2430
+ pRipple
2431
+ tabindex="0"
2432
+ [attr.href]="item.url"
2433
+ [attr.target]="item.target"
2434
+ [ngClass]="item.class"
2435
+ (click)="itemClick($event)">
2436
+ <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
2437
+ <span class="layout-menuitem-text">{{ item.label }}</span>
2438
+ <i *ngIf="item.items" class="pi pi-fw pi-angle-down layout-submenu-toggler"></i>
2439
+ </a>
2440
+ <a
2441
+ *ngIf="item.routerLink && !item.items && item.visible !== false"
2442
+ pRipple
2443
+ routerLinkActive="active-route"
2444
+ tabindex="0"
2445
+ [attr.target]="item.target"
2446
+ [fragment]="item.fragment"
2447
+ [ngClass]="item.class"
2448
+ [preserveFragment]="item.preserveFragment"
2449
+ [queryParams]="item.queryParams"
2450
+ [queryParamsHandling]="item.queryParamsHandling"
2451
+ [replaceUrl]="item.replaceUrl"
2452
+ [routerLink]="item.routerLink"
2453
+ [routerLinkActiveOptions]="
2454
+ item.routerLinkActiveOptions || {
2455
+ paths: 'exact',
2456
+ queryParams: 'ignored',
2457
+ matrixParams: 'ignored',
2458
+ fragment: 'ignored'
2459
+ }
2460
+ "
2461
+ [skipLocationChange]="item.skipLocationChange"
2462
+ [state]="item.state"
2463
+ (click)="itemClick($event)"
2464
+ (contextmenu)="onContextMenu($event, item)">
2465
+ <i class="layout-menuitem-icon" [ngClass]="item.icon"></i>
2466
+ <span class="layout-menuitem-text">{{ item.label }}</span>
2467
+ <i *ngIf="item.items" class="pi pi-fw pi-angle-down layout-submenu-toggler"></i>
2468
+ </a>
2469
+
2470
+ <ul
2471
+ *ngIf="item.items && item.visible !== false"
2472
+ [@children]="submenuAnimation"
2473
+ (contextmenu)="onContextMenu($event, item)">
2474
+ <ng-template let-child let-i="index" ngFor [ngForOf]="item.items">
2475
+ <li
2476
+ app-menuitem
2477
+ [class]="child.badgeClass"
2478
+ [contextMenu]="contextMenu"
2479
+ [index]="i"
2480
+ [item]="child"
2481
+ [menuItemCreateDialogComponent]="menuItemCreateDialogComponent"
2482
+ [menuItemEditDialogComponent]="menuItemEditDialogComponent"
2483
+ [parentKey]="key"></li>
2484
+ </ng-template>
2485
+ </ul>
2486
+ </ng-container>
2487
+ `,
2488
+ animations: [
2489
+ trigger('children', [
2490
+ state('collapsed', style({
2491
+ height: '0'
2492
+ })),
2493
+ state('expanded', style({
2494
+ height: '*'
2495
+ })),
2496
+ transition('collapsed <=> expanded', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
2497
+ ])
2498
+ ],
2499
+ imports: [NgIf, RippleModule, NgClass, RouterLinkActive, RouterLink, NgFor, ContextMenuModule, ConfirmDialog],
2500
+ providers: [ConfirmationService]
2501
+ }]
2502
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$3.Router }, { type: MenuService }], propDecorators: { item: [{
2503
+ type: Input
2504
+ }], index: [{
2505
+ type: Input
2506
+ }], root: [{
2507
+ type: Input
2508
+ }, {
2509
+ type: HostBinding,
2510
+ args: ['class.layout-root-menuitem']
2511
+ }], parentKey: [{
2512
+ type: Input
2513
+ }], menuItemCreateDialogComponent: [{
2514
+ type: Input
2515
+ }], menuItemEditDialogComponent: [{
2516
+ type: Input
2517
+ }], contextMenu: [{
2518
+ type: Input
2519
+ }], activeClass: [{
2520
+ type: HostBinding,
2521
+ args: ['class.active-menuitem']
2522
+ }] } });
2523
+
2524
+ class MenuItemCreateDialogComponent {
2525
+ constructor() {
2526
+ this.menuService = inject(MenuService);
2527
+ this.menu = inject(Menu);
2528
+ this.visibleChange = new EventEmitter();
2529
+ this.modules = [];
2530
+ this.selectIcon = 'pi pi-box';
2531
+ }
2532
+ async ngOnInit() {
2533
+ this.modules = await this.menu.menuGetModules();
2534
+ }
2535
+ changeVisible() {
2536
+ this.visible = !this.visible;
2537
+ this.visibleChange.emit(this.visible);
2538
+ }
2539
+ async save() {
2540
+ const item = {
2541
+ moduleId: this.selectModule,
2542
+ label: this.label,
2543
+ icon: this.selectIcon,
2544
+ parentId: this.menuService.contextMenuItem?.moduleInstanceId
2545
+ };
2546
+ await this.menuService.addModuleInstance(item);
2547
+ await this.menuService.loadMenu();
2548
+ this.hide();
2549
+ }
2550
+ hide() {
2551
+ this.visible = false;
2552
+ this.visibleChange.emit(this.visible);
2553
+ }
2554
+ showDialog() {
2555
+ this.visible = true;
2556
+ this.visibleChange.emit(this.visible);
2557
+ }
2558
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuItemCreateDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2559
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: MenuItemCreateDialogComponent, isStandalone: true, selector: "menu-item-create-dialog", inputs: { visible: "visible" }, outputs: { visibleChange: "visibleChange" }, ngImport: i0, template: `
2560
+ <p-dialog
2561
+ header="{{ 'menuItemCreateDialogComponent.header' | translate }}"
2562
+ [modal]="true"
2563
+ [style]="{ width: '40rem' }"
2564
+ [(visible)]="visible">
2565
+ @if (menuService.contextMenuItem) {
2566
+ <div class="flex items-center gap-4 mb-4 mt-1">
2567
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-parent-input">
2568
+ {{ 'menuItemCreateDialogComponent.parentLabel' | translate }}
2569
+ </label>
2570
+ <input
2571
+ autocomplete="off"
2572
+ class="flex-auto"
2573
+ id="oip-menu-item-create-dialog-parent-input"
2574
+ pInputText
2575
+ readonly
2576
+ [ngModel]="menuService.contextMenuItem?.label"/>
2577
+ </div>
2578
+ }
2579
+ <div class="flex items-center gap-4 mb-4">
2580
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-label">
2581
+ {{ 'menuItemCreateDialogComponent.label' | translate }}
2582
+ </label>
2583
+ <input autocomplete="off" class="flex-auto" id="oip-menu-item-create-label" pInputText [(ngModel)]="label"/>
2584
+ </div>
2585
+ <div class="flex items-center gap-4 mb-4">
2586
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-module">
2587
+ {{ 'menuItemCreateDialogComponent.module' | translate }}
2588
+ </label>
2589
+ <p-select
2590
+ appendTo="body"
2591
+ class="flex-auto"
2592
+ id="oip-menu-item-create-module"
2593
+ optionLabel="value"
2594
+ optionValue="key"
2595
+ placeholder="{{ 'menuItemCreateDialogComponent.selectModule' | translate }}"
2596
+ [options]="modules"
2597
+ [(ngModel)]="selectModule"/>
2598
+ </div>
2599
+ <div class="flex items-center gap-4 mb-4">
2600
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-icon">
2601
+ {{ 'menuItemCreateDialogComponent.icon' | translate }}
2602
+ </label>
2603
+ <i class="{{ selectIcon }}"></i>
2604
+ <input class="flex-auto" id="oip-menu-item-create-dialog-icon" pInputText [(ngModel)]="selectIcon"/>
2605
+ </div>
2606
+ <div class="flex justify-end gap-2">
2607
+ <p-button
2608
+ id="oip-menu-item-create-cancel"
2609
+ label="{{ 'menuItemCreateDialogComponent.cancel' | translate }}"
2610
+ severity="secondary"
2611
+ (click)="changeVisible()"
2612
+ (keydown)="changeVisible()"/>
2613
+ <p-button
2614
+ id="oip-menu-item-create-save"
2615
+ label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
2616
+ (click)="save()"
2617
+ (keydown)="save()"/>
2618
+ </div>
2619
+ </p-dialog>
2620
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$2.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i4$1.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: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
2621
+ }
2622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuItemCreateDialogComponent, decorators: [{
2623
+ type: Component,
2624
+ args: [{
2625
+ selector: 'menu-item-create-dialog',
2626
+ standalone: true,
2627
+ imports: [ButtonModule, DialogModule, InputTextModule, SelectModule, FormsModule, TranslatePipe],
2628
+ template: `
2629
+ <p-dialog
2630
+ header="{{ 'menuItemCreateDialogComponent.header' | translate }}"
2631
+ [modal]="true"
2632
+ [style]="{ width: '40rem' }"
2633
+ [(visible)]="visible">
2634
+ @if (menuService.contextMenuItem) {
2635
+ <div class="flex items-center gap-4 mb-4 mt-1">
2636
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-parent-input">
2637
+ {{ 'menuItemCreateDialogComponent.parentLabel' | translate }}
2638
+ </label>
2639
+ <input
2640
+ autocomplete="off"
2641
+ class="flex-auto"
2642
+ id="oip-menu-item-create-dialog-parent-input"
2643
+ pInputText
2644
+ readonly
2645
+ [ngModel]="menuService.contextMenuItem?.label"/>
2646
+ </div>
2647
+ }
2648
+ <div class="flex items-center gap-4 mb-4">
2649
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-label">
2650
+ {{ 'menuItemCreateDialogComponent.label' | translate }}
2651
+ </label>
2652
+ <input autocomplete="off" class="flex-auto" id="oip-menu-item-create-label" pInputText [(ngModel)]="label"/>
2653
+ </div>
2654
+ <div class="flex items-center gap-4 mb-4">
2655
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-module">
2656
+ {{ 'menuItemCreateDialogComponent.module' | translate }}
2657
+ </label>
2658
+ <p-select
2659
+ appendTo="body"
2660
+ class="flex-auto"
2661
+ id="oip-menu-item-create-module"
2662
+ optionLabel="value"
2663
+ optionValue="key"
2664
+ placeholder="{{ 'menuItemCreateDialogComponent.selectModule' | translate }}"
2665
+ [options]="modules"
2666
+ [(ngModel)]="selectModule"/>
2667
+ </div>
2668
+ <div class="flex items-center gap-4 mb-4">
2669
+ <label class="font-semibold w-1/3" for="oip-menu-item-create-dialog-icon">
2670
+ {{ 'menuItemCreateDialogComponent.icon' | translate }}
2671
+ </label>
2672
+ <i class="{{ selectIcon }}"></i>
2673
+ <input class="flex-auto" id="oip-menu-item-create-dialog-icon" pInputText [(ngModel)]="selectIcon"/>
2674
+ </div>
2675
+ <div class="flex justify-end gap-2">
2676
+ <p-button
2677
+ id="oip-menu-item-create-cancel"
2678
+ label="{{ 'menuItemCreateDialogComponent.cancel' | translate }}"
2679
+ severity="secondary"
2680
+ (click)="changeVisible()"
2681
+ (keydown)="changeVisible()"/>
2682
+ <p-button
2683
+ id="oip-menu-item-create-save"
2684
+ label="{{ 'menuItemCreateDialogComponent.save' | translate }}"
2685
+ (click)="save()"
2686
+ (keydown)="save()"/>
2687
+ </div>
2688
+ </p-dialog>
2689
+ `
2690
+ }]
2691
+ }], propDecorators: { visible: [{
2692
+ type: Input
2693
+ }], visibleChange: [{
2694
+ type: Output
2695
+ }] } });
2696
+
2697
+ class MenuItemEditDialogComponent {
2698
+ constructor() {
2699
+ this.menuService = inject(MenuService);
2700
+ this.securityDataService = inject(SecurityDataService);
2701
+ this.visibleChange = new EventEmitter();
2702
+ this.modules = [];
2703
+ this.roles = [];
2704
+ this.item = {
2705
+ icon: '',
2706
+ label: '',
2707
+ viewRoles: [''],
2708
+ moduleId: 0,
2709
+ moduleInstanceId: 0,
2710
+ parentId: 0
2711
+ };
2712
+ }
2713
+ changeVisible() {
2714
+ this.visible = !this.visible;
2715
+ this.visibleChange.emit(this.visible);
2716
+ }
2717
+ async save() {
2718
+ await this.menuService.editModuleInstance(this.item);
2719
+ await this.menuService.loadMenu();
2720
+ this.hide();
2721
+ }
2722
+ hide() {
2723
+ this.visible = false;
2724
+ this.visibleChange.emit(this.visible);
2725
+ }
2726
+ async showDialog() {
2727
+ this.item = {
2728
+ moduleInstanceId: this.menuService.contextMenuItem?.moduleInstanceId,
2729
+ moduleId: this.menuService.contextMenuItem?.moduleId,
2730
+ parentId: this.menuService.contextMenuItem?.parentId,
2731
+ label: this.menuService.contextMenuItem?.label,
2732
+ icon: this.menuService.contextMenuItem?.icon,
2733
+ viewRoles: this.menuService.contextMenuItem?.securities
2734
+ };
2735
+ this.roles = await this.securityDataService.getRealmRoles();
2736
+ this.menuService.getModules().then((data) => {
2737
+ this.modules = data;
2738
+ });
2739
+ this.visible = true;
2740
+ this.visibleChange.emit(this.visible);
2741
+ }
2742
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuItemEditDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2743
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: MenuItemEditDialogComponent, isStandalone: true, selector: "menu-item-edit-dialog", inputs: { visible: "visible" }, outputs: { visibleChange: "visibleChange" }, ngImport: i0, template: `
2744
+ <p-dialog
2745
+ header="{{ 'menuItemEditDialogComponent.header' | translate }}"
2746
+ [modal]="true"
2747
+ [style]="{ width: '40rem' }"
2748
+ [(visible)]="visible">
2749
+ <div class="flex items-center gap-4 mb-4 mt-1">
2750
+ <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-menu-input">
2751
+ {{ 'menuItemEditDialogComponent.label' | translate }}
2752
+ </label>
2753
+ <input
2754
+ autocomplete="off"
2755
+ class="flex-auto"
2756
+ id="oip-menu-item-edit-dialog-menu-input"
2757
+ pInputText
2758
+ [(ngModel)]="item.label"/>
2759
+ </div>
2760
+
2761
+ <div class="flex items-center gap-4 mb-4">
2762
+ <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-icon">
2763
+ {{ 'menuItemEditDialogComponent.icon' | translate }}
2764
+ </label>
2765
+ <i class="{{ item.icon }}"></i>
2766
+ <input class="flex-auto" id="oip-menu-item-edit-dialog-icon" pInputText [(ngModel)]="item.icon"/>
2767
+ </div>
2768
+
2769
+ <div class="flex items-center gap-4 mb-4">
2770
+ <label class="font-semibold w-1/3" for="security">
2771
+ {{ 'menuItemEditDialogComponent.security' | translate }}
2772
+ </label>
2773
+ <p-multiSelect
2774
+ appendTo="body"
2775
+ class="flex-auto"
2776
+ id="oip-menu-item-edit-dialog-roles-multi-select"
2777
+ placeholder="Select roles"
2778
+ [maxSelectedLabels]="10"
2779
+ [options]="roles"
2780
+ [(ngModel)]="item.viewRoles"/>
2781
+ </div>
2782
+
2783
+ <div class="flex justify-end gap-2">
2784
+ <p-button
2785
+ id="oip-menu-item-edit-dialog-cancel-edit-button"
2786
+ label="{{ 'menuItemEditDialogComponent.cancel' | translate }}"
2787
+ severity="secondary"
2788
+ (click)="changeVisible()"
2789
+ (keydown)="changeVisible()"/>
2790
+ <p-button
2791
+ id="oip-menu-item-edit-dialog-save-edit-button"
2792
+ label="{{ 'menuItemEditDialogComponent.save' | translate }}"
2793
+ (click)="save()"
2794
+ (keydown)="save()"/>
2795
+ </div>
2796
+ </p-dialog>
2797
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$2.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.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" }] }); }
2798
+ }
2799
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuItemEditDialogComponent, decorators: [{
2800
+ type: Component,
2801
+ args: [{
2802
+ imports: [ButtonModule, DialogModule, InputTextModule, FormsModule, TranslatePipe, MultiSelectModule],
2803
+ selector: 'menu-item-edit-dialog',
2804
+ standalone: true,
2805
+ template: `
2806
+ <p-dialog
2807
+ header="{{ 'menuItemEditDialogComponent.header' | translate }}"
2808
+ [modal]="true"
2809
+ [style]="{ width: '40rem' }"
2810
+ [(visible)]="visible">
2811
+ <div class="flex items-center gap-4 mb-4 mt-1">
2812
+ <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-menu-input">
2813
+ {{ 'menuItemEditDialogComponent.label' | translate }}
2814
+ </label>
2815
+ <input
2816
+ autocomplete="off"
2817
+ class="flex-auto"
2818
+ id="oip-menu-item-edit-dialog-menu-input"
2819
+ pInputText
2820
+ [(ngModel)]="item.label"/>
2821
+ </div>
2822
+
2823
+ <div class="flex items-center gap-4 mb-4">
2824
+ <label class="font-semibold w-1/3" for="oip-menu-item-edit-dialog-icon">
2825
+ {{ 'menuItemEditDialogComponent.icon' | translate }}
2826
+ </label>
2827
+ <i class="{{ item.icon }}"></i>
2828
+ <input class="flex-auto" id="oip-menu-item-edit-dialog-icon" pInputText [(ngModel)]="item.icon"/>
2829
+ </div>
2830
+
2831
+ <div class="flex items-center gap-4 mb-4">
2832
+ <label class="font-semibold w-1/3" for="security">
2833
+ {{ 'menuItemEditDialogComponent.security' | translate }}
2834
+ </label>
2835
+ <p-multiSelect
2836
+ appendTo="body"
2837
+ class="flex-auto"
2838
+ id="oip-menu-item-edit-dialog-roles-multi-select"
2839
+ placeholder="Select roles"
2840
+ [maxSelectedLabels]="10"
2841
+ [options]="roles"
2842
+ [(ngModel)]="item.viewRoles"/>
2843
+ </div>
2844
+
2845
+ <div class="flex justify-end gap-2">
2846
+ <p-button
2847
+ id="oip-menu-item-edit-dialog-cancel-edit-button"
2848
+ label="{{ 'menuItemEditDialogComponent.cancel' | translate }}"
2849
+ severity="secondary"
2850
+ (click)="changeVisible()"
2851
+ (keydown)="changeVisible()"/>
2852
+ <p-button
2853
+ id="oip-menu-item-edit-dialog-save-edit-button"
2854
+ label="{{ 'menuItemEditDialogComponent.save' | translate }}"
2855
+ (click)="save()"
2856
+ (keydown)="save()"/>
2857
+ </div>
2858
+ </p-dialog>
2859
+ `
2860
+ }]
2861
+ }], propDecorators: { visible: [{
2862
+ type: Input
2863
+ }], visibleChange: [{
2864
+ type: Output
2865
+ }] } });
2866
+
2867
+ class MenuComponent {
2868
+ constructor() {
2869
+ this.menuService = inject(MenuService);
2870
+ this.securityService = inject(SecurityService);
2871
+ this.translateService = inject(TranslateService);
2872
+ }
2873
+ ngOnInit() {
2874
+ this.menuService.loadMenu().then();
2875
+ }
2876
+ newClick(e) {
2877
+ this.menuItemCreateDialogComponent.showDialog();
2878
+ }
2879
+ onContextMenu($event) {
2880
+ this.menuService.contextMenuItem = null;
2881
+ this.contextMenu.model = [
2882
+ {
2883
+ label: this.translateService.instant('menuComponent.new'),
2884
+ icon: PrimeIcons.PLUS,
2885
+ command: (event) => this.newClick(event)
2886
+ }
2887
+ ];
2888
+ }
2889
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2890
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: MenuComponent, isStandalone: true, selector: "app-menu", providers: [Menu], viewQueries: [{ propertyName: "menuItemCreateDialogComponent", first: true, predicate: MenuItemCreateDialogComponent, descendants: true }, { propertyName: "menuItemEditDialogComponent", first: true, predicate: MenuItemEditDialogComponent, descendants: true }, { propertyName: "contextMenu", first: true, predicate: ContextMenu, descendants: true }], ngImport: i0, template: ` <div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
2891
+ <ul class="layout-menu">
2892
+ @for (item of menuService.menu; track item; let i = $index) {
2893
+ <ng-container>
2894
+ @if (item.separator) {
2895
+ <li class="menu-separator"></li>
2896
+ } @else {
2897
+ <li
2898
+ app-menuitem
2899
+ [contextMenu]="contextMenu"
2900
+ [index]="i"
2901
+ [item]="item"
2902
+ [menuItemCreateDialogComponent]="menuItemCreateDialogComponent"
2903
+ [menuItemEditDialogComponent]="menuItemEditDialogComponent"
2904
+ [root]="true"></li>
2905
+ }
2906
+ </ng-container>
2907
+ }
2908
+ </ul>
2909
+ </div>
2910
+ <p-contextMenu [target]="empty" />
2911
+ @if (securityService.isAdmin) {
2912
+ <menu-item-create-dialog />
2913
+ <menu-item-edit-dialog />
2914
+ }`, 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"] }] }); }
2915
+ }
2916
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: MenuComponent, decorators: [{
2917
+ type: Component,
2918
+ args: [{
2919
+ imports: [
2920
+ MenuItemComponent,
2921
+ ButtonModule,
2922
+ ContextMenuModule,
2923
+ DialogModule,
2924
+ InputTextModule,
2925
+ MenuItemCreateDialogComponent,
2926
+ FormsModule,
2927
+ MenuItemEditDialogComponent
2928
+ ],
2929
+ providers: [Menu],
2930
+ selector: 'app-menu',
2931
+ standalone: true,
2932
+ template: ` <div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
2933
+ <ul class="layout-menu">
2934
+ @for (item of menuService.menu; track item; let i = $index) {
2935
+ <ng-container>
2936
+ @if (item.separator) {
2937
+ <li class="menu-separator"></li>
2938
+ } @else {
2939
+ <li
2940
+ app-menuitem
2941
+ [contextMenu]="contextMenu"
2942
+ [index]="i"
2943
+ [item]="item"
2944
+ [menuItemCreateDialogComponent]="menuItemCreateDialogComponent"
2945
+ [menuItemEditDialogComponent]="menuItemEditDialogComponent"
2946
+ [root]="true"></li>
2947
+ }
2948
+ </ng-container>
2949
+ }
2950
+ </ul>
2951
+ </div>
2952
+ <p-contextMenu [target]="empty" />
2953
+ @if (securityService.isAdmin) {
2954
+ <menu-item-create-dialog />
2955
+ <menu-item-edit-dialog />
2956
+ }`
2957
+ }]
2958
+ }], propDecorators: { menuItemCreateDialogComponent: [{
2959
+ type: ViewChild,
2960
+ args: [MenuItemCreateDialogComponent]
2961
+ }], menuItemEditDialogComponent: [{
2962
+ type: ViewChild,
2963
+ args: [MenuItemEditDialogComponent]
2964
+ }], contextMenu: [{
2965
+ type: ViewChild,
2966
+ args: [ContextMenu]
2967
+ }] } });
2968
+
2969
+ class SidebarComponent {
2970
+ constructor() { }
2971
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2972
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: SidebarComponent, isStandalone: true, selector: "app-sidebar", ngImport: i0, template: ` <app-menu></app-menu>`, isInline: true, dependencies: [{ kind: "component", type: MenuComponent, selector: "app-menu" }] }); }
2973
+ }
2974
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SidebarComponent, decorators: [{
2975
+ type: Component,
2976
+ args: [{
2977
+ selector: 'app-sidebar',
2978
+ template: ` <app-menu></app-menu>`,
2979
+ standalone: true,
2980
+ imports: [MenuComponent]
2981
+ }]
2982
+ }], ctorParameters: () => [] });
2983
+
2984
+ class AppLayoutComponent {
2985
+ constructor() {
2986
+ this.layoutService = inject(LayoutService);
2987
+ this.router = inject(Router);
2988
+ this.renderer = inject(Renderer2);
2989
+ this.overlayMenuOpenSubscription = this.layoutService.overlayOpen$.subscribe(() => {
2990
+ if (!this.menuOutsideClickListener) {
2991
+ this.menuOutsideClickListener = this.renderer.listen('document', 'click', (event) => {
2992
+ if (this.isOutsideClicked(event)) {
2993
+ this.hideMenu();
2994
+ }
2995
+ });
2996
+ }
2997
+ if (this.layoutService.layoutState().staticMenuMobileActive) {
2998
+ this.blockBodyScroll();
2999
+ }
3000
+ });
3001
+ this.router.events.pipe(filter$1((event) => event instanceof NavigationEnd)).subscribe(() => {
3002
+ this.hideMenu();
3003
+ });
3004
+ }
3005
+ isOutsideClicked(event) {
3006
+ const sidebarEl = document.querySelector('.layout-sidebar');
3007
+ const topbarEl = document.querySelector('.layout-menu-button');
3008
+ const eventTarget = event.target;
3009
+ return !(sidebarEl?.isSameNode(eventTarget) ||
3010
+ sidebarEl?.contains(eventTarget) ||
3011
+ topbarEl?.isSameNode(eventTarget) ||
3012
+ topbarEl?.contains(eventTarget));
3013
+ }
3014
+ hideMenu() {
3015
+ this.layoutService.layoutState.update((prev) => ({
3016
+ ...prev,
3017
+ overlayMenuActive: false,
3018
+ staticMenuMobileActive: false,
3019
+ menuHoverActive: false
3020
+ }));
3021
+ if (this.menuOutsideClickListener) {
3022
+ this.menuOutsideClickListener();
3023
+ this.menuOutsideClickListener = null;
3024
+ }
3025
+ this.unblockBodyScroll();
3026
+ }
3027
+ blockBodyScroll() {
3028
+ if (document.body.classList) {
3029
+ document.body.classList.add('blocked-scroll');
3030
+ }
3031
+ else {
3032
+ document.body.className += ' blocked-scroll';
3033
+ }
3034
+ }
3035
+ unblockBodyScroll() {
3036
+ if (document.body.classList) {
3037
+ document.body.classList.remove('blocked-scroll');
3038
+ }
3039
+ else {
3040
+ document.body.className = document.body.className.replace(new RegExp('(^|\\b)' + 'blocked-scroll'.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
3041
+ }
3042
+ }
3043
+ get containerClass() {
3044
+ return {
3045
+ 'layout-overlay': this.layoutService.layoutConfig().menuMode === 'overlay',
3046
+ 'layout-static': this.layoutService.layoutConfig().menuMode === 'static',
3047
+ 'layout-static-inactive': this.layoutService.layoutState().staticMenuDesktopInactive &&
3048
+ this.layoutService.layoutConfig().menuMode === 'static',
3049
+ 'layout-overlay-active': this.layoutService.layoutState().overlayMenuActive,
3050
+ 'layout-mobile-active': this.layoutService.layoutState().staticMenuMobileActive
3051
+ };
3052
+ }
3053
+ ngOnDestroy() {
3054
+ if (this.overlayMenuOpenSubscription) {
3055
+ this.overlayMenuOpenSubscription.unsubscribe();
3056
+ }
3057
+ if (this.menuOutsideClickListener) {
3058
+ this.menuOutsideClickListener();
3059
+ }
3060
+ }
3061
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3062
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: AppLayoutComponent, isStandalone: true, selector: "app-layout", providers: [MenuService, Menu], viewQueries: [{ propertyName: "appSidebar", first: true, predicate: SidebarComponent, descendants: true }, { propertyName: "appTopBar", first: true, predicate: AppTopbar, descendants: true }], ngImport: i0, template: `
3063
+ <div class="layout-wrapper" [ngClass]="containerClass">
3064
+ <app-topbar></app-topbar>
3065
+ <app-sidebar></app-sidebar>
3066
+ <div class="layout-main-container">
3067
+ <div class="layout-main">
3068
+ <router-outlet></router-outlet>
3069
+ </div>
3070
+ <app-footer></app-footer>
3071
+ </div>
3072
+ <div class="layout-mask animate-fadein"></div>
3073
+ </div>
3074
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.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" }] }); }
3075
+ }
3076
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppLayoutComponent, decorators: [{
3077
+ type: Component,
3078
+ args: [{
3079
+ selector: 'app-layout',
3080
+ standalone: true,
3081
+ imports: [CommonModule, AppTopbar, SidebarComponent, RouterModule, FooterComponent],
3082
+ template: `
3083
+ <div class="layout-wrapper" [ngClass]="containerClass">
3084
+ <app-topbar></app-topbar>
3085
+ <app-sidebar></app-sidebar>
3086
+ <div class="layout-main-container">
3087
+ <div class="layout-main">
3088
+ <router-outlet></router-outlet>
3089
+ </div>
3090
+ <app-footer></app-footer>
3091
+ </div>
3092
+ <div class="layout-mask animate-fadein"></div>
3093
+ </div>
3094
+ `,
3095
+ providers: [MenuService, Menu]
3096
+ }]
3097
+ }], ctorParameters: () => [], propDecorators: { appSidebar: [{
3098
+ type: ViewChild,
3099
+ args: [SidebarComponent]
3100
+ }], appTopBar: [{
3101
+ type: ViewChild,
3102
+ args: [AppTopbar]
3103
+ }] } });
3104
+
3105
+ class AppFloatingConfiguratorComponent {
3106
+ constructor() {
3107
+ this.LayoutService = inject(LayoutService);
3108
+ this.isDarkTheme = computed(() => this.LayoutService.layoutConfig().darkTheme, ...(ngDevMode ? [{ debugName: "isDarkTheme" }] : []));
3109
+ }
3110
+ toggleDarkMode() {
3111
+ this.LayoutService.layoutConfig.update((state) => ({
3112
+ ...state,
3113
+ darkTheme: !state.darkTheme
3114
+ }));
3115
+ }
3116
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppFloatingConfiguratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3117
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: AppFloatingConfiguratorComponent, isStandalone: true, selector: "app-floating-configurator", ngImport: i0, template: `
3118
+ <div class="fixed flex gap-4 top-8 right-8">
3119
+ <p-button
3120
+ id="oip-app-floating-configurator-dark-theme-button"
3121
+ severity="secondary"
3122
+ type="button"
3123
+ [icon]="isDarkTheme() ? 'pi pi-moon' : 'pi pi-sun'"
3124
+ [rounded]="true"
3125
+ (onClick)="toggleDarkMode()" />
3126
+ <div class="relative">
3127
+ <p-button
3128
+ enterActiveClass="animate-scalein"
3129
+ enterFromClass="hidden"
3130
+ icon="pi pi-palette"
3131
+ id="oip-app-floating-configurator-next-button"
3132
+ leaveActiveClass="animate-fadeout"
3133
+ leaveToClass="hidden"
3134
+ pStyleClass="@next"
3135
+ type="button"
3136
+ [hideOnOutsideClick]="true"
3137
+ [rounded]="true" />
3138
+ <app-configurator />
3139
+ </div>
3140
+ </div>
3141
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i4.StyleClass, selector: "[pStyleClass]", inputs: ["pStyleClass", "enterFromClass", "enterActiveClass", "enterToClass", "leaveFromClass", "leaveActiveClass", "leaveToClass", "hideOnOutsideClick", "toggleClass", "hideOnEscape", "hideOnResize", "resizeSelector"] }, { kind: "component", type: AppConfiguratorComponent, selector: "app-configurator" }] }); }
3142
+ }
3143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppFloatingConfiguratorComponent, decorators: [{
3144
+ type: Component,
3145
+ args: [{
3146
+ selector: 'app-floating-configurator',
3147
+ imports: [ButtonModule, StyleClassModule, AppConfiguratorComponent],
3148
+ template: `
3149
+ <div class="fixed flex gap-4 top-8 right-8">
3150
+ <p-button
3151
+ id="oip-app-floating-configurator-dark-theme-button"
3152
+ severity="secondary"
3153
+ type="button"
3154
+ [icon]="isDarkTheme() ? 'pi pi-moon' : 'pi pi-sun'"
3155
+ [rounded]="true"
3156
+ (onClick)="toggleDarkMode()" />
3157
+ <div class="relative">
3158
+ <p-button
3159
+ enterActiveClass="animate-scalein"
3160
+ enterFromClass="hidden"
3161
+ icon="pi pi-palette"
3162
+ id="oip-app-floating-configurator-next-button"
3163
+ leaveActiveClass="animate-fadeout"
3164
+ leaveToClass="hidden"
3165
+ pStyleClass="@next"
3166
+ type="button"
3167
+ [hideOnOutsideClick]="true"
3168
+ [rounded]="true" />
3169
+ <app-configurator />
3170
+ </div>
3171
+ </div>
3172
+ `
3173
+ }]
3174
+ }] });
3175
+
3176
+ class NotfoundComponent {
3177
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NotfoundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3178
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: NotfoundComponent, isStandalone: true, selector: "app-notfound", ngImport: i0, template: ` <app-floating-configurator />
3179
+ <div class="flex items-center justify-center min-h-screen overflow-hidden">
3180
+ <div class="flex flex-col items-center justify-center">
3181
+ <div
3182
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, color-mix(in srgb, var(--primary-color), transparent 60%) 10%, var(--surface-ground) 30%)">
3183
+ <div
3184
+ class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20 flex flex-col items-center"
3185
+ style="border-radius: 53px">
3186
+ <div class="flex flex-col items-center justify-center">
3187
+ <logo height="96" width="96"></logo>
3188
+ </div>
3189
+ <span class="text-primary font-bold text-3xl">404</span>
3190
+ <h1 class="text-surface-900 dark:text-surface-0 font-bold text-3xl lg:text-5xl mb-2">Not Found</h1>
3191
+ <div class="text-surface-600 dark:text-surface-200 mb-8">Requested resource is not available.</div>
3192
+ <p-button id="oip-app-notfound-go-to-home-button" label="Go to home" routerLink="/" />
3193
+ </div>
3194
+ </div>
3195
+ </div>
3196
+ </div>`, isInline: true, dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: LogoComponent, selector: "logo", inputs: ["width", "height"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: AppFloatingConfiguratorComponent, selector: "app-floating-configurator" }] }); }
3197
+ }
3198
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NotfoundComponent, decorators: [{
3199
+ type: Component,
3200
+ args: [{
3201
+ selector: 'app-notfound',
3202
+ template: ` <app-floating-configurator />
3203
+ <div class="flex items-center justify-center min-h-screen overflow-hidden">
3204
+ <div class="flex flex-col items-center justify-center">
3205
+ <div
3206
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, color-mix(in srgb, var(--primary-color), transparent 60%) 10%, var(--surface-ground) 30%)">
3207
+ <div
3208
+ class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20 flex flex-col items-center"
3209
+ style="border-radius: 53px">
3210
+ <div class="flex flex-col items-center justify-center">
3211
+ <logo height="96" width="96"></logo>
3212
+ </div>
3213
+ <span class="text-primary font-bold text-3xl">404</span>
3214
+ <h1 class="text-surface-900 dark:text-surface-0 font-bold text-3xl lg:text-5xl mb-2">Not Found</h1>
3215
+ <div class="text-surface-600 dark:text-surface-200 mb-8">Requested resource is not available.</div>
3216
+ <p-button id="oip-app-notfound-go-to-home-button" label="Go to home" routerLink="/" />
3217
+ </div>
3218
+ </div>
3219
+ </div>
3220
+ </div>`,
3221
+ imports: [RouterLink, LogoComponent, Button, AppFloatingConfiguratorComponent],
3222
+ standalone: true
3223
+ }]
3224
+ }] });
3225
+
3226
+ class UnauthorizedComponent {
3227
+ constructor() {
3228
+ this.securityService = inject(SecurityService);
3229
+ }
3230
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: UnauthorizedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3231
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: UnauthorizedComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
3232
+ <app-floating-configurator />
3233
+ <div
3234
+ class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
3235
+ <div class="flex flex-col items-center justify-center">
3236
+ <div
3237
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
3238
+ <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
3239
+ <div class="flex flex-col items-center justify-center">
3240
+ <logo [height]="96" [width]="96" />
3241
+ </div>
3242
+ <div class="text-center mb-8">
3243
+ <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
3244
+ {{ 'unauthorized.welcomeToOip' | translate }}
3245
+ </div>
3246
+ <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
3247
+ </div>
3248
+ <div>
3249
+ <p-button
3250
+ id="oip-unauthorized-error-sign-in-button"
3251
+ label="{{ 'unauthorized.signIn' | translate }}"
3252
+ styleClass="w-full"
3253
+ (click)="securityService.authorize()"></p-button>
3254
+ </div>
3255
+ </div>
3256
+ </div>
3257
+ </div>
3258
+ </div>
3259
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "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" }] }); }
3260
+ }
3261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: UnauthorizedComponent, decorators: [{
3262
+ type: Component,
3263
+ args: [{
3264
+ template: `
3265
+ <app-floating-configurator />
3266
+ <div
3267
+ class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
3268
+ <div class="flex flex-col items-center justify-center">
3269
+ <div
3270
+ style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
3271
+ <div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
3272
+ <div class="flex flex-col items-center justify-center">
3273
+ <logo [height]="96" [width]="96" />
3274
+ </div>
3275
+ <div class="text-center mb-8">
3276
+ <div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">
3277
+ {{ 'unauthorized.welcomeToOip' | translate }}
3278
+ </div>
3279
+ <span class="text-muted-color font-medium">{{ 'unauthorized.signInToContinue' | translate }}</span>
3280
+ </div>
3281
+ <div>
3282
+ <p-button
3283
+ id="oip-unauthorized-error-sign-in-button"
3284
+ label="{{ 'unauthorized.signIn' | translate }}"
3285
+ styleClass="w-full"
3286
+ (click)="securityService.authorize()"></p-button>
3287
+ </div>
3288
+ </div>
3289
+ </div>
3290
+ </div>
3291
+ </div>
3292
+ `,
3293
+ imports: [
3294
+ ButtonModule,
3295
+ RippleModule,
3296
+ LogoComponent,
3297
+ AppFloatingConfiguratorComponent,
3298
+ ReactiveFormsModule,
3299
+ TranslatePipe
3300
+ ]
3301
+ }]
3302
+ }] });
3303
+
3304
+ class ErrorComponent {
3305
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3306
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: ErrorComponent, isStandalone: true, selector: "app-error", ngImport: i0, template: `<div
3307
+ class="surface-ground flex align-items-center justify-content-center min-h-screen min-w-screen overflow-hidden">
3308
+ <div class="flex flex-column align-items-center justify-content-center">
3309
+ <img alt="Sakai logo" class="mb-5 w-6rem flex-shrink-0" src="assets/demo/images/error/logo-error.svg" />
3310
+ <div
3311
+ style="border-radius:56px; padding:0.3rem; background: linear-gradient(180deg, rgba(233, 30, 99, 0.4) 10%, rgba(33, 150, 243, 0) 30%);">
3312
+ <div
3313
+ class="w-full surface-card py-8 px-5 sm:px-8 flex flex-column align-items-center"
3314
+ style="border-radius:53px">
3315
+ <div class="grid flex flex-column align-items-center">
3316
+ <div
3317
+ class="flex justify-content-center align-items-center bg-pink-500 border-circle"
3318
+ style="height:3.2rem; width:3.2rem;">
3319
+ <i class="pi pi-fw pi-exclamation-circle text-2xl text-white"></i>
3320
+ </div>
3321
+ <h1 class="text-900 font-bold text-5xl mb-2">Error Occured</h1>
3322
+ <span class="text-600 mb-5">Requested resource is not available.</span>
3323
+ <img alt="Error" class="mb-5" src="assets/demo/images/error/asset-error.svg" width="80%" />
3324
+ <button
3325
+ class="p-button-text"
3326
+ icon="pi pi-arrow-left"
3327
+ id="oip-app-error-go-to-dashboard-button"
3328
+ label="Go to Dashboard"
3329
+ pButton
3330
+ pRipple
3331
+ [routerLink]="['/']"></button>
3332
+ </div>
3333
+ </div>
3334
+ </div>
3335
+ </div>
3336
+ </div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i3$1.Ripple, selector: "[pRipple]" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
3337
+ }
3338
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ErrorComponent, decorators: [{
3339
+ type: Component,
3340
+ args: [{
3341
+ selector: 'app-error',
3342
+ template: `<div
3343
+ class="surface-ground flex align-items-center justify-content-center min-h-screen min-w-screen overflow-hidden">
3344
+ <div class="flex flex-column align-items-center justify-content-center">
3345
+ <img alt="Sakai logo" class="mb-5 w-6rem flex-shrink-0" src="assets/demo/images/error/logo-error.svg" />
3346
+ <div
3347
+ style="border-radius:56px; padding:0.3rem; background: linear-gradient(180deg, rgba(233, 30, 99, 0.4) 10%, rgba(33, 150, 243, 0) 30%);">
3348
+ <div
3349
+ class="w-full surface-card py-8 px-5 sm:px-8 flex flex-column align-items-center"
3350
+ style="border-radius:53px">
3351
+ <div class="grid flex flex-column align-items-center">
3352
+ <div
3353
+ class="flex justify-content-center align-items-center bg-pink-500 border-circle"
3354
+ style="height:3.2rem; width:3.2rem;">
3355
+ <i class="pi pi-fw pi-exclamation-circle text-2xl text-white"></i>
3356
+ </div>
3357
+ <h1 class="text-900 font-bold text-5xl mb-2">Error Occured</h1>
3358
+ <span class="text-600 mb-5">Requested resource is not available.</span>
3359
+ <img alt="Error" class="mb-5" src="assets/demo/images/error/asset-error.svg" width="80%" />
3360
+ <button
3361
+ class="p-button-text"
3362
+ icon="pi pi-arrow-left"
3363
+ id="oip-app-error-go-to-dashboard-button"
3364
+ label="Go to Dashboard"
3365
+ pButton
3366
+ pRipple
3367
+ [routerLink]="['/']"></button>
3368
+ </div>
3369
+ </div>
3370
+ </div>
3371
+ </div>
3372
+ </div>`,
3373
+ standalone: true,
3374
+ imports: [ButtonModule, RippleModule, RouterLink]
3375
+ }]
3376
+ }] });
3377
+
3378
+ class ProfileComponent {
3379
+ constructor() {
3380
+ this.userService = inject(UserService);
3381
+ this.msgService = inject(MsgService);
3382
+ this.translateService = inject(TranslateService);
3383
+ }
3384
+ onBasicUploadAuto($event) {
3385
+ this.msgService.success(this.translateService.instant('profileComponent.successfullyUploaded'));
3386
+ }
3387
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ProfileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3388
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: ProfileComponent, isStandalone: true, selector: "user-profile", ngImport: i0, template: `
3389
+ <p-avatar
3390
+ class="mr-2"
3391
+ id="oip-user-profile-photo-avatar"
3392
+ shape="circle"
3393
+ size="xlarge"
3394
+ [image]="userService.photoLoaded ? userService.photo : null"/>
3395
+ <div class="mt-2">
3396
+ <p-fileupload
3397
+ accept="image/*"
3398
+ chooseIcon="pi pi-upload"
3399
+ chooseLabel="{{ 'profileComponent.changePhoto' | translate }}"
3400
+ id="oip-user-profile-file-upload"
3401
+ maxFileSize="1000000"
3402
+ mode="basic"
3403
+ name="files"
3404
+ url="/api/user-profile/post-user-photo"
3405
+ withCredentials="true"
3406
+ [auto]="true"
3407
+ (onUpload)="onBasicUploadAuto($event)"/>
3408
+ </div>
3409
+ `, 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: i5$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3410
+ }
3411
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ProfileComponent, decorators: [{
3412
+ type: Component,
3413
+ args: [{
3414
+ selector: 'user-profile',
3415
+ standalone: true,
3416
+ imports: [FileUploadModule, ImageModule, ImageModule, FileUploadModule, ImageModule, AvatarModule, TranslatePipe],
3417
+ template: `
3418
+ <p-avatar
3419
+ class="mr-2"
3420
+ id="oip-user-profile-photo-avatar"
3421
+ shape="circle"
3422
+ size="xlarge"
3423
+ [image]="userService.photoLoaded ? userService.photo : null"/>
3424
+ <div class="mt-2">
3425
+ <p-fileupload
3426
+ accept="image/*"
3427
+ chooseIcon="pi pi-upload"
3428
+ chooseLabel="{{ 'profileComponent.changePhoto' | translate }}"
3429
+ id="oip-user-profile-file-upload"
3430
+ maxFileSize="1000000"
3431
+ mode="basic"
3432
+ name="files"
3433
+ url="/api/user-profile/post-user-photo"
3434
+ withCredentials="true"
3435
+ [auto]="true"
3436
+ (onUpload)="onBasicUploadAuto($event)"/>
3437
+ </div>
3438
+ `
3439
+ }]
3440
+ }] });
3441
+
3442
+ /**
3443
+ * Service for managing translation loading in the application
3444
+ */
3445
+ class L10nService {
3446
+ constructor() {
3447
+ this.loadedTranslations = new Set();
3448
+ this.httpClient = inject(HttpClient$1);
3449
+ this.translateService = inject(TranslateService);
3450
+ }
3451
+ /**
3452
+ * Loads translations for a specific component
3453
+ * @param component - Name of the component to load translations for
3454
+ */
3455
+ async loadComponentTranslations(component) {
3456
+ const lang = this.translateService.currentLang;
3457
+ await this.loadTranslations(component, lang);
3458
+ }
3459
+ /**
3460
+ * Gets the translated value of a key (or an array of keys)
3461
+ * @returns the translated key, or an object of translated keys
3462
+ */
3463
+ async get(key) {
3464
+ await this.loadComponentTranslations(key);
3465
+ return this.translateService.get(key);
3466
+ }
3467
+ /**
3468
+ * Internal method to load translations from JSON files
3469
+ * @param component - Component or translation namespace
3470
+ * @param lang - Language code to load translations for
3471
+ */
3472
+ async loadTranslations(component, lang) {
3473
+ // Create unique key for this component-language combination
3474
+ const key = `${component}.${lang}`;
3475
+ // Skip if translations are already loaded
3476
+ if (this.loadedTranslations.has(key)) {
3477
+ return;
3478
+ }
3479
+ try {
3480
+ // Load translation file from assets
3481
+ const translations = await lastValueFrom(this.httpClient.get(`./assets/i18n/${component}.${lang}.json`));
3482
+ // Get existing translations for the language
3483
+ const current = this.translateService.translations[lang] || {};
3484
+ // Merge new translations with existing ones
3485
+ this.translateService.setTranslation(lang, { ...current, ...translations }, true);
3486
+ // Mark these translations as loaded
3487
+ this.loadedTranslations.add(key);
3488
+ }
3489
+ catch (e) {
3490
+ console.warn(`No translations found for ${component}.${lang}.json`);
3491
+ console.error(e);
3492
+ }
3493
+ }
3494
+ /**
3495
+ * Changes the lang currently used
3496
+ */
3497
+ use(selectedLanguage) {
3498
+ this.translateService.use(selectedLanguage);
3499
+ }
3500
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: L10nService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3501
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: L10nService, providedIn: 'root' }); }
3502
+ }
3503
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: L10nService, decorators: [{
3504
+ type: Injectable,
3505
+ args: [{ providedIn: 'root' }]
3506
+ }] });
3507
+
3508
+ class ConfigComponent {
3509
+ constructor() {
3510
+ this.layoutService = inject(LayoutService);
3511
+ this.l10nService = inject(L10nService);
3512
+ this.userService = inject(UserService);
3513
+ this.securityService = inject(SecurityService);
3514
+ this.menuService = inject(MenuService);
3515
+ this.l10n = {};
3516
+ this.languages = [
3517
+ { value: 'en', label: 'English' },
3518
+ { value: 'ru', label: 'Русский' }
3519
+ ];
3520
+ this.selectedLanguage = this.layoutService.language();
3521
+ }
3522
+ async ngOnInit() {
3523
+ (await this.l10nService.get('config')).subscribe((l10n) => {
3524
+ this.l10n = l10n;
3525
+ });
3526
+ }
3527
+ /**
3528
+ * Changes the application's language.
3529
+ * @return {void}
3530
+ */
3531
+ changeLanguage() {
3532
+ this.layoutService.layoutConfig.update((config) => ({
3533
+ ...config,
3534
+ language: this.selectedLanguage
3535
+ }));
3536
+ this.l10nService.use(this.selectedLanguage);
3537
+ }
3538
+ async onSwitchChange() {
3539
+ await this.menuService.loadMenu();
3540
+ }
3541
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3542
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: ConfigComponent, isStandalone: true, selector: "app-config", ngImport: i0, template: `
3543
+ <p-fluid>
3544
+ <div class="flex flex-col md:flex-row gap-4">
3545
+ <div class="md:w-1/2">
3546
+ <div class="card flex flex-col gap-4">
3547
+ <div class="font-semibold text-xl">{{ l10n.profile }}</div>
3548
+ <div class="flex justify-content-end flex-wrap">
3549
+ {{ userService.userName }}
3550
+ </div>
3551
+ <label>
3552
+ {{ l10n.photo }}
3553
+ <span
3554
+ class="pi pi-question-circle"
3555
+ pTooltip="{{ l10n.usePhoto256x256Pixel }}"
3556
+ tooltipPosition="right"></span>
3557
+ </label>
3558
+ <div class="flex justify-content-end flex-wrap">
3559
+ <user-profile></user-profile>
3560
+ </div>
3561
+ </div>
3562
+ </div>
3563
+ <div class="md:w-1/2">
3564
+ <div class="card flex flex-col gap-4">
3565
+ <div class="font-semibold text-xl">{{ l10n.localization }}</div>
3566
+ <label> {{ l10n.selectLanguage }} </label>
3567
+ <div class="flex justify-content-end flex-wrap">
3568
+ <p-select
3569
+ class="w-full md:w-56"
3570
+ id="oip-app-config-language-select"
3571
+ optionLabel="label"
3572
+ optionValue="value"
3573
+ [options]="languages"
3574
+ [(ngModel)]="selectedLanguage"
3575
+ (onChange)="changeLanguage()" />
3576
+ </div>
3577
+ </div>
3578
+ </div>
3579
+ @if (securityService.isAdmin) {
3580
+ <div class="md:w-1/2">
3581
+ <div class="card flex flex-col gap-4">
3582
+ <div class="font-semibold text-xl">{{ l10n.menu }}</div>
3583
+ <div class="flex items-center gap-2">
3584
+ <label for="oip-app-config-admin-mode">{{ l10n.all }}</label>
3585
+ <p-toggle-switch
3586
+ id="oip-app-config-admin-mode"
3587
+ [(ngModel)]="menuService.adminMode"
3588
+ (onChange)="onSwitchChange()"></p-toggle-switch>
3589
+ </div>
3590
+ <div class="flex items-center gap-2">
3591
+ <label for="oip-app-config-admin-mode">{{ l10n.moduleManagement }}</label>
3592
+ <p-button icon="pi pi-cog" label="{{ l10n.goTo }}" routerLink="/modules" />
3593
+ </div>
3594
+ </div>
3595
+ </div>
3596
+ }
3597
+ </div>
3598
+ </p-fluid>
3599
+ `, isInline: true, dependencies: [{ kind: "component", type: ProfileComponent, selector: "user-profile" }, { kind: "component", type: Fluid, selector: "p-fluid" }, { 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"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.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$2.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }] }); }
3600
+ }
3601
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ConfigComponent, decorators: [{
3602
+ type: Component,
3603
+ args: [{
3604
+ selector: 'app-config',
3605
+ template: `
3606
+ <p-fluid>
3607
+ <div class="flex flex-col md:flex-row gap-4">
3608
+ <div class="md:w-1/2">
3609
+ <div class="card flex flex-col gap-4">
3610
+ <div class="font-semibold text-xl">{{ l10n.profile }}</div>
3611
+ <div class="flex justify-content-end flex-wrap">
3612
+ {{ userService.userName }}
3613
+ </div>
3614
+ <label>
3615
+ {{ l10n.photo }}
3616
+ <span
3617
+ class="pi pi-question-circle"
3618
+ pTooltip="{{ l10n.usePhoto256x256Pixel }}"
3619
+ tooltipPosition="right"></span>
3620
+ </label>
3621
+ <div class="flex justify-content-end flex-wrap">
3622
+ <user-profile></user-profile>
3623
+ </div>
3624
+ </div>
3625
+ </div>
3626
+ <div class="md:w-1/2">
3627
+ <div class="card flex flex-col gap-4">
3628
+ <div class="font-semibold text-xl">{{ l10n.localization }}</div>
3629
+ <label> {{ l10n.selectLanguage }} </label>
3630
+ <div class="flex justify-content-end flex-wrap">
3631
+ <p-select
3632
+ class="w-full md:w-56"
3633
+ id="oip-app-config-language-select"
3634
+ optionLabel="label"
3635
+ optionValue="value"
3636
+ [options]="languages"
3637
+ [(ngModel)]="selectedLanguage"
3638
+ (onChange)="changeLanguage()" />
3639
+ </div>
3640
+ </div>
3641
+ </div>
3642
+ @if (securityService.isAdmin) {
3643
+ <div class="md:w-1/2">
3644
+ <div class="card flex flex-col gap-4">
3645
+ <div class="font-semibold text-xl">{{ l10n.menu }}</div>
3646
+ <div class="flex items-center gap-2">
3647
+ <label for="oip-app-config-admin-mode">{{ l10n.all }}</label>
3648
+ <p-toggle-switch
3649
+ id="oip-app-config-admin-mode"
3650
+ [(ngModel)]="menuService.adminMode"
3651
+ (onChange)="onSwitchChange()"></p-toggle-switch>
3652
+ </div>
3653
+ <div class="flex items-center gap-2">
3654
+ <label for="oip-app-config-admin-mode">{{ l10n.moduleManagement }}</label>
3655
+ <p-button icon="pi pi-cog" label="{{ l10n.goTo }}" routerLink="/modules" />
3656
+ </div>
3657
+ </div>
3658
+ </div>
3659
+ }
3660
+ </div>
3661
+ </p-fluid>
3662
+ `,
3663
+ imports: [ProfileComponent, Fluid, Tooltip, FormsModule, Select, TableModule, ToggleSwitchModule, RouterLink, Button]
3664
+ }]
3665
+ }], ctorParameters: () => [] });
3666
+
3667
+ class DbMigrationComponent extends BaseModuleComponent {
3668
+ async ngOnInit() {
3669
+ await super.ngOnInit();
3670
+ await this.refreshAction();
3671
+ }
3672
+ async refreshAction() {
3673
+ this.getData()
3674
+ .then((response) => {
3675
+ this.data = response;
3676
+ })
3677
+ .catch((error) => {
3678
+ console.log(error);
3679
+ this.msgService.error('Error refreshing database');
3680
+ });
3681
+ }
3682
+ async getData() {
3683
+ return this.baseDataService.sendRequest(`api/${this.controller}/get-migrations`, 'GET');
3684
+ }
3685
+ async applyMigration(rowData) {
3686
+ const request = { name: rowData.name };
3687
+ return this.baseDataService.sendRequest(`api/${this.controller}/apply-migration`, 'POST', request);
3688
+ }
3689
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: DbMigrationComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3690
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: DbMigrationComponent, isStandalone: true, selector: "db-migration", providers: [ConfirmationService], usesInheritance: true, ngImport: i0, template: `
3691
+ <div *ngIf="isContent" class="card" style="height: 100%">
3692
+ <p-confirmDialog/>
3693
+ <div>
3694
+ <h5>Migration manager</h5>
3695
+ <div class="flex flex-row gap-2">
3696
+ <p-button
3697
+ icon="pi pi-refresh"
3698
+ pTooltip="Refresh"
3699
+ severity="secondary"
3700
+ tooltipPosition="bottom"
3701
+ [outlined]="true"
3702
+ (click)="refreshAction()"/>
3703
+ <p-button
3704
+ icon="pi pi-filter-slash"
3705
+ pTooltip="Clean filter"
3706
+ severity="secondary"
3707
+ tooltipPosition="bottom"
3708
+ [outlined]="true"
3709
+ (click)="dt.clear()"/>
3710
+ </div>
3711
+ <div>
3712
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
3713
+ <ng-template let-columns pTemplate="header">
3714
+ <tr>
3715
+ <th pSortableColumn="name" scope="col">
3716
+ Migration name
3717
+ <p-columnFilter display="menu" field="name" type="text"/>
3718
+ </th>
3719
+ <th scope="col">Applied</th>
3720
+ <th scope="col">Exist</th>
3721
+ <th>Pending</th>
3722
+ <th scope="col"></th>
3723
+ </tr>
3724
+ </ng-template>
3725
+
3726
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
3727
+ <tr [pEditableRow]="rowData">
3728
+ <td>
3729
+ {{ rowData.name }}
3730
+ </td>
3731
+ <td>
3732
+ <p-button
3733
+ *ngIf="rowData.applied"
3734
+ icon="pi pi-check"
3735
+ severity="success"
3736
+ [rounded]="true"
3737
+ [text]="true">
3738
+ </p-button>
3739
+ </td>
3740
+ <td>
3741
+ @if (rowData.exist) {
3742
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"/>
3743
+ }
3744
+ </td>
3745
+ <td>
3746
+ @if (rowData.pending) {
3747
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
3748
+ }
3749
+ </td>
3750
+ <td>
3751
+ <p-button
3752
+ icon="pi pi-bolt"
3753
+ pCancelEditableRow
3754
+ pTooltip="Apply migration"
3755
+ severity="secondary"
3756
+ tooltipPosition="left"
3757
+ [rounded]="true"
3758
+ [text]="true"
3759
+ (click)="applyMigration(rowData)">
3760
+ </p-button>
3761
+ </td>
3762
+ </tr>
3763
+ </ng-template>
3764
+ </p-table>
3765
+ </div>
3766
+ </div>
3767
+ </div>
3768
+ @if (isSecurity) {
3769
+ <security [controller]="controller" [id]="id"/>
3770
+ }
3771
+ `, 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$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "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", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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"] }] }); }
3772
+ }
3773
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: DbMigrationComponent, decorators: [{
3774
+ type: Component,
3775
+ args: [{
3776
+ imports: [
3777
+ TableModule,
3778
+ SharedModule,
3779
+ TagModule,
3780
+ InputTextModule,
3781
+ TextareaModule,
3782
+ ButtonModule,
3783
+ FormsModule,
3784
+ ConfirmDialog,
3785
+ NgIf,
3786
+ SecurityComponent,
3787
+ Tooltip
3788
+ ],
3789
+ selector: 'db-migration',
3790
+ template: `
3791
+ <div *ngIf="isContent" class="card" style="height: 100%">
3792
+ <p-confirmDialog/>
3793
+ <div>
3794
+ <h5>Migration manager</h5>
3795
+ <div class="flex flex-row gap-2">
3796
+ <p-button
3797
+ icon="pi pi-refresh"
3798
+ pTooltip="Refresh"
3799
+ severity="secondary"
3800
+ tooltipPosition="bottom"
3801
+ [outlined]="true"
3802
+ (click)="refreshAction()"/>
3803
+ <p-button
3804
+ icon="pi pi-filter-slash"
3805
+ pTooltip="Clean filter"
3806
+ severity="secondary"
3807
+ tooltipPosition="bottom"
3808
+ [outlined]="true"
3809
+ (click)="dt.clear()"/>
3810
+ </div>
3811
+ <div>
3812
+ <p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
3813
+ <ng-template let-columns pTemplate="header">
3814
+ <tr>
3815
+ <th pSortableColumn="name" scope="col">
3816
+ Migration name
3817
+ <p-columnFilter display="menu" field="name" type="text"/>
3818
+ </th>
3819
+ <th scope="col">Applied</th>
3820
+ <th scope="col">Exist</th>
3821
+ <th>Pending</th>
3822
+ <th scope="col"></th>
3823
+ </tr>
3824
+ </ng-template>
3825
+
3826
+ <ng-template #body let-columns="columns" let-editing="editing" let-ri="rowIndex" let-rowData>
3827
+ <tr [pEditableRow]="rowData">
3828
+ <td>
3829
+ {{ rowData.name }}
3830
+ </td>
3831
+ <td>
3832
+ <p-button
3833
+ *ngIf="rowData.applied"
3834
+ icon="pi pi-check"
3835
+ severity="success"
3836
+ [rounded]="true"
3837
+ [text]="true">
3838
+ </p-button>
3839
+ </td>
3840
+ <td>
3841
+ @if (rowData.exist) {
3842
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"/>
3843
+ }
3844
+ </td>
3845
+ <td>
3846
+ @if (rowData.pending) {
3847
+ <p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"></p-button>
3848
+ }
3849
+ </td>
3850
+ <td>
3851
+ <p-button
3852
+ icon="pi pi-bolt"
3853
+ pCancelEditableRow
3854
+ pTooltip="Apply migration"
3855
+ severity="secondary"
3856
+ tooltipPosition="left"
3857
+ [rounded]="true"
3858
+ [text]="true"
3859
+ (click)="applyMigration(rowData)">
3860
+ </p-button>
3861
+ </td>
3862
+ </tr>
3863
+ </ng-template>
3864
+ </p-table>
3865
+ </div>
3866
+ </div>
3867
+ </div>
3868
+ @if (isSecurity) {
3869
+ <security [controller]="controller" [id]="id"/>
3870
+ }
3871
+ `,
3872
+ providers: [ConfirmationService]
3873
+ }]
3874
+ }] });
3875
+
3876
+ /* eslint-disable */
3877
+ /* tslint:disable */
3878
+ // @ts-nocheck
3879
+ /*
3880
+ * ---------------------------------------------------------------
3881
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
3882
+ * ## ##
3883
+ * ## AUTHOR: acacode ##
3884
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
3885
+ * ---------------------------------------------------------------
3886
+ */
3887
+ class Module extends HttpClient {
3888
+ constructor() {
3889
+ super(...arguments);
3890
+ /**
3891
+ * @description Retrieves all modules stored in the system.
3892
+ *
3893
+ * @tags Module
3894
+ * @name moduleGetAll
3895
+ * @request GET:/api/module/get-all
3896
+ * @secure
3897
+ */
3898
+ this.moduleGetAll = (params = {}) => this.request({
3899
+ path: `/api/module/get-all`,
3900
+ method: "GET",
3901
+ secure: true,
3902
+ format: "json",
3903
+ ...params,
3904
+ });
3905
+ /**
3906
+ * @description Inserts a new module into the system.
3907
+ *
3908
+ * @tags Module
3909
+ * @name moduleInsert
3910
+ * @request POST:/api/module/insert
3911
+ * @secure
3912
+ */
3913
+ this.moduleInsert = (data, params = {}) => this.request({
3914
+ path: `/api/module/insert`,
3915
+ method: "POST",
3916
+ body: data,
3917
+ secure: true,
3918
+ type: ContentType.Json,
3919
+ ...params,
3920
+ });
3921
+ /**
3922
+ * @description Deletes a module by its identifier.
3923
+ *
3924
+ * @tags Module
3925
+ * @name moduleDelete
3926
+ * @request DELETE:/api/module/delete
3927
+ * @secure
3928
+ */
3929
+ this.moduleDelete = (data, params = {}) => this.request({
3930
+ path: `/api/module/delete`,
3931
+ method: "DELETE",
3932
+ body: data,
3933
+ secure: true,
3934
+ type: ContentType.Json,
3935
+ ...params,
3936
+ });
3937
+ /**
3938
+ * @description Returns all registered modules and indicates whether each one is currently loaded into the application.
3939
+ *
3940
+ * @tags Module
3941
+ * @name moduleGetModulesWithLoadStatus
3942
+ * @request GET:/api/module/get-modules-with-load-status
3943
+ * @secure
3944
+ */
3945
+ this.moduleGetModulesWithLoadStatus = (params = {}) => this.request({
3946
+ path: `/api/module/get-modules-with-load-status`,
3947
+ method: "GET",
3948
+ secure: true,
3949
+ format: "json",
3950
+ ...params,
3951
+ });
3952
+ }
3953
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Module, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
3954
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Module }); }
3955
+ }
3956
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: Module, decorators: [{
3957
+ type: Injectable
3958
+ }] });
3959
+
3960
+ class AppModulesComponent {
3961
+ constructor() {
3962
+ this.dataService = inject(BaseDataService);
3963
+ this.modules = [];
3964
+ this.msgService = inject(MsgService);
3965
+ this.confirmationService = inject(ConfirmationService);
3966
+ this.l10nService = inject(L10nService);
3967
+ this.l10n = {};
3968
+ this.titleService = inject(AppTitleService);
3969
+ this.moduleService = inject(Module);
3970
+ }
3971
+ async ngOnInit() {
3972
+ (await this.l10nService.get('app-modules')).subscribe((l) => {
3973
+ this.l10n = l;
3974
+ });
3975
+ this.titleService.setTitle(this.l10n.title);
3976
+ await this.refreshAction();
3977
+ }
3978
+ async refreshAction() {
3979
+ this.modules = await this.moduleService.moduleGetModulesWithLoadStatus();
3980
+ }
3981
+ deleteModule(module) {
3982
+ this.confirmationService.confirm({
3983
+ header: this.l10n.confirm.header,
3984
+ message: this.l10n.confirm.message,
3985
+ icon: 'pi pi-trash',
3986
+ rejectButtonProps: {
3987
+ label: this.l10n.confirm.cancel,
3988
+ severity: 'secondary',
3989
+ outlined: true
3990
+ },
3991
+ acceptButtonProps: {
3992
+ label: this.l10n.confirm.delete,
3993
+ severity: 'danger'
3994
+ },
3995
+ accept: async () => {
3996
+ this.dataService
3997
+ .sendRequest(`api/module/delete`, 'DELETE', {
3998
+ moduleId: module.moduleId
3999
+ })
4000
+ .then(() => this.refreshAction())
4001
+ .catch((error) => console.error(error));
4002
+ this.msgService.success(this.l10n.messages.deleteSuccess);
4003
+ }
4004
+ });
4005
+ }
4006
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppModulesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4007
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: AppModulesComponent, isStandalone: true, selector: "app-modules", providers: [ConfirmationService, Module], ngImport: i0, template: `
4008
+ <p-confirmDialog></p-confirmDialog>
4009
+ <div class="flex flex-col md:flex-row gap-4">
4010
+ <div class="card w-full">
4011
+ <div class="font-semibold text-xl mb-4">
4012
+ {{ l10n.title }}
4013
+ </div>
4014
+ <div class="mb-4">
4015
+ <p-toolbar>
4016
+ <p-button
4017
+ icon="pi pi-refresh"
4018
+ rounded="true"
4019
+ severity="secondary"
4020
+ text="true"
4021
+ tooltipPosition="bottom"
4022
+ [pTooltip]="l10n.refreshTooltip"
4023
+ (onClick)="refreshAction()"></p-button>
4024
+ </p-toolbar>
4025
+ </div>
4026
+ <p-table class="mt-4" [paginator]="true" [rows]="100" [value]="modules">
4027
+ <ng-template pTemplate="header">
4028
+ <tr>
4029
+ <th>{{ l10n.table.moduleId }}</th>
4030
+ <th>{{ l10n.table.name }}</th>
4031
+ <th>{{ l10n.table.currentlyLoaded }}</th>
4032
+ <th style="width: 4rem"></th>
4033
+ </tr>
4034
+ </ng-template>
4035
+ <ng-template let-module pTemplate="body">
4036
+ <tr>
4037
+ <td>{{ module.moduleId }}</td>
4038
+ <td>{{ module.name }}</td>
4039
+ <td>
4040
+ <p-tag
4041
+ [severity]="module.currentlyLoaded ? 'success' : 'danger'"
4042
+ [value]="module.currentlyLoaded ? l10n.table.yes : l10n.table.no"></p-tag>
4043
+ </td>
4044
+ <td>
4045
+ <p-button
4046
+ icon="pi pi-trash"
4047
+ rounded="true"
4048
+ severity="danger"
4049
+ text="true"
4050
+ tooltipPosition="bottom"
4051
+ [pTooltip]="l10n.table.deleteTooltip"
4052
+ (onClick)="deleteModule(module)"></p-button>
4053
+ </td>
4054
+ </tr>
4055
+ </ng-template>
4056
+ </p-table>
4057
+ </div>
4058
+ </div>
4059
+ `, 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$1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "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"] }, { 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", "visible", "position", "draggable"], outputs: ["onHide"] }] }); }
4060
+ }
4061
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AppModulesComponent, decorators: [{
4062
+ type: Component,
4063
+ args: [{
4064
+ imports: [FormsModule, TableModule, Tag, ButtonModule, ToolbarModule, Tooltip, ConfirmDialog],
4065
+ providers: [ConfirmationService, Module],
4066
+ selector: 'app-modules',
4067
+ template: `
4068
+ <p-confirmDialog></p-confirmDialog>
4069
+ <div class="flex flex-col md:flex-row gap-4">
4070
+ <div class="card w-full">
4071
+ <div class="font-semibold text-xl mb-4">
4072
+ {{ l10n.title }}
4073
+ </div>
4074
+ <div class="mb-4">
4075
+ <p-toolbar>
4076
+ <p-button
4077
+ icon="pi pi-refresh"
4078
+ rounded="true"
4079
+ severity="secondary"
4080
+ text="true"
4081
+ tooltipPosition="bottom"
4082
+ [pTooltip]="l10n.refreshTooltip"
4083
+ (onClick)="refreshAction()"></p-button>
4084
+ </p-toolbar>
4085
+ </div>
4086
+ <p-table class="mt-4" [paginator]="true" [rows]="100" [value]="modules">
4087
+ <ng-template pTemplate="header">
4088
+ <tr>
4089
+ <th>{{ l10n.table.moduleId }}</th>
4090
+ <th>{{ l10n.table.name }}</th>
4091
+ <th>{{ l10n.table.currentlyLoaded }}</th>
4092
+ <th style="width: 4rem"></th>
4093
+ </tr>
4094
+ </ng-template>
4095
+ <ng-template let-module pTemplate="body">
4096
+ <tr>
4097
+ <td>{{ module.moduleId }}</td>
4098
+ <td>{{ module.name }}</td>
4099
+ <td>
4100
+ <p-tag
4101
+ [severity]="module.currentlyLoaded ? 'success' : 'danger'"
4102
+ [value]="module.currentlyLoaded ? l10n.table.yes : l10n.table.no"></p-tag>
4103
+ </td>
4104
+ <td>
4105
+ <p-button
4106
+ icon="pi pi-trash"
4107
+ rounded="true"
4108
+ severity="danger"
4109
+ text="true"
4110
+ tooltipPosition="bottom"
4111
+ [pTooltip]="l10n.table.deleteTooltip"
4112
+ (onClick)="deleteModule(module)"></p-button>
4113
+ </td>
4114
+ </tr>
4115
+ </ng-template>
4116
+ </p-table>
4117
+ </div>
4118
+ </div>
4119
+ `
4120
+ }]
4121
+ }] });
4122
+
4123
+ /**
4124
+ * A route guard that ensures the user is authenticated and has a valid access token.
4125
+ * If the access token is expired, it attempts to refresh the session.
4126
+ * If authentication fails or refresh is unsuccessful, redirects to the unauthorized page.
4127
+ */
4128
+ class AuthGuardService {
4129
+ constructor() {
4130
+ this.oidcSecurityService = inject(SecurityService);
4131
+ this.router = inject(Router);
4132
+ }
4133
+ /**
4134
+ * Checks whether the route can be activated.
4135
+ * - Returns `true` if the user is authenticated and the token is valid.
4136
+ * - Attempts to refresh the token if expired.
4137
+ * - Redirects to `/unauthorized` if not authenticated or refresh fails.
4138
+ *
4139
+ * @returns {Observable<boolean | UrlTree>} A stream resolving to true (allow), or UrlTree (redirect).
4140
+ */
4141
+ canActivate() {
4142
+ return combineLatest([this.oidcSecurityService.isAuthenticated(), this.oidcSecurityService.isTokenExpired()]).pipe(switchMap(([authenticated, tokenExpired]) => {
4143
+ if (!authenticated) {
4144
+ return of(this.router.parseUrl('/unauthorized'));
4145
+ }
4146
+ if (!tokenExpired) {
4147
+ return of(true);
4148
+ }
4149
+ // Token is expired; attempt to refresh
4150
+ return this.tryRefreshToken();
4151
+ }));
4152
+ }
4153
+ /**
4154
+ * Attempts to refresh the session using the refresh token.
4155
+ * If successful, allows route activation; otherwise, redirects to `/unauthorized`.
4156
+ *
4157
+ * @returns {boolean | UrlTree} A stream resolving to true or redirect UrlTree.
4158
+ */
4159
+ tryRefreshToken() {
4160
+ return this.oidcSecurityService.forceRefreshSession().pipe(map((refreshSuccess) => {
4161
+ return refreshSuccess ? true : this.router.parseUrl('/unauthorized');
4162
+ }), catchError((err) => {
4163
+ console.warn(err);
4164
+ return of(this.router.parseUrl('/unauthorized'));
4165
+ }));
4166
+ }
4167
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AuthGuardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4168
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AuthGuardService }); }
4169
+ }
4170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: AuthGuardService, decorators: [{
4171
+ type: Injectable
4172
+ }] });
4173
+
4174
+ class SecurityStorageService {
4175
+ read(key) {
4176
+ return localStorage.getItem(key);
4177
+ }
4178
+ write(key, value) {
4179
+ localStorage.setItem(key, value);
4180
+ }
4181
+ remove(key) {
4182
+ localStorage.removeItem(key);
4183
+ }
4184
+ clear() {
4185
+ localStorage.clear();
4186
+ }
4187
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4188
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityStorageService }); }
4189
+ }
4190
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurityStorageService, decorators: [{
4191
+ type: Injectable
4192
+ }] });
4193
+
4194
+ const langIntercept = (req, next) => {
4195
+ const layoutService = inject(LayoutService);
4196
+ const lang = layoutService.language() ? layoutService.language() : 'en';
4197
+ const httpHeaders = req.headers.set('Accept-language', lang);
4198
+ const authReq = req.clone({
4199
+ headers: httpHeaders
4200
+ });
4201
+ return next(authReq);
4202
+ };
4203
+
4204
+ class SecurePipe {
4205
+ constructor() {
4206
+ this.http = inject(HttpClient$1);
4207
+ this.sanitizer = inject(DomSanitizer);
4208
+ }
4209
+ transform(url) {
4210
+ return this.http
4211
+ .get(url, { responseType: 'blob' })
4212
+ .pipe(map$1((val) => this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(val))));
4213
+ }
4214
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
4215
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: SecurePipe, isStandalone: true, name: "secure" }); }
4216
+ }
4217
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SecurePipe, decorators: [{
4218
+ type: Pipe,
4219
+ args: [{
4220
+ standalone: true,
4221
+ name: 'secure'
4222
+ }]
4223
+ }] });
4224
+
4225
+ /**
4226
+ * Load keycloak settings from backend and save to sessionStorage
4227
+ * @param httpClient
4228
+ * @returns StsConfigHttpLoader
4229
+ */
4230
+ const httpLoaderAuthFactory = (httpClient) => {
4231
+ const KEYCLOAK_SETTINGS_KEY = 'keycloak-client-settings';
4232
+ const settingsStings = sessionStorage.getItem(KEYCLOAK_SETTINGS_KEY);
4233
+ if (settingsStings) {
4234
+ const config$ = new Observable((subscribe) => {
4235
+ subscribe.next(JSON.parse(settingsStings));
4236
+ });
4237
+ return new StsConfigHttpLoader(config$);
4238
+ }
4239
+ else {
4240
+ const config$ = httpClient.get(`api/security/get-keycloak-client-settings`).pipe(map$1((config) => {
4241
+ const authConfig = {
4242
+ authority: config.authority,
4243
+ redirectUrl: window.location.origin,
4244
+ postLogoutRedirectUri: window.location.origin,
4245
+ clientId: config.clientId,
4246
+ scope: config.scope,
4247
+ responseType: config.responseType,
4248
+ useRefreshToken: config.useRefreshToken,
4249
+ silentRenew: config.silentRenew,
4250
+ logLevel: config.logLevel,
4251
+ secureRoutes: config.secureRoutes
4252
+ };
4253
+ sessionStorage.setItem(KEYCLOAK_SETTINGS_KEY, JSON.stringify(authConfig));
4254
+ return authConfig;
4255
+ }));
4256
+ return new StsConfigHttpLoader(config$);
4257
+ }
4258
+ };
4259
+
4260
+ // Components
4261
+
4262
+ /**
4263
+ * Generated bundle index. Do not edit.
4264
+ */
4265
+
4266
+ export { AppLayoutComponent, AppModulesComponent, AppTopbar, AuthGuardService, BaseDataService, BaseModuleComponent, ConfigComponent, DbMigrationComponent, ErrorComponent, FooterComponent, LayoutService, LogoComponent, MenuComponent, MenuService, MsgService, NotfoundComponent, ProfileComponent, SecurePipe, SecurityComponent, SecurityDataService, SecurityService, SecurityStorageService, SidebarComponent, TopBarService, UnauthorizedComponent, UserService, httpLoaderAuthFactory, langIntercept };
4267
+ //# sourceMappingURL=oip-common.mjs.map