oip-common 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/i18n/extensions.en.json +1 -0
- package/assets/i18n/extensions.ru.json +1 -0
- package/fesm2022/oip-common.mjs +2468 -576
- package/fesm2022/oip-common.mjs.map +1 -1
- package/index.d.ts +397 -67
- package/package.json +2 -2
- package/scripts/generate-api.mjs +4 -4
- package/templates/http-client.ejs +48 -9
- package/assets/i18n/app-modules.en.json +0 -23
- package/assets/i18n/app-modules.ru.json +0 -23
- package/assets/i18n/applications.en.json +0 -46
- package/assets/i18n/applications.ru.json +0 -46
- package/assets/i18n/config.en.json +0 -18
- package/assets/i18n/config.ru.json +0 -18
- package/assets/i18n/db-migration.en.json +0 -19
- package/assets/i18n/db-migration.ru.json +0 -19
- package/assets/i18n/en.json +0 -137
- package/assets/i18n/iframe-module.en.json +0 -10
- package/assets/i18n/iframe-module.ru.json +0 -10
- package/assets/i18n/notfound.en.json +0 -8
- package/assets/i18n/notfound.ru.json +0 -8
- package/assets/i18n/ru.json +0 -281
package/fesm2022/oip-common.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, inject, signal, computed, effect, DestroyRef, ChangeDetectorRef, Component, Input, InjectionToken, PLATFORM_ID, ViewChild, HostBinding, EventEmitter, Output, Renderer2, SecurityContext, ChangeDetectionStrategy, makeEnvironmentProviders, importProvidersFrom } from '@angular/core';
|
|
2
|
+
import { Injectable, inject, signal, computed, effect, DestroyRef, ChangeDetectorRef, Component, Input, InjectionToken, PLATFORM_ID, ViewChild, HostBinding, EventEmitter, Output, Renderer2, SecurityContext, ChangeDetectionStrategy, Injector, EnvironmentInjector, ViewContainerRef, makeEnvironmentProviders, importProvidersFrom } from '@angular/core';
|
|
3
3
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
-
import
|
|
4
|
+
import { Subject, BehaviorSubject, of, tap, shareReplay, ReplaySubject, firstValueFrom, from, filter as filter$1 } from 'rxjs';
|
|
5
|
+
import * as i2$3 from 'primeng/api';
|
|
5
6
|
import { MessageService, ConfirmationService, PrimeIcons, SharedModule } from 'primeng/api';
|
|
6
7
|
import { HttpErrorResponse, HttpClient as HttpClient$1, provideHttpClient, withInterceptors, withFetch } from '@angular/common/http';
|
|
7
|
-
import * as i2$
|
|
8
|
+
import * as i2$4 from '@ngx-translate/core';
|
|
8
9
|
import { TranslateService, TranslatePipe, TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
|
9
10
|
import * as i1$5 from '@angular/router';
|
|
10
|
-
import {
|
|
11
|
-
import { BehaviorSubject, Subject, of, tap, shareReplay, ReplaySubject, firstValueFrom, from, filter as filter$1 } from 'rxjs';
|
|
11
|
+
import { Router, ActivatedRoute, RouterModule, NavigationEnd, RouterLinkActive, RouterLink } from '@angular/router';
|
|
12
12
|
import { tap as tap$1, catchError, filter, distinctUntilChanged, switchMap, map, take } from 'rxjs/operators';
|
|
13
13
|
import { Title, DomSanitizer } from '@angular/platform-browser';
|
|
14
14
|
import { PrimeNG } from 'primeng/config';
|
|
@@ -24,7 +24,7 @@ import * as i1$3 from '@angular/common';
|
|
|
24
24
|
import { isPlatformBrowser, CommonModule, NgComponentOutlet, NgClass, DatePipe, PathLocationStrategy, LocationStrategy } from '@angular/common';
|
|
25
25
|
import * as i3$3 from 'primeng/styleclass';
|
|
26
26
|
import { StyleClassModule } from 'primeng/styleclass';
|
|
27
|
-
import { updatePreset, updateSurfacePalette, $t } from '@primeng/themes';
|
|
27
|
+
import { updatePreset, updateSurfacePalette, $t, definePreset } from '@primeng/themes';
|
|
28
28
|
import Aura from '@primeng/themes/aura';
|
|
29
29
|
import Lara from '@primeng/themes/lara';
|
|
30
30
|
import Nora from '@primeng/themes/nora';
|
|
@@ -49,11 +49,11 @@ import * as i3$2 from 'primeng/menu';
|
|
|
49
49
|
import { MenuModule } from 'primeng/menu';
|
|
50
50
|
import * as i1$6 from 'primeng/contextmenu';
|
|
51
51
|
import { ContextMenuModule, ContextMenu } from 'primeng/contextmenu';
|
|
52
|
-
import * as i3$
|
|
52
|
+
import * as i3$4 from 'primeng/dialog';
|
|
53
53
|
import { DialogModule } from 'primeng/dialog';
|
|
54
54
|
import * as i4$1 from 'primeng/inputtext';
|
|
55
55
|
import { InputTextModule, InputText } from 'primeng/inputtext';
|
|
56
|
-
import * as
|
|
56
|
+
import * as i2$2 from 'primeng/ripple';
|
|
57
57
|
import { RippleModule } from 'primeng/ripple';
|
|
58
58
|
import * as i5 from 'primeng/select';
|
|
59
59
|
import { SelectModule, Select } from 'primeng/select';
|
|
@@ -62,16 +62,18 @@ import { FileUploadModule } from 'primeng/fileupload';
|
|
|
62
62
|
import { ImageModule } from 'primeng/image';
|
|
63
63
|
import * as i1$8 from 'primeng/table';
|
|
64
64
|
import { TableModule } from 'primeng/table';
|
|
65
|
-
import * as i2$
|
|
65
|
+
import * as i2$5 from 'primeng/toggleswitch';
|
|
66
66
|
import { ToggleSwitchModule } from 'primeng/toggleswitch';
|
|
67
67
|
import { TextareaModule, Textarea } from 'primeng/textarea';
|
|
68
|
-
import * as
|
|
68
|
+
import * as i5$1 from 'primeng/toolbar';
|
|
69
69
|
import { ToolbarModule } from 'primeng/toolbar';
|
|
70
|
-
import * as i5$
|
|
70
|
+
import * as i5$2 from 'primeng/card';
|
|
71
71
|
import { CardModule } from 'primeng/card';
|
|
72
72
|
import { DividerModule } from 'primeng/divider';
|
|
73
73
|
import * as i6 from 'primeng/panel';
|
|
74
74
|
import { PanelModule } from 'primeng/panel';
|
|
75
|
+
import { loadRemoteModule } from '@angular-architects/module-federation';
|
|
76
|
+
import { primitive } from '@primeng/themes/aura/base';
|
|
75
77
|
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
76
78
|
|
|
77
79
|
class TopBarService {
|
|
@@ -89,22 +91,24 @@ class TopBarService {
|
|
|
89
91
|
}
|
|
90
92
|
set activeId(value) {
|
|
91
93
|
this._activeId = value;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
const activeTopBarItem = this.activeTopBarItem;
|
|
95
|
+
if (activeTopBarItem?.click)
|
|
96
|
+
activeTopBarItem.click();
|
|
97
|
+
this.activeIdSubject.next(value);
|
|
94
98
|
}
|
|
95
99
|
constructor() {
|
|
96
100
|
this.topBarItems = [];
|
|
101
|
+
this.activeIdSubject = new Subject();
|
|
102
|
+
this.activeId$ = this.activeIdSubject.asObservable();
|
|
97
103
|
}
|
|
98
104
|
// Set tob bar items
|
|
99
105
|
setTopBarItems(items) {
|
|
100
106
|
this.topBarItems = items;
|
|
101
107
|
}
|
|
102
108
|
checkId(id) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return false;
|
|
107
|
-
return this.activeTopBarItem.id == id;
|
|
109
|
+
const activeTopBarItem = this.activeTopBarItem;
|
|
110
|
+
const result = activeTopBarItem === undefined ? id === 'content' : activeTopBarItem.id == id;
|
|
111
|
+
return result;
|
|
108
112
|
}
|
|
109
113
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: TopBarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
110
114
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: TopBarService, providedIn: 'root' }); }
|
|
@@ -150,18 +154,17 @@ class MsgService {
|
|
|
150
154
|
});
|
|
151
155
|
}
|
|
152
156
|
error(detail, summary = this.translate.instant('msgService.error'), life = this.lifetime) {
|
|
153
|
-
|
|
154
|
-
if (validationMessage) {
|
|
155
|
-
detail = validationMessage;
|
|
156
|
-
}
|
|
157
|
-
else if (detail instanceof HttpErrorResponse) {
|
|
157
|
+
if (detail instanceof HttpErrorResponse) {
|
|
158
158
|
summary = `Error: ${detail.status} ${detail.statusText}`;
|
|
159
|
-
detail = `${detail.name} \r\n ${detail.message}
|
|
159
|
+
detail = this.extractErrorMessage(detail, `${detail.name} \r\n ${detail.message}`);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
detail = this.extractErrorMessage(detail, detail?.toString?.() ?? this.translate.instant('msgService.error'));
|
|
160
163
|
}
|
|
161
164
|
this.messageService.add({
|
|
162
165
|
severity: 'error',
|
|
163
166
|
summary: summary,
|
|
164
|
-
detail: detail
|
|
167
|
+
detail: detail,
|
|
165
168
|
life: life
|
|
166
169
|
});
|
|
167
170
|
}
|
|
@@ -170,14 +173,9 @@ class MsgService {
|
|
|
170
173
|
if (validationMessage) {
|
|
171
174
|
return validationMessage;
|
|
172
175
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
typeof error.error === 'object' &&
|
|
177
|
-
error.error &&
|
|
178
|
-
'message' in error.error &&
|
|
179
|
-
typeof error.error.message === 'string') {
|
|
180
|
-
return error.error.message;
|
|
176
|
+
const apiExceptionMessage = this.extractApiExceptionMessage(error);
|
|
177
|
+
if (apiExceptionMessage) {
|
|
178
|
+
return apiExceptionMessage;
|
|
181
179
|
}
|
|
182
180
|
if (typeof error === 'object' && error && 'message' in error && typeof error.message === 'string') {
|
|
183
181
|
return error.message;
|
|
@@ -195,6 +193,15 @@ class MsgService {
|
|
|
195
193
|
.filter((message) => message.length > 0);
|
|
196
194
|
return messages.length > 0 ? messages.join('\n') : null;
|
|
197
195
|
}
|
|
196
|
+
extractApiExceptionMessage(error) {
|
|
197
|
+
const responseError = this.getObjectProperty(error, 'error');
|
|
198
|
+
const message = this.getStringProperty(responseError, 'message') ?? this.getStringProperty(error, 'message');
|
|
199
|
+
const title = this.getStringProperty(responseError, 'title') ?? this.getStringProperty(error, 'title');
|
|
200
|
+
if (message && title) {
|
|
201
|
+
return `${title}: ${message}`;
|
|
202
|
+
}
|
|
203
|
+
return message ?? title;
|
|
204
|
+
}
|
|
198
205
|
toValidationMessages(field, value) {
|
|
199
206
|
if (Array.isArray(value)) {
|
|
200
207
|
return value
|
|
@@ -213,6 +220,13 @@ class MsgService {
|
|
|
213
220
|
const value = source[property];
|
|
214
221
|
return typeof value === 'object' && value !== null ? value : null;
|
|
215
222
|
}
|
|
223
|
+
getStringProperty(source, property) {
|
|
224
|
+
if (typeof source !== 'object' || source === null || !(property in source)) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
const value = source[property];
|
|
228
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
229
|
+
}
|
|
216
230
|
errorFromException(error, fallback, summary = fallback, life = this.lifetime) {
|
|
217
231
|
this.error(this.extractErrorMessage(error, fallback), summary, life);
|
|
218
232
|
}
|
|
@@ -399,6 +413,7 @@ class LayoutService {
|
|
|
399
413
|
return ngDateFormat;
|
|
400
414
|
}, ...(ngDevMode ? [{ debugName: "monthFormat" }] : []));
|
|
401
415
|
this.timeZone = computed(() => this.layoutConfig().timeZone, ...(ngDevMode ? [{ debugName: "timeZone" }] : []));
|
|
416
|
+
this.adminMode = computed(() => this.layoutConfig().adminMode ?? false, ...(ngDevMode ? [{ debugName: "adminMode" }] : []));
|
|
402
417
|
this.transitionComplete = signal(false, ...(ngDevMode ? [{ debugName: "transitionComplete" }] : []));
|
|
403
418
|
this.initialized = false;
|
|
404
419
|
effect(() => {
|
|
@@ -437,7 +452,8 @@ class LayoutService {
|
|
|
437
452
|
dateFormat: 'yyyy-MM-dd',
|
|
438
453
|
timeFormat: 'HH:mm:ss',
|
|
439
454
|
dateTimeFormat: 'yyyy-MM-dd HH:mm:ss',
|
|
440
|
-
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
455
|
+
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
456
|
+
adminMode: false
|
|
441
457
|
};
|
|
442
458
|
}
|
|
443
459
|
handleDarkModeTransition(config) {
|
|
@@ -522,10 +538,539 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
522
538
|
args: [{ providedIn: 'root' }]
|
|
523
539
|
}], ctorParameters: () => [] });
|
|
524
540
|
|
|
541
|
+
var msgService$1 = {
|
|
542
|
+
success: "Success",
|
|
543
|
+
info: "Info",
|
|
544
|
+
warn: "Warn",
|
|
545
|
+
error: "Error",
|
|
546
|
+
secondary: "Secondary"
|
|
547
|
+
};
|
|
548
|
+
var securityComponent$1 = {
|
|
549
|
+
security: "Security",
|
|
550
|
+
save: "Save",
|
|
551
|
+
savedSecurity: "Security settings saved",
|
|
552
|
+
selectRoles: "Select roles"
|
|
553
|
+
};
|
|
554
|
+
var profileComponent$1 = {
|
|
555
|
+
changePhoto: "Upload Photo",
|
|
556
|
+
successfullyUploaded: "Uploaded successfully",
|
|
557
|
+
failedToLoadPhoto: "Failed to load user photo"
|
|
558
|
+
};
|
|
559
|
+
var configComponent$1 = {
|
|
560
|
+
profile: "Profile",
|
|
561
|
+
photo: "Photo",
|
|
562
|
+
usePhoto256x256Pixel: "Use a 256x256 pixel photo",
|
|
563
|
+
localization: "Language",
|
|
564
|
+
selectLanguage: "Select language"
|
|
565
|
+
};
|
|
566
|
+
var baseComponent$1 = {
|
|
567
|
+
content: "Content",
|
|
568
|
+
settings: "Settings",
|
|
569
|
+
security: "Security",
|
|
570
|
+
success: "Saved successfully"
|
|
571
|
+
};
|
|
572
|
+
var menuComponent$1 = {
|
|
573
|
+
all: "All",
|
|
574
|
+
"new": "Add"
|
|
575
|
+
};
|
|
576
|
+
var menuItemEditDialogComponent$1 = {
|
|
577
|
+
header: "Edit menu item",
|
|
578
|
+
parentLabel: "Parent item",
|
|
579
|
+
label: "Label",
|
|
580
|
+
module: "Module",
|
|
581
|
+
selectModule: "Select module",
|
|
582
|
+
icon: "Icon",
|
|
583
|
+
cancel: "Cancel",
|
|
584
|
+
save: "Save",
|
|
585
|
+
security: "Read access"
|
|
586
|
+
};
|
|
587
|
+
var menuItemCreateDialogComponent$1 = {
|
|
588
|
+
header: "New menu item",
|
|
589
|
+
parentLabel: "Parent item",
|
|
590
|
+
label: "Label",
|
|
591
|
+
module: "Module",
|
|
592
|
+
selectModule: "Select module",
|
|
593
|
+
searchModule: "Search module",
|
|
594
|
+
icon: "Icon",
|
|
595
|
+
cancel: "Cancel",
|
|
596
|
+
save: "Save"
|
|
597
|
+
};
|
|
598
|
+
var unauthorized$1 = {
|
|
599
|
+
welcomeToOip: "Welcome to OIP!",
|
|
600
|
+
signInToContinue: "Sign in to continue",
|
|
601
|
+
signIn: "Sign In"
|
|
602
|
+
};
|
|
603
|
+
var menuItemComponent$1 = {
|
|
604
|
+
"new": "Add",
|
|
605
|
+
edit: "Edit",
|
|
606
|
+
"delete": "Delete",
|
|
607
|
+
deleteItemConfirmHeader: "Delete",
|
|
608
|
+
deleteItemConfirmMessage: "Are you sure you want to delete the item?",
|
|
609
|
+
deleteItemSuccessMessage: "Deleted successfully",
|
|
610
|
+
deleteItemConfirmRejectButtonPropsLabel: "Cancel",
|
|
611
|
+
deleteItemConfirmAcceptButtonPropsLabel: "Delete",
|
|
612
|
+
moveUp: "Move up",
|
|
613
|
+
moveDown: "Move down"
|
|
614
|
+
};
|
|
615
|
+
var topbar$1 = {
|
|
616
|
+
logout: "Logout",
|
|
617
|
+
logoutConfirmHeader: "Logout",
|
|
618
|
+
logoutConfirmMessage: "Are you sure you want to logout?",
|
|
619
|
+
logoutConfirmCancel: "Cancel",
|
|
620
|
+
logoutConfirmAccept: "Logout",
|
|
621
|
+
profile: "Profile",
|
|
622
|
+
applications: "Applications"
|
|
623
|
+
};
|
|
624
|
+
var userNotifications$1 = {
|
|
625
|
+
title: "Notifications",
|
|
626
|
+
empty: "No unread notifications",
|
|
627
|
+
refresh: "Refresh",
|
|
628
|
+
markAsRead: "Read",
|
|
629
|
+
markedAsRead: "Notification marked as read"
|
|
630
|
+
};
|
|
631
|
+
var discussionComponent$1 = {
|
|
632
|
+
writeCommentPlaceholder: "Write a comment. Use @email or @first.last for mentions.",
|
|
633
|
+
mentionSuggestions: "Mention suggestions",
|
|
634
|
+
edit: "Edit",
|
|
635
|
+
preview: "Preview",
|
|
636
|
+
attachFiles: "Attach files",
|
|
637
|
+
send: "Send",
|
|
638
|
+
loadingComments: "Loading comments...",
|
|
639
|
+
noCommentsYet: "No comments yet.",
|
|
640
|
+
edited: "Edited",
|
|
641
|
+
editCommentPlaceholder: "Edit comment",
|
|
642
|
+
addAttachment: "Add attachment",
|
|
643
|
+
save: "Save",
|
|
644
|
+
cancel: "Cancel",
|
|
645
|
+
editHistory: "Edit history",
|
|
646
|
+
loadingHistory: "Loading history...",
|
|
647
|
+
before: "Before",
|
|
648
|
+
after: "After",
|
|
649
|
+
warning: "Warning",
|
|
650
|
+
"delete": "Delete",
|
|
651
|
+
confirmDeleteComment: "Are you sure you want to delete this comment?",
|
|
652
|
+
confirmDeleteFile: "Are you sure you want to delete the file \"{{fileName}}\"?",
|
|
653
|
+
units: {
|
|
654
|
+
bytes: "B",
|
|
655
|
+
kilobytes: "KB",
|
|
656
|
+
megabytes: "MB"
|
|
657
|
+
},
|
|
658
|
+
errors: {
|
|
659
|
+
loadComments: "Failed to load comments.",
|
|
660
|
+
createComment: "Failed to create comment.",
|
|
661
|
+
updateComment: "Failed to update comment.",
|
|
662
|
+
loadEditHistory: "Failed to load edit history.",
|
|
663
|
+
uploadAttachment: "Failed to upload attachment.",
|
|
664
|
+
deleteComment: "Failed to delete comment.",
|
|
665
|
+
deleteAttachment: "Failed to delete attachment.",
|
|
666
|
+
downloadAttachment: "Failed to download attachment.",
|
|
667
|
+
updateReaction: "Failed to update reaction.",
|
|
668
|
+
addReaction: "Failed to add reaction."
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
var primeng$1 = "";
|
|
672
|
+
var en$6 = {
|
|
673
|
+
"app-configurator": {
|
|
674
|
+
primary: "Primary",
|
|
675
|
+
surface: "Surface",
|
|
676
|
+
presets: "Presets",
|
|
677
|
+
menuMode: "Menu Mode"
|
|
678
|
+
},
|
|
679
|
+
msgService: msgService$1,
|
|
680
|
+
securityComponent: securityComponent$1,
|
|
681
|
+
profileComponent: profileComponent$1,
|
|
682
|
+
configComponent: configComponent$1,
|
|
683
|
+
baseComponent: baseComponent$1,
|
|
684
|
+
menuComponent: menuComponent$1,
|
|
685
|
+
menuItemEditDialogComponent: menuItemEditDialogComponent$1,
|
|
686
|
+
menuItemCreateDialogComponent: menuItemCreateDialogComponent$1,
|
|
687
|
+
unauthorized: unauthorized$1,
|
|
688
|
+
menuItemComponent: menuItemComponent$1,
|
|
689
|
+
topbar: topbar$1,
|
|
690
|
+
userNotifications: userNotifications$1,
|
|
691
|
+
discussionComponent: discussionComponent$1,
|
|
692
|
+
primeng: primeng$1
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
var msgService = {
|
|
696
|
+
success: "Успешно",
|
|
697
|
+
info: "Информация",
|
|
698
|
+
warn: "Внимание",
|
|
699
|
+
error: "Ошибка",
|
|
700
|
+
secondary: "Вспомогательный"
|
|
701
|
+
};
|
|
702
|
+
var securityComponent = {
|
|
703
|
+
security: "Безопасность",
|
|
704
|
+
save: "Сохранить",
|
|
705
|
+
savedSecurity: "Настройки сохранены",
|
|
706
|
+
selectRoles: "Выберите роли"
|
|
707
|
+
};
|
|
708
|
+
var profileComponent = {
|
|
709
|
+
changePhoto: "Загрузить фото",
|
|
710
|
+
successfullyUploaded: "Загружено",
|
|
711
|
+
failedToLoadPhoto: "Не удалось загрузить фото пользователя"
|
|
712
|
+
};
|
|
713
|
+
var configComponent = {
|
|
714
|
+
profile: "Профиль",
|
|
715
|
+
photo: "Фото",
|
|
716
|
+
usePhoto256x256Pixel: "Используйте фото 256х256 пикселей",
|
|
717
|
+
localization: "Язык",
|
|
718
|
+
selectLanguage: "Выберите язык"
|
|
719
|
+
};
|
|
720
|
+
var baseComponent = {
|
|
721
|
+
content: "Содержимое",
|
|
722
|
+
settings: "Настройки",
|
|
723
|
+
security: "Безопасность",
|
|
724
|
+
success: "Сохранено"
|
|
725
|
+
};
|
|
726
|
+
var menuComponent = {
|
|
727
|
+
all: "Все",
|
|
728
|
+
"new": "Добавить"
|
|
729
|
+
};
|
|
730
|
+
var menuItemEditDialogComponent = {
|
|
731
|
+
header: "Редактировать элемент меню",
|
|
732
|
+
parentLabel: "Родительский узел",
|
|
733
|
+
label: "Имя",
|
|
734
|
+
module: "Модуль",
|
|
735
|
+
selectModule: "Выберите модуль",
|
|
736
|
+
icon: "Иконка",
|
|
737
|
+
cancel: "Отмена",
|
|
738
|
+
save: "Сохранить",
|
|
739
|
+
security: "Доступ на чтение"
|
|
740
|
+
};
|
|
741
|
+
var menuItemCreateDialogComponent = {
|
|
742
|
+
header: "Новый элемент меню",
|
|
743
|
+
parentLabel: "Родительский узел",
|
|
744
|
+
label: "Имя",
|
|
745
|
+
module: "Модуль",
|
|
746
|
+
selectModule: "Выберите модуль",
|
|
747
|
+
searchModule: "Поиск модуля",
|
|
748
|
+
icon: "Иконка",
|
|
749
|
+
cancel: "Отмена",
|
|
750
|
+
save: "Сохранить"
|
|
751
|
+
};
|
|
752
|
+
var unauthorized = {
|
|
753
|
+
welcomeToOip: "Добро пожаловать в OIP!",
|
|
754
|
+
signInToContinue: "Войдите чтобы продолжить",
|
|
755
|
+
signIn: "Войти"
|
|
756
|
+
};
|
|
757
|
+
var menuItemComponent = {
|
|
758
|
+
"new": "Добавить",
|
|
759
|
+
edit: "Редактировать",
|
|
760
|
+
"delete": "Удалить",
|
|
761
|
+
deleteItemConfirmHeader: "Удаление",
|
|
762
|
+
deleteItemConfirmMessage: "Вы уверены что хотите удалить элемент?",
|
|
763
|
+
deleteItemSuccessMessage: "Успешно удалено",
|
|
764
|
+
deleteItemConfirmRejectButtonPropsLabel: "Отмена",
|
|
765
|
+
deleteItemConfirmAcceptButtonPropsLabel: "Удалить",
|
|
766
|
+
moveUp: "Вверх",
|
|
767
|
+
moveDown: "Вниз"
|
|
768
|
+
};
|
|
769
|
+
var topbar = {
|
|
770
|
+
logout: "Выход",
|
|
771
|
+
logoutConfirmHeader: "Выход",
|
|
772
|
+
logoutConfirmMessage: "Вы уверены, что хотите выйти?",
|
|
773
|
+
logoutConfirmCancel: "Отмена",
|
|
774
|
+
logoutConfirmAccept: "Выйти",
|
|
775
|
+
profile: "Профиль",
|
|
776
|
+
applications: "Приложения"
|
|
777
|
+
};
|
|
778
|
+
var userNotifications = {
|
|
779
|
+
title: "Оповещения",
|
|
780
|
+
empty: "Непрочитанных оповещений нет",
|
|
781
|
+
refresh: "Обновить",
|
|
782
|
+
markAsRead: "Прочитано",
|
|
783
|
+
markedAsRead: "Оповещение отмечено прочитанным"
|
|
784
|
+
};
|
|
785
|
+
var discussionComponent = {
|
|
786
|
+
writeCommentPlaceholder: "Напишите комментарий. Используйте @email или @first.last для упоминаний.",
|
|
787
|
+
mentionSuggestions: "Варианты упоминаний",
|
|
788
|
+
edit: "Редактировать",
|
|
789
|
+
preview: "Предпросмотр",
|
|
790
|
+
attachFiles: "Прикрепить файлы",
|
|
791
|
+
send: "Отправить",
|
|
792
|
+
loadingComments: "Загрузка комментариев...",
|
|
793
|
+
noCommentsYet: "Комментариев пока нет.",
|
|
794
|
+
edited: "Изменено",
|
|
795
|
+
editCommentPlaceholder: "Изменить комментарий",
|
|
796
|
+
addAttachment: "Добавить вложение",
|
|
797
|
+
save: "Сохранить",
|
|
798
|
+
cancel: "Отмена",
|
|
799
|
+
editHistory: "История изменений",
|
|
800
|
+
loadingHistory: "Загрузка истории...",
|
|
801
|
+
before: "До",
|
|
802
|
+
after: "После",
|
|
803
|
+
warning: "Предупреждение",
|
|
804
|
+
"delete": "Удалить",
|
|
805
|
+
confirmDeleteComment: "Вы уверены, что хотите удалить этот комментарий?",
|
|
806
|
+
confirmDeleteFile: "Вы уверены, что хотите удалить файл \"{{fileName}}\"?",
|
|
807
|
+
units: {
|
|
808
|
+
bytes: "Б",
|
|
809
|
+
kilobytes: "КБ",
|
|
810
|
+
megabytes: "МБ"
|
|
811
|
+
},
|
|
812
|
+
errors: {
|
|
813
|
+
loadComments: "Не удалось загрузить комментарии.",
|
|
814
|
+
createComment: "Не удалось создать комментарий.",
|
|
815
|
+
updateComment: "Не удалось обновить комментарий.",
|
|
816
|
+
loadEditHistory: "Не удалось загрузить историю изменений.",
|
|
817
|
+
uploadAttachment: "Не удалось загрузить вложение.",
|
|
818
|
+
deleteComment: "Не удалось удалить комментарий.",
|
|
819
|
+
deleteAttachment: "Не удалось удалить вложение.",
|
|
820
|
+
downloadAttachment: "Не удалось скачать вложение.",
|
|
821
|
+
updateReaction: "Не удалось обновить реакцию.",
|
|
822
|
+
addReaction: "Не удалось добавить реакцию."
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
var primeng = {
|
|
826
|
+
accept: "Да",
|
|
827
|
+
addRule: "Добавить правило",
|
|
828
|
+
am: "до полудня",
|
|
829
|
+
apply: "Принять",
|
|
830
|
+
cancel: "Отмена",
|
|
831
|
+
choose: "Выбрать",
|
|
832
|
+
chooseDate: "Выбрать дату",
|
|
833
|
+
chooseMonth: "Выбрать месяц",
|
|
834
|
+
chooseYear: "Выбрать год",
|
|
835
|
+
clear: "Очистить",
|
|
836
|
+
completed: "Завершено",
|
|
837
|
+
contains: "Содержит",
|
|
838
|
+
custom: "Пользовательский",
|
|
839
|
+
dateAfter: "Дата после",
|
|
840
|
+
dateBefore: "Дата до",
|
|
841
|
+
dateFormat: "dd.mm.yy",
|
|
842
|
+
dateIs: "Дата равна",
|
|
843
|
+
dateIsNot: "Дата не равна",
|
|
844
|
+
dayNames: [
|
|
845
|
+
"Воскресенье",
|
|
846
|
+
"Понедельник",
|
|
847
|
+
"Вторник",
|
|
848
|
+
"Среда",
|
|
849
|
+
"Четверг",
|
|
850
|
+
"Пятница",
|
|
851
|
+
"Суббота"
|
|
852
|
+
],
|
|
853
|
+
dayNamesMin: [
|
|
854
|
+
"Вс",
|
|
855
|
+
"Пн",
|
|
856
|
+
"Вт",
|
|
857
|
+
"Ср",
|
|
858
|
+
"Чт",
|
|
859
|
+
"Пт",
|
|
860
|
+
"Сб"
|
|
861
|
+
],
|
|
862
|
+
dayNamesShort: [
|
|
863
|
+
"Вск",
|
|
864
|
+
"Пнд",
|
|
865
|
+
"Втр",
|
|
866
|
+
"Срд",
|
|
867
|
+
"Чтв",
|
|
868
|
+
"Птн",
|
|
869
|
+
"Сбт"
|
|
870
|
+
],
|
|
871
|
+
emptyFilterMessage: "Результатов не найдено",
|
|
872
|
+
emptyMessage: "Нет доступных вариантов",
|
|
873
|
+
emptySearchMessage: "Результатов не найдено",
|
|
874
|
+
emptySelectionMessage: "Нет выбранного элемента",
|
|
875
|
+
endsWith: "Заканчивается",
|
|
876
|
+
equals: "Равно",
|
|
877
|
+
fileChosenMessage: "{0} файлов",
|
|
878
|
+
fileSizeTypes: [
|
|
879
|
+
"Б",
|
|
880
|
+
"Кб",
|
|
881
|
+
"Мб",
|
|
882
|
+
"Гб",
|
|
883
|
+
"Тб",
|
|
884
|
+
"Пб",
|
|
885
|
+
"Эб",
|
|
886
|
+
"Зб",
|
|
887
|
+
"Йб"
|
|
888
|
+
],
|
|
889
|
+
filter: "Фильтр",
|
|
890
|
+
firstDayOfWeek: 1,
|
|
891
|
+
gt: "Более чем",
|
|
892
|
+
gte: "Более чем или равно",
|
|
893
|
+
lt: "Меньше чем",
|
|
894
|
+
lte: "Меньше чем или равно",
|
|
895
|
+
matchAll: "Сопоставить все",
|
|
896
|
+
matchAny: "Совпадение с любым",
|
|
897
|
+
medium: "Нормальный",
|
|
898
|
+
monthNames: [
|
|
899
|
+
"Январь",
|
|
900
|
+
"Февраль",
|
|
901
|
+
"Март",
|
|
902
|
+
"Апрель",
|
|
903
|
+
"Май",
|
|
904
|
+
"Июнь",
|
|
905
|
+
"Июль",
|
|
906
|
+
"Август",
|
|
907
|
+
"Сентябрь",
|
|
908
|
+
"Октябрь",
|
|
909
|
+
"Ноябрь",
|
|
910
|
+
"Декабрь"
|
|
911
|
+
],
|
|
912
|
+
monthNamesShort: [
|
|
913
|
+
"Янв",
|
|
914
|
+
"Фев",
|
|
915
|
+
"Мар",
|
|
916
|
+
"Апр",
|
|
917
|
+
"Май",
|
|
918
|
+
"Июн",
|
|
919
|
+
"Июл",
|
|
920
|
+
"Авг",
|
|
921
|
+
"Сен",
|
|
922
|
+
"Окт",
|
|
923
|
+
"Ноя",
|
|
924
|
+
"Дек"
|
|
925
|
+
],
|
|
926
|
+
nextDecade: "Следующее десятилетие",
|
|
927
|
+
nextHour: "Следующий час",
|
|
928
|
+
nextMinute: "Следующая минута",
|
|
929
|
+
nextMonth: "Следующий месяц",
|
|
930
|
+
nextSecond: "Следующая секунда",
|
|
931
|
+
nextYear: "Следующий год",
|
|
932
|
+
noFileChosenMessage: "Файл не выбран",
|
|
933
|
+
noFilter: "Нет фильтра",
|
|
934
|
+
notContains: "Не содержит",
|
|
935
|
+
notEquals: "Не равно",
|
|
936
|
+
now: "Сейчас",
|
|
937
|
+
passwordPrompt: "Введите пароль",
|
|
938
|
+
pending: "В ожидании",
|
|
939
|
+
pm: "после полудня",
|
|
940
|
+
prevDecade: "Предыдущее десятилетие",
|
|
941
|
+
prevHour: "Предыдущий час",
|
|
942
|
+
prevMinute: "Предыдущая минута",
|
|
943
|
+
prevMonth: "Предыдущий месяц",
|
|
944
|
+
prevSecond: "Предыдущая секунда",
|
|
945
|
+
prevYear: "Предыдущий год",
|
|
946
|
+
reject: "Нет",
|
|
947
|
+
removeRule: "Удалить правило",
|
|
948
|
+
searchMessage: "{0} результатов доступно",
|
|
949
|
+
selectionMessage: "{0} элементов выбрано",
|
|
950
|
+
showMonthAfterYear: false,
|
|
951
|
+
startsWith: "Начинается с",
|
|
952
|
+
strong: "Хороший",
|
|
953
|
+
today: "Сегодня",
|
|
954
|
+
upload: "Загрузить",
|
|
955
|
+
weak: "Простой",
|
|
956
|
+
weekHeader: "Нед.",
|
|
957
|
+
aria: {
|
|
958
|
+
cancelEdit: "Отменить правку",
|
|
959
|
+
close: "Закрыть",
|
|
960
|
+
collapseLabel: "Свернуть",
|
|
961
|
+
collapseRow: "Свернуть строку",
|
|
962
|
+
editRow: "Редактировать строку",
|
|
963
|
+
expandLabel: "Развернуть",
|
|
964
|
+
expandRow: "Развернуть строку",
|
|
965
|
+
falseLabel: "Неверно",
|
|
966
|
+
filterConstraint: "Ограничение фильтра",
|
|
967
|
+
filterOperator: "Оператор фильтра",
|
|
968
|
+
firstPageLabel: "Первая страница",
|
|
969
|
+
gridView: "В виде сетки",
|
|
970
|
+
hideFilterMenu: "Скрыть меню фильтра",
|
|
971
|
+
jumpToPageDropdownLabel: "Перейти к раскрывающемуся списку страниц",
|
|
972
|
+
jumpToPageInputLabel: "Перейти к вводу страницы",
|
|
973
|
+
lastPageLabel: "Последняя страница",
|
|
974
|
+
listLabel: "Список опций",
|
|
975
|
+
listView: "В виде списка",
|
|
976
|
+
moveAllToSource: "Переместить всё в источник",
|
|
977
|
+
moveAllToTarget: "Переместить всё в приёмник",
|
|
978
|
+
moveBottom: "Переместить в конец",
|
|
979
|
+
moveDown: "Переместить вниз",
|
|
980
|
+
moveTop: "Переместить в начало",
|
|
981
|
+
moveToSource: "Переместить в источник",
|
|
982
|
+
moveToTarget: "Переместить в приёмник",
|
|
983
|
+
moveUp: "Переместить вверх",
|
|
984
|
+
navigation: "Навигация",
|
|
985
|
+
next: "Следующий",
|
|
986
|
+
nextPageLabel: "Следующая страница",
|
|
987
|
+
nullLabel: "Не выбран",
|
|
988
|
+
otpLabel: "Введите символ одноразового пароля {0}",
|
|
989
|
+
pageLabel: "{page}",
|
|
990
|
+
passwordHide: "Скрыть пароль",
|
|
991
|
+
passwordShow: "Показать пароль",
|
|
992
|
+
previous: "Предыдущий",
|
|
993
|
+
prevPageLabel: "Предыдущая страница",
|
|
994
|
+
removeLabel: "Удалить",
|
|
995
|
+
rotateLeft: "Повернуть влево",
|
|
996
|
+
rotateRight: "Повернуть вправо",
|
|
997
|
+
rowsPerPageLabel: "Строк на странице",
|
|
998
|
+
saveEdit: "Сохранить правку",
|
|
999
|
+
scrollTop: "Прокрутить в начало",
|
|
1000
|
+
selectAll: "Выбрать все строки",
|
|
1001
|
+
selectLabel: "Выбрать",
|
|
1002
|
+
selectRow: "Выбрать строку",
|
|
1003
|
+
showFilterMenu: "Показать меню фильтра",
|
|
1004
|
+
slide: "Слайд",
|
|
1005
|
+
slideNumber: "{slideNumber}",
|
|
1006
|
+
star: "1 звезда",
|
|
1007
|
+
stars: "{star} звёзд",
|
|
1008
|
+
trueLabel: "Верно",
|
|
1009
|
+
unselectAll: "Отменить выбор всех строк",
|
|
1010
|
+
unselectLabel: "Отменить выбор",
|
|
1011
|
+
unselectRow: "Отменить выбор строки",
|
|
1012
|
+
zoomImage: "Увеличить изображение",
|
|
1013
|
+
zoomIn: "Увеличить",
|
|
1014
|
+
zoomOut: "Уменьшить"
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
var ru$6 = {
|
|
1018
|
+
"app-configurator": {
|
|
1019
|
+
primary: "Основной",
|
|
1020
|
+
surface: "Фон",
|
|
1021
|
+
presets: "Стиль",
|
|
1022
|
+
menuMode: "Режим меню"
|
|
1023
|
+
},
|
|
1024
|
+
msgService: msgService,
|
|
1025
|
+
securityComponent: securityComponent,
|
|
1026
|
+
profileComponent: profileComponent,
|
|
1027
|
+
configComponent: configComponent,
|
|
1028
|
+
baseComponent: baseComponent,
|
|
1029
|
+
menuComponent: menuComponent,
|
|
1030
|
+
menuItemEditDialogComponent: menuItemEditDialogComponent,
|
|
1031
|
+
menuItemCreateDialogComponent: menuItemCreateDialogComponent,
|
|
1032
|
+
unauthorized: unauthorized,
|
|
1033
|
+
menuItemComponent: menuItemComponent,
|
|
1034
|
+
topbar: topbar,
|
|
1035
|
+
userNotifications: userNotifications,
|
|
1036
|
+
discussionComponent: discussionComponent,
|
|
1037
|
+
primeng: primeng
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* Global dictionaries shared by all components. They are bundled with the library,
|
|
1042
|
+
* so the application never requests `assets/i18n/{lang}.json`.
|
|
1043
|
+
*/
|
|
1044
|
+
const globalTranslations = { en: en$6, ru: ru$6 };
|
|
525
1045
|
/**
|
|
526
1046
|
* Service for managing translation loading in the application
|
|
527
1047
|
*/
|
|
528
1048
|
class L10nService {
|
|
1049
|
+
/**
|
|
1050
|
+
* Translations bundled with components, registered at module load time.
|
|
1051
|
+
*/
|
|
1052
|
+
static { this.staticTranslations = new Map(); }
|
|
1053
|
+
/**
|
|
1054
|
+
* Registers translations bundled with a component instead of loading them over HTTP.
|
|
1055
|
+
* Namespaces are taken from the root keys of the passed dictionaries.
|
|
1056
|
+
* Components derived from <c>BaseModuleComponent</c> don't call it directly - it is enough
|
|
1057
|
+
* to declare the static <c>translations</c> field.
|
|
1058
|
+
* @param byLang - Translations grouped by language code
|
|
1059
|
+
* @param namespace - Explicit namespace, needed when the dictionaries are still empty
|
|
1060
|
+
*/
|
|
1061
|
+
static registerTranslations(byLang, namespace) {
|
|
1062
|
+
if (!byLang) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
if (namespace) {
|
|
1066
|
+
L10nService.staticTranslations.set(namespace, byLang);
|
|
1067
|
+
}
|
|
1068
|
+
for (const translations of Object.values(byLang)) {
|
|
1069
|
+
for (const namespace of Object.keys(translations)) {
|
|
1070
|
+
L10nService.staticTranslations.set(namespace, byLang);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
529
1074
|
constructor() {
|
|
530
1075
|
this.loadedTranslations = new Set();
|
|
531
1076
|
this.loadingTranslations = new Map();
|
|
@@ -533,6 +1078,18 @@ class L10nService {
|
|
|
533
1078
|
this.translateService = inject(TranslateService);
|
|
534
1079
|
this.primeNg = inject(PrimeNG);
|
|
535
1080
|
this.layoutService = inject(LayoutService);
|
|
1081
|
+
// Global dictionaries are available before the first `use()` call, so TranslateHttpLoader is never asked for them.
|
|
1082
|
+
L10nService.registerTranslations(globalTranslations);
|
|
1083
|
+
Object.entries(globalTranslations).forEach(([lang, translations]) => this.mergeTranslation(lang, translations));
|
|
1084
|
+
// Static translations are merged once per language, so they have to be re-merged on every language change.
|
|
1085
|
+
this.translateService.onLangChange.subscribe((event) => {
|
|
1086
|
+
L10nService.staticTranslations.forEach((byLang) => {
|
|
1087
|
+
const translations = byLang[event.lang];
|
|
1088
|
+
if (translations) {
|
|
1089
|
+
this.mergeTranslation(event.lang, translations);
|
|
1090
|
+
}
|
|
1091
|
+
});
|
|
1092
|
+
});
|
|
536
1093
|
}
|
|
537
1094
|
/**
|
|
538
1095
|
* Loads translations for a specific component
|
|
@@ -542,6 +1099,35 @@ class L10nService {
|
|
|
542
1099
|
const lang = this.translateService.currentLang || this.layoutService.language() || 'en';
|
|
543
1100
|
return this.loadTranslations(component, lang);
|
|
544
1101
|
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Loads translations from an explicit asset URL and merges them into the active language dictionary.
|
|
1104
|
+
* Use this for extension modules whose assets are hosted outside the shell application.
|
|
1105
|
+
*/
|
|
1106
|
+
loadTranslationsFromUrl(namespace, url, lang) {
|
|
1107
|
+
const selectedLang = lang || this.translateService.currentLang || this.layoutService.language() || 'en';
|
|
1108
|
+
const key = `${namespace}.${selectedLang}.${url}`;
|
|
1109
|
+
if (this.loadedTranslations.has(key)) {
|
|
1110
|
+
return of(null);
|
|
1111
|
+
}
|
|
1112
|
+
const loading = this.loadingTranslations.get(key);
|
|
1113
|
+
if (loading) {
|
|
1114
|
+
return loading;
|
|
1115
|
+
}
|
|
1116
|
+
const request = this.httpClient.get(url).pipe(tap((translations) => {
|
|
1117
|
+
this.mergeTranslation(selectedLang, translations);
|
|
1118
|
+
this.loadedTranslations.add(key);
|
|
1119
|
+
this.loadingTranslations.delete(key);
|
|
1120
|
+
}), shareReplay(1));
|
|
1121
|
+
this.loadingTranslations.set(key, request);
|
|
1122
|
+
request.subscribe({
|
|
1123
|
+
error: (e) => {
|
|
1124
|
+
this.loadingTranslations.delete(key);
|
|
1125
|
+
console.error(`No translations found for ${namespace}.${selectedLang}.json at ${url}`);
|
|
1126
|
+
console.error(e);
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
return request;
|
|
1130
|
+
}
|
|
545
1131
|
/**
|
|
546
1132
|
* Gets the translated value of a key (or an array of keys)
|
|
547
1133
|
* @returns the translated key, or an object of translated keys
|
|
@@ -560,13 +1146,21 @@ class L10nService {
|
|
|
560
1146
|
if (this.loadedTranslations.has(key)) {
|
|
561
1147
|
return of(null);
|
|
562
1148
|
}
|
|
1149
|
+
// Translations bundled with the component - no HTTP request needed.
|
|
1150
|
+
const staticTranslations = L10nService.staticTranslations.get(component);
|
|
1151
|
+
if (staticTranslations) {
|
|
1152
|
+
const translations = staticTranslations[lang];
|
|
1153
|
+
if (translations) {
|
|
1154
|
+
this.mergeTranslation(lang, translations);
|
|
1155
|
+
}
|
|
1156
|
+
return of(null);
|
|
1157
|
+
}
|
|
563
1158
|
const loading = this.loadingTranslations.get(key);
|
|
564
1159
|
if (loading) {
|
|
565
1160
|
return loading;
|
|
566
1161
|
}
|
|
567
1162
|
const request = this.httpClient.get(`./assets/i18n/${component}.${lang}.json`).pipe(tap((translations) => {
|
|
568
|
-
|
|
569
|
-
this.translateService.setTranslation(lang, { ...current, ...translations }, true);
|
|
1163
|
+
this.mergeTranslation(lang, translations);
|
|
570
1164
|
this.loadedTranslations.add(key);
|
|
571
1165
|
this.loadingTranslations.delete(key);
|
|
572
1166
|
}), shareReplay(1));
|
|
@@ -580,6 +1174,15 @@ class L10nService {
|
|
|
580
1174
|
});
|
|
581
1175
|
return request;
|
|
582
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Merges a translation dictionary into the dictionary of the given language
|
|
1179
|
+
* @param lang - Language code
|
|
1180
|
+
* @param translations - Translations to merge
|
|
1181
|
+
*/
|
|
1182
|
+
mergeTranslation(lang, translations) {
|
|
1183
|
+
const current = this.translateService.translations[lang] || {};
|
|
1184
|
+
this.translateService.setTranslation(lang, { ...current, ...translations }, true);
|
|
1185
|
+
}
|
|
583
1186
|
/**
|
|
584
1187
|
* Changes the lang currently used
|
|
585
1188
|
*/
|
|
@@ -608,7 +1211,7 @@ class L10nService {
|
|
|
608
1211
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: L10nService, decorators: [{
|
|
609
1212
|
type: Injectable,
|
|
610
1213
|
args: [{ providedIn: 'root' }]
|
|
611
|
-
}] });
|
|
1214
|
+
}], ctorParameters: () => [] });
|
|
612
1215
|
|
|
613
1216
|
class SecurityService {
|
|
614
1217
|
}
|
|
@@ -620,16 +1223,21 @@ class BffSecurityService {
|
|
|
620
1223
|
this.csrfToken = new ReplaySubject(1);
|
|
621
1224
|
this.payload = new BehaviorSubject(null);
|
|
622
1225
|
}
|
|
1226
|
+
static { this.authorizeAfterLogoutReturnUrlKey = 'oip.authorizeAfterLogoutReturnUrl'; }
|
|
623
1227
|
auth() {
|
|
624
|
-
this.http
|
|
1228
|
+
this.http
|
|
1229
|
+
.get(this.buildUrl('api/security/get-current-auth-session'), {
|
|
625
1230
|
withCredentials: true
|
|
626
|
-
})
|
|
1231
|
+
})
|
|
1232
|
+
.pipe(tap$1((session) => this.applySession(session)), catchError(() => {
|
|
627
1233
|
this.applyAnonymousSession();
|
|
628
1234
|
return of(null);
|
|
629
|
-
}))
|
|
1235
|
+
}))
|
|
1236
|
+
.subscribe();
|
|
630
1237
|
}
|
|
631
1238
|
logout() {
|
|
632
1239
|
firstValueFrom(this.getCsrfToken()).then((csrfToken) => {
|
|
1240
|
+
this.storeAuthorizeAfterLogoutReturnUrl();
|
|
633
1241
|
const form = this.createPostForm(this.buildUrl('api/security/delete-auth-session'));
|
|
634
1242
|
if (csrfToken?.token) {
|
|
635
1243
|
const tokenInput = document.createElement('input');
|
|
@@ -665,15 +1273,20 @@ class BffSecurityService {
|
|
|
665
1273
|
});
|
|
666
1274
|
}
|
|
667
1275
|
getCsrfToken() {
|
|
668
|
-
this.http
|
|
1276
|
+
this.http
|
|
1277
|
+
.get(this.buildUrl('api/security/get-auth-csrf-token'), {
|
|
669
1278
|
withCredentials: true
|
|
670
|
-
})
|
|
1279
|
+
})
|
|
1280
|
+
.pipe(catchError(() => of(null)))
|
|
1281
|
+
.subscribe((token) => this.csrfToken.next(token));
|
|
671
1282
|
return this.csrfToken.asObservable();
|
|
672
1283
|
}
|
|
673
1284
|
isAdmin() {
|
|
674
1285
|
return this.payload.getValue()?.realm_access?.roles?.includes('admin') ?? false;
|
|
675
1286
|
}
|
|
676
|
-
authorize() {
|
|
1287
|
+
authorize(returnUrl) {
|
|
1288
|
+
const normalizedReturnUrl = this.normalizeReturnUrl(returnUrl);
|
|
1289
|
+
this.replaceWithUnauthorizedUrl(normalizedReturnUrl);
|
|
677
1290
|
const form = this.createPostForm(this.buildUrl('api/security/create-auth-session'));
|
|
678
1291
|
document.body.appendChild(form);
|
|
679
1292
|
form.submit();
|
|
@@ -724,10 +1337,40 @@ class BffSecurityService {
|
|
|
724
1337
|
form.style.display = 'none';
|
|
725
1338
|
return form;
|
|
726
1339
|
}
|
|
1340
|
+
normalizeReturnUrl(returnUrl) {
|
|
1341
|
+
const candidate = returnUrl?.trim();
|
|
1342
|
+
if (!candidate || /[\u0000-\u001f\u007f\\]/.test(candidate)) {
|
|
1343
|
+
return '/';
|
|
1344
|
+
}
|
|
1345
|
+
if (!candidate.startsWith('/') || candidate.startsWith('//')) {
|
|
1346
|
+
return '/';
|
|
1347
|
+
}
|
|
1348
|
+
try {
|
|
1349
|
+
const url = new URL(candidate, window.location.origin);
|
|
1350
|
+
if (url.origin !== window.location.origin) {
|
|
1351
|
+
return '/';
|
|
1352
|
+
}
|
|
1353
|
+
const normalizedUrl = `${url.pathname}${url.search}${url.hash}`;
|
|
1354
|
+
return normalizedUrl.startsWith('/unauthorized') ? '/' : normalizedUrl;
|
|
1355
|
+
}
|
|
1356
|
+
catch {
|
|
1357
|
+
return '/';
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
replaceWithUnauthorizedUrl(returnUrl) {
|
|
1361
|
+
const unauthorizedUrl = new URL('unauthorized', this.getBaseUrl());
|
|
1362
|
+
unauthorizedUrl.searchParams.set('returnUrl', returnUrl);
|
|
1363
|
+
history.replaceState(history.state, '', `${unauthorizedUrl.pathname}${unauthorizedUrl.search}`);
|
|
1364
|
+
}
|
|
1365
|
+
storeAuthorizeAfterLogoutReturnUrl() {
|
|
1366
|
+
sessionStorage.setItem(BffSecurityService.authorizeAfterLogoutReturnUrlKey, this.normalizeReturnUrl(`${window.location.pathname}${window.location.search}${window.location.hash}`));
|
|
1367
|
+
}
|
|
727
1368
|
buildUrl(path) {
|
|
1369
|
+
return `${this.getBaseUrl()}${path}`;
|
|
1370
|
+
}
|
|
1371
|
+
getBaseUrl() {
|
|
728
1372
|
const baseUrl = document.getElementsByTagName('base')[0].href;
|
|
729
|
-
|
|
730
|
-
return `${normalizedBase}${path}`;
|
|
1373
|
+
return baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
731
1374
|
}
|
|
732
1375
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: BffSecurityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
733
1376
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: BffSecurityService }); }
|
|
@@ -751,15 +1394,22 @@ class HttpClient {
|
|
|
751
1394
|
constructor() {
|
|
752
1395
|
this.securityService = inject(SecurityService);
|
|
753
1396
|
this.layoutService = inject(LayoutService);
|
|
1397
|
+
this.router = inject(Router);
|
|
754
1398
|
this.baseUrl = "";
|
|
755
|
-
this.securityWorker = () =>
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
:
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1399
|
+
this.securityWorker = () => {
|
|
1400
|
+
const moduleInstanceId = this.getCurrentModuleInstanceId();
|
|
1401
|
+
return {
|
|
1402
|
+
headers: {
|
|
1403
|
+
"Accept-language": this.layoutService.language()
|
|
1404
|
+
? this.layoutService.language()
|
|
1405
|
+
: "en",
|
|
1406
|
+
"X-Timezone": this.layoutService.timeZone(),
|
|
1407
|
+
...(moduleInstanceId != null
|
|
1408
|
+
? { "X-Module-Instance-Id": String(moduleInstanceId) }
|
|
1409
|
+
: {}),
|
|
1410
|
+
},
|
|
1411
|
+
};
|
|
1412
|
+
};
|
|
763
1413
|
this.abortControllers = new Map();
|
|
764
1414
|
this.customFetch = (...fetchParams) => fetch(...fetchParams);
|
|
765
1415
|
this.baseApiParams = {
|
|
@@ -864,12 +1514,29 @@ class HttpClient {
|
|
|
864
1514
|
if (cancelToken) {
|
|
865
1515
|
this.abortControllers.delete(cancelToken);
|
|
866
1516
|
}
|
|
867
|
-
if (!response.ok)
|
|
1517
|
+
if (!response.ok) {
|
|
1518
|
+
this.authorizeOnUnauthorized(response, path);
|
|
868
1519
|
throw data;
|
|
1520
|
+
}
|
|
869
1521
|
return data.data;
|
|
870
1522
|
});
|
|
871
1523
|
};
|
|
872
1524
|
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Reads the module instance id of the deepest activated route.
|
|
1527
|
+
* The backend uses it to check module instance rights on endpoints that do not carry the id in their contract.
|
|
1528
|
+
*/
|
|
1529
|
+
getCurrentModuleInstanceId() {
|
|
1530
|
+
// May run before the first navigation completes, when route snapshots are not available yet.
|
|
1531
|
+
let route = this.router.routerState?.root;
|
|
1532
|
+
let id = null;
|
|
1533
|
+
while (route) {
|
|
1534
|
+
id = route.snapshot?.paramMap?.get("id") ?? id;
|
|
1535
|
+
route = route.firstChild;
|
|
1536
|
+
}
|
|
1537
|
+
const parsed = id != null ? Number(id) : Number.NaN;
|
|
1538
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
1539
|
+
}
|
|
873
1540
|
encodeQueryParam(key, value) {
|
|
874
1541
|
const encodedKey = encodeURIComponent(key);
|
|
875
1542
|
return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
|
|
@@ -906,6 +1573,13 @@ class HttpClient {
|
|
|
906
1573
|
},
|
|
907
1574
|
};
|
|
908
1575
|
}
|
|
1576
|
+
authorizeOnUnauthorized(response, path) {
|
|
1577
|
+
if (response.status !== 401 ||
|
|
1578
|
+
path.includes("/api/security/create-auth-session")) {
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
this.securityService.authorize(`${window.location.pathname}${window.location.search}${window.location.hash}`);
|
|
1582
|
+
}
|
|
909
1583
|
async getCsrfRequestParams(method, path) {
|
|
910
1584
|
if (!method ||
|
|
911
1585
|
!["POST", "PUT", "PATCH", "DELETE"].includes(method.toUpperCase())) {
|
|
@@ -1077,6 +1751,8 @@ class BaseModuleComponent {
|
|
|
1077
1751
|
{ id: 'settings', icon: 'pi-cog', caption: '' },
|
|
1078
1752
|
{ id: 'security', icon: 'pi-lock', caption: '' }
|
|
1079
1753
|
];
|
|
1754
|
+
// Must run before the route subscription below asks L10nService for the translations.
|
|
1755
|
+
L10nService.registerTranslations(this.constructor.translations);
|
|
1080
1756
|
effect(() => {
|
|
1081
1757
|
const config = this.localSettings();
|
|
1082
1758
|
if (config) {
|
|
@@ -1085,6 +1761,8 @@ class BaseModuleComponent {
|
|
|
1085
1761
|
});
|
|
1086
1762
|
this.subscriptions.push(this.route.url.subscribe((url) => {
|
|
1087
1763
|
this.controller = url[0].path;
|
|
1764
|
+
// The route path is the translation namespace, register it before asking for translations.
|
|
1765
|
+
L10nService.registerTranslations(this.constructor.translations, this.controller);
|
|
1088
1766
|
this.l10n$ = this.l10nService.get(this.controller);
|
|
1089
1767
|
}));
|
|
1090
1768
|
this.subscriptions.push(this.route.paramMap.subscribe((params) => {
|
|
@@ -1185,20 +1863,31 @@ class BaseModuleComponent {
|
|
|
1185
1863
|
this.rightsSubscription?.unsubscribe();
|
|
1186
1864
|
this.resetRightsState();
|
|
1187
1865
|
if (!controller || id == null) {
|
|
1188
|
-
return;
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1866
|
+
return Promise.resolve();
|
|
1867
|
+
}
|
|
1868
|
+
return new Promise((resolve) => {
|
|
1869
|
+
let settled = false;
|
|
1870
|
+
const settle = () => {
|
|
1871
|
+
if (!settled) {
|
|
1872
|
+
settled = true;
|
|
1873
|
+
resolve();
|
|
1874
|
+
}
|
|
1875
|
+
};
|
|
1876
|
+
this.rightsSubscription = this.securityService.payload
|
|
1877
|
+
.pipe(switchMap((payload) => from(this.getSecurity(controller, id)).pipe(map((securitySettings) => ({ payload, securitySettings })))), takeUntilDestroyed(this.destroyRef))
|
|
1878
|
+
.subscribe({
|
|
1879
|
+
next: ({ payload, securitySettings }) => {
|
|
1880
|
+
const roles = payload?.realm_access?.roles ?? [];
|
|
1881
|
+
this.updateRightsState(roles, securitySettings);
|
|
1882
|
+
settle();
|
|
1883
|
+
},
|
|
1884
|
+
error: (error) => {
|
|
1885
|
+
this.securityRightsLoaded = true;
|
|
1886
|
+
console.error('Не удалось загрузить права', error);
|
|
1887
|
+
this.onSecurityRightsChange();
|
|
1888
|
+
settle();
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1202
1891
|
});
|
|
1203
1892
|
}
|
|
1204
1893
|
resetRightsState() {
|
|
@@ -1219,9 +1908,7 @@ class BaseModuleComponent {
|
|
|
1219
1908
|
this.onSecurityRightsChange();
|
|
1220
1909
|
}
|
|
1221
1910
|
hasSecurityRight(roles, securitySettings, code) {
|
|
1222
|
-
return securitySettings
|
|
1223
|
-
.find((security) => security.code === code)
|
|
1224
|
-
?.roles?.some((role) => roles.includes(role)) ?? false;
|
|
1911
|
+
return (securitySettings.find((security) => security.code === code)?.roles?.some((role) => roles.includes(role)) ?? false);
|
|
1225
1912
|
}
|
|
1226
1913
|
getSecurity(controller = this.controller, id = this.id) {
|
|
1227
1914
|
if (!controller || id == null) {
|
|
@@ -1230,7 +1917,6 @@ class BaseModuleComponent {
|
|
|
1230
1917
|
return this.httpClient.request({
|
|
1231
1918
|
path: `/api/${controller}/get-security`,
|
|
1232
1919
|
method: 'GET',
|
|
1233
|
-
query: { id },
|
|
1234
1920
|
secure: true,
|
|
1235
1921
|
format: 'json'
|
|
1236
1922
|
});
|
|
@@ -1244,11 +1930,10 @@ class BaseModuleComponent {
|
|
|
1244
1930
|
type: ContentType.Json
|
|
1245
1931
|
});
|
|
1246
1932
|
}
|
|
1247
|
-
getModuleInstanceSettings(controller = this.controller
|
|
1933
|
+
getModuleInstanceSettings(controller = this.controller) {
|
|
1248
1934
|
return this.httpClient.request({
|
|
1249
1935
|
path: `/api/${controller}/get-module-instance-settings`,
|
|
1250
1936
|
method: 'GET',
|
|
1251
|
-
query: { id },
|
|
1252
1937
|
secure: true,
|
|
1253
1938
|
format: 'json'
|
|
1254
1939
|
});
|
|
@@ -1281,8 +1966,12 @@ class BaseModuleComponent {
|
|
|
1281
1966
|
}
|
|
1282
1967
|
async reloadModuleInstance() {
|
|
1283
1968
|
this.moduleInstanceReloadPromise = this.moduleInstanceReloadPromise.then(async () => {
|
|
1969
|
+
// Rights first: the backend rejects settings and data requests without the read right.
|
|
1970
|
+
await this.watchSecurityRights();
|
|
1971
|
+
if (!this.canRead) {
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1284
1974
|
await this.getSettings();
|
|
1285
|
-
this.watchSecurityRights();
|
|
1286
1975
|
await this.onModuleInstanceChange();
|
|
1287
1976
|
});
|
|
1288
1977
|
await this.moduleInstanceReloadPromise;
|
|
@@ -1396,7 +2085,7 @@ class SecurityComponent {
|
|
|
1396
2085
|
return;
|
|
1397
2086
|
}
|
|
1398
2087
|
try {
|
|
1399
|
-
const result = await this.getSecurity(controller
|
|
2088
|
+
const result = await this.getSecurity(controller);
|
|
1400
2089
|
if (loadToken === this.securityLoadToken) {
|
|
1401
2090
|
this.securityData = result;
|
|
1402
2091
|
}
|
|
@@ -1407,11 +2096,10 @@ class SecurityComponent {
|
|
|
1407
2096
|
}
|
|
1408
2097
|
}
|
|
1409
2098
|
}
|
|
1410
|
-
getSecurity(controller
|
|
2099
|
+
getSecurity(controller) {
|
|
1411
2100
|
return this.httpClient.request({
|
|
1412
2101
|
path: `/api/${controller}/get-security`,
|
|
1413
2102
|
method: 'GET',
|
|
1414
|
-
query: { id },
|
|
1415
2103
|
secure: true,
|
|
1416
2104
|
format: 'json'
|
|
1417
2105
|
});
|
|
@@ -1548,8 +2236,7 @@ class AppConfiguratorComponent {
|
|
|
1548
2236
|
this.themePresets = this.getThemePresets();
|
|
1549
2237
|
this.themePresetsMap = new Map(this.themePresets.map((theme) => [theme.id, theme]));
|
|
1550
2238
|
this.defaultThemePreset = this.themePresets[0] ?? DEFAULT_THEME_PRESETS[0];
|
|
1551
|
-
this.fallbackPrimaryColors = (DEFAULT_THEME_PRESETS[0].preset
|
|
1552
|
-
.primitive ?? {});
|
|
2239
|
+
this.fallbackPrimaryColors = (DEFAULT_THEME_PRESETS[0].preset.primitive ?? {});
|
|
1553
2240
|
this.presets = this.themePresets.map((theme) => ({ label: theme.label ?? theme.id, value: theme.id }));
|
|
1554
2241
|
this.showMenuModeButton = signal(!this.router.url.includes('auth'), ...(ngDevMode ? [{ debugName: "showMenuModeButton" }] : []));
|
|
1555
2242
|
this.menuModeOptions = [
|
|
@@ -1868,7 +2555,7 @@ class AppConfiguratorComponent {
|
|
|
1868
2555
|
.filter((entry) => Boolean(entry[1]))
|
|
1869
2556
|
.map(([name, palette]) => ({ name, palette }));
|
|
1870
2557
|
}
|
|
1871
|
-
const presetPalette =
|
|
2558
|
+
const presetPalette = activeThemePreset.preset.primitive ?? {};
|
|
1872
2559
|
const palettes = [{ name: 'noir', palette: {} }];
|
|
1873
2560
|
PRIMARY_COLORS.forEach((color) => {
|
|
1874
2561
|
palettes.push({
|
|
@@ -1927,7 +2614,9 @@ class AppConfiguratorComponent {
|
|
|
1927
2614
|
this.layoutService.layoutConfig.update((state) => ({
|
|
1928
2615
|
...state,
|
|
1929
2616
|
preset: nextThemeId,
|
|
1930
|
-
primary: primaryColors.some((color) => color.name === state.primary)
|
|
2617
|
+
primary: primaryColors.some((color) => color.name === state.primary)
|
|
2618
|
+
? state.primary
|
|
2619
|
+
: (primaryColors[0]?.name ?? state.primary),
|
|
1931
2620
|
surface: nextTheme.surfaceColors && !surfaceColors.some((color) => color.name === state.surface)
|
|
1932
2621
|
? (surfaceColors[0]?.name ?? state.surface)
|
|
1933
2622
|
: state.surface
|
|
@@ -1991,12 +2680,12 @@ class AppConfiguratorComponent {
|
|
|
1991
2680
|
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.presets' | translate }}</span>
|
|
1992
2681
|
<p-selectButton
|
|
1993
2682
|
id="oip-app-configurator-preset-select-button"
|
|
2683
|
+
optionLabel="label"
|
|
2684
|
+
optionValue="value"
|
|
1994
2685
|
size="small"
|
|
1995
2686
|
[allowEmpty]="false"
|
|
1996
2687
|
[ngModel]="selectedPreset()"
|
|
1997
2688
|
[options]="presets"
|
|
1998
|
-
optionLabel="label"
|
|
1999
|
-
optionValue="value"
|
|
2000
2689
|
(ngModelChange)="onPresetChange($event)" />
|
|
2001
2690
|
</div>
|
|
2002
2691
|
@if (showMenuModeButton()) {
|
|
@@ -2068,12 +2757,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
2068
2757
|
<span class="text-sm text-muted-color font-semibold">{{ 'app-configurator.presets' | translate }}</span>
|
|
2069
2758
|
<p-selectButton
|
|
2070
2759
|
id="oip-app-configurator-preset-select-button"
|
|
2760
|
+
optionLabel="label"
|
|
2761
|
+
optionValue="value"
|
|
2071
2762
|
size="small"
|
|
2072
2763
|
[allowEmpty]="false"
|
|
2073
2764
|
[ngModel]="selectedPreset()"
|
|
2074
2765
|
[options]="presets"
|
|
2075
|
-
optionLabel="label"
|
|
2076
|
-
optionValue="value"
|
|
2077
2766
|
(ngModelChange)="onPresetChange($event)" />
|
|
2078
2767
|
</div>
|
|
2079
2768
|
@if (showMenuModeButton()) {
|
|
@@ -2102,10 +2791,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
2102
2791
|
class UserProfileApi extends HttpClient {
|
|
2103
2792
|
constructor() {
|
|
2104
2793
|
super(...arguments);
|
|
2105
|
-
this.getUserPhoto = (
|
|
2794
|
+
this.getUserPhoto = (params = {}) => this.request({
|
|
2106
2795
|
path: `/api/user-profile/get-user-photo`,
|
|
2107
2796
|
method: "GET",
|
|
2108
|
-
|
|
2797
|
+
secure: true,
|
|
2798
|
+
format: "blob",
|
|
2799
|
+
...params,
|
|
2800
|
+
});
|
|
2801
|
+
this.getUserPhotoById = ({ userId, ...query }, params = {}) => this.request({
|
|
2802
|
+
path: `/api/user-profile/get-user-photo-by-id/${userId}`,
|
|
2803
|
+
method: "GET",
|
|
2109
2804
|
secure: true,
|
|
2110
2805
|
format: "blob",
|
|
2111
2806
|
...params,
|
|
@@ -2149,7 +2844,9 @@ class UserService {
|
|
|
2149
2844
|
constructor() {
|
|
2150
2845
|
this.securityService = inject(SecurityService);
|
|
2151
2846
|
this.userProfileApi = inject(UserProfileApi);
|
|
2152
|
-
this.
|
|
2847
|
+
this.msgService = inject(MsgService);
|
|
2848
|
+
this.translateService = inject(TranslateService);
|
|
2849
|
+
this.requestedPhotoKey = null;
|
|
2153
2850
|
/**
|
|
2154
2851
|
* Stores the user's photo as a data URL or binary blob, depending on how it's processed.
|
|
2155
2852
|
*/
|
|
@@ -2160,7 +2857,7 @@ class UserService {
|
|
|
2160
2857
|
this.photoLoaded = false;
|
|
2161
2858
|
this.securityService
|
|
2162
2859
|
.getCurrentUser$()
|
|
2163
|
-
.pipe(map((user) => user
|
|
2860
|
+
.pipe(map((user) => this.getCurrentUserPhotoKey(user)), filter((photoKey) => !!photoKey), distinctUntilChanged())
|
|
2164
2861
|
.subscribe(() => {
|
|
2165
2862
|
this.getUserPhoto();
|
|
2166
2863
|
});
|
|
@@ -2178,35 +2875,41 @@ class UserService {
|
|
|
2178
2875
|
}
|
|
2179
2876
|
get userName() {
|
|
2180
2877
|
const data = this.securityService.getCurrentUser();
|
|
2181
|
-
return [data?.given_name, data?.family_name].filter(Boolean).join(' ')
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2878
|
+
return ([data?.given_name, data?.family_name].filter(Boolean).join(' ') ||
|
|
2879
|
+
data?.displayName ||
|
|
2880
|
+
data?.name ||
|
|
2881
|
+
data?.userName ||
|
|
2882
|
+
data?.preferred_username ||
|
|
2883
|
+
data?.email ||
|
|
2884
|
+
'');
|
|
2188
2885
|
}
|
|
2189
2886
|
/**
|
|
2190
|
-
* Initiates an HTTP request to fetch the user's photo
|
|
2887
|
+
* Initiates an HTTP request to fetch the current user's photo,
|
|
2191
2888
|
* and updates the `photo` and `photoLoaded` properties accordingly.
|
|
2192
2889
|
*/
|
|
2193
2890
|
getUserPhoto() {
|
|
2194
|
-
const
|
|
2195
|
-
if (!
|
|
2891
|
+
const photoKey = this.getCurrentUserPhotoKey(this.securityService.getCurrentUser());
|
|
2892
|
+
if (!photoKey) {
|
|
2196
2893
|
return;
|
|
2197
2894
|
}
|
|
2198
|
-
if (this.
|
|
2895
|
+
if (this.requestedPhotoKey === photoKey && (this.photoLoaded || this.photo)) {
|
|
2199
2896
|
return;
|
|
2200
2897
|
}
|
|
2201
|
-
this.
|
|
2202
|
-
this.userProfileApi.getUserPhoto({
|
|
2898
|
+
this.requestedPhotoKey = photoKey;
|
|
2899
|
+
this.userProfileApi.getUserPhoto({ format: 'blob' }).then((data) => {
|
|
2203
2900
|
this.createImageFromBlob(data);
|
|
2204
2901
|
this.photoLoaded = true;
|
|
2205
2902
|
}, (error) => {
|
|
2206
|
-
|
|
2903
|
+
this.msgService.errorFromException(error, this.translateService.instant('profileComponent.failedToLoadPhoto'));
|
|
2207
2904
|
this.photoLoaded = false;
|
|
2208
2905
|
});
|
|
2209
2906
|
}
|
|
2907
|
+
refreshUserPhoto() {
|
|
2908
|
+
this.requestedPhotoKey = null;
|
|
2909
|
+
this.photo = null;
|
|
2910
|
+
this.photoLoaded = false;
|
|
2911
|
+
this.getUserPhoto();
|
|
2912
|
+
}
|
|
2210
2913
|
/**
|
|
2211
2914
|
* Converts a Blob image into a Base64 data URL and stores it in the `photo` property.
|
|
2212
2915
|
*
|
|
@@ -2222,14 +2925,17 @@ class UserService {
|
|
|
2222
2925
|
}
|
|
2223
2926
|
}
|
|
2224
2927
|
getInitials(value) {
|
|
2225
|
-
return value
|
|
2928
|
+
return (value
|
|
2226
2929
|
?.trim()
|
|
2227
2930
|
.split(/\s+/)
|
|
2228
2931
|
.filter(Boolean)
|
|
2229
2932
|
.slice(0, 2)
|
|
2230
2933
|
.map((part) => part[0])
|
|
2231
2934
|
.join('')
|
|
2232
|
-
.toUpperCase() ?? '';
|
|
2935
|
+
.toUpperCase() ?? '');
|
|
2936
|
+
}
|
|
2937
|
+
getCurrentUserPhotoKey(user) {
|
|
2938
|
+
return user?.sub || user?.userName || user?.preferred_username || user?.displayName || user?.name || null;
|
|
2233
2939
|
}
|
|
2234
2940
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: UserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2235
2941
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: UserService }); }
|
|
@@ -2502,8 +3208,8 @@ class UserNotificationsComponent {
|
|
|
2502
3208
|
class="layout-topbar-action relative"
|
|
2503
3209
|
id="oip-app-topbar-notification-button"
|
|
2504
3210
|
type="button"
|
|
2505
|
-
|
|
2506
|
-
|
|
3211
|
+
[attr.aria-label]="'Notifications: ' + unreadNotificationCount()"
|
|
3212
|
+
(click)="toggle($event)">
|
|
2507
3213
|
<i class="pi pi-bell"></i>
|
|
2508
3214
|
@if (unreadNotificationCount() > 0) {
|
|
2509
3215
|
<p-badge
|
|
@@ -2576,11 +3282,11 @@ class UserNotificationsComponent {
|
|
|
2576
3282
|
</div>
|
|
2577
3283
|
|
|
2578
3284
|
<p-paginator
|
|
2579
|
-
|
|
3285
|
+
class="mt-3"
|
|
2580
3286
|
[first]="skip"
|
|
2581
3287
|
[rows]="take"
|
|
2582
|
-
[totalRecords]="totalCount"
|
|
2583
3288
|
[rowsPerPageOptions]="[5, 10, 20]"
|
|
3289
|
+
[totalRecords]="totalCount"
|
|
2584
3290
|
(onPageChange)="onPageChange($event)"></p-paginator>
|
|
2585
3291
|
}
|
|
2586
3292
|
</p-popover>
|
|
@@ -2591,14 +3297,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
2591
3297
|
args: [{
|
|
2592
3298
|
selector: 'app-user-notifications',
|
|
2593
3299
|
standalone: true,
|
|
2594
|
-
imports: [
|
|
3300
|
+
imports: [
|
|
3301
|
+
CommonModule,
|
|
3302
|
+
BadgeModule,
|
|
3303
|
+
ButtonModule,
|
|
3304
|
+
PaginatorModule,
|
|
3305
|
+
Popover,
|
|
3306
|
+
ProgressSpinnerModule,
|
|
3307
|
+
Tag,
|
|
3308
|
+
Tooltip,
|
|
3309
|
+
TranslatePipe
|
|
3310
|
+
],
|
|
2595
3311
|
template: `
|
|
2596
3312
|
<button
|
|
2597
3313
|
class="layout-topbar-action relative"
|
|
2598
3314
|
id="oip-app-topbar-notification-button"
|
|
2599
3315
|
type="button"
|
|
2600
|
-
|
|
2601
|
-
|
|
3316
|
+
[attr.aria-label]="'Notifications: ' + unreadNotificationCount()"
|
|
3317
|
+
(click)="toggle($event)">
|
|
2602
3318
|
<i class="pi pi-bell"></i>
|
|
2603
3319
|
@if (unreadNotificationCount() > 0) {
|
|
2604
3320
|
<p-badge
|
|
@@ -2671,11 +3387,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
2671
3387
|
</div>
|
|
2672
3388
|
|
|
2673
3389
|
<p-paginator
|
|
2674
|
-
|
|
3390
|
+
class="mt-3"
|
|
2675
3391
|
[first]="skip"
|
|
2676
3392
|
[rows]="take"
|
|
2677
|
-
[totalRecords]="totalCount"
|
|
2678
3393
|
[rowsPerPageOptions]="[5, 10, 20]"
|
|
3394
|
+
[totalRecords]="totalCount"
|
|
2679
3395
|
(onPageChange)="onPageChange($event)"></p-paginator>
|
|
2680
3396
|
}
|
|
2681
3397
|
</p-popover>
|
|
@@ -2839,6 +3555,10 @@ class AppTopbar {
|
|
|
2839
3555
|
this.confirmationService = inject(ConfirmationService);
|
|
2840
3556
|
this.translateService = inject(TranslateService);
|
|
2841
3557
|
}
|
|
3558
|
+
onActiveTabChange(value) {
|
|
3559
|
+
const nextActiveId = value == null ? undefined : String(value);
|
|
3560
|
+
this.topBarService.activeId = nextActiveId;
|
|
3561
|
+
}
|
|
2842
3562
|
toggleDarkMode() {
|
|
2843
3563
|
this.layoutService.layoutConfig.update((state) => ({
|
|
2844
3564
|
...state,
|
|
@@ -2871,106 +3591,108 @@ class AppTopbar {
|
|
|
2871
3591
|
});
|
|
2872
3592
|
}
|
|
2873
3593
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AppTopbar, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2874
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: AppTopbar, isStandalone: true, selector: "app-topbar", providers: [ConfirmationService], ngImport: i0, template: `
|
|
2875
|
-
<
|
|
2876
|
-
|
|
2877
|
-
<
|
|
2878
|
-
<
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
<
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
</div>
|
|
3594
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: AppTopbar, isStandalone: true, selector: "app-topbar", providers: [ConfirmationService], ngImport: i0, template: ` <div class="layout-topbar">
|
|
3595
|
+
<p-confirmDialog appendTo="body" />
|
|
3596
|
+
<div class="layout-topbar-logo-container">
|
|
3597
|
+
<button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
|
|
3598
|
+
<i class="pi pi-bars"></i>
|
|
3599
|
+
</button>
|
|
3600
|
+
<a class="layout-topbar-logo" id="oip-app-topbar-logo-link" routerLink="">
|
|
3601
|
+
<ng-container
|
|
3602
|
+
*ngComponentOutlet="logoService.getLogoComponent(); inputs: { width: 36, height: 36 }"></ng-container>
|
|
3603
|
+
<span>{{ 'app-info.title' | translate }}</span>
|
|
3604
|
+
</a>
|
|
3605
|
+
</div>
|
|
2887
3606
|
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
3607
|
+
@if (securityService.isAdmin() && topBarService.topBarItems.length > 0) {
|
|
3608
|
+
<p-tabs
|
|
3609
|
+
class="layout-topbar-tabs ml-2"
|
|
3610
|
+
[value]="topBarService.activeId"
|
|
3611
|
+
(valueChange)="onActiveTabChange($event)">
|
|
3612
|
+
<p-tablist>
|
|
3613
|
+
@for (tab of topBarService.availableTopBarItems; track tab.id) {
|
|
3614
|
+
<p-tab id="oip-app-topbar-tab-{{ tab.id }}" [value]="tab.id">
|
|
3615
|
+
<i class="pi {{ tab.icon }}"></i>
|
|
3616
|
+
<span class="ml-2">{{ tab.caption }}</span>
|
|
3617
|
+
</p-tab>
|
|
3618
|
+
}
|
|
3619
|
+
</p-tablist>
|
|
3620
|
+
</p-tabs>
|
|
3621
|
+
}
|
|
3622
|
+
<div class="layout-topbar-actions">
|
|
3623
|
+
<div class="layout-config-menu">
|
|
3624
|
+
<app-topbar-application-switcher />
|
|
3625
|
+
<app-user-notifications />
|
|
3626
|
+
<p-button
|
|
3627
|
+
class="layout-topbar-action"
|
|
3628
|
+
id="oip-app-topbar-theme-button"
|
|
3629
|
+
severity="secondary"
|
|
3630
|
+
type="button"
|
|
3631
|
+
[rounded]="true"
|
|
3632
|
+
[text]="true"
|
|
3633
|
+
(click)="toggleDarkMode()">
|
|
3634
|
+
<i
|
|
3635
|
+
class="pi"
|
|
3636
|
+
[ngClass]="{
|
|
2915
3637
|
'pi-moon': layoutService.isDarkTheme(),
|
|
2916
3638
|
'pi-sun': !layoutService.isDarkTheme()
|
|
2917
3639
|
}"></i>
|
|
3640
|
+
</p-button>
|
|
3641
|
+
<div class="relative">
|
|
3642
|
+
<p-button
|
|
3643
|
+
class="layout-topbar-action layout-topbar-action-highlight"
|
|
3644
|
+
enterActiveClass="animate-scalein"
|
|
3645
|
+
enterFromClass="hidden"
|
|
3646
|
+
id="oip-app-topbar-palette-button"
|
|
3647
|
+
leaveActiveClass="animate-fadeout"
|
|
3648
|
+
leaveToClass="hidden"
|
|
3649
|
+
pStyleClass="@next"
|
|
3650
|
+
[hideOnOutsideClick]="true"
|
|
3651
|
+
[rounded]="true">
|
|
3652
|
+
<i class="pi pi-palette"></i>
|
|
2918
3653
|
</p-button>
|
|
2919
|
-
<
|
|
2920
|
-
<p-button
|
|
2921
|
-
class="layout-topbar-action layout-topbar-action-highlight"
|
|
2922
|
-
enterActiveClass="animate-scalein"
|
|
2923
|
-
enterFromClass="hidden"
|
|
2924
|
-
id="oip-app-topbar-palette-button"
|
|
2925
|
-
leaveActiveClass="animate-fadeout"
|
|
2926
|
-
leaveToClass="hidden"
|
|
2927
|
-
pStyleClass="@next"
|
|
2928
|
-
[hideOnOutsideClick]="true"
|
|
2929
|
-
[rounded]="true">
|
|
2930
|
-
<i class="pi pi-palette"></i>
|
|
2931
|
-
</p-button>
|
|
2932
|
-
<app-configurator/>
|
|
2933
|
-
</div>
|
|
3654
|
+
<app-configurator />
|
|
2934
3655
|
</div>
|
|
3656
|
+
</div>
|
|
2935
3657
|
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
3658
|
+
<button
|
|
3659
|
+
class="layout-topbar-menu-button layout-topbar-action"
|
|
3660
|
+
enterActiveClass="animate-scalein"
|
|
3661
|
+
enterFromClass="hidden"
|
|
3662
|
+
id="oip-app-topbar-menu-expand-button"
|
|
3663
|
+
leaveActiveClass="animate-fadeout"
|
|
3664
|
+
leaveToClass="hidden"
|
|
3665
|
+
pStyleClass="@next"
|
|
3666
|
+
[hideOnOutsideClick]="true">
|
|
3667
|
+
<i class="pi pi-ellipsis-v"></i>
|
|
3668
|
+
</button>
|
|
2947
3669
|
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3670
|
+
<div class="layout-topbar-menu hidden lg:block">
|
|
3671
|
+
<div class="layout-topbar-menu-content">
|
|
3672
|
+
<button
|
|
3673
|
+
class="layout-topbar-action"
|
|
3674
|
+
id="oip-app-topbar-logout-button"
|
|
3675
|
+
type="button"
|
|
3676
|
+
(click)="confirmLogout()"
|
|
3677
|
+
(keydown)="logoutKeyDown($event)">
|
|
3678
|
+
<i class="pi pi-sign-out"></i>
|
|
3679
|
+
<span>{{ 'topbar.logout' | translate }}</span>
|
|
3680
|
+
</button>
|
|
3681
|
+
<button class="layout-topbar-action" routerLink="config">
|
|
3682
|
+
<p-avatar
|
|
3683
|
+
class="p-link flex align-items-center"
|
|
3684
|
+
id="oip-app-topbar-user-avatar"
|
|
3685
|
+
shape="circle"
|
|
3686
|
+
size="normal"
|
|
3687
|
+
[image]="userService.photoLoaded ? userService.photo : null"
|
|
2966
3688
|
>{{ !userService.photoLoaded ? userService.shortLabel : null }}
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
</div>
|
|
3689
|
+
</p-avatar>
|
|
3690
|
+
<span class="ml-2">{{ 'topbar.profile' | translate }}</span>
|
|
3691
|
+
</button>
|
|
2971
3692
|
</div>
|
|
2972
3693
|
</div>
|
|
2973
|
-
</div
|
|
3694
|
+
</div>
|
|
3695
|
+
</div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$5.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$3.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "ngmodule", type: StyleClassModule }, { kind: "directive", type: i3$3.StyleClass, selector: "[pStyleClass]", inputs: ["pStyleClass", "enterFromClass", "enterActiveClass", "enterToClass", "leaveFromClass", "leaveActiveClass", "leaveToClass", "hideOnOutsideClick", "toggleClass", "hideOnEscape", "hideOnResize", "resizeSelector"] }, { kind: "component", type: AppConfiguratorComponent, selector: "app-configurator" }, { kind: "component", type: Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: TabList, selector: "p-tablist" }, { kind: "component", type: Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "component", type: UserNotificationsComponent, selector: "app-user-notifications" }, { kind: "component", type: AppTopbarApplicationSwitcherComponent, selector: "app-topbar-application-switcher" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
2974
3696
|
}
|
|
2975
3697
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AppTopbar, decorators: [{
|
|
2976
3698
|
type: Component,
|
|
@@ -2992,106 +3714,108 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
2992
3714
|
TranslatePipe,
|
|
2993
3715
|
AppTopbarApplicationSwitcherComponent
|
|
2994
3716
|
],
|
|
2995
|
-
template: `
|
|
2996
|
-
<
|
|
2997
|
-
|
|
2998
|
-
<
|
|
2999
|
-
<
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
<
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
</div>
|
|
3717
|
+
template: ` <div class="layout-topbar">
|
|
3718
|
+
<p-confirmDialog appendTo="body" />
|
|
3719
|
+
<div class="layout-topbar-logo-container">
|
|
3720
|
+
<button class="layout-menu-button layout-topbar-action" (click)="layoutService.onMenuToggle()">
|
|
3721
|
+
<i class="pi pi-bars"></i>
|
|
3722
|
+
</button>
|
|
3723
|
+
<a class="layout-topbar-logo" id="oip-app-topbar-logo-link" routerLink="">
|
|
3724
|
+
<ng-container
|
|
3725
|
+
*ngComponentOutlet="logoService.getLogoComponent(); inputs: { width: 36, height: 36 }"></ng-container>
|
|
3726
|
+
<span>{{ 'app-info.title' | translate }}</span>
|
|
3727
|
+
</a>
|
|
3728
|
+
</div>
|
|
3008
3729
|
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3730
|
+
@if (securityService.isAdmin() && topBarService.topBarItems.length > 0) {
|
|
3731
|
+
<p-tabs
|
|
3732
|
+
class="layout-topbar-tabs ml-2"
|
|
3733
|
+
[value]="topBarService.activeId"
|
|
3734
|
+
(valueChange)="onActiveTabChange($event)">
|
|
3735
|
+
<p-tablist>
|
|
3736
|
+
@for (tab of topBarService.availableTopBarItems; track tab.id) {
|
|
3737
|
+
<p-tab id="oip-app-topbar-tab-{{ tab.id }}" [value]="tab.id">
|
|
3738
|
+
<i class="pi {{ tab.icon }}"></i>
|
|
3739
|
+
<span class="ml-2">{{ tab.caption }}</span>
|
|
3740
|
+
</p-tab>
|
|
3741
|
+
}
|
|
3742
|
+
</p-tablist>
|
|
3743
|
+
</p-tabs>
|
|
3744
|
+
}
|
|
3745
|
+
<div class="layout-topbar-actions">
|
|
3746
|
+
<div class="layout-config-menu">
|
|
3747
|
+
<app-topbar-application-switcher />
|
|
3748
|
+
<app-user-notifications />
|
|
3749
|
+
<p-button
|
|
3750
|
+
class="layout-topbar-action"
|
|
3751
|
+
id="oip-app-topbar-theme-button"
|
|
3752
|
+
severity="secondary"
|
|
3753
|
+
type="button"
|
|
3754
|
+
[rounded]="true"
|
|
3755
|
+
[text]="true"
|
|
3756
|
+
(click)="toggleDarkMode()">
|
|
3757
|
+
<i
|
|
3758
|
+
class="pi"
|
|
3759
|
+
[ngClass]="{
|
|
3036
3760
|
'pi-moon': layoutService.isDarkTheme(),
|
|
3037
3761
|
'pi-sun': !layoutService.isDarkTheme()
|
|
3038
3762
|
}"></i>
|
|
3763
|
+
</p-button>
|
|
3764
|
+
<div class="relative">
|
|
3765
|
+
<p-button
|
|
3766
|
+
class="layout-topbar-action layout-topbar-action-highlight"
|
|
3767
|
+
enterActiveClass="animate-scalein"
|
|
3768
|
+
enterFromClass="hidden"
|
|
3769
|
+
id="oip-app-topbar-palette-button"
|
|
3770
|
+
leaveActiveClass="animate-fadeout"
|
|
3771
|
+
leaveToClass="hidden"
|
|
3772
|
+
pStyleClass="@next"
|
|
3773
|
+
[hideOnOutsideClick]="true"
|
|
3774
|
+
[rounded]="true">
|
|
3775
|
+
<i class="pi pi-palette"></i>
|
|
3039
3776
|
</p-button>
|
|
3040
|
-
<
|
|
3041
|
-
<p-button
|
|
3042
|
-
class="layout-topbar-action layout-topbar-action-highlight"
|
|
3043
|
-
enterActiveClass="animate-scalein"
|
|
3044
|
-
enterFromClass="hidden"
|
|
3045
|
-
id="oip-app-topbar-palette-button"
|
|
3046
|
-
leaveActiveClass="animate-fadeout"
|
|
3047
|
-
leaveToClass="hidden"
|
|
3048
|
-
pStyleClass="@next"
|
|
3049
|
-
[hideOnOutsideClick]="true"
|
|
3050
|
-
[rounded]="true">
|
|
3051
|
-
<i class="pi pi-palette"></i>
|
|
3052
|
-
</p-button>
|
|
3053
|
-
<app-configurator/>
|
|
3054
|
-
</div>
|
|
3777
|
+
<app-configurator />
|
|
3055
3778
|
</div>
|
|
3779
|
+
</div>
|
|
3056
3780
|
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3781
|
+
<button
|
|
3782
|
+
class="layout-topbar-menu-button layout-topbar-action"
|
|
3783
|
+
enterActiveClass="animate-scalein"
|
|
3784
|
+
enterFromClass="hidden"
|
|
3785
|
+
id="oip-app-topbar-menu-expand-button"
|
|
3786
|
+
leaveActiveClass="animate-fadeout"
|
|
3787
|
+
leaveToClass="hidden"
|
|
3788
|
+
pStyleClass="@next"
|
|
3789
|
+
[hideOnOutsideClick]="true">
|
|
3790
|
+
<i class="pi pi-ellipsis-v"></i>
|
|
3791
|
+
</button>
|
|
3068
3792
|
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3793
|
+
<div class="layout-topbar-menu hidden lg:block">
|
|
3794
|
+
<div class="layout-topbar-menu-content">
|
|
3795
|
+
<button
|
|
3796
|
+
class="layout-topbar-action"
|
|
3797
|
+
id="oip-app-topbar-logout-button"
|
|
3798
|
+
type="button"
|
|
3799
|
+
(click)="confirmLogout()"
|
|
3800
|
+
(keydown)="logoutKeyDown($event)">
|
|
3801
|
+
<i class="pi pi-sign-out"></i>
|
|
3802
|
+
<span>{{ 'topbar.logout' | translate }}</span>
|
|
3803
|
+
</button>
|
|
3804
|
+
<button class="layout-topbar-action" routerLink="config">
|
|
3805
|
+
<p-avatar
|
|
3806
|
+
class="p-link flex align-items-center"
|
|
3807
|
+
id="oip-app-topbar-user-avatar"
|
|
3808
|
+
shape="circle"
|
|
3809
|
+
size="normal"
|
|
3810
|
+
[image]="userService.photoLoaded ? userService.photo : null"
|
|
3087
3811
|
>{{ !userService.photoLoaded ? userService.shortLabel : null }}
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
</div>
|
|
3812
|
+
</p-avatar>
|
|
3813
|
+
<span class="ml-2">{{ 'topbar.profile' | translate }}</span>
|
|
3814
|
+
</button>
|
|
3092
3815
|
</div>
|
|
3093
3816
|
</div>
|
|
3094
|
-
</div
|
|
3817
|
+
</div>
|
|
3818
|
+
</div>`,
|
|
3095
3819
|
providers: [ConfirmationService]
|
|
3096
3820
|
}]
|
|
3097
3821
|
}] });
|
|
@@ -3148,6 +3872,14 @@ class MenuApi extends HttpClient {
|
|
|
3148
3872
|
format: "json",
|
|
3149
3873
|
...params,
|
|
3150
3874
|
});
|
|
3875
|
+
this.getModuleInstanceRights = (query, params = {}) => this.request({
|
|
3876
|
+
path: `/api/menu/get-module-instance-rights`,
|
|
3877
|
+
method: "GET",
|
|
3878
|
+
query: query,
|
|
3879
|
+
secure: true,
|
|
3880
|
+
format: "json",
|
|
3881
|
+
...params,
|
|
3882
|
+
});
|
|
3151
3883
|
this.getAdminMenu = (params = {}) => this.request({
|
|
3152
3884
|
path: `/api/menu/get-admin-menu`,
|
|
3153
3885
|
method: "GET",
|
|
@@ -3206,10 +3938,16 @@ class MenuService {
|
|
|
3206
3938
|
this.resetSource = new Subject();
|
|
3207
3939
|
this.titleService = inject(AppTitleService);
|
|
3208
3940
|
this.menuDataService = inject(MenuApi);
|
|
3941
|
+
this.layoutService = inject(LayoutService);
|
|
3209
3942
|
this.menuSource$ = this.menuSource.asObservable();
|
|
3210
3943
|
this.resetSource$ = this.resetSource.asObservable();
|
|
3211
3944
|
this.menu = [];
|
|
3212
|
-
|
|
3945
|
+
}
|
|
3946
|
+
get adminMode() {
|
|
3947
|
+
return this.layoutService.adminMode();
|
|
3948
|
+
}
|
|
3949
|
+
set adminMode(value) {
|
|
3950
|
+
this.layoutService.layoutConfig.update((config) => ({ ...config, adminMode: value }));
|
|
3213
3951
|
}
|
|
3214
3952
|
async loadMenu() {
|
|
3215
3953
|
this.menu = this.adminMode ? await this.getAdminMenu() : await this.getMenu();
|
|
@@ -3560,7 +4298,7 @@ class MenuItemComponent {
|
|
|
3560
4298
|
</ul>
|
|
3561
4299
|
}
|
|
3562
4300
|
</ng-container>
|
|
3563
|
-
`, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type:
|
|
4301
|
+
`, isInline: true, dependencies: [{ kind: "component", type: MenuItemComponent, selector: "[app-menuitem]", inputs: ["item", "index", "root", "parentKey", "menuItemCreateDialogComponent", "menuItemEditDialogComponent", "contextMenu"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i2$2.Ripple, selector: "[pRipple]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }] }); }
|
|
3564
4302
|
}
|
|
3565
4303
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: MenuItemComponent, decorators: [{
|
|
3566
4304
|
type: Component,
|
|
@@ -3762,10 +4500,14 @@ class MenuItemCreateDialogComponent {
|
|
|
3762
4500
|
<p-select
|
|
3763
4501
|
appendTo="body"
|
|
3764
4502
|
class="flex-auto"
|
|
4503
|
+
filterBy="value"
|
|
4504
|
+
filterPlaceholder="{{ 'menuItemCreateDialogComponent.searchModule' | translate }}"
|
|
3765
4505
|
id="oip-menu-item-create-module"
|
|
3766
4506
|
optionLabel="value"
|
|
3767
4507
|
optionValue="key"
|
|
3768
4508
|
placeholder="{{ 'menuItemCreateDialogComponent.selectModule' | translate }}"
|
|
4509
|
+
scrollHeight="18rem"
|
|
4510
|
+
[filter]="true"
|
|
3769
4511
|
[options]="modules"
|
|
3770
4512
|
[(ngModel)]="selectModule" />
|
|
3771
4513
|
</div>
|
|
@@ -3813,7 +4555,7 @@ class MenuItemCreateDialogComponent {
|
|
|
3813
4555
|
(click)="save()" />
|
|
3814
4556
|
</div>
|
|
3815
4557
|
</p-dialog>
|
|
3816
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$
|
|
4558
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
3817
4559
|
}
|
|
3818
4560
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: MenuItemCreateDialogComponent, decorators: [{
|
|
3819
4561
|
type: Component,
|
|
@@ -3855,10 +4597,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
3855
4597
|
<p-select
|
|
3856
4598
|
appendTo="body"
|
|
3857
4599
|
class="flex-auto"
|
|
4600
|
+
filterBy="value"
|
|
4601
|
+
filterPlaceholder="{{ 'menuItemCreateDialogComponent.searchModule' | translate }}"
|
|
3858
4602
|
id="oip-menu-item-create-module"
|
|
3859
4603
|
optionLabel="value"
|
|
3860
4604
|
optionValue="key"
|
|
3861
4605
|
placeholder="{{ 'menuItemCreateDialogComponent.selectModule' | translate }}"
|
|
4606
|
+
scrollHeight="18rem"
|
|
4607
|
+
[filter]="true"
|
|
3862
4608
|
[options]="modules"
|
|
3863
4609
|
[(ngModel)]="selectModule" />
|
|
3864
4610
|
</div>
|
|
@@ -3920,7 +4666,6 @@ class MenuItemEditDialogComponent {
|
|
|
3920
4666
|
this.securityApi = inject(SecurityApi);
|
|
3921
4667
|
this.msgService = inject(MsgService);
|
|
3922
4668
|
this.visibleChange = new EventEmitter();
|
|
3923
|
-
this.modules = [];
|
|
3924
4669
|
this.roles = [];
|
|
3925
4670
|
this.iconOptions = Object.values(PrimeIcons)
|
|
3926
4671
|
.filter((icon) => typeof icon === 'string')
|
|
@@ -3974,9 +4719,6 @@ class MenuItemEditDialogComponent {
|
|
|
3974
4719
|
viewRoles: this.menuService.contextMenuItem?.securities
|
|
3975
4720
|
};
|
|
3976
4721
|
this.roles = await this.securityApi.getRealmRoles();
|
|
3977
|
-
this.menuService.getModules().then((data) => {
|
|
3978
|
-
this.modules = data;
|
|
3979
|
-
});
|
|
3980
4722
|
this.visible = true;
|
|
3981
4723
|
this.visibleChange.emit(this.visible);
|
|
3982
4724
|
}
|
|
@@ -4059,7 +4801,7 @@ class MenuItemEditDialogComponent {
|
|
|
4059
4801
|
(click)="save()" />
|
|
4060
4802
|
</div>
|
|
4061
4803
|
</p-dialog>
|
|
4062
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$
|
|
4804
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i1.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
4063
4805
|
}
|
|
4064
4806
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: MenuItemEditDialogComponent, decorators: [{
|
|
4065
4807
|
type: Component,
|
|
@@ -4179,8 +4921,7 @@ class MenuComponent {
|
|
|
4179
4921
|
];
|
|
4180
4922
|
}
|
|
4181
4923
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4182
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: MenuComponent, isStandalone: true, selector: "app-menu", providers: [MenuApi], 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: `
|
|
4183
|
-
<div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
|
|
4924
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: MenuComponent, isStandalone: true, selector: "app-menu", providers: [MenuApi], 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)">
|
|
4184
4925
|
<ul class="layout-menu">
|
|
4185
4926
|
@for (item of menuService.menu; track item; let i = $index) {
|
|
4186
4927
|
<ng-container>
|
|
@@ -4201,9 +4942,9 @@ class MenuComponent {
|
|
|
4201
4942
|
</ul>
|
|
4202
4943
|
</div>
|
|
4203
4944
|
@if (securityService.isAdmin()) {
|
|
4204
|
-
<p-contextMenu [target]="empty"/>
|
|
4205
|
-
<menu-item-create-dialog/>
|
|
4206
|
-
<menu-item-edit-dialog/>
|
|
4945
|
+
<p-contextMenu [target]="empty" />
|
|
4946
|
+
<menu-item-create-dialog />
|
|
4947
|
+
<menu-item-edit-dialog />
|
|
4207
4948
|
}`, 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$6.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"] }] }); }
|
|
4208
4949
|
}
|
|
4209
4950
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: MenuComponent, decorators: [{
|
|
@@ -4222,8 +4963,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
4222
4963
|
providers: [MenuApi],
|
|
4223
4964
|
selector: 'app-menu',
|
|
4224
4965
|
standalone: true,
|
|
4225
|
-
template: `
|
|
4226
|
-
<div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
|
|
4966
|
+
template: ` <div #empty class="layout-sidebar" (contextmenu)="onContextMenu($event)">
|
|
4227
4967
|
<ul class="layout-menu">
|
|
4228
4968
|
@for (item of menuService.menu; track item; let i = $index) {
|
|
4229
4969
|
<ng-container>
|
|
@@ -4244,9 +4984,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
4244
4984
|
</ul>
|
|
4245
4985
|
</div>
|
|
4246
4986
|
@if (securityService.isAdmin()) {
|
|
4247
|
-
<p-contextMenu [target]="empty"/>
|
|
4248
|
-
<menu-item-create-dialog/>
|
|
4249
|
-
<menu-item-edit-dialog/>
|
|
4987
|
+
<p-contextMenu [target]="empty" />
|
|
4988
|
+
<menu-item-create-dialog />
|
|
4989
|
+
<menu-item-edit-dialog />
|
|
4250
4990
|
}`
|
|
4251
4991
|
}]
|
|
4252
4992
|
}], propDecorators: { menuItemCreateDialogComponent: [{
|
|
@@ -4467,6 +5207,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
4467
5207
|
}]
|
|
4468
5208
|
}] });
|
|
4469
5209
|
|
|
5210
|
+
var notfound$1 = {
|
|
5211
|
+
title: "Not Found",
|
|
5212
|
+
errorCode: "404",
|
|
5213
|
+
description: "Requested resource is not available.",
|
|
5214
|
+
button: "Go to home"
|
|
5215
|
+
};
|
|
5216
|
+
var en$5 = {
|
|
5217
|
+
notfound: notfound$1
|
|
5218
|
+
};
|
|
5219
|
+
|
|
5220
|
+
var notfound = {
|
|
5221
|
+
title: "Не найдено",
|
|
5222
|
+
errorCode: "404",
|
|
5223
|
+
description: "Запрашиваемый ресурс недоступен.",
|
|
5224
|
+
button: "На главную"
|
|
5225
|
+
};
|
|
5226
|
+
var ru$5 = {
|
|
5227
|
+
notfound: notfound
|
|
5228
|
+
};
|
|
5229
|
+
|
|
5230
|
+
L10nService.registerTranslations({ en: en$5, ru: ru$5 });
|
|
4470
5231
|
class NotfoundComponent {
|
|
4471
5232
|
constructor(l10nService) {
|
|
4472
5233
|
l10nService.get('notfound');
|
|
@@ -4492,7 +5253,7 @@ class NotfoundComponent {
|
|
|
4492
5253
|
</div>
|
|
4493
5254
|
</div>
|
|
4494
5255
|
</div>
|
|
4495
|
-
</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: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: AppFloatingConfiguratorComponent, selector: "app-floating-configurator" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$
|
|
5256
|
+
</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: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: AppFloatingConfiguratorComponent, selector: "app-floating-configurator" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$4.TranslatePipe, name: "translate" }] }); }
|
|
4496
5257
|
}
|
|
4497
5258
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: NotfoundComponent, decorators: [{
|
|
4498
5259
|
type: Component,
|
|
@@ -4528,14 +5289,18 @@ class UnauthorizedComponent {
|
|
|
4528
5289
|
constructor() {
|
|
4529
5290
|
this.securityService = inject(SecurityService);
|
|
4530
5291
|
this.route = inject(ActivatedRoute);
|
|
4531
|
-
this.router = inject(Router);
|
|
4532
5292
|
}
|
|
4533
|
-
|
|
4534
|
-
const returnUrl =
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
5293
|
+
ngOnInit() {
|
|
5294
|
+
const returnUrl = sessionStorage.getItem(BffSecurityService.authorizeAfterLogoutReturnUrlKey);
|
|
5295
|
+
if (!returnUrl) {
|
|
5296
|
+
return;
|
|
5297
|
+
}
|
|
5298
|
+
sessionStorage.removeItem(BffSecurityService.authorizeAfterLogoutReturnUrlKey);
|
|
5299
|
+
this.securityService.authorize(returnUrl);
|
|
5300
|
+
}
|
|
5301
|
+
signIn() {
|
|
5302
|
+
const returnUrl = this.route.snapshot.queryParamMap.get('returnUrl') || '/';
|
|
5303
|
+
this.securityService.authorize(returnUrl);
|
|
4539
5304
|
}
|
|
4540
5305
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: UnauthorizedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4541
5306
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.24", type: UnauthorizedComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `
|
|
@@ -4611,6 +5376,80 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
4611
5376
|
}]
|
|
4612
5377
|
}] });
|
|
4613
5378
|
|
|
5379
|
+
class AccessComponent {
|
|
5380
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AccessComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5381
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.24", type: AccessComponent, isStandalone: true, selector: "app-access", ngImport: i0, template: `<div
|
|
5382
|
+
class="surface-ground flex align-items-center justify-content-center min-h-screen min-w-screen overflow-hidden">
|
|
5383
|
+
<div class="flex flex-column align-items-center justify-content-center">
|
|
5384
|
+
<img alt="Sakai logo" class="mb-5 w-6rem flex-shrink-0" src="assets/demo/images/access/logo-orange.svg" />
|
|
5385
|
+
<div
|
|
5386
|
+
style="border-radius:56px; padding:0.3rem; background: linear-gradient(180deg, rgba(247, 149, 48, 0.4) 10%, rgba(247, 149, 48, 0) 30%);">
|
|
5387
|
+
<div
|
|
5388
|
+
class="w-full surface-card py-8 px-5 sm:px-8 flex flex-column align-items-center"
|
|
5389
|
+
style="border-radius:53px">
|
|
5390
|
+
<div class="grid flex-column align-items-center">
|
|
5391
|
+
<div
|
|
5392
|
+
class="flex justify-content-center align-items-center bg-orange-500 border-circle"
|
|
5393
|
+
style="width:3.2rem; height:3.2rem;">
|
|
5394
|
+
<i class="text-50 pi pi-fw pi-lock text-2xl"></i>
|
|
5395
|
+
</div>
|
|
5396
|
+
<h1 class="text-900 font-bold text-4xl lg:text-5xl mb-2">Access Denied</h1>
|
|
5397
|
+
<span class="text-600 mb-5">You do not have the necessary permisions. Please contact admins.</span>
|
|
5398
|
+
<img alt="Access denied" class="mb-5" src="assets/demo/images/access/asset-access.svg" width="80%" />
|
|
5399
|
+
<p-button
|
|
5400
|
+
class="p-button-text"
|
|
5401
|
+
icon="pi pi-arrow-left"
|
|
5402
|
+
id="oip-app-access-go-to-dashboard-button"
|
|
5403
|
+
label="Go to Dashboard"
|
|
5404
|
+
pButton
|
|
5405
|
+
pRipple
|
|
5406
|
+
[routerLink]="['/']"></p-button>
|
|
5407
|
+
</div>
|
|
5408
|
+
</div>
|
|
5409
|
+
</div>
|
|
5410
|
+
</div>
|
|
5411
|
+
</div>`, isInline: true, dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i2$2.Ripple, selector: "[pRipple]" }] }); }
|
|
5412
|
+
}
|
|
5413
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AccessComponent, decorators: [{
|
|
5414
|
+
type: Component,
|
|
5415
|
+
args: [{
|
|
5416
|
+
selector: 'app-access',
|
|
5417
|
+
template: `<div
|
|
5418
|
+
class="surface-ground flex align-items-center justify-content-center min-h-screen min-w-screen overflow-hidden">
|
|
5419
|
+
<div class="flex flex-column align-items-center justify-content-center">
|
|
5420
|
+
<img alt="Sakai logo" class="mb-5 w-6rem flex-shrink-0" src="assets/demo/images/access/logo-orange.svg" />
|
|
5421
|
+
<div
|
|
5422
|
+
style="border-radius:56px; padding:0.3rem; background: linear-gradient(180deg, rgba(247, 149, 48, 0.4) 10%, rgba(247, 149, 48, 0) 30%);">
|
|
5423
|
+
<div
|
|
5424
|
+
class="w-full surface-card py-8 px-5 sm:px-8 flex flex-column align-items-center"
|
|
5425
|
+
style="border-radius:53px">
|
|
5426
|
+
<div class="grid flex-column align-items-center">
|
|
5427
|
+
<div
|
|
5428
|
+
class="flex justify-content-center align-items-center bg-orange-500 border-circle"
|
|
5429
|
+
style="width:3.2rem; height:3.2rem;">
|
|
5430
|
+
<i class="text-50 pi pi-fw pi-lock text-2xl"></i>
|
|
5431
|
+
</div>
|
|
5432
|
+
<h1 class="text-900 font-bold text-4xl lg:text-5xl mb-2">Access Denied</h1>
|
|
5433
|
+
<span class="text-600 mb-5">You do not have the necessary permisions. Please contact admins.</span>
|
|
5434
|
+
<img alt="Access denied" class="mb-5" src="assets/demo/images/access/asset-access.svg" width="80%" />
|
|
5435
|
+
<p-button
|
|
5436
|
+
class="p-button-text"
|
|
5437
|
+
icon="pi pi-arrow-left"
|
|
5438
|
+
id="oip-app-access-go-to-dashboard-button"
|
|
5439
|
+
label="Go to Dashboard"
|
|
5440
|
+
pButton
|
|
5441
|
+
pRipple
|
|
5442
|
+
[routerLink]="['/']"></p-button>
|
|
5443
|
+
</div>
|
|
5444
|
+
</div>
|
|
5445
|
+
</div>
|
|
5446
|
+
</div>
|
|
5447
|
+
</div>`,
|
|
5448
|
+
imports: [RouterLink, ButtonModule, RippleModule],
|
|
5449
|
+
standalone: true
|
|
5450
|
+
}]
|
|
5451
|
+
}] });
|
|
5452
|
+
|
|
4614
5453
|
class ErrorComponent {
|
|
4615
5454
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4616
5455
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.24", type: ErrorComponent, isStandalone: true, selector: "app-error", ngImport: i0, template: `<div
|
|
@@ -4643,7 +5482,7 @@ class ErrorComponent {
|
|
|
4643
5482
|
</div>
|
|
4644
5483
|
</div>
|
|
4645
5484
|
</div>
|
|
4646
|
-
</div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type:
|
|
5485
|
+
</div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$2.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i2$2.Ripple, selector: "[pRipple]" }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
|
|
4647
5486
|
}
|
|
4648
5487
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ErrorComponent, decorators: [{
|
|
4649
5488
|
type: Component,
|
|
@@ -4690,9 +5529,21 @@ class ProfileComponent {
|
|
|
4690
5529
|
this.userService = inject(UserService);
|
|
4691
5530
|
this.msgService = inject(MsgService);
|
|
4692
5531
|
this.translateService = inject(TranslateService);
|
|
5532
|
+
this.userProfileApi = inject(UserProfileApi);
|
|
4693
5533
|
}
|
|
4694
|
-
|
|
4695
|
-
|
|
5534
|
+
async uploadPhoto(event) {
|
|
5535
|
+
const file = event.files?.[0];
|
|
5536
|
+
if (!file) {
|
|
5537
|
+
return;
|
|
5538
|
+
}
|
|
5539
|
+
try {
|
|
5540
|
+
await this.userProfileApi.postUserPhoto({ files: file });
|
|
5541
|
+
this.userService.refreshUserPhoto();
|
|
5542
|
+
this.msgService.success(this.translateService.instant('profileComponent.successfullyUploaded'));
|
|
5543
|
+
}
|
|
5544
|
+
catch (error) {
|
|
5545
|
+
this.msgService.error(error);
|
|
5546
|
+
}
|
|
4696
5547
|
}
|
|
4697
5548
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ProfileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4698
5549
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.24", type: ProfileComponent, isStandalone: true, selector: "user-profile", ngImport: i0, template: `
|
|
@@ -4711,10 +5562,9 @@ class ProfileComponent {
|
|
|
4711
5562
|
maxFileSize="1000000"
|
|
4712
5563
|
mode="basic"
|
|
4713
5564
|
name="files"
|
|
4714
|
-
url="/api/user-profile/post-user-photo"
|
|
4715
|
-
withCredentials="true"
|
|
4716
5565
|
[auto]="true"
|
|
4717
|
-
|
|
5566
|
+
[customUpload]="true"
|
|
5567
|
+
(uploadHandler)="uploadPhoto($event)" />
|
|
4718
5568
|
</div>
|
|
4719
5569
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i1$7.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: ImageModule }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
4720
5570
|
}
|
|
@@ -4723,7 +5573,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
4723
5573
|
args: [{
|
|
4724
5574
|
selector: 'user-profile',
|
|
4725
5575
|
standalone: true,
|
|
4726
|
-
imports: [FileUploadModule, ImageModule,
|
|
5576
|
+
imports: [FileUploadModule, ImageModule, AvatarModule, TranslatePipe],
|
|
4727
5577
|
template: `
|
|
4728
5578
|
<p-avatar
|
|
4729
5579
|
class="mr-2"
|
|
@@ -4740,15 +5590,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
4740
5590
|
maxFileSize="1000000"
|
|
4741
5591
|
mode="basic"
|
|
4742
5592
|
name="files"
|
|
4743
|
-
url="/api/user-profile/post-user-photo"
|
|
4744
|
-
withCredentials="true"
|
|
4745
5593
|
[auto]="true"
|
|
4746
|
-
|
|
5594
|
+
[customUpload]="true"
|
|
5595
|
+
(uploadHandler)="uploadPhoto($event)" />
|
|
4747
5596
|
</div>
|
|
4748
5597
|
`
|
|
4749
5598
|
}]
|
|
4750
5599
|
}] });
|
|
4751
5600
|
|
|
5601
|
+
var config$1 = {
|
|
5602
|
+
all: "All",
|
|
5603
|
+
applicationManagement: "Application management",
|
|
5604
|
+
dateFormat: "Date format",
|
|
5605
|
+
dateTimeFormat: "Date and time format:",
|
|
5606
|
+
goTo: "Go to",
|
|
5607
|
+
localization: "Localization",
|
|
5608
|
+
menu: "Menu",
|
|
5609
|
+
moduleManagement: "Module management",
|
|
5610
|
+
photo: "Photo",
|
|
5611
|
+
profile: "Profile",
|
|
5612
|
+
selectLanguage: "Select language",
|
|
5613
|
+
timeFormat: "Time format",
|
|
5614
|
+
timeZone: "Time zone",
|
|
5615
|
+
usePhoto256x256Pixel: "Use photo 256x256 pixel"
|
|
5616
|
+
};
|
|
5617
|
+
var en$4 = {
|
|
5618
|
+
config: config$1
|
|
5619
|
+
};
|
|
5620
|
+
|
|
5621
|
+
var config = {
|
|
5622
|
+
all: "Все",
|
|
5623
|
+
applicationManagement: "Управление приложениями",
|
|
5624
|
+
dateFormat: "Формат даты",
|
|
5625
|
+
dateTimeFormat: "Формат даты и времени:",
|
|
5626
|
+
goTo: "Перейти",
|
|
5627
|
+
localization: "Локализация",
|
|
5628
|
+
menu: "Меню",
|
|
5629
|
+
moduleManagement: "Управление модулями",
|
|
5630
|
+
photo: "Фото",
|
|
5631
|
+
profile: "Профиль",
|
|
5632
|
+
selectLanguage: "Выберите язык",
|
|
5633
|
+
timeFormat: "Формат времени",
|
|
5634
|
+
timeZone: "Часовой пояс",
|
|
5635
|
+
usePhoto256x256Pixel: "Используйте фото 256x256 пикселей"
|
|
5636
|
+
};
|
|
5637
|
+
var ru$4 = {
|
|
5638
|
+
config: config
|
|
5639
|
+
};
|
|
5640
|
+
|
|
5641
|
+
L10nService.registerTranslations({ en: en$4, ru: ru$4 });
|
|
4752
5642
|
class ConfigComponent {
|
|
4753
5643
|
constructor() {
|
|
4754
5644
|
this.layoutService = inject(LayoutService);
|
|
@@ -4890,7 +5780,7 @@ class ConfigComponent {
|
|
|
4890
5780
|
</div>
|
|
4891
5781
|
}
|
|
4892
5782
|
</div>
|
|
4893
|
-
`, isInline: true, dependencies: [{ kind: "component", type: ProfileComponent, selector: "user-profile" }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: TableModule }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i2$
|
|
5783
|
+
`, isInline: true, dependencies: [{ kind: "component", type: ProfileComponent, selector: "user-profile" }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: TableModule }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i2$5.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
4894
5784
|
}
|
|
4895
5785
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ConfigComponent, decorators: [{
|
|
4896
5786
|
type: Component,
|
|
@@ -5015,11 +5905,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5015
5905
|
}]
|
|
5016
5906
|
}], ctorParameters: () => [] });
|
|
5017
5907
|
|
|
5908
|
+
var en$3 = {
|
|
5909
|
+
"db-migration": {
|
|
5910
|
+
migrationManager: "Migration manager",
|
|
5911
|
+
actions: {
|
|
5912
|
+
refresh: "Refresh",
|
|
5913
|
+
cleanFilter: "Clean filter",
|
|
5914
|
+
applyMigration: "Apply migration"
|
|
5915
|
+
},
|
|
5916
|
+
columns: {
|
|
5917
|
+
name: "Migration name",
|
|
5918
|
+
applied: "Applied",
|
|
5919
|
+
exist: "Exist",
|
|
5920
|
+
pending: "Pending"
|
|
5921
|
+
},
|
|
5922
|
+
messages: {
|
|
5923
|
+
errorRefreshing: "Error refreshing database"
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
5926
|
+
};
|
|
5927
|
+
|
|
5928
|
+
var ru$3 = {
|
|
5929
|
+
"db-migration": {
|
|
5930
|
+
migrationManager: "Менеджер миграций",
|
|
5931
|
+
actions: {
|
|
5932
|
+
refresh: "Обновить",
|
|
5933
|
+
cleanFilter: "Очистить фильтр",
|
|
5934
|
+
applyMigration: "Применить миграцию"
|
|
5935
|
+
},
|
|
5936
|
+
columns: {
|
|
5937
|
+
name: "Название миграции",
|
|
5938
|
+
applied: "Применена",
|
|
5939
|
+
exist: "Существует",
|
|
5940
|
+
pending: "Ожидает"
|
|
5941
|
+
},
|
|
5942
|
+
messages: {
|
|
5943
|
+
errorRefreshing: "Ошибка обновления базы данных"
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5946
|
+
};
|
|
5947
|
+
|
|
5018
5948
|
class DbMigrationComponent extends BaseModuleComponent {
|
|
5019
|
-
|
|
5020
|
-
super();
|
|
5021
|
-
this.l10nService.loadComponentTranslations('db-migration');
|
|
5022
|
-
}
|
|
5949
|
+
static { this.translations = { en: en$3, ru: ru$3 }; }
|
|
5023
5950
|
async ngOnInit() {
|
|
5024
5951
|
await super.ngOnInit();
|
|
5025
5952
|
await this.refreshAction();
|
|
@@ -5041,11 +5968,11 @@ class DbMigrationComponent extends BaseModuleComponent {
|
|
|
5041
5968
|
const request = { name: rowData.name };
|
|
5042
5969
|
return this.applyModuleMigration(request);
|
|
5043
5970
|
}
|
|
5044
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DbMigrationComponent, deps:
|
|
5971
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DbMigrationComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
5045
5972
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: DbMigrationComponent, isStandalone: true, selector: "db-migration", providers: [ConfirmationService], usesInheritance: true, ngImport: i0, template: `
|
|
5046
5973
|
@if (isContent) {
|
|
5047
5974
|
<div class="card" style="height: 100%">
|
|
5048
|
-
<p-confirmDialog/>
|
|
5975
|
+
<p-confirmDialog />
|
|
5049
5976
|
<div>
|
|
5050
5977
|
<h5>{{ 'db-migration.migrationManager' | translate }}</h5>
|
|
5051
5978
|
<div class="flex flex-row gap-2">
|
|
@@ -5055,14 +5982,14 @@ class DbMigrationComponent extends BaseModuleComponent {
|
|
|
5055
5982
|
tooltipPosition="bottom"
|
|
5056
5983
|
[outlined]="true"
|
|
5057
5984
|
[pTooltip]="'db-migration.actions.refresh' | translate"
|
|
5058
|
-
(click)="refreshAction()"/>
|
|
5985
|
+
(click)="refreshAction()" />
|
|
5059
5986
|
<p-button
|
|
5060
5987
|
icon="pi pi-filter-slash"
|
|
5061
5988
|
severity="secondary"
|
|
5062
5989
|
tooltipPosition="bottom"
|
|
5063
5990
|
[outlined]="true"
|
|
5064
5991
|
[pTooltip]="'db-migration.actions.cleanFilter' | translate"
|
|
5065
|
-
(click)="dt.clear()"/>
|
|
5992
|
+
(click)="dt.clear()" />
|
|
5066
5993
|
</div>
|
|
5067
5994
|
<div>
|
|
5068
5995
|
<p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
|
|
@@ -5070,7 +5997,7 @@ class DbMigrationComponent extends BaseModuleComponent {
|
|
|
5070
5997
|
<tr>
|
|
5071
5998
|
<th pSortableColumn="name" scope="col">
|
|
5072
5999
|
{{ 'db-migration.columns.name' | translate }}
|
|
5073
|
-
<p-columnFilter display="menu" field="name" type="text"/>
|
|
6000
|
+
<p-columnFilter display="menu" field="name" type="text" />
|
|
5074
6001
|
</th>
|
|
5075
6002
|
<th scope="col">{{ 'db-migration.columns.applied' | translate }}</th>
|
|
5076
6003
|
<th scope="col">{{ 'db-migration.columns.exist' | translate }}</th>
|
|
@@ -5091,7 +6018,7 @@ class DbMigrationComponent extends BaseModuleComponent {
|
|
|
5091
6018
|
</td>
|
|
5092
6019
|
<td>
|
|
5093
6020
|
@if (rowData.exist) {
|
|
5094
|
-
<p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"/>
|
|
6021
|
+
<p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true" />
|
|
5095
6022
|
}
|
|
5096
6023
|
</td>
|
|
5097
6024
|
<td>
|
|
@@ -5118,9 +6045,9 @@ class DbMigrationComponent extends BaseModuleComponent {
|
|
|
5118
6045
|
</div>
|
|
5119
6046
|
</div>
|
|
5120
6047
|
} @else if (isSecurity) {
|
|
5121
|
-
<security [controller]="controller" [id]="id"/>
|
|
6048
|
+
<security [controller]="controller" [id]="id" />
|
|
5122
6049
|
}
|
|
5123
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$8.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$
|
|
6050
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$8.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$8.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i1$8.EditableRow, selector: "[pEditableRow]", inputs: ["pEditableRow", "pEditableRowDisabled"] }, { kind: "directive", type: i1$8.CancelEditableRow, selector: "[pCancelEditableRow]" }, { kind: "component", type: i1$8.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: TagModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: TextareaModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
5124
6051
|
}
|
|
5125
6052
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DbMigrationComponent, decorators: [{
|
|
5126
6053
|
type: Component,
|
|
@@ -5142,7 +6069,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5142
6069
|
template: `
|
|
5143
6070
|
@if (isContent) {
|
|
5144
6071
|
<div class="card" style="height: 100%">
|
|
5145
|
-
<p-confirmDialog/>
|
|
6072
|
+
<p-confirmDialog />
|
|
5146
6073
|
<div>
|
|
5147
6074
|
<h5>{{ 'db-migration.migrationManager' | translate }}</h5>
|
|
5148
6075
|
<div class="flex flex-row gap-2">
|
|
@@ -5152,14 +6079,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5152
6079
|
tooltipPosition="bottom"
|
|
5153
6080
|
[outlined]="true"
|
|
5154
6081
|
[pTooltip]="'db-migration.actions.refresh' | translate"
|
|
5155
|
-
(click)="refreshAction()"/>
|
|
6082
|
+
(click)="refreshAction()" />
|
|
5156
6083
|
<p-button
|
|
5157
6084
|
icon="pi pi-filter-slash"
|
|
5158
6085
|
severity="secondary"
|
|
5159
6086
|
tooltipPosition="bottom"
|
|
5160
6087
|
[outlined]="true"
|
|
5161
6088
|
[pTooltip]="'db-migration.actions.cleanFilter' | translate"
|
|
5162
|
-
(click)="dt.clear()"/>
|
|
6089
|
+
(click)="dt.clear()" />
|
|
5163
6090
|
</div>
|
|
5164
6091
|
<div>
|
|
5165
6092
|
<p-table #dt dataKey="name" editMode="row" size="small" [scrollable]="true" [value]="data">
|
|
@@ -5167,7 +6094,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5167
6094
|
<tr>
|
|
5168
6095
|
<th pSortableColumn="name" scope="col">
|
|
5169
6096
|
{{ 'db-migration.columns.name' | translate }}
|
|
5170
|
-
<p-columnFilter display="menu" field="name" type="text"/>
|
|
6097
|
+
<p-columnFilter display="menu" field="name" type="text" />
|
|
5171
6098
|
</th>
|
|
5172
6099
|
<th scope="col">{{ 'db-migration.columns.applied' | translate }}</th>
|
|
5173
6100
|
<th scope="col">{{ 'db-migration.columns.exist' | translate }}</th>
|
|
@@ -5188,7 +6115,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5188
6115
|
</td>
|
|
5189
6116
|
<td>
|
|
5190
6117
|
@if (rowData.exist) {
|
|
5191
|
-
<p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true"/>
|
|
6118
|
+
<p-button icon="pi pi-check" severity="success" [rounded]="true" [text]="true" />
|
|
5192
6119
|
}
|
|
5193
6120
|
</td>
|
|
5194
6121
|
<td>
|
|
@@ -5215,12 +6142,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5215
6142
|
</div>
|
|
5216
6143
|
</div>
|
|
5217
6144
|
} @else if (isSecurity) {
|
|
5218
|
-
<security [controller]="controller" [id]="id"/>
|
|
6145
|
+
<security [controller]="controller" [id]="id" />
|
|
5219
6146
|
}
|
|
5220
6147
|
`,
|
|
5221
6148
|
providers: [ConfirmationService]
|
|
5222
6149
|
}]
|
|
5223
|
-
}]
|
|
6150
|
+
}] });
|
|
6151
|
+
|
|
6152
|
+
/* eslint-disable */
|
|
6153
|
+
/* tslint:disable */
|
|
6154
|
+
// @ts-nocheck
|
|
6155
|
+
class ExtensionModulesApi extends HttpClient {
|
|
6156
|
+
constructor() {
|
|
6157
|
+
super(...arguments);
|
|
6158
|
+
this.getExtensionModules = (params = {}) => this.request({
|
|
6159
|
+
path: `/api/extension-modules/get-extension-modules`,
|
|
6160
|
+
method: "GET",
|
|
6161
|
+
secure: true,
|
|
6162
|
+
format: "json",
|
|
6163
|
+
...params,
|
|
6164
|
+
});
|
|
6165
|
+
this.getExtensionModuleByKey = ({ extensionKey, ...query }, params = {}) => this.request({
|
|
6166
|
+
path: `/api/extension-modules/get-extension-module-by-key/${extensionKey}`,
|
|
6167
|
+
method: "GET",
|
|
6168
|
+
secure: true,
|
|
6169
|
+
format: "json",
|
|
6170
|
+
...params,
|
|
6171
|
+
});
|
|
6172
|
+
this.registerExtensionModule = (data, params = {}) => this.request({
|
|
6173
|
+
path: `/api/extension-modules/register-extension-module`,
|
|
6174
|
+
method: "POST",
|
|
6175
|
+
body: data,
|
|
6176
|
+
secure: true,
|
|
6177
|
+
type: ContentType.Json,
|
|
6178
|
+
format: "json",
|
|
6179
|
+
...params,
|
|
6180
|
+
});
|
|
6181
|
+
this.updateExtensionModule = ({ id, ...query }, data, params = {}) => this.request({
|
|
6182
|
+
path: `/api/extension-modules/update-extension-module/${id}`,
|
|
6183
|
+
method: "PUT",
|
|
6184
|
+
body: data,
|
|
6185
|
+
secure: true,
|
|
6186
|
+
type: ContentType.Json,
|
|
6187
|
+
format: "json",
|
|
6188
|
+
...params,
|
|
6189
|
+
});
|
|
6190
|
+
this.deleteExtensionModule = ({ id, ...query }, params = {}) => this.request({
|
|
6191
|
+
path: `/api/extension-modules/delete-extension-module/${id}`,
|
|
6192
|
+
method: "DELETE",
|
|
6193
|
+
secure: true,
|
|
6194
|
+
...params,
|
|
6195
|
+
});
|
|
6196
|
+
}
|
|
6197
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionModulesApi, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6198
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionModulesApi }); }
|
|
6199
|
+
}
|
|
6200
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionModulesApi, decorators: [{
|
|
6201
|
+
type: Injectable
|
|
6202
|
+
}] });
|
|
5224
6203
|
|
|
5225
6204
|
/* eslint-disable */
|
|
5226
6205
|
/* tslint:disable */
|
|
@@ -5266,6 +6245,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5266
6245
|
type: Injectable
|
|
5267
6246
|
}] });
|
|
5268
6247
|
|
|
6248
|
+
var en$2 = {
|
|
6249
|
+
"app-modules": {
|
|
6250
|
+
title: "Modules",
|
|
6251
|
+
refreshTooltip: "Refresh",
|
|
6252
|
+
register: {
|
|
6253
|
+
manifestUrlPlaceholder: "External module manifest URL",
|
|
6254
|
+
button: "Register"
|
|
6255
|
+
},
|
|
6256
|
+
table: {
|
|
6257
|
+
moduleId: "Module ID",
|
|
6258
|
+
name: "Name",
|
|
6259
|
+
currentlyLoaded: "Currently Loaded",
|
|
6260
|
+
yes: "Yes",
|
|
6261
|
+
no: "No",
|
|
6262
|
+
deleteTooltip: "Delete"
|
|
6263
|
+
},
|
|
6264
|
+
confirm: {
|
|
6265
|
+
header: "Warning",
|
|
6266
|
+
message: "Are you sure you want to delete the module?",
|
|
6267
|
+
cancel: "Cancel",
|
|
6268
|
+
"delete": "Delete"
|
|
6269
|
+
},
|
|
6270
|
+
messages: {
|
|
6271
|
+
deleteSuccess: "Module deleted",
|
|
6272
|
+
deleteError: "Module delete failed",
|
|
6273
|
+
registerError: "External module registration failed",
|
|
6274
|
+
registerSuccess: "External module registered"
|
|
6275
|
+
}
|
|
6276
|
+
}
|
|
6277
|
+
};
|
|
6278
|
+
|
|
6279
|
+
var ru$2 = {
|
|
6280
|
+
"app-modules": {
|
|
6281
|
+
title: "Модули",
|
|
6282
|
+
refreshTooltip: "Обновить",
|
|
6283
|
+
register: {
|
|
6284
|
+
manifestUrlPlaceholder: "URL манифеста внешнего модуля",
|
|
6285
|
+
button: "Зарегистрировать"
|
|
6286
|
+
},
|
|
6287
|
+
table: {
|
|
6288
|
+
moduleId: "ID модуля",
|
|
6289
|
+
name: "Название",
|
|
6290
|
+
currentlyLoaded: "Загружен",
|
|
6291
|
+
yes: "Да",
|
|
6292
|
+
no: "Нет",
|
|
6293
|
+
deleteTooltip: "Удалить"
|
|
6294
|
+
},
|
|
6295
|
+
confirm: {
|
|
6296
|
+
header: "Внимание",
|
|
6297
|
+
message: "Вы уверены, что хотите удалить модуль?",
|
|
6298
|
+
cancel: "Отмена",
|
|
6299
|
+
"delete": "Удалить"
|
|
6300
|
+
},
|
|
6301
|
+
messages: {
|
|
6302
|
+
deleteSuccess: "Модуль удален",
|
|
6303
|
+
deleteError: "Не удалось удалить модуль",
|
|
6304
|
+
registerError: "Не удалось зарегистрировать внешний модуль",
|
|
6305
|
+
registerSuccess: "Внешний модуль зарегистрирован"
|
|
6306
|
+
}
|
|
6307
|
+
}
|
|
6308
|
+
};
|
|
6309
|
+
|
|
6310
|
+
L10nService.registerTranslations({ en: en$2, ru: ru$2 });
|
|
5269
6311
|
class AppModulesComponent {
|
|
5270
6312
|
constructor() {
|
|
5271
6313
|
this.modules = [];
|
|
@@ -5273,7 +6315,10 @@ class AppModulesComponent {
|
|
|
5273
6315
|
this.confirmationService = inject(ConfirmationService);
|
|
5274
6316
|
this.l10nService = inject(L10nService);
|
|
5275
6317
|
this.titleService = inject(AppTitleService);
|
|
6318
|
+
this.externalModuleManifestUrl = '';
|
|
6319
|
+
this.registeringExternalModule = false;
|
|
5276
6320
|
this.moduleService = inject(ModuleApi);
|
|
6321
|
+
this.extensionModulesService = inject(ExtensionModulesApi);
|
|
5277
6322
|
this.translationsReady = firstValueFrom(this.l10nService.loadComponentTranslations('app-modules'));
|
|
5278
6323
|
}
|
|
5279
6324
|
async ngOnInit() {
|
|
@@ -5284,6 +6329,30 @@ class AppModulesComponent {
|
|
|
5284
6329
|
async refreshAction() {
|
|
5285
6330
|
this.modules = await this.moduleService.getModulesWithLoadStatus();
|
|
5286
6331
|
}
|
|
6332
|
+
get canRegisterExternalModule() {
|
|
6333
|
+
return !!this.externalModuleManifestUrl.trim() && !this.registeringExternalModule;
|
|
6334
|
+
}
|
|
6335
|
+
async registerExternalModule() {
|
|
6336
|
+
if (!this.canRegisterExternalModule) {
|
|
6337
|
+
return;
|
|
6338
|
+
}
|
|
6339
|
+
await this.translationsReady;
|
|
6340
|
+
this.registeringExternalModule = true;
|
|
6341
|
+
try {
|
|
6342
|
+
await this.extensionModulesService.registerExtensionModule({
|
|
6343
|
+
manifestUrl: this.externalModuleManifestUrl.trim()
|
|
6344
|
+
});
|
|
6345
|
+
this.externalModuleManifestUrl = '';
|
|
6346
|
+
await this.refreshAction();
|
|
6347
|
+
this.msgService.success(this.t('app-modules.messages.registerSuccess'));
|
|
6348
|
+
}
|
|
6349
|
+
catch (error) {
|
|
6350
|
+
this.msgService.errorFromException(error, this.t('app-modules.messages.registerError'), this.t('app-modules.messages.registerError'));
|
|
6351
|
+
}
|
|
6352
|
+
finally {
|
|
6353
|
+
this.registeringExternalModule = false;
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
5287
6356
|
async deleteModule(module) {
|
|
5288
6357
|
await this.translationsReady;
|
|
5289
6358
|
this.confirmationService.confirm({
|
|
@@ -5308,7 +6377,7 @@ class AppModulesComponent {
|
|
|
5308
6377
|
this.msgService.success(this.t('app-modules.messages.deleteSuccess'));
|
|
5309
6378
|
}
|
|
5310
6379
|
catch (error) {
|
|
5311
|
-
this.msgService.error(
|
|
6380
|
+
this.msgService.errorFromException(error, this.t('app-modules.messages.deleteError'), this.t('app-modules.messages.deleteError'));
|
|
5312
6381
|
}
|
|
5313
6382
|
}
|
|
5314
6383
|
});
|
|
@@ -5317,7 +6386,7 @@ class AppModulesComponent {
|
|
|
5317
6386
|
return this.l10nService.instant(key);
|
|
5318
6387
|
}
|
|
5319
6388
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AppModulesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5320
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.24", type: AppModulesComponent, isStandalone: true, selector: "app-modules", providers: [ConfirmationService, ModuleApi], ngImport: i0, template: `
|
|
6389
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.24", type: AppModulesComponent, isStandalone: true, selector: "app-modules", providers: [ConfirmationService, ModuleApi, ExtensionModulesApi], ngImport: i0, template: `
|
|
5321
6390
|
<p-confirmDialog></p-confirmDialog>
|
|
5322
6391
|
<div class="flex flex-col md:flex-row gap-4">
|
|
5323
6392
|
<div class="card w-full">
|
|
@@ -5326,14 +6395,33 @@ class AppModulesComponent {
|
|
|
5326
6395
|
</div>
|
|
5327
6396
|
<div class="mb-4">
|
|
5328
6397
|
<p-toolbar>
|
|
5329
|
-
<
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
6398
|
+
<div class="flex flex-col md:flex-row md:items-center gap-2 w-full">
|
|
6399
|
+
<div class="flex flex-col sm:flex-row gap-2 flex-1">
|
|
6400
|
+
<input
|
|
6401
|
+
class="w-full"
|
|
6402
|
+
pInputText
|
|
6403
|
+
type="url"
|
|
6404
|
+
[disabled]="registeringExternalModule"
|
|
6405
|
+
[placeholder]="'app-modules.register.manifestUrlPlaceholder' | translate"
|
|
6406
|
+
[(ngModel)]="externalModuleManifestUrl"
|
|
6407
|
+
(keydown.enter)="registerExternalModule()" />
|
|
6408
|
+
<p-button
|
|
6409
|
+
icon="pi pi-plus"
|
|
6410
|
+
severity="success"
|
|
6411
|
+
[disabled]="!canRegisterExternalModule"
|
|
6412
|
+
[label]="'app-modules.register.button' | translate"
|
|
6413
|
+
[loading]="registeringExternalModule"
|
|
6414
|
+
(onClick)="registerExternalModule()"></p-button>
|
|
6415
|
+
</div>
|
|
6416
|
+
<p-button
|
|
6417
|
+
icon="pi pi-refresh"
|
|
6418
|
+
rounded="true"
|
|
6419
|
+
severity="secondary"
|
|
6420
|
+
text="true"
|
|
6421
|
+
tooltipPosition="bottom"
|
|
6422
|
+
[pTooltip]="'app-modules.refreshTooltip' | translate"
|
|
6423
|
+
(onClick)="refreshAction()"></p-button>
|
|
6424
|
+
</div>
|
|
5337
6425
|
</p-toolbar>
|
|
5338
6426
|
</div>
|
|
5339
6427
|
<p-table class="mt-4" [paginator]="true" [rows]="100" [value]="modules">
|
|
@@ -5371,13 +6459,23 @@ class AppModulesComponent {
|
|
|
5371
6459
|
</p-table>
|
|
5372
6460
|
</div>
|
|
5373
6461
|
</div>
|
|
5374
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$8.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$
|
|
6462
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$8.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i5$1.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
5375
6463
|
}
|
|
5376
6464
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AppModulesComponent, decorators: [{
|
|
5377
6465
|
type: Component,
|
|
5378
6466
|
args: [{
|
|
5379
|
-
imports: [
|
|
5380
|
-
|
|
6467
|
+
imports: [
|
|
6468
|
+
FormsModule,
|
|
6469
|
+
TableModule,
|
|
6470
|
+
Tag,
|
|
6471
|
+
ButtonModule,
|
|
6472
|
+
ToolbarModule,
|
|
6473
|
+
Tooltip,
|
|
6474
|
+
ConfirmDialog,
|
|
6475
|
+
TranslatePipe,
|
|
6476
|
+
InputTextModule
|
|
6477
|
+
],
|
|
6478
|
+
providers: [ConfirmationService, ModuleApi, ExtensionModulesApi],
|
|
5381
6479
|
selector: 'app-modules',
|
|
5382
6480
|
template: `
|
|
5383
6481
|
<p-confirmDialog></p-confirmDialog>
|
|
@@ -5388,14 +6486,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
5388
6486
|
</div>
|
|
5389
6487
|
<div class="mb-4">
|
|
5390
6488
|
<p-toolbar>
|
|
5391
|
-
<
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
6489
|
+
<div class="flex flex-col md:flex-row md:items-center gap-2 w-full">
|
|
6490
|
+
<div class="flex flex-col sm:flex-row gap-2 flex-1">
|
|
6491
|
+
<input
|
|
6492
|
+
class="w-full"
|
|
6493
|
+
pInputText
|
|
6494
|
+
type="url"
|
|
6495
|
+
[disabled]="registeringExternalModule"
|
|
6496
|
+
[placeholder]="'app-modules.register.manifestUrlPlaceholder' | translate"
|
|
6497
|
+
[(ngModel)]="externalModuleManifestUrl"
|
|
6498
|
+
(keydown.enter)="registerExternalModule()" />
|
|
6499
|
+
<p-button
|
|
6500
|
+
icon="pi pi-plus"
|
|
6501
|
+
severity="success"
|
|
6502
|
+
[disabled]="!canRegisterExternalModule"
|
|
6503
|
+
[label]="'app-modules.register.button' | translate"
|
|
6504
|
+
[loading]="registeringExternalModule"
|
|
6505
|
+
(onClick)="registerExternalModule()"></p-button>
|
|
6506
|
+
</div>
|
|
6507
|
+
<p-button
|
|
6508
|
+
icon="pi pi-refresh"
|
|
6509
|
+
rounded="true"
|
|
6510
|
+
severity="secondary"
|
|
6511
|
+
text="true"
|
|
6512
|
+
tooltipPosition="bottom"
|
|
6513
|
+
[pTooltip]="'app-modules.refreshTooltip' | translate"
|
|
6514
|
+
(onClick)="refreshAction()"></p-button>
|
|
6515
|
+
</div>
|
|
5399
6516
|
</p-toolbar>
|
|
5400
6517
|
</div>
|
|
5401
6518
|
<p-table class="mt-4" [paginator]="true" [rows]="100" [value]="modules">
|
|
@@ -5443,6 +6560,103 @@ var ServiceType;
|
|
|
5443
6560
|
ServiceType["Application"] = "Application";
|
|
5444
6561
|
})(ServiceType || (ServiceType = {}));
|
|
5445
6562
|
|
|
6563
|
+
var applications$1 = {
|
|
6564
|
+
title: "Applications",
|
|
6565
|
+
subtitle: "Manage the frontend application registry",
|
|
6566
|
+
searchPlaceholder: "Search applications",
|
|
6567
|
+
search: "Search",
|
|
6568
|
+
clear: "Clear",
|
|
6569
|
+
add: "Add",
|
|
6570
|
+
refreshTooltip: "Refresh",
|
|
6571
|
+
empty: "No applications found",
|
|
6572
|
+
table: {
|
|
6573
|
+
code: "Code",
|
|
6574
|
+
displayName: "Name",
|
|
6575
|
+
baseUrl: "Base URL",
|
|
6576
|
+
internalBaseUrl: "Internal Base URL",
|
|
6577
|
+
icon: "Icon",
|
|
6578
|
+
order: "Order",
|
|
6579
|
+
enabled: "Enabled",
|
|
6580
|
+
serviceType: "Service type",
|
|
6581
|
+
current: "Current",
|
|
6582
|
+
actions: "Actions",
|
|
6583
|
+
yes: "Yes",
|
|
6584
|
+
no: "No",
|
|
6585
|
+
editTooltip: "Edit",
|
|
6586
|
+
deleteTooltip: "Delete",
|
|
6587
|
+
saveTooltip: "Save",
|
|
6588
|
+
cancelTooltip: "Cancel"
|
|
6589
|
+
},
|
|
6590
|
+
serviceTypes: {
|
|
6591
|
+
service: "Service",
|
|
6592
|
+
application: "Application"
|
|
6593
|
+
},
|
|
6594
|
+
confirm: {
|
|
6595
|
+
header: "Warning",
|
|
6596
|
+
message: "Are you sure you want to delete application {{displayName}}?",
|
|
6597
|
+
cancel: "Cancel",
|
|
6598
|
+
"delete": "Delete"
|
|
6599
|
+
},
|
|
6600
|
+
messages: {
|
|
6601
|
+
requiredFields: "Fill code, name and Base URL",
|
|
6602
|
+
createSuccess: "Application created",
|
|
6603
|
+
updateSuccess: "Application updated",
|
|
6604
|
+
deleteSuccess: "Application deleted"
|
|
6605
|
+
}
|
|
6606
|
+
};
|
|
6607
|
+
var en$1 = {
|
|
6608
|
+
applications: applications$1
|
|
6609
|
+
};
|
|
6610
|
+
|
|
6611
|
+
var applications = {
|
|
6612
|
+
title: "Приложения",
|
|
6613
|
+
subtitle: "Управление реестром фронтенд-приложений",
|
|
6614
|
+
searchPlaceholder: "Поиск по приложениям",
|
|
6615
|
+
search: "Найти",
|
|
6616
|
+
clear: "Очистить",
|
|
6617
|
+
add: "Добавить",
|
|
6618
|
+
refreshTooltip: "Обновить",
|
|
6619
|
+
empty: "Приложения не найдены",
|
|
6620
|
+
table: {
|
|
6621
|
+
code: "Код",
|
|
6622
|
+
displayName: "Название",
|
|
6623
|
+
baseUrl: "Base URL",
|
|
6624
|
+
internalBaseUrl: "Internal Base URL",
|
|
6625
|
+
icon: "Иконка",
|
|
6626
|
+
order: "Порядок",
|
|
6627
|
+
enabled: "Включено",
|
|
6628
|
+
serviceType: "Тип сервиса",
|
|
6629
|
+
current: "Текущее",
|
|
6630
|
+
actions: "Действия",
|
|
6631
|
+
yes: "Да",
|
|
6632
|
+
no: "Нет",
|
|
6633
|
+
editTooltip: "Редактировать",
|
|
6634
|
+
deleteTooltip: "Удалить",
|
|
6635
|
+
saveTooltip: "Сохранить",
|
|
6636
|
+
cancelTooltip: "Отменить"
|
|
6637
|
+
},
|
|
6638
|
+
serviceTypes: {
|
|
6639
|
+
service: "Сервис",
|
|
6640
|
+
application: "Приложение"
|
|
6641
|
+
},
|
|
6642
|
+
confirm: {
|
|
6643
|
+
header: "Внимание",
|
|
6644
|
+
message: "Вы уверены, что хотите удалить приложение {{displayName}}?",
|
|
6645
|
+
cancel: "Отмена",
|
|
6646
|
+
"delete": "Удалить"
|
|
6647
|
+
},
|
|
6648
|
+
messages: {
|
|
6649
|
+
requiredFields: "Заполните код, название и Base URL",
|
|
6650
|
+
createSuccess: "Приложение создано",
|
|
6651
|
+
updateSuccess: "Приложение обновлено",
|
|
6652
|
+
deleteSuccess: "Приложение удалено"
|
|
6653
|
+
}
|
|
6654
|
+
};
|
|
6655
|
+
var ru$1 = {
|
|
6656
|
+
applications: applications
|
|
6657
|
+
};
|
|
6658
|
+
|
|
6659
|
+
L10nService.registerTranslations({ en: en$1, ru: ru$1 });
|
|
5446
6660
|
class ApplicationsComponent {
|
|
5447
6661
|
get serviceTypeOptions() {
|
|
5448
6662
|
return [
|
|
@@ -5649,9 +6863,7 @@ class ApplicationsComponent {
|
|
|
5649
6863
|
this.visibleApplications = this.filterApplications(this.globalFilter);
|
|
5650
6864
|
}
|
|
5651
6865
|
filterApplications(filter) {
|
|
5652
|
-
const source = this.draftApplication
|
|
5653
|
-
? [this.draftApplication, ...this.applications]
|
|
5654
|
-
: [...this.applications];
|
|
6866
|
+
const source = this.draftApplication ? [this.draftApplication, ...this.applications] : [...this.applications];
|
|
5655
6867
|
const normalizedFilter = filter.trim().toLocaleLowerCase();
|
|
5656
6868
|
if (!normalizedFilter) {
|
|
5657
6869
|
return source;
|
|
@@ -5750,7 +6962,7 @@ class ApplicationsComponent {
|
|
|
5750
6962
|
{{ 'applications.table.icon' | translate }}
|
|
5751
6963
|
<p-sortIcon field="icon"></p-sortIcon>
|
|
5752
6964
|
</th>
|
|
5753
|
-
<th
|
|
6965
|
+
<th class="text-right" pSortableColumn="order">
|
|
5754
6966
|
{{ 'applications.table.order' | translate }}
|
|
5755
6967
|
<p-sortIcon field="order"></p-sortIcon>
|
|
5756
6968
|
</th>
|
|
@@ -5823,16 +7035,16 @@ class ApplicationsComponent {
|
|
|
5823
7035
|
[severity]="application.enabled ? 'success' : 'danger'"
|
|
5824
7036
|
[value]="
|
|
5825
7037
|
(application.enabled ? 'applications.table.yes' : 'applications.table.no') | translate
|
|
5826
|
-
|
|
7038
|
+
"></p-tag>
|
|
5827
7039
|
}
|
|
5828
7040
|
</td>
|
|
5829
7041
|
<td>
|
|
5830
7042
|
@if (application._isEditing && application._editModel; as editModel) {
|
|
5831
7043
|
<p-select
|
|
7044
|
+
appendTo="body"
|
|
5832
7045
|
class="w-full min-w-36"
|
|
5833
7046
|
optionLabel="label"
|
|
5834
7047
|
optionValue="value"
|
|
5835
|
-
appendTo="body"
|
|
5836
7048
|
[options]="serviceTypeOptions"
|
|
5837
7049
|
[(ngModel)]="editModel.serviceType"></p-select>
|
|
5838
7050
|
} @else {
|
|
@@ -5853,33 +7065,33 @@ class ApplicationsComponent {
|
|
|
5853
7065
|
icon="pi pi-check"
|
|
5854
7066
|
severity="success"
|
|
5855
7067
|
text="true"
|
|
7068
|
+
tooltipPosition="bottom"
|
|
5856
7069
|
[disabled]="activeRowAction"
|
|
5857
7070
|
[pTooltip]="'applications.table.saveTooltip' | translate"
|
|
5858
|
-
tooltipPosition="bottom"
|
|
5859
7071
|
(onClick)="saveApplication(application)"></p-button>
|
|
5860
7072
|
<p-button
|
|
5861
7073
|
icon="pi pi-times"
|
|
5862
7074
|
severity="secondary"
|
|
5863
7075
|
text="true"
|
|
7076
|
+
tooltipPosition="bottom"
|
|
5864
7077
|
[disabled]="activeRowAction"
|
|
5865
7078
|
[pTooltip]="'applications.table.cancelTooltip' | translate"
|
|
5866
|
-
tooltipPosition="bottom"
|
|
5867
7079
|
(onClick)="cancelEdit(application)"></p-button>
|
|
5868
7080
|
} @else {
|
|
5869
7081
|
<p-button
|
|
5870
7082
|
icon="pi pi-pencil"
|
|
5871
7083
|
text="true"
|
|
7084
|
+
tooltipPosition="bottom"
|
|
5872
7085
|
[disabled]="activeRowAction"
|
|
5873
7086
|
[pTooltip]="'applications.table.editTooltip' | translate"
|
|
5874
|
-
tooltipPosition="bottom"
|
|
5875
7087
|
(onClick)="editApplication(application)"></p-button>
|
|
5876
7088
|
<p-button
|
|
5877
7089
|
icon="pi pi-trash"
|
|
5878
7090
|
severity="danger"
|
|
5879
7091
|
text="true"
|
|
7092
|
+
tooltipPosition="bottom"
|
|
5880
7093
|
[disabled]="activeRowAction"
|
|
5881
7094
|
[pTooltip]="'applications.table.deleteTooltip' | translate"
|
|
5882
|
-
tooltipPosition="bottom"
|
|
5883
7095
|
(onClick)="deleteApplication(application)"></p-button>
|
|
5884
7096
|
}
|
|
5885
7097
|
</div>
|
|
@@ -5889,7 +7101,7 @@ class ApplicationsComponent {
|
|
|
5889
7101
|
|
|
5890
7102
|
<ng-template pTemplate="emptymessage">
|
|
5891
7103
|
<tr>
|
|
5892
|
-
<td
|
|
7104
|
+
<td class="py-8 text-center text-surface-500" colspan="10">
|
|
5893
7105
|
{{ 'applications.empty' | translate }}
|
|
5894
7106
|
</td>
|
|
5895
7107
|
</tr>
|
|
@@ -5897,7 +7109,7 @@ class ApplicationsComponent {
|
|
|
5897
7109
|
</p-table>
|
|
5898
7110
|
</div>
|
|
5899
7111
|
</div>
|
|
5900
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$8.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$
|
|
7112
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$8.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$8.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i1$8.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i5$1.Toolbar, selector: "p-toolbar", inputs: ["styleClass", "ariaLabelledBy"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i2$5.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
5901
7113
|
}
|
|
5902
7114
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ApplicationsComponent, decorators: [{
|
|
5903
7115
|
type: Component,
|
|
@@ -6000,7 +7212,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
6000
7212
|
{{ 'applications.table.icon' | translate }}
|
|
6001
7213
|
<p-sortIcon field="icon"></p-sortIcon>
|
|
6002
7214
|
</th>
|
|
6003
|
-
<th
|
|
7215
|
+
<th class="text-right" pSortableColumn="order">
|
|
6004
7216
|
{{ 'applications.table.order' | translate }}
|
|
6005
7217
|
<p-sortIcon field="order"></p-sortIcon>
|
|
6006
7218
|
</th>
|
|
@@ -6073,16 +7285,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
6073
7285
|
[severity]="application.enabled ? 'success' : 'danger'"
|
|
6074
7286
|
[value]="
|
|
6075
7287
|
(application.enabled ? 'applications.table.yes' : 'applications.table.no') | translate
|
|
6076
|
-
|
|
7288
|
+
"></p-tag>
|
|
6077
7289
|
}
|
|
6078
7290
|
</td>
|
|
6079
7291
|
<td>
|
|
6080
7292
|
@if (application._isEditing && application._editModel; as editModel) {
|
|
6081
7293
|
<p-select
|
|
7294
|
+
appendTo="body"
|
|
6082
7295
|
class="w-full min-w-36"
|
|
6083
7296
|
optionLabel="label"
|
|
6084
7297
|
optionValue="value"
|
|
6085
|
-
appendTo="body"
|
|
6086
7298
|
[options]="serviceTypeOptions"
|
|
6087
7299
|
[(ngModel)]="editModel.serviceType"></p-select>
|
|
6088
7300
|
} @else {
|
|
@@ -6103,33 +7315,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
6103
7315
|
icon="pi pi-check"
|
|
6104
7316
|
severity="success"
|
|
6105
7317
|
text="true"
|
|
7318
|
+
tooltipPosition="bottom"
|
|
6106
7319
|
[disabled]="activeRowAction"
|
|
6107
7320
|
[pTooltip]="'applications.table.saveTooltip' | translate"
|
|
6108
|
-
tooltipPosition="bottom"
|
|
6109
7321
|
(onClick)="saveApplication(application)"></p-button>
|
|
6110
7322
|
<p-button
|
|
6111
7323
|
icon="pi pi-times"
|
|
6112
7324
|
severity="secondary"
|
|
6113
7325
|
text="true"
|
|
7326
|
+
tooltipPosition="bottom"
|
|
6114
7327
|
[disabled]="activeRowAction"
|
|
6115
7328
|
[pTooltip]="'applications.table.cancelTooltip' | translate"
|
|
6116
|
-
tooltipPosition="bottom"
|
|
6117
7329
|
(onClick)="cancelEdit(application)"></p-button>
|
|
6118
7330
|
} @else {
|
|
6119
7331
|
<p-button
|
|
6120
7332
|
icon="pi pi-pencil"
|
|
6121
7333
|
text="true"
|
|
7334
|
+
tooltipPosition="bottom"
|
|
6122
7335
|
[disabled]="activeRowAction"
|
|
6123
7336
|
[pTooltip]="'applications.table.editTooltip' | translate"
|
|
6124
|
-
tooltipPosition="bottom"
|
|
6125
7337
|
(onClick)="editApplication(application)"></p-button>
|
|
6126
7338
|
<p-button
|
|
6127
7339
|
icon="pi pi-trash"
|
|
6128
7340
|
severity="danger"
|
|
6129
7341
|
text="true"
|
|
7342
|
+
tooltipPosition="bottom"
|
|
6130
7343
|
[disabled]="activeRowAction"
|
|
6131
7344
|
[pTooltip]="'applications.table.deleteTooltip' | translate"
|
|
6132
|
-
tooltipPosition="bottom"
|
|
6133
7345
|
(onClick)="deleteApplication(application)"></p-button>
|
|
6134
7346
|
}
|
|
6135
7347
|
</div>
|
|
@@ -6139,7 +7351,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
6139
7351
|
|
|
6140
7352
|
<ng-template pTemplate="emptymessage">
|
|
6141
7353
|
<tr>
|
|
6142
|
-
<td
|
|
7354
|
+
<td class="py-8 text-center text-surface-500" colspan="10">
|
|
6143
7355
|
{{ 'applications.empty' | translate }}
|
|
6144
7356
|
</td>
|
|
6145
7357
|
</tr>
|
|
@@ -6468,7 +7680,9 @@ class DiscussionComponent {
|
|
|
6468
7680
|
deleteAttachment(comment, attachment) {
|
|
6469
7681
|
this.confirmationService.confirm({
|
|
6470
7682
|
header: this.translateService.instant('discussionComponent.warning'),
|
|
6471
|
-
message: this.translateService.instant('discussionComponent.confirmDeleteFile', {
|
|
7683
|
+
message: this.translateService.instant('discussionComponent.confirmDeleteFile', {
|
|
7684
|
+
fileName: attachment.fileName
|
|
7685
|
+
}),
|
|
6472
7686
|
icon: 'pi pi-trash',
|
|
6473
7687
|
rejectButtonProps: {
|
|
6474
7688
|
label: this.translateService.instant('discussionComponent.cancel'),
|
|
@@ -6671,27 +7885,24 @@ class DiscussionComponent {
|
|
|
6671
7885
|
}
|
|
6672
7886
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DiscussionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6673
7887
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: DiscussionComponent, isStandalone: true, selector: "discussion", inputs: { objectTypeId: "objectTypeId", objectId: "objectId" }, providers: [ConfirmationService, DiscussionApi], usesOnChanges: true, ngImport: i0, template: `
|
|
6674
|
-
<p-confirmDialog/>
|
|
7888
|
+
<p-confirmDialog />
|
|
6675
7889
|
|
|
6676
7890
|
<section class="flex flex-col gap-4">
|
|
6677
|
-
|
|
6678
7891
|
<p-card class="block">
|
|
6679
7892
|
<div class="flex flex-col gap-4">
|
|
6680
7893
|
@if (!previewMode) {
|
|
6681
7894
|
<textarea
|
|
6682
|
-
pTextarea
|
|
6683
7895
|
class="min-h-28 w-full"
|
|
6684
|
-
|
|
7896
|
+
pTextarea
|
|
6685
7897
|
rows="5"
|
|
6686
|
-
[
|
|
6687
|
-
(ngModelChange)="onComposerInput()"
|
|
7898
|
+
[autoResize]="true"
|
|
6688
7899
|
[placeholder]="'discussionComponent.writeCommentPlaceholder' | translate"
|
|
6689
|
-
|
|
7900
|
+
[(ngModel)]="newComment"
|
|
7901
|
+
(ngModelChange)="onComposerInput()"></textarea>
|
|
6690
7902
|
} @else {
|
|
6691
7903
|
<div
|
|
6692
7904
|
class="markdown-preview min-h-28 rounded-2xl border border-surface-200 bg-surface-50 px-4 py-3 leading-7 dark:border-surface-700 dark:bg-surface-900/40"
|
|
6693
|
-
[innerHTML]="renderMarkdown(newComment)"
|
|
6694
|
-
></div>
|
|
7905
|
+
[innerHTML]="renderMarkdown(newComment)"></div>
|
|
6695
7906
|
}
|
|
6696
7907
|
|
|
6697
7908
|
@if (mentionSuggestions.length > 0) {
|
|
@@ -6706,10 +7917,9 @@ class DiscussionComponent {
|
|
|
6706
7917
|
<div class="flex flex-col gap-3">
|
|
6707
7918
|
@for (candidate of mentionSuggestions; track candidate.userId) {
|
|
6708
7919
|
<button
|
|
6709
|
-
type="button"
|
|
6710
7920
|
class="flex w-full items-center justify-between gap-4 rounded-xl border border-transparent px-3 py-3 text-left transition hover:border-primary-200 hover:bg-primary-50 dark:hover:border-primary-800 dark:hover:bg-primary-950/30"
|
|
6711
|
-
|
|
6712
|
-
|
|
7921
|
+
type="button"
|
|
7922
|
+
(click)="insertMention(candidate)">
|
|
6713
7923
|
<div class="min-w-0">
|
|
6714
7924
|
<strong>{{ candidate.displayName }}</strong>
|
|
6715
7925
|
<small class="mt-1 block text-surface-500">{{ candidate.email }}</small>
|
|
@@ -6729,15 +7939,14 @@ class DiscussionComponent {
|
|
|
6729
7939
|
<div class="inline-flex items-center gap-2">
|
|
6730
7940
|
<i class="pi pi-file"></i>
|
|
6731
7941
|
<span class="break-all">{{ file.name }}</span>
|
|
6732
|
-
<p-tag [value]="formatBytes(file.size)"
|
|
7942
|
+
<p-tag severity="contrast" [value]="formatBytes(file.size)" />
|
|
6733
7943
|
</div>
|
|
6734
7944
|
<p-button
|
|
6735
7945
|
icon="pi pi-times"
|
|
6736
7946
|
severity="danger"
|
|
6737
7947
|
[rounded]="true"
|
|
6738
7948
|
[text]="true"
|
|
6739
|
-
(onClick)="removePendingFile(file)"
|
|
6740
|
-
/>
|
|
7949
|
+
(onClick)="removePendingFile(file)" />
|
|
6741
7950
|
</div>
|
|
6742
7951
|
}
|
|
6743
7952
|
</div>
|
|
@@ -6745,33 +7954,28 @@ class DiscussionComponent {
|
|
|
6745
7954
|
|
|
6746
7955
|
<div class="flex flex-col gap-2 sm:flex-row sm:justify-end">
|
|
6747
7956
|
<p-button
|
|
7957
|
+
severity="secondary"
|
|
7958
|
+
[icon]="previewMode ? 'pi pi-pencil' : 'pi pi-eye'"
|
|
6748
7959
|
[label]="
|
|
6749
|
-
previewMode
|
|
6750
|
-
? ('discussionComponent.edit' | translate)
|
|
6751
|
-
: ('discussionComponent.preview' | translate)
|
|
7960
|
+
previewMode ? ('discussionComponent.edit' | translate) : ('discussionComponent.preview' | translate)
|
|
6752
7961
|
"
|
|
6753
|
-
[icon]="previewMode ? 'pi pi-pencil' : 'pi pi-eye'"
|
|
6754
|
-
severity="secondary"
|
|
6755
7962
|
[text]="true"
|
|
6756
|
-
(onClick)="previewMode = !previewMode"
|
|
6757
|
-
/>
|
|
7963
|
+
(onClick)="previewMode = !previewMode" />
|
|
6758
7964
|
|
|
6759
7965
|
<label class="file-trigger">
|
|
6760
7966
|
<p-button
|
|
6761
|
-
[label]="'discussionComponent.attachFiles' | translate"
|
|
6762
7967
|
icon="pi pi-paperclip"
|
|
6763
7968
|
severity="secondary"
|
|
6764
|
-
[
|
|
6765
|
-
|
|
6766
|
-
<input type="file"
|
|
7969
|
+
[label]="'discussionComponent.attachFiles' | translate"
|
|
7970
|
+
[text]="true" />
|
|
7971
|
+
<input multiple type="file" (change)="onFilesSelected($event)" />
|
|
6767
7972
|
</label>
|
|
6768
7973
|
<p-button
|
|
6769
|
-
[label]="'discussionComponent.send' | translate"
|
|
6770
7974
|
icon="pi pi-send"
|
|
6771
|
-
[loading]="submitting"
|
|
6772
7975
|
[disabled]="submitting || !newComment.trim()"
|
|
6773
|
-
|
|
6774
|
-
|
|
7976
|
+
[label]="'discussionComponent.send' | translate"
|
|
7977
|
+
[loading]="submitting"
|
|
7978
|
+
(onClick)="createComment()" />
|
|
6775
7979
|
</div>
|
|
6776
7980
|
</div>
|
|
6777
7981
|
</p-card>
|
|
@@ -6779,7 +7983,7 @@ class DiscussionComponent {
|
|
|
6779
7983
|
@if (loading) {
|
|
6780
7984
|
<div
|
|
6781
7985
|
class="flex min-h-20 flex-col items-center justify-center gap-3 rounded-2xl border border-surface-200 px-4 py-5 text-surface-500 dark:border-surface-700">
|
|
6782
|
-
<p-progressSpinner strokeWidth="4"/>
|
|
7986
|
+
<p-progressSpinner strokeWidth="4" />
|
|
6783
7987
|
<span>{{ 'discussionComponent.loadingComments' | translate }}</span>
|
|
6784
7988
|
</div>
|
|
6785
7989
|
} @else if (comments.length === 0) {
|
|
@@ -6795,24 +7999,25 @@ class DiscussionComponent {
|
|
|
6795
7999
|
<ng-template pTemplate="content">
|
|
6796
8000
|
<div class="grid gap-4 md:grid-cols-[3.2rem_minmax(0,1fr)]">
|
|
6797
8001
|
<div>
|
|
6798
|
-
<p-avatar
|
|
6799
|
-
[label]="getInitialsFromString(comment.authorDisplayName)"
|
|
6800
|
-
shape="circle"
|
|
6801
|
-
/>
|
|
8002
|
+
<p-avatar shape="circle" [label]="getInitialsFromString(comment.authorDisplayName)" />
|
|
6802
8003
|
</div>
|
|
6803
8004
|
|
|
6804
8005
|
<div class="flex flex-col gap-2">
|
|
6805
8006
|
<div class="flex flex-row gap-3 justify-between">
|
|
6806
8007
|
<div class="flex flex-wrap items-center gap-2">
|
|
6807
8008
|
<strong>{{ comment.authorDisplayName }}</strong>
|
|
6808
|
-
<span
|
|
6809
|
-
|
|
8009
|
+
<span class="text-sm text-surface-500">{{
|
|
8010
|
+
comment.createdAt | date: layoutService.dateTimeFormat()
|
|
8011
|
+
}}</span>
|
|
6810
8012
|
</div>
|
|
6811
8013
|
|
|
6812
8014
|
<div class="flex flex-wrap items-center justify-end gap-2">
|
|
6813
8015
|
<div class="flex flex-wrap items-center">
|
|
6814
8016
|
@if (comment.isEdited) {
|
|
6815
|
-
<p-tag
|
|
8017
|
+
<p-tag
|
|
8018
|
+
icon="pi pi-pencil"
|
|
8019
|
+
severity="warn"
|
|
8020
|
+
[value]="'discussionComponent.edited' | translate" />
|
|
6816
8021
|
}
|
|
6817
8022
|
</div>
|
|
6818
8023
|
@if (comment.canEdit) {
|
|
@@ -6821,8 +8026,7 @@ class DiscussionComponent {
|
|
|
6821
8026
|
severity="secondary"
|
|
6822
8027
|
[rounded]="true"
|
|
6823
8028
|
[text]="true"
|
|
6824
|
-
(onClick)="startEdit(comment)"
|
|
6825
|
-
/>
|
|
8029
|
+
(onClick)="startEdit(comment)" />
|
|
6826
8030
|
}
|
|
6827
8031
|
@if (comment.historyCount > 0) {
|
|
6828
8032
|
<p-button
|
|
@@ -6830,8 +8034,7 @@ class DiscussionComponent {
|
|
|
6830
8034
|
severity="secondary"
|
|
6831
8035
|
[rounded]="true"
|
|
6832
8036
|
[text]="true"
|
|
6833
|
-
(onClick)="toggleHistory(comment)"
|
|
6834
|
-
/>
|
|
8037
|
+
(onClick)="toggleHistory(comment)" />
|
|
6835
8038
|
}
|
|
6836
8039
|
@if (comment.canDelete) {
|
|
6837
8040
|
<p-button
|
|
@@ -6839,47 +8042,42 @@ class DiscussionComponent {
|
|
|
6839
8042
|
severity="danger"
|
|
6840
8043
|
[rounded]="true"
|
|
6841
8044
|
[text]="true"
|
|
6842
|
-
(onClick)="deleteComment(comment)"
|
|
6843
|
-
/>
|
|
8045
|
+
(onClick)="deleteComment(comment)" />
|
|
6844
8046
|
}
|
|
6845
8047
|
</div>
|
|
6846
8048
|
</div>
|
|
6847
8049
|
@if (editingCommentId === comment.commentId) {
|
|
6848
8050
|
<div class="flex flex-col gap-4">
|
|
6849
8051
|
<textarea
|
|
6850
|
-
pTextarea
|
|
6851
8052
|
class="min-h-24 w-full"
|
|
6852
|
-
|
|
8053
|
+
pTextarea
|
|
6853
8054
|
rows="4"
|
|
6854
|
-
[
|
|
8055
|
+
[autoResize]="true"
|
|
6855
8056
|
[placeholder]="'discussionComponent.editCommentPlaceholder' | translate"
|
|
6856
|
-
|
|
8057
|
+
[(ngModel)]="editContent"></textarea>
|
|
6857
8058
|
<div class="flex flex-col gap-2 sm:flex-row sm:justify-end">
|
|
6858
8059
|
<div>
|
|
6859
8060
|
<label class="file-trigger">
|
|
6860
8061
|
<p-button
|
|
6861
|
-
[label]="'discussionComponent.addAttachment' | translate"
|
|
6862
8062
|
icon="pi pi-paperclip"
|
|
6863
|
-
[text]="true"
|
|
6864
8063
|
severity="secondary"
|
|
6865
|
-
|
|
6866
|
-
|
|
8064
|
+
[label]="'discussionComponent.addAttachment' | translate"
|
|
8065
|
+
[text]="true" />
|
|
8066
|
+
<input multiple type="file" (change)="onInlineFilesSelected(comment, $event)" />
|
|
6867
8067
|
</label>
|
|
6868
8068
|
</div>
|
|
6869
8069
|
|
|
6870
8070
|
<p-button
|
|
6871
|
-
[label]="'discussionComponent.save' | translate"
|
|
6872
8071
|
icon="pi pi-check"
|
|
6873
8072
|
[disabled]="!editContent.trim()"
|
|
6874
|
-
|
|
6875
|
-
|
|
8073
|
+
[label]="'discussionComponent.save' | translate"
|
|
8074
|
+
(onClick)="saveEdit(comment)" />
|
|
6876
8075
|
<p-button
|
|
6877
|
-
[label]="'discussionComponent.cancel' | translate"
|
|
6878
8076
|
icon="pi pi-times"
|
|
6879
8077
|
severity="secondary"
|
|
8078
|
+
[label]="'discussionComponent.cancel' | translate"
|
|
6880
8079
|
[text]="true"
|
|
6881
|
-
(onClick)="cancelEdit()"
|
|
6882
|
-
/>
|
|
8080
|
+
(onClick)="cancelEdit()" />
|
|
6883
8081
|
</div>
|
|
6884
8082
|
</div>
|
|
6885
8083
|
} @else {
|
|
@@ -6894,13 +8092,12 @@ class DiscussionComponent {
|
|
|
6894
8092
|
<div class="inline-flex items-center gap-2">
|
|
6895
8093
|
<i class="pi pi-file"></i>
|
|
6896
8094
|
<button
|
|
6897
|
-
type="button"
|
|
6898
8095
|
class="break-all bg-transparent p-0 text-left font-semibold text-primary-600 transition hover:text-primary-500"
|
|
6899
|
-
|
|
6900
|
-
|
|
8096
|
+
type="button"
|
|
8097
|
+
(click)="downloadAttachment(attachment)">
|
|
6901
8098
|
{{ attachment.fileName }}
|
|
6902
8099
|
</button>
|
|
6903
|
-
<p-tag [value]="formatBytes(attachment.fileSize)"
|
|
8100
|
+
<p-tag severity="contrast" [value]="formatBytes(attachment.fileSize)" />
|
|
6904
8101
|
</div>
|
|
6905
8102
|
|
|
6906
8103
|
@if (comment.canEdit) {
|
|
@@ -6909,8 +8106,7 @@ class DiscussionComponent {
|
|
|
6909
8106
|
severity="danger"
|
|
6910
8107
|
[rounded]="true"
|
|
6911
8108
|
[text]="true"
|
|
6912
|
-
(onClick)="deleteAttachment(comment, attachment)"
|
|
6913
|
-
/>
|
|
8109
|
+
(onClick)="deleteAttachment(comment, attachment)" />
|
|
6914
8110
|
}
|
|
6915
8111
|
</div>
|
|
6916
8112
|
}
|
|
@@ -6921,11 +8117,10 @@ class DiscussionComponent {
|
|
|
6921
8117
|
<div class="flex flex-wrap items-center gap-2">
|
|
6922
8118
|
@for (reaction of getReactions(comment); track reaction.emojiCode) {
|
|
6923
8119
|
<p-button
|
|
6924
|
-
[label]="reaction.emojiCode + ' ' + reaction.count"
|
|
6925
8120
|
severity="secondary"
|
|
8121
|
+
[label]="reaction.emojiCode + ' ' + reaction.count"
|
|
6926
8122
|
[outlined]="false"
|
|
6927
|
-
(onClick)="toggleReaction(comment, reaction)"
|
|
6928
|
-
/>
|
|
8123
|
+
(onClick)="toggleReaction(comment, reaction)" />
|
|
6929
8124
|
}
|
|
6930
8125
|
|
|
6931
8126
|
@if (!hasUserReaction(comment)) {
|
|
@@ -6934,16 +8129,14 @@ class DiscussionComponent {
|
|
|
6934
8129
|
severity="secondary"
|
|
6935
8130
|
[rounded]="true"
|
|
6936
8131
|
[text]="true"
|
|
6937
|
-
(onClick)="reactionPopover.toggle($event)"
|
|
6938
|
-
/>
|
|
8132
|
+
(onClick)="reactionPopover.toggle($event)" />
|
|
6939
8133
|
<p-popover #reactionPopover>
|
|
6940
8134
|
<div class="emoji-popover">
|
|
6941
8135
|
@for (emoji of emojiPalette; track emoji) {
|
|
6942
8136
|
<button
|
|
6943
|
-
type="button"
|
|
6944
8137
|
class="emoji-option"
|
|
6945
|
-
|
|
6946
|
-
|
|
8138
|
+
type="button"
|
|
8139
|
+
(click)="reactWithEmoji(comment, emoji, reactionPopover)">
|
|
6947
8140
|
{{ emoji }}
|
|
6948
8141
|
</button>
|
|
6949
8142
|
}
|
|
@@ -6953,7 +8146,7 @@ class DiscussionComponent {
|
|
|
6953
8146
|
</div>
|
|
6954
8147
|
|
|
6955
8148
|
@if (historyByComment[comment.commentId]?.opened) {
|
|
6956
|
-
<p-panel class="block" [
|
|
8149
|
+
<p-panel class="block" [collapsed]="false" [toggleable]="true">
|
|
6957
8150
|
<ng-template pTemplate="header">
|
|
6958
8151
|
<div class="inline-flex items-center gap-2 text-sm font-medium">
|
|
6959
8152
|
<i class="pi pi-history"></i>
|
|
@@ -6963,12 +8156,15 @@ class DiscussionComponent {
|
|
|
6963
8156
|
|
|
6964
8157
|
@if (historyByComment[comment.commentId]?.loading) {
|
|
6965
8158
|
<div class="flex items-center gap-3 text-surface-500">
|
|
6966
|
-
<p-progressSpinner strokeWidth="4"/>
|
|
8159
|
+
<p-progressSpinner strokeWidth="4" />
|
|
6967
8160
|
<span>{{ 'discussionComponent.loadingHistory' | translate }}</span>
|
|
6968
8161
|
</div>
|
|
6969
8162
|
} @else {
|
|
6970
8163
|
<div class="flex flex-col gap-4">
|
|
6971
|
-
@for (
|
|
8164
|
+
@for (
|
|
8165
|
+
item of historyByComment[comment.commentId]?.items ?? [];
|
|
8166
|
+
track item.commentEditHistoryId
|
|
8167
|
+
) {
|
|
6972
8168
|
<div class="rounded-2xl border border-surface-200 px-4 py-4 dark:border-surface-700">
|
|
6973
8169
|
<div class="mb-3 inline-flex items-center gap-2 text-sm font-semibold">
|
|
6974
8170
|
<i class="pi pi-clock"></i>
|
|
@@ -6976,18 +8172,16 @@ class DiscussionComponent {
|
|
|
6976
8172
|
</div>
|
|
6977
8173
|
<div class="grid gap-4 lg:grid-cols-2">
|
|
6978
8174
|
<div class="flex flex-col gap-2">
|
|
6979
|
-
<p-tag [value]="'discussionComponent.before' | translate"
|
|
8175
|
+
<p-tag severity="secondary" [value]="'discussionComponent.before' | translate" />
|
|
6980
8176
|
<div
|
|
6981
8177
|
class="history-markdown rounded-2xl bg-surface-50 px-4 py-3 leading-7 dark:bg-surface-900/40"
|
|
6982
|
-
[innerHTML]="renderMarkdown(item.oldContent)"
|
|
6983
|
-
></div>
|
|
8178
|
+
[innerHTML]="renderMarkdown(item.oldContent)"></div>
|
|
6984
8179
|
</div>
|
|
6985
8180
|
<div class="flex flex-col gap-2">
|
|
6986
|
-
<p-tag [value]="'discussionComponent.after' | translate"
|
|
8181
|
+
<p-tag severity="success" [value]="'discussionComponent.after' | translate" />
|
|
6987
8182
|
<div
|
|
6988
8183
|
class="history-markdown rounded-2xl bg-surface-50 px-4 py-3 leading-7 dark:bg-surface-900/40"
|
|
6989
|
-
[innerHTML]="renderMarkdown(item.newContent)"
|
|
6990
|
-
></div>
|
|
8184
|
+
[innerHTML]="renderMarkdown(item.newContent)"></div>
|
|
6991
8185
|
</div>
|
|
6992
8186
|
</div>
|
|
6993
8187
|
</div>
|
|
@@ -7004,7 +8198,7 @@ class DiscussionComponent {
|
|
|
7004
8198
|
</div>
|
|
7005
8199
|
}
|
|
7006
8200
|
</section>
|
|
7007
|
-
`, isInline: true, styles: [":host{display:block}.file-trigger{position:relative;display:inline-flex}.file-trigger input{position:absolute;inset:0;opacity:0;cursor:pointer}.markdown-preview,.history-markdown{word-break:break-word}.markdown-preview :is(h1,h2,h3),.history-markdown :is(h1,h2,h3){margin:0 0 .75rem;font-weight:600}.markdown-preview a,.history-markdown a{color:#2563eb;text-decoration:underline;text-underline-offset:.18em}.emoji-popover{display:flex;flex-wrap:wrap;gap:.5rem;max-width:16rem}.emoji-option{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;font-size:1.25rem;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "directive", type: i2$
|
|
8201
|
+
`, isInline: true, styles: [":host{display:block}.file-trigger{position:relative;display:inline-flex}.file-trigger input{position:absolute;inset:0;opacity:0;cursor:pointer}.markdown-preview,.history-markdown{word-break:break-word}.markdown-preview :is(h1,h2,h3),.history-markdown :is(h1,h2,h3){margin:0 0 .75rem;font-weight:600}.markdown-preview a,.history-markdown a{color:#2563eb;text-decoration:underline;text-underline-offset:.18em}.emoji-popover{display:flex;flex-wrap:wrap;gap:.5rem;max-width:16rem}.emoji-option{display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;font-size:1.25rem;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i2$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i5$2.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: DividerModule }, { kind: "ngmodule", type: PanelModule }, { kind: "component", type: i6.Panel, selector: "p-panel", inputs: ["id", "toggleable", "header", "collapsed", "styleClass", "iconPos", "showHeader", "toggler", "transitionOptions", "toggleButtonProps"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i7.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i9.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "pipe", type: i1$3.DatePipe, name: "date" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7008
8202
|
}
|
|
7009
8203
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DiscussionComponent, decorators: [{
|
|
7010
8204
|
type: Component,
|
|
@@ -7024,27 +8218,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7024
8218
|
DatePipe,
|
|
7025
8219
|
TranslatePipe
|
|
7026
8220
|
], template: `
|
|
7027
|
-
<p-confirmDialog/>
|
|
8221
|
+
<p-confirmDialog />
|
|
7028
8222
|
|
|
7029
8223
|
<section class="flex flex-col gap-4">
|
|
7030
|
-
|
|
7031
8224
|
<p-card class="block">
|
|
7032
8225
|
<div class="flex flex-col gap-4">
|
|
7033
8226
|
@if (!previewMode) {
|
|
7034
8227
|
<textarea
|
|
7035
|
-
pTextarea
|
|
7036
8228
|
class="min-h-28 w-full"
|
|
7037
|
-
|
|
8229
|
+
pTextarea
|
|
7038
8230
|
rows="5"
|
|
7039
|
-
[
|
|
7040
|
-
(ngModelChange)="onComposerInput()"
|
|
8231
|
+
[autoResize]="true"
|
|
7041
8232
|
[placeholder]="'discussionComponent.writeCommentPlaceholder' | translate"
|
|
7042
|
-
|
|
8233
|
+
[(ngModel)]="newComment"
|
|
8234
|
+
(ngModelChange)="onComposerInput()"></textarea>
|
|
7043
8235
|
} @else {
|
|
7044
8236
|
<div
|
|
7045
8237
|
class="markdown-preview min-h-28 rounded-2xl border border-surface-200 bg-surface-50 px-4 py-3 leading-7 dark:border-surface-700 dark:bg-surface-900/40"
|
|
7046
|
-
[innerHTML]="renderMarkdown(newComment)"
|
|
7047
|
-
></div>
|
|
8238
|
+
[innerHTML]="renderMarkdown(newComment)"></div>
|
|
7048
8239
|
}
|
|
7049
8240
|
|
|
7050
8241
|
@if (mentionSuggestions.length > 0) {
|
|
@@ -7059,10 +8250,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7059
8250
|
<div class="flex flex-col gap-3">
|
|
7060
8251
|
@for (candidate of mentionSuggestions; track candidate.userId) {
|
|
7061
8252
|
<button
|
|
7062
|
-
type="button"
|
|
7063
8253
|
class="flex w-full items-center justify-between gap-4 rounded-xl border border-transparent px-3 py-3 text-left transition hover:border-primary-200 hover:bg-primary-50 dark:hover:border-primary-800 dark:hover:bg-primary-950/30"
|
|
7064
|
-
|
|
7065
|
-
|
|
8254
|
+
type="button"
|
|
8255
|
+
(click)="insertMention(candidate)">
|
|
7066
8256
|
<div class="min-w-0">
|
|
7067
8257
|
<strong>{{ candidate.displayName }}</strong>
|
|
7068
8258
|
<small class="mt-1 block text-surface-500">{{ candidate.email }}</small>
|
|
@@ -7082,15 +8272,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7082
8272
|
<div class="inline-flex items-center gap-2">
|
|
7083
8273
|
<i class="pi pi-file"></i>
|
|
7084
8274
|
<span class="break-all">{{ file.name }}</span>
|
|
7085
|
-
<p-tag [value]="formatBytes(file.size)"
|
|
8275
|
+
<p-tag severity="contrast" [value]="formatBytes(file.size)" />
|
|
7086
8276
|
</div>
|
|
7087
8277
|
<p-button
|
|
7088
8278
|
icon="pi pi-times"
|
|
7089
8279
|
severity="danger"
|
|
7090
8280
|
[rounded]="true"
|
|
7091
8281
|
[text]="true"
|
|
7092
|
-
(onClick)="removePendingFile(file)"
|
|
7093
|
-
/>
|
|
8282
|
+
(onClick)="removePendingFile(file)" />
|
|
7094
8283
|
</div>
|
|
7095
8284
|
}
|
|
7096
8285
|
</div>
|
|
@@ -7098,33 +8287,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7098
8287
|
|
|
7099
8288
|
<div class="flex flex-col gap-2 sm:flex-row sm:justify-end">
|
|
7100
8289
|
<p-button
|
|
8290
|
+
severity="secondary"
|
|
8291
|
+
[icon]="previewMode ? 'pi pi-pencil' : 'pi pi-eye'"
|
|
7101
8292
|
[label]="
|
|
7102
|
-
previewMode
|
|
7103
|
-
? ('discussionComponent.edit' | translate)
|
|
7104
|
-
: ('discussionComponent.preview' | translate)
|
|
8293
|
+
previewMode ? ('discussionComponent.edit' | translate) : ('discussionComponent.preview' | translate)
|
|
7105
8294
|
"
|
|
7106
|
-
[icon]="previewMode ? 'pi pi-pencil' : 'pi pi-eye'"
|
|
7107
|
-
severity="secondary"
|
|
7108
8295
|
[text]="true"
|
|
7109
|
-
(onClick)="previewMode = !previewMode"
|
|
7110
|
-
/>
|
|
8296
|
+
(onClick)="previewMode = !previewMode" />
|
|
7111
8297
|
|
|
7112
8298
|
<label class="file-trigger">
|
|
7113
8299
|
<p-button
|
|
7114
|
-
[label]="'discussionComponent.attachFiles' | translate"
|
|
7115
8300
|
icon="pi pi-paperclip"
|
|
7116
8301
|
severity="secondary"
|
|
7117
|
-
[
|
|
7118
|
-
|
|
7119
|
-
<input type="file"
|
|
8302
|
+
[label]="'discussionComponent.attachFiles' | translate"
|
|
8303
|
+
[text]="true" />
|
|
8304
|
+
<input multiple type="file" (change)="onFilesSelected($event)" />
|
|
7120
8305
|
</label>
|
|
7121
8306
|
<p-button
|
|
7122
|
-
[label]="'discussionComponent.send' | translate"
|
|
7123
8307
|
icon="pi pi-send"
|
|
7124
|
-
[loading]="submitting"
|
|
7125
8308
|
[disabled]="submitting || !newComment.trim()"
|
|
7126
|
-
|
|
7127
|
-
|
|
8309
|
+
[label]="'discussionComponent.send' | translate"
|
|
8310
|
+
[loading]="submitting"
|
|
8311
|
+
(onClick)="createComment()" />
|
|
7128
8312
|
</div>
|
|
7129
8313
|
</div>
|
|
7130
8314
|
</p-card>
|
|
@@ -7132,7 +8316,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7132
8316
|
@if (loading) {
|
|
7133
8317
|
<div
|
|
7134
8318
|
class="flex min-h-20 flex-col items-center justify-center gap-3 rounded-2xl border border-surface-200 px-4 py-5 text-surface-500 dark:border-surface-700">
|
|
7135
|
-
<p-progressSpinner strokeWidth="4"/>
|
|
8319
|
+
<p-progressSpinner strokeWidth="4" />
|
|
7136
8320
|
<span>{{ 'discussionComponent.loadingComments' | translate }}</span>
|
|
7137
8321
|
</div>
|
|
7138
8322
|
} @else if (comments.length === 0) {
|
|
@@ -7148,24 +8332,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7148
8332
|
<ng-template pTemplate="content">
|
|
7149
8333
|
<div class="grid gap-4 md:grid-cols-[3.2rem_minmax(0,1fr)]">
|
|
7150
8334
|
<div>
|
|
7151
|
-
<p-avatar
|
|
7152
|
-
[label]="getInitialsFromString(comment.authorDisplayName)"
|
|
7153
|
-
shape="circle"
|
|
7154
|
-
/>
|
|
8335
|
+
<p-avatar shape="circle" [label]="getInitialsFromString(comment.authorDisplayName)" />
|
|
7155
8336
|
</div>
|
|
7156
8337
|
|
|
7157
8338
|
<div class="flex flex-col gap-2">
|
|
7158
8339
|
<div class="flex flex-row gap-3 justify-between">
|
|
7159
8340
|
<div class="flex flex-wrap items-center gap-2">
|
|
7160
8341
|
<strong>{{ comment.authorDisplayName }}</strong>
|
|
7161
|
-
<span
|
|
7162
|
-
|
|
8342
|
+
<span class="text-sm text-surface-500">{{
|
|
8343
|
+
comment.createdAt | date: layoutService.dateTimeFormat()
|
|
8344
|
+
}}</span>
|
|
7163
8345
|
</div>
|
|
7164
8346
|
|
|
7165
8347
|
<div class="flex flex-wrap items-center justify-end gap-2">
|
|
7166
8348
|
<div class="flex flex-wrap items-center">
|
|
7167
8349
|
@if (comment.isEdited) {
|
|
7168
|
-
<p-tag
|
|
8350
|
+
<p-tag
|
|
8351
|
+
icon="pi pi-pencil"
|
|
8352
|
+
severity="warn"
|
|
8353
|
+
[value]="'discussionComponent.edited' | translate" />
|
|
7169
8354
|
}
|
|
7170
8355
|
</div>
|
|
7171
8356
|
@if (comment.canEdit) {
|
|
@@ -7174,8 +8359,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7174
8359
|
severity="secondary"
|
|
7175
8360
|
[rounded]="true"
|
|
7176
8361
|
[text]="true"
|
|
7177
|
-
(onClick)="startEdit(comment)"
|
|
7178
|
-
/>
|
|
8362
|
+
(onClick)="startEdit(comment)" />
|
|
7179
8363
|
}
|
|
7180
8364
|
@if (comment.historyCount > 0) {
|
|
7181
8365
|
<p-button
|
|
@@ -7183,8 +8367,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7183
8367
|
severity="secondary"
|
|
7184
8368
|
[rounded]="true"
|
|
7185
8369
|
[text]="true"
|
|
7186
|
-
(onClick)="toggleHistory(comment)"
|
|
7187
|
-
/>
|
|
8370
|
+
(onClick)="toggleHistory(comment)" />
|
|
7188
8371
|
}
|
|
7189
8372
|
@if (comment.canDelete) {
|
|
7190
8373
|
<p-button
|
|
@@ -7192,47 +8375,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7192
8375
|
severity="danger"
|
|
7193
8376
|
[rounded]="true"
|
|
7194
8377
|
[text]="true"
|
|
7195
|
-
(onClick)="deleteComment(comment)"
|
|
7196
|
-
/>
|
|
8378
|
+
(onClick)="deleteComment(comment)" />
|
|
7197
8379
|
}
|
|
7198
8380
|
</div>
|
|
7199
8381
|
</div>
|
|
7200
8382
|
@if (editingCommentId === comment.commentId) {
|
|
7201
8383
|
<div class="flex flex-col gap-4">
|
|
7202
8384
|
<textarea
|
|
7203
|
-
pTextarea
|
|
7204
8385
|
class="min-h-24 w-full"
|
|
7205
|
-
|
|
8386
|
+
pTextarea
|
|
7206
8387
|
rows="4"
|
|
7207
|
-
[
|
|
8388
|
+
[autoResize]="true"
|
|
7208
8389
|
[placeholder]="'discussionComponent.editCommentPlaceholder' | translate"
|
|
7209
|
-
|
|
8390
|
+
[(ngModel)]="editContent"></textarea>
|
|
7210
8391
|
<div class="flex flex-col gap-2 sm:flex-row sm:justify-end">
|
|
7211
8392
|
<div>
|
|
7212
8393
|
<label class="file-trigger">
|
|
7213
8394
|
<p-button
|
|
7214
|
-
[label]="'discussionComponent.addAttachment' | translate"
|
|
7215
8395
|
icon="pi pi-paperclip"
|
|
7216
|
-
[text]="true"
|
|
7217
8396
|
severity="secondary"
|
|
7218
|
-
|
|
7219
|
-
|
|
8397
|
+
[label]="'discussionComponent.addAttachment' | translate"
|
|
8398
|
+
[text]="true" />
|
|
8399
|
+
<input multiple type="file" (change)="onInlineFilesSelected(comment, $event)" />
|
|
7220
8400
|
</label>
|
|
7221
8401
|
</div>
|
|
7222
8402
|
|
|
7223
8403
|
<p-button
|
|
7224
|
-
[label]="'discussionComponent.save' | translate"
|
|
7225
8404
|
icon="pi pi-check"
|
|
7226
8405
|
[disabled]="!editContent.trim()"
|
|
7227
|
-
|
|
7228
|
-
|
|
8406
|
+
[label]="'discussionComponent.save' | translate"
|
|
8407
|
+
(onClick)="saveEdit(comment)" />
|
|
7229
8408
|
<p-button
|
|
7230
|
-
[label]="'discussionComponent.cancel' | translate"
|
|
7231
8409
|
icon="pi pi-times"
|
|
7232
8410
|
severity="secondary"
|
|
8411
|
+
[label]="'discussionComponent.cancel' | translate"
|
|
7233
8412
|
[text]="true"
|
|
7234
|
-
(onClick)="cancelEdit()"
|
|
7235
|
-
/>
|
|
8413
|
+
(onClick)="cancelEdit()" />
|
|
7236
8414
|
</div>
|
|
7237
8415
|
</div>
|
|
7238
8416
|
} @else {
|
|
@@ -7247,13 +8425,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7247
8425
|
<div class="inline-flex items-center gap-2">
|
|
7248
8426
|
<i class="pi pi-file"></i>
|
|
7249
8427
|
<button
|
|
7250
|
-
type="button"
|
|
7251
8428
|
class="break-all bg-transparent p-0 text-left font-semibold text-primary-600 transition hover:text-primary-500"
|
|
7252
|
-
|
|
7253
|
-
|
|
8429
|
+
type="button"
|
|
8430
|
+
(click)="downloadAttachment(attachment)">
|
|
7254
8431
|
{{ attachment.fileName }}
|
|
7255
8432
|
</button>
|
|
7256
|
-
<p-tag [value]="formatBytes(attachment.fileSize)"
|
|
8433
|
+
<p-tag severity="contrast" [value]="formatBytes(attachment.fileSize)" />
|
|
7257
8434
|
</div>
|
|
7258
8435
|
|
|
7259
8436
|
@if (comment.canEdit) {
|
|
@@ -7262,8 +8439,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7262
8439
|
severity="danger"
|
|
7263
8440
|
[rounded]="true"
|
|
7264
8441
|
[text]="true"
|
|
7265
|
-
(onClick)="deleteAttachment(comment, attachment)"
|
|
7266
|
-
/>
|
|
8442
|
+
(onClick)="deleteAttachment(comment, attachment)" />
|
|
7267
8443
|
}
|
|
7268
8444
|
</div>
|
|
7269
8445
|
}
|
|
@@ -7274,11 +8450,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7274
8450
|
<div class="flex flex-wrap items-center gap-2">
|
|
7275
8451
|
@for (reaction of getReactions(comment); track reaction.emojiCode) {
|
|
7276
8452
|
<p-button
|
|
7277
|
-
[label]="reaction.emojiCode + ' ' + reaction.count"
|
|
7278
8453
|
severity="secondary"
|
|
8454
|
+
[label]="reaction.emojiCode + ' ' + reaction.count"
|
|
7279
8455
|
[outlined]="false"
|
|
7280
|
-
(onClick)="toggleReaction(comment, reaction)"
|
|
7281
|
-
/>
|
|
8456
|
+
(onClick)="toggleReaction(comment, reaction)" />
|
|
7282
8457
|
}
|
|
7283
8458
|
|
|
7284
8459
|
@if (!hasUserReaction(comment)) {
|
|
@@ -7287,16 +8462,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7287
8462
|
severity="secondary"
|
|
7288
8463
|
[rounded]="true"
|
|
7289
8464
|
[text]="true"
|
|
7290
|
-
(onClick)="reactionPopover.toggle($event)"
|
|
7291
|
-
/>
|
|
8465
|
+
(onClick)="reactionPopover.toggle($event)" />
|
|
7292
8466
|
<p-popover #reactionPopover>
|
|
7293
8467
|
<div class="emoji-popover">
|
|
7294
8468
|
@for (emoji of emojiPalette; track emoji) {
|
|
7295
8469
|
<button
|
|
7296
|
-
type="button"
|
|
7297
8470
|
class="emoji-option"
|
|
7298
|
-
|
|
7299
|
-
|
|
8471
|
+
type="button"
|
|
8472
|
+
(click)="reactWithEmoji(comment, emoji, reactionPopover)">
|
|
7300
8473
|
{{ emoji }}
|
|
7301
8474
|
</button>
|
|
7302
8475
|
}
|
|
@@ -7306,7 +8479,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7306
8479
|
</div>
|
|
7307
8480
|
|
|
7308
8481
|
@if (historyByComment[comment.commentId]?.opened) {
|
|
7309
|
-
<p-panel class="block" [
|
|
8482
|
+
<p-panel class="block" [collapsed]="false" [toggleable]="true">
|
|
7310
8483
|
<ng-template pTemplate="header">
|
|
7311
8484
|
<div class="inline-flex items-center gap-2 text-sm font-medium">
|
|
7312
8485
|
<i class="pi pi-history"></i>
|
|
@@ -7316,12 +8489,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7316
8489
|
|
|
7317
8490
|
@if (historyByComment[comment.commentId]?.loading) {
|
|
7318
8491
|
<div class="flex items-center gap-3 text-surface-500">
|
|
7319
|
-
<p-progressSpinner strokeWidth="4"/>
|
|
8492
|
+
<p-progressSpinner strokeWidth="4" />
|
|
7320
8493
|
<span>{{ 'discussionComponent.loadingHistory' | translate }}</span>
|
|
7321
8494
|
</div>
|
|
7322
8495
|
} @else {
|
|
7323
8496
|
<div class="flex flex-col gap-4">
|
|
7324
|
-
@for (
|
|
8497
|
+
@for (
|
|
8498
|
+
item of historyByComment[comment.commentId]?.items ?? [];
|
|
8499
|
+
track item.commentEditHistoryId
|
|
8500
|
+
) {
|
|
7325
8501
|
<div class="rounded-2xl border border-surface-200 px-4 py-4 dark:border-surface-700">
|
|
7326
8502
|
<div class="mb-3 inline-flex items-center gap-2 text-sm font-semibold">
|
|
7327
8503
|
<i class="pi pi-clock"></i>
|
|
@@ -7329,18 +8505,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7329
8505
|
</div>
|
|
7330
8506
|
<div class="grid gap-4 lg:grid-cols-2">
|
|
7331
8507
|
<div class="flex flex-col gap-2">
|
|
7332
|
-
<p-tag [value]="'discussionComponent.before' | translate"
|
|
8508
|
+
<p-tag severity="secondary" [value]="'discussionComponent.before' | translate" />
|
|
7333
8509
|
<div
|
|
7334
8510
|
class="history-markdown rounded-2xl bg-surface-50 px-4 py-3 leading-7 dark:bg-surface-900/40"
|
|
7335
|
-
[innerHTML]="renderMarkdown(item.oldContent)"
|
|
7336
|
-
></div>
|
|
8511
|
+
[innerHTML]="renderMarkdown(item.oldContent)"></div>
|
|
7337
8512
|
</div>
|
|
7338
8513
|
<div class="flex flex-col gap-2">
|
|
7339
|
-
<p-tag [value]="'discussionComponent.after' | translate"
|
|
8514
|
+
<p-tag severity="success" [value]="'discussionComponent.after' | translate" />
|
|
7340
8515
|
<div
|
|
7341
8516
|
class="history-markdown rounded-2xl bg-surface-50 px-4 py-3 leading-7 dark:bg-surface-900/40"
|
|
7342
|
-
[innerHTML]="renderMarkdown(item.newContent)"
|
|
7343
|
-
></div>
|
|
8517
|
+
[innerHTML]="renderMarkdown(item.newContent)"></div>
|
|
7344
8518
|
</div>
|
|
7345
8519
|
</div>
|
|
7346
8520
|
</div>
|
|
@@ -7366,13 +8540,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7366
8540
|
args: [{ required: true }]
|
|
7367
8541
|
}] } });
|
|
7368
8542
|
|
|
8543
|
+
var en = {
|
|
8544
|
+
"iframe-module": {
|
|
8545
|
+
iframeModule: {
|
|
8546
|
+
urlPlaceholder: "Site URL",
|
|
8547
|
+
settingSaveButtonLabel: "Save",
|
|
8548
|
+
emptyUrlMessage: "Site URL is not specified.",
|
|
8549
|
+
siteLoadingMessage: "Failed to load the site."
|
|
8550
|
+
}
|
|
8551
|
+
}
|
|
8552
|
+
};
|
|
8553
|
+
|
|
8554
|
+
var ru = {
|
|
8555
|
+
"iframe-module": {
|
|
8556
|
+
iframeModule: {
|
|
8557
|
+
urlPlaceholder: "URL сайта",
|
|
8558
|
+
settingSaveButtonLabel: "Сохранить",
|
|
8559
|
+
emptyUrlMessage: "URL сайта не указан.",
|
|
8560
|
+
siteLoadingMessage: "Не удалось загрузить сайт."
|
|
8561
|
+
}
|
|
8562
|
+
}
|
|
8563
|
+
};
|
|
8564
|
+
|
|
7369
8565
|
class IframeModuleComponent extends BaseModuleComponent {
|
|
8566
|
+
static { this.translations = { en, ru }; }
|
|
7370
8567
|
constructor() {
|
|
7371
8568
|
super();
|
|
7372
8569
|
this.renderer = inject(Renderer2);
|
|
7373
8570
|
this.translate = inject(TranslateService);
|
|
7374
8571
|
this.iframeUrl = null;
|
|
7375
|
-
this.l10nService.loadComponentTranslations('iframe-module');
|
|
7376
8572
|
}
|
|
7377
8573
|
set iframeElement(element) {
|
|
7378
8574
|
this.iframe = element;
|
|
@@ -7445,7 +8641,7 @@ class IframeModuleComponent extends BaseModuleComponent {
|
|
|
7445
8641
|
placeholder="{{ 'iframe-module.iframeModule.urlPlaceholder' | translate }}"
|
|
7446
8642
|
qa-id="iframe-module-settings-site-url-input"
|
|
7447
8643
|
type="text"
|
|
7448
|
-
[(ngModel)]="settings.url"/>
|
|
8644
|
+
[(ngModel)]="settings.url" />
|
|
7449
8645
|
</div>
|
|
7450
8646
|
<div class="flex justify-end">
|
|
7451
8647
|
<p-button
|
|
@@ -7459,7 +8655,7 @@ class IframeModuleComponent extends BaseModuleComponent {
|
|
|
7459
8655
|
</div>
|
|
7460
8656
|
</div>
|
|
7461
8657
|
} @else if (isSecurity) {
|
|
7462
|
-
<security [controller]="controller" [id]="id"/>
|
|
8658
|
+
<security [controller]="controller" [id]="id" />
|
|
7463
8659
|
}
|
|
7464
8660
|
`, isInline: true, dependencies: [{ kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
7465
8661
|
}
|
|
@@ -7489,7 +8685,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7489
8685
|
placeholder="{{ 'iframe-module.iframeModule.urlPlaceholder' | translate }}"
|
|
7490
8686
|
qa-id="iframe-module-settings-site-url-input"
|
|
7491
8687
|
type="text"
|
|
7492
|
-
[(ngModel)]="settings.url"/>
|
|
8688
|
+
[(ngModel)]="settings.url" />
|
|
7493
8689
|
</div>
|
|
7494
8690
|
<div class="flex justify-end">
|
|
7495
8691
|
<p-button
|
|
@@ -7503,7 +8699,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7503
8699
|
</div>
|
|
7504
8700
|
</div>
|
|
7505
8701
|
} @else if (isSecurity) {
|
|
7506
|
-
<security [controller]="controller" [id]="id"/>
|
|
8702
|
+
<security [controller]="controller" [id]="id" />
|
|
7507
8703
|
}
|
|
7508
8704
|
`
|
|
7509
8705
|
}]
|
|
@@ -7512,6 +8708,563 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7512
8708
|
args: ['iframe']
|
|
7513
8709
|
}] } });
|
|
7514
8710
|
|
|
8711
|
+
const OIP_EXTENSION_EVENTS = {
|
|
8712
|
+
contextChange: 'oip:context-change',
|
|
8713
|
+
titleChange: 'oip:title-change',
|
|
8714
|
+
settingsChange: 'oip:settings-change',
|
|
8715
|
+
notify: 'oip:notify',
|
|
8716
|
+
navigate: 'oip:navigate',
|
|
8717
|
+
error: 'oip:error'
|
|
8718
|
+
};
|
|
8719
|
+
function emitOipTitleChange(element, title) {
|
|
8720
|
+
element.dispatchEvent(new CustomEvent(OIP_EXTENSION_EVENTS.titleChange, { detail: title, bubbles: true }));
|
|
8721
|
+
}
|
|
8722
|
+
function emitOipSettingsChange(element, settings) {
|
|
8723
|
+
element.dispatchEvent(new CustomEvent(OIP_EXTENSION_EVENTS.settingsChange, { detail: settings, bubbles: true }));
|
|
8724
|
+
}
|
|
8725
|
+
function emitOipNotify(element, notification) {
|
|
8726
|
+
element.dispatchEvent(new CustomEvent(OIP_EXTENSION_EVENTS.notify, { detail: notification, bubbles: true }));
|
|
8727
|
+
}
|
|
8728
|
+
function emitOipNavigate(element, navigation) {
|
|
8729
|
+
element.dispatchEvent(new CustomEvent(OIP_EXTENSION_EVENTS.navigate, { detail: navigation, bubbles: true }));
|
|
8730
|
+
}
|
|
8731
|
+
function emitOipError(element, error) {
|
|
8732
|
+
element.dispatchEvent(new CustomEvent(OIP_EXTENSION_EVENTS.error, { detail: error, bubbles: true }));
|
|
8733
|
+
}
|
|
8734
|
+
function emitOipContextChange(element, context) {
|
|
8735
|
+
element.dispatchEvent(new CustomEvent(OIP_EXTENSION_EVENTS.contextChange, { detail: context }));
|
|
8736
|
+
}
|
|
8737
|
+
|
|
8738
|
+
class ExtensionLoaderService {
|
|
8739
|
+
constructor() {
|
|
8740
|
+
this.loadedScripts = new Map();
|
|
8741
|
+
}
|
|
8742
|
+
loadScript(scriptUrl) {
|
|
8743
|
+
const existing = this.loadedScripts.get(scriptUrl);
|
|
8744
|
+
if (existing) {
|
|
8745
|
+
return existing;
|
|
8746
|
+
}
|
|
8747
|
+
const loadPromise = new Promise((resolve, reject) => {
|
|
8748
|
+
const script = document.createElement('script');
|
|
8749
|
+
script.type = 'module';
|
|
8750
|
+
script.src = scriptUrl;
|
|
8751
|
+
script.async = true;
|
|
8752
|
+
script.onload = () => resolve();
|
|
8753
|
+
script.onerror = () => {
|
|
8754
|
+
this.loadedScripts.delete(scriptUrl);
|
|
8755
|
+
reject(new Error(`Extension script could not be loaded: ${scriptUrl}`));
|
|
8756
|
+
};
|
|
8757
|
+
document.head.appendChild(script);
|
|
8758
|
+
});
|
|
8759
|
+
this.loadedScripts.set(scriptUrl, loadPromise);
|
|
8760
|
+
return loadPromise;
|
|
8761
|
+
}
|
|
8762
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
8763
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionLoaderService, providedIn: 'root' }); }
|
|
8764
|
+
}
|
|
8765
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionLoaderService, decorators: [{
|
|
8766
|
+
type: Injectable,
|
|
8767
|
+
args: [{ providedIn: 'root' }]
|
|
8768
|
+
}] });
|
|
8769
|
+
|
|
8770
|
+
class CustomElementExtensionModuleHostComponent extends BaseModuleComponent {
|
|
8771
|
+
set extensionContainer(element) {
|
|
8772
|
+
this.container = element;
|
|
8773
|
+
this.queueRenderExtension();
|
|
8774
|
+
}
|
|
8775
|
+
get showContent() {
|
|
8776
|
+
return this.isActiveTab('content');
|
|
8777
|
+
}
|
|
8778
|
+
get showSettings() {
|
|
8779
|
+
return this.isActiveTab('settings');
|
|
8780
|
+
}
|
|
8781
|
+
get showSecurity() {
|
|
8782
|
+
return this.isActiveTab('security');
|
|
8783
|
+
}
|
|
8784
|
+
get extensionKey() {
|
|
8785
|
+
return this.route.snapshot.paramMap.get('extensionKey') ?? '';
|
|
8786
|
+
}
|
|
8787
|
+
constructor() {
|
|
8788
|
+
super();
|
|
8789
|
+
this.extensionLoader = inject(ExtensionLoaderService);
|
|
8790
|
+
this.router = inject(Router);
|
|
8791
|
+
this.hostChangeDetectorRef = inject(ChangeDetectorRef);
|
|
8792
|
+
this.extensionModulesApi = inject(ExtensionModulesApi);
|
|
8793
|
+
this.removeListeners = [];
|
|
8794
|
+
this.renderQueued = false;
|
|
8795
|
+
this.activeTabSyncQueued = false;
|
|
8796
|
+
this.activeTabId = this.getCurrentActiveTabId();
|
|
8797
|
+
this.destroyed = false;
|
|
8798
|
+
this.loadError = null;
|
|
8799
|
+
this.subscriptions.push(this.topBarService.activeId$.subscribe(() => {
|
|
8800
|
+
this.queueActiveTabSync();
|
|
8801
|
+
}));
|
|
8802
|
+
}
|
|
8803
|
+
async onModuleInstanceChange() {
|
|
8804
|
+
await this.loadExtensionMetadata();
|
|
8805
|
+
await this.renderExtension();
|
|
8806
|
+
}
|
|
8807
|
+
onSecurityRightsChange() {
|
|
8808
|
+
this.updateExtensionContext();
|
|
8809
|
+
}
|
|
8810
|
+
ngOnDestroy() {
|
|
8811
|
+
this.destroyed = true;
|
|
8812
|
+
this.destroyExtensionElement();
|
|
8813
|
+
super.ngOnDestroy();
|
|
8814
|
+
}
|
|
8815
|
+
async reloadExtension() {
|
|
8816
|
+
this.loadError = null;
|
|
8817
|
+
this.extensionMetadata = undefined;
|
|
8818
|
+
await this.loadExtensionMetadata();
|
|
8819
|
+
await this.renderExtension();
|
|
8820
|
+
}
|
|
8821
|
+
async loadExtensionMetadata() {
|
|
8822
|
+
if (this.extensionMetadata) {
|
|
8823
|
+
return;
|
|
8824
|
+
}
|
|
8825
|
+
if (!this.extensionKey) {
|
|
8826
|
+
this.loadError = 'Extension key is missing.';
|
|
8827
|
+
return;
|
|
8828
|
+
}
|
|
8829
|
+
this.extensionMetadata = (await this.extensionModulesApi.getExtensionModuleByKey({
|
|
8830
|
+
extensionKey: this.extensionKey
|
|
8831
|
+
}));
|
|
8832
|
+
await this.loadExtensionTranslations(this.extensionMetadata);
|
|
8833
|
+
}
|
|
8834
|
+
async renderExtension() {
|
|
8835
|
+
if (this.destroyed || !this.container || !this.extensionMetadata || !this.showContent) {
|
|
8836
|
+
return;
|
|
8837
|
+
}
|
|
8838
|
+
try {
|
|
8839
|
+
this.loadError = null;
|
|
8840
|
+
this.destroyExtensionElement();
|
|
8841
|
+
await this.renderCustomElementExtension(this.extensionMetadata);
|
|
8842
|
+
}
|
|
8843
|
+
catch (error) {
|
|
8844
|
+
this.loadError = error instanceof Error ? error.message : 'Extension could not be loaded.';
|
|
8845
|
+
this.msgService.error(error);
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
queueRenderExtension() {
|
|
8849
|
+
if (this.renderQueued) {
|
|
8850
|
+
return;
|
|
8851
|
+
}
|
|
8852
|
+
this.renderQueued = true;
|
|
8853
|
+
queueMicrotask(() => {
|
|
8854
|
+
this.renderQueued = false;
|
|
8855
|
+
void this.renderExtension();
|
|
8856
|
+
});
|
|
8857
|
+
}
|
|
8858
|
+
isActiveTab(id) {
|
|
8859
|
+
return this.activeTabId === id;
|
|
8860
|
+
}
|
|
8861
|
+
queueActiveTabSync() {
|
|
8862
|
+
const nextActiveTabId = this.getCurrentActiveTabId();
|
|
8863
|
+
if (this.activeTabId === nextActiveTabId || this.activeTabSyncQueued) {
|
|
8864
|
+
return;
|
|
8865
|
+
}
|
|
8866
|
+
this.activeTabSyncQueued = true;
|
|
8867
|
+
queueMicrotask(() => {
|
|
8868
|
+
this.activeTabSyncQueued = false;
|
|
8869
|
+
if (this.destroyed) {
|
|
8870
|
+
return;
|
|
8871
|
+
}
|
|
8872
|
+
this.activeTabId = this.getCurrentActiveTabId();
|
|
8873
|
+
this.hostChangeDetectorRef.detectChanges();
|
|
8874
|
+
if (this.showContent) {
|
|
8875
|
+
this.queueRenderExtension();
|
|
8876
|
+
}
|
|
8877
|
+
else {
|
|
8878
|
+
this.destroyExtensionElement();
|
|
8879
|
+
}
|
|
8880
|
+
});
|
|
8881
|
+
}
|
|
8882
|
+
getCurrentActiveTabId() {
|
|
8883
|
+
return this.topBarService.activeTopBarItem?.id ?? 'content';
|
|
8884
|
+
}
|
|
8885
|
+
updateExtensionContext() {
|
|
8886
|
+
if (!this.extensionElement || !this.extensionMetadata?.extensionKey) {
|
|
8887
|
+
return;
|
|
8888
|
+
}
|
|
8889
|
+
const context = {
|
|
8890
|
+
moduleInstanceId: this.id,
|
|
8891
|
+
extensionKey: this.extensionMetadata.extensionKey,
|
|
8892
|
+
apiBasePath: this.buildUrl(`api/extensions/${this.extensionMetadata.extensionKey}`),
|
|
8893
|
+
settings: this.settings,
|
|
8894
|
+
locale: this.layoutService.language(),
|
|
8895
|
+
theme: this.layoutService.layoutConfig(),
|
|
8896
|
+
user: this.securityService.getCurrentUser(),
|
|
8897
|
+
activeTabId: this.topBarService.activeId ?? 'content',
|
|
8898
|
+
permissions: {
|
|
8899
|
+
canRead: this.canRead,
|
|
8900
|
+
canEdit: this.canEdit,
|
|
8901
|
+
canDelete: this.canDelete
|
|
8902
|
+
}
|
|
8903
|
+
};
|
|
8904
|
+
Object.assign(this.extensionElement, { oipContext: context });
|
|
8905
|
+
emitOipContextChange(this.extensionElement, context);
|
|
8906
|
+
}
|
|
8907
|
+
attachListeners(element) {
|
|
8908
|
+
this.addListener(element, OIP_EXTENSION_EVENTS.titleChange, (event) => {
|
|
8909
|
+
const title = event.detail;
|
|
8910
|
+
if (title) {
|
|
8911
|
+
this.appTitleService.setTitle(title);
|
|
8912
|
+
}
|
|
8913
|
+
});
|
|
8914
|
+
this.addListener(element, OIP_EXTENSION_EVENTS.settingsChange, (event) => {
|
|
8915
|
+
this.settings = event.detail;
|
|
8916
|
+
void this.saveSettings(this.settings);
|
|
8917
|
+
});
|
|
8918
|
+
this.addListener(element, OIP_EXTENSION_EVENTS.notify, (event) => {
|
|
8919
|
+
const detail = event.detail;
|
|
8920
|
+
const severity = detail?.severity ?? 'info';
|
|
8921
|
+
const message = detail?.detail ?? detail?.summary ?? '';
|
|
8922
|
+
switch (severity) {
|
|
8923
|
+
case 'success':
|
|
8924
|
+
this.msgService.success(message, detail?.summary);
|
|
8925
|
+
break;
|
|
8926
|
+
case 'warn':
|
|
8927
|
+
this.msgService.warn(message, detail?.summary);
|
|
8928
|
+
break;
|
|
8929
|
+
case 'error':
|
|
8930
|
+
this.msgService.error(message, detail?.summary);
|
|
8931
|
+
break;
|
|
8932
|
+
default:
|
|
8933
|
+
this.msgService.info(message, detail?.summary);
|
|
8934
|
+
}
|
|
8935
|
+
});
|
|
8936
|
+
this.addListener(element, OIP_EXTENSION_EVENTS.navigate, (event) => {
|
|
8937
|
+
const detail = event.detail;
|
|
8938
|
+
if (detail?.commands) {
|
|
8939
|
+
void this.router.navigate(detail.commands);
|
|
8940
|
+
}
|
|
8941
|
+
else if (detail?.url) {
|
|
8942
|
+
void this.router.navigateByUrl(detail.url);
|
|
8943
|
+
}
|
|
8944
|
+
});
|
|
8945
|
+
this.addListener(element, OIP_EXTENSION_EVENTS.error, (event) => {
|
|
8946
|
+
this.msgService.error(event.detail);
|
|
8947
|
+
});
|
|
8948
|
+
}
|
|
8949
|
+
buildUrl(path) {
|
|
8950
|
+
const baseUrl = document.getElementsByTagName('base')[0]?.href ?? `${window.location.origin}/`;
|
|
8951
|
+
return `${baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`}${path}`;
|
|
8952
|
+
}
|
|
8953
|
+
async loadExtensionTranslations(metadata) {
|
|
8954
|
+
const extensionKey = metadata.extensionKey ?? this.extensionKey;
|
|
8955
|
+
const apiBaseUrl = metadata.apiBaseUrl;
|
|
8956
|
+
if (!extensionKey || !apiBaseUrl) {
|
|
8957
|
+
return;
|
|
8958
|
+
}
|
|
8959
|
+
const lang = this.translateService.currentLang || this.layoutService.language() || 'en';
|
|
8960
|
+
const url = this.buildExtensionI18nUrl(apiBaseUrl, extensionKey, lang);
|
|
8961
|
+
try {
|
|
8962
|
+
await firstValueFrom(this.l10nService.loadTranslationsFromUrl(extensionKey, url, lang));
|
|
8963
|
+
}
|
|
8964
|
+
catch (error) {
|
|
8965
|
+
console.error(`No translations found for extension ${extensionKey}.${lang}.json`, error);
|
|
8966
|
+
}
|
|
8967
|
+
}
|
|
8968
|
+
buildExtensionI18nUrl(apiBaseUrl, extensionKey, lang) {
|
|
8969
|
+
return `${apiBaseUrl.replace(/\/+$/, '')}/assets/i18n/${encodeURIComponent(extensionKey)}.${encodeURIComponent(lang)}.json`;
|
|
8970
|
+
}
|
|
8971
|
+
addListener(element, eventName, listener) {
|
|
8972
|
+
element.addEventListener(eventName, listener);
|
|
8973
|
+
this.removeListeners.push(() => element.removeEventListener(eventName, listener));
|
|
8974
|
+
}
|
|
8975
|
+
destroyExtensionElement() {
|
|
8976
|
+
this.removeListeners.forEach((remove) => remove());
|
|
8977
|
+
this.removeListeners = [];
|
|
8978
|
+
this.extensionElement?.remove();
|
|
8979
|
+
this.extensionElement = undefined;
|
|
8980
|
+
}
|
|
8981
|
+
async renderCustomElementExtension(metadata) {
|
|
8982
|
+
const { elementName, scriptUrl } = metadata;
|
|
8983
|
+
if (!this.container || !elementName || !scriptUrl) {
|
|
8984
|
+
this.loadError = 'Custom Element extension metadata is incomplete.';
|
|
8985
|
+
return;
|
|
8986
|
+
}
|
|
8987
|
+
await this.extensionLoader.loadScript(scriptUrl);
|
|
8988
|
+
await customElements.whenDefined(elementName);
|
|
8989
|
+
const element = document.createElement(elementName);
|
|
8990
|
+
this.extensionElement = element;
|
|
8991
|
+
this.attachListeners(element);
|
|
8992
|
+
this.container.nativeElement.appendChild(element);
|
|
8993
|
+
this.updateExtensionContext();
|
|
8994
|
+
}
|
|
8995
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CustomElementExtensionModuleHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8996
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: CustomElementExtensionModuleHostComponent, isStandalone: true, selector: "ng-component", providers: [ExtensionModulesApi], viewQueries: [{ propertyName: "extensionContainer", first: true, predicate: ["extensionContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
|
|
8997
|
+
@if (showContent) {
|
|
8998
|
+
<div class="min-h-[calc(100vh-10rem)] w-full">
|
|
8999
|
+
@if (loadError) {
|
|
9000
|
+
<div class="card flex flex-col gap-4">
|
|
9001
|
+
<div class="font-semibold text-xl">{{ loadError }}</div>
|
|
9002
|
+
<p-button icon="pi pi-refresh" label="Retry" (onClick)="reloadExtension()"></p-button>
|
|
9003
|
+
</div>
|
|
9004
|
+
} @else {
|
|
9005
|
+
<div #extensionContainer class="w-full"></div>
|
|
9006
|
+
}
|
|
9007
|
+
</div>
|
|
9008
|
+
} @else if (showSettings) {
|
|
9009
|
+
<div class="flex flex-col md:flex-row gap-8">
|
|
9010
|
+
<div class="md:w-1/2">
|
|
9011
|
+
<div class="card flex flex-col gap-4">
|
|
9012
|
+
<div class="font-semibold text-xl">{{ 'baseComponent.settings' | translate }}</div>
|
|
9013
|
+
<p-button icon="pi pi-save" label="Save" (onClick)="saveSettings(settings)"></p-button>
|
|
9014
|
+
</div>
|
|
9015
|
+
</div>
|
|
9016
|
+
</div>
|
|
9017
|
+
} @else if (showSecurity) {
|
|
9018
|
+
<security [controller]="controller" [id]="id" />
|
|
9019
|
+
}
|
|
9020
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: SecurityComponent, selector: "security", inputs: ["id", "controller"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
9021
|
+
}
|
|
9022
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CustomElementExtensionModuleHostComponent, decorators: [{
|
|
9023
|
+
type: Component,
|
|
9024
|
+
args: [{
|
|
9025
|
+
standalone: true,
|
|
9026
|
+
imports: [CommonModule, SecurityComponent, TranslatePipe, Button],
|
|
9027
|
+
providers: [ExtensionModulesApi],
|
|
9028
|
+
template: `
|
|
9029
|
+
@if (showContent) {
|
|
9030
|
+
<div class="min-h-[calc(100vh-10rem)] w-full">
|
|
9031
|
+
@if (loadError) {
|
|
9032
|
+
<div class="card flex flex-col gap-4">
|
|
9033
|
+
<div class="font-semibold text-xl">{{ loadError }}</div>
|
|
9034
|
+
<p-button icon="pi pi-refresh" label="Retry" (onClick)="reloadExtension()"></p-button>
|
|
9035
|
+
</div>
|
|
9036
|
+
} @else {
|
|
9037
|
+
<div #extensionContainer class="w-full"></div>
|
|
9038
|
+
}
|
|
9039
|
+
</div>
|
|
9040
|
+
} @else if (showSettings) {
|
|
9041
|
+
<div class="flex flex-col md:flex-row gap-8">
|
|
9042
|
+
<div class="md:w-1/2">
|
|
9043
|
+
<div class="card flex flex-col gap-4">
|
|
9044
|
+
<div class="font-semibold text-xl">{{ 'baseComponent.settings' | translate }}</div>
|
|
9045
|
+
<p-button icon="pi pi-save" label="Save" (onClick)="saveSettings(settings)"></p-button>
|
|
9046
|
+
</div>
|
|
9047
|
+
</div>
|
|
9048
|
+
</div>
|
|
9049
|
+
} @else if (showSecurity) {
|
|
9050
|
+
<security [controller]="controller" [id]="id" />
|
|
9051
|
+
}
|
|
9052
|
+
`
|
|
9053
|
+
}]
|
|
9054
|
+
}], ctorParameters: () => [], propDecorators: { extensionContainer: [{
|
|
9055
|
+
type: ViewChild,
|
|
9056
|
+
args: ['extensionContainer']
|
|
9057
|
+
}] } });
|
|
9058
|
+
|
|
9059
|
+
class ExtensionModuleHostComponent extends BaseModuleComponent {
|
|
9060
|
+
set extensionViewContainer(viewContainer) {
|
|
9061
|
+
this.viewContainer = viewContainer;
|
|
9062
|
+
this.queueRenderExtension();
|
|
9063
|
+
}
|
|
9064
|
+
get extensionKey() {
|
|
9065
|
+
return this.route.snapshot.paramMap.get('extensionKey') ?? '';
|
|
9066
|
+
}
|
|
9067
|
+
constructor() {
|
|
9068
|
+
super();
|
|
9069
|
+
this.injector = inject(Injector);
|
|
9070
|
+
this.environmentInjector = inject(EnvironmentInjector);
|
|
9071
|
+
this.extensionModulesApi = inject(ExtensionModulesApi);
|
|
9072
|
+
this.renderQueued = false;
|
|
9073
|
+
this.destroyed = false;
|
|
9074
|
+
this.loadError = null;
|
|
9075
|
+
this.subscriptions.push(this.topBarService.activeId$.subscribe(() => {
|
|
9076
|
+
this.updateExtensionContext();
|
|
9077
|
+
}));
|
|
9078
|
+
}
|
|
9079
|
+
async reloadExtension() {
|
|
9080
|
+
this.loadError = null;
|
|
9081
|
+
this.extensionMetadata = undefined;
|
|
9082
|
+
await this.loadExtensionMetadata();
|
|
9083
|
+
await this.renderExtension();
|
|
9084
|
+
}
|
|
9085
|
+
async onModuleInstanceChange() {
|
|
9086
|
+
await this.loadExtensionMetadata();
|
|
9087
|
+
await this.renderExtension();
|
|
9088
|
+
}
|
|
9089
|
+
onSecurityRightsChange() {
|
|
9090
|
+
this.updateExtensionContext();
|
|
9091
|
+
}
|
|
9092
|
+
ngOnDestroy() {
|
|
9093
|
+
this.destroyed = true;
|
|
9094
|
+
this.destroyExtensionComponent();
|
|
9095
|
+
super.ngOnDestroy();
|
|
9096
|
+
}
|
|
9097
|
+
async loadExtensionMetadata() {
|
|
9098
|
+
if (this.extensionMetadata) {
|
|
9099
|
+
return;
|
|
9100
|
+
}
|
|
9101
|
+
if (!this.extensionKey) {
|
|
9102
|
+
this.loadError = 'Extension key is missing.';
|
|
9103
|
+
return;
|
|
9104
|
+
}
|
|
9105
|
+
this.extensionMetadata = (await this.extensionModulesApi.getExtensionModuleByKey({
|
|
9106
|
+
extensionKey: this.extensionKey
|
|
9107
|
+
}));
|
|
9108
|
+
await this.loadExtensionTranslations(this.extensionMetadata);
|
|
9109
|
+
}
|
|
9110
|
+
async renderExtension() {
|
|
9111
|
+
if (this.destroyed || !this.viewContainer) {
|
|
9112
|
+
return;
|
|
9113
|
+
}
|
|
9114
|
+
try {
|
|
9115
|
+
this.loadError = null;
|
|
9116
|
+
await this.loadExtensionMetadata();
|
|
9117
|
+
if (!this.extensionMetadata) {
|
|
9118
|
+
return;
|
|
9119
|
+
}
|
|
9120
|
+
this.destroyExtensionComponent();
|
|
9121
|
+
if (this.extensionMetadata.loadType === 'moduleFederation') {
|
|
9122
|
+
await this.renderFederatedExtension(this.extensionMetadata);
|
|
9123
|
+
}
|
|
9124
|
+
else {
|
|
9125
|
+
this.extensionComponent = this.viewContainer.createComponent(CustomElementExtensionModuleHostComponent, {
|
|
9126
|
+
injector: this.injector,
|
|
9127
|
+
environmentInjector: this.environmentInjector
|
|
9128
|
+
});
|
|
9129
|
+
}
|
|
9130
|
+
}
|
|
9131
|
+
catch (error) {
|
|
9132
|
+
this.loadError = error instanceof Error ? error.message : 'Extension could not be loaded.';
|
|
9133
|
+
console.error(error);
|
|
9134
|
+
}
|
|
9135
|
+
}
|
|
9136
|
+
queueRenderExtension() {
|
|
9137
|
+
if (this.renderQueued) {
|
|
9138
|
+
return;
|
|
9139
|
+
}
|
|
9140
|
+
this.renderQueued = true;
|
|
9141
|
+
queueMicrotask(() => {
|
|
9142
|
+
this.renderQueued = false;
|
|
9143
|
+
void this.renderExtension();
|
|
9144
|
+
});
|
|
9145
|
+
}
|
|
9146
|
+
destroyExtensionComponent() {
|
|
9147
|
+
this.extensionComponent?.destroy();
|
|
9148
|
+
this.extensionComponent = undefined;
|
|
9149
|
+
this.extensionElement = undefined;
|
|
9150
|
+
this.viewContainer?.clear();
|
|
9151
|
+
}
|
|
9152
|
+
async renderFederatedExtension(metadata) {
|
|
9153
|
+
const { remoteEntryUrl, exposedModule, componentName } = metadata;
|
|
9154
|
+
if (!remoteEntryUrl || !exposedModule || !componentName) {
|
|
9155
|
+
this.loadError = 'Module Federation extension metadata is incomplete.';
|
|
9156
|
+
return;
|
|
9157
|
+
}
|
|
9158
|
+
const remoteModule = await loadRemoteModule({
|
|
9159
|
+
type: 'module',
|
|
9160
|
+
remoteEntry: remoteEntryUrl,
|
|
9161
|
+
exposedModule
|
|
9162
|
+
});
|
|
9163
|
+
const component = remoteModule[componentName];
|
|
9164
|
+
if (!component) {
|
|
9165
|
+
throw new Error(`Remote component '${componentName}' was not exported by '${exposedModule}'.`);
|
|
9166
|
+
}
|
|
9167
|
+
this.extensionComponent = this.viewContainer?.createComponent(component, {
|
|
9168
|
+
environmentInjector: this.environmentInjector
|
|
9169
|
+
});
|
|
9170
|
+
this.extensionElement = this.extensionComponent?.location.nativeElement;
|
|
9171
|
+
this.updateExtensionContext();
|
|
9172
|
+
}
|
|
9173
|
+
async loadExtensionTranslations(metadata) {
|
|
9174
|
+
const extensionKey = metadata.extensionKey ?? this.extensionKey;
|
|
9175
|
+
const apiBaseUrl = metadata.apiBaseUrl;
|
|
9176
|
+
if (!extensionKey || !apiBaseUrl) {
|
|
9177
|
+
return;
|
|
9178
|
+
}
|
|
9179
|
+
const lang = this.translateService.currentLang || this.layoutService.language() || 'en';
|
|
9180
|
+
for (const namespace of this.getExtensionTranslationNamespaces(metadata, extensionKey)) {
|
|
9181
|
+
const url = this.buildExtensionI18nUrl(apiBaseUrl, namespace, lang);
|
|
9182
|
+
try {
|
|
9183
|
+
await firstValueFrom(this.l10nService.loadTranslationsFromUrl(namespace, url, lang));
|
|
9184
|
+
return;
|
|
9185
|
+
}
|
|
9186
|
+
catch (error) {
|
|
9187
|
+
console.error(`No translations found for extension ${namespace}.${lang}.json`, error);
|
|
9188
|
+
}
|
|
9189
|
+
}
|
|
9190
|
+
}
|
|
9191
|
+
buildExtensionI18nUrl(apiBaseUrl, extensionKey, lang) {
|
|
9192
|
+
return `${apiBaseUrl.replace(/\/+$/, '')}/assets/i18n/${encodeURIComponent(extensionKey)}.${encodeURIComponent(lang)}.json`;
|
|
9193
|
+
}
|
|
9194
|
+
getExtensionTranslationNamespaces(metadata, extensionKey) {
|
|
9195
|
+
const namespaces = [extensionKey];
|
|
9196
|
+
const componentNamespace = this.toKebabCase(metadata.componentName?.replace(/Component$/, '') ?? '');
|
|
9197
|
+
if (componentNamespace && !namespaces.includes(componentNamespace)) {
|
|
9198
|
+
namespaces.push(componentNamespace);
|
|
9199
|
+
}
|
|
9200
|
+
return namespaces;
|
|
9201
|
+
}
|
|
9202
|
+
toKebabCase(value) {
|
|
9203
|
+
return value
|
|
9204
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
9205
|
+
.replace(/[\s_]+/g, '-')
|
|
9206
|
+
.toLowerCase();
|
|
9207
|
+
}
|
|
9208
|
+
updateExtensionContext() {
|
|
9209
|
+
if (!this.extensionElement || !this.extensionMetadata?.extensionKey) {
|
|
9210
|
+
return;
|
|
9211
|
+
}
|
|
9212
|
+
const context = {
|
|
9213
|
+
moduleInstanceId: this.id,
|
|
9214
|
+
extensionKey: this.extensionMetadata.extensionKey,
|
|
9215
|
+
apiBasePath: this.buildUrl(`api/extensions/${this.extensionMetadata.extensionKey}`),
|
|
9216
|
+
settings: this.settings,
|
|
9217
|
+
locale: this.layoutService.language(),
|
|
9218
|
+
theme: this.layoutService.layoutConfig(),
|
|
9219
|
+
user: this.securityService.getCurrentUser(),
|
|
9220
|
+
activeTabId: this.topBarService.activeId ?? 'content',
|
|
9221
|
+
permissions: {
|
|
9222
|
+
canRead: this.canRead,
|
|
9223
|
+
canEdit: this.canEdit,
|
|
9224
|
+
canDelete: this.canDelete
|
|
9225
|
+
}
|
|
9226
|
+
};
|
|
9227
|
+
Object.assign(this.extensionElement, { oipContext: context });
|
|
9228
|
+
emitOipContextChange(this.extensionElement, context);
|
|
9229
|
+
}
|
|
9230
|
+
buildUrl(path) {
|
|
9231
|
+
const baseUrl = document.getElementsByTagName('base')[0]?.href ?? `${window.location.origin}/`;
|
|
9232
|
+
return `${baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`}${path}`;
|
|
9233
|
+
}
|
|
9234
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionModuleHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9235
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: ExtensionModuleHostComponent, isStandalone: true, selector: "ng-component", providers: [ExtensionModulesApi], viewQueries: [{ propertyName: "extensionViewContainer", first: true, predicate: ["extensionContainer"], descendants: true, read: ViewContainerRef }], usesInheritance: true, ngImport: i0, template: `
|
|
9236
|
+
@if (loadError) {
|
|
9237
|
+
<div class="card flex flex-col gap-4">
|
|
9238
|
+
<div class="font-semibold text-xl">{{ loadError }}</div>
|
|
9239
|
+
<p-button icon="pi pi-refresh" label="Retry" (onClick)="reloadExtension()"></p-button>
|
|
9240
|
+
</div>
|
|
9241
|
+
} @else {
|
|
9242
|
+
<ng-container #extensionContainer></ng-container>
|
|
9243
|
+
}
|
|
9244
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }] }); }
|
|
9245
|
+
}
|
|
9246
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ExtensionModuleHostComponent, decorators: [{
|
|
9247
|
+
type: Component,
|
|
9248
|
+
args: [{
|
|
9249
|
+
standalone: true,
|
|
9250
|
+
imports: [CommonModule, Button],
|
|
9251
|
+
providers: [ExtensionModulesApi],
|
|
9252
|
+
template: `
|
|
9253
|
+
@if (loadError) {
|
|
9254
|
+
<div class="card flex flex-col gap-4">
|
|
9255
|
+
<div class="font-semibold text-xl">{{ loadError }}</div>
|
|
9256
|
+
<p-button icon="pi pi-refresh" label="Retry" (onClick)="reloadExtension()"></p-button>
|
|
9257
|
+
</div>
|
|
9258
|
+
} @else {
|
|
9259
|
+
<ng-container #extensionContainer></ng-container>
|
|
9260
|
+
}
|
|
9261
|
+
`
|
|
9262
|
+
}]
|
|
9263
|
+
}], ctorParameters: () => [], propDecorators: { extensionViewContainer: [{
|
|
9264
|
+
type: ViewChild,
|
|
9265
|
+
args: ['extensionContainer', { read: ViewContainerRef }]
|
|
9266
|
+
}] } });
|
|
9267
|
+
|
|
7515
9268
|
/**
|
|
7516
9269
|
* A route guard that ensures the user is authenticated and has a valid access token.
|
|
7517
9270
|
* If the access token is expired, it attempts to refresh the session.
|
|
@@ -7520,24 +9273,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7520
9273
|
class AuthGuardService {
|
|
7521
9274
|
constructor() {
|
|
7522
9275
|
this.oidcSecurityService = inject(SecurityService);
|
|
7523
|
-
this.router = inject(Router);
|
|
7524
9276
|
}
|
|
7525
9277
|
/**
|
|
7526
9278
|
* Checks whether the route can be activated.
|
|
7527
9279
|
* - Returns `true` if the user is authenticated and the token is valid.
|
|
7528
9280
|
* - Attempts to refresh the token if expired.
|
|
7529
|
-
* -
|
|
9281
|
+
* - Starts the authorization flow if not authenticated or refresh fails.
|
|
7530
9282
|
*
|
|
7531
|
-
* @returns {Observable<boolean
|
|
9283
|
+
* @returns {Observable<boolean>} A stream resolving to true (allow), or false after starting authorization.
|
|
7532
9284
|
*/
|
|
7533
9285
|
canActivate(returnUrl = '/') {
|
|
7534
9286
|
this.oidcSecurityService.auth();
|
|
7535
|
-
return this.oidcSecurityService.isAuthenticated().pipe(map((authenticated) =>
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
9287
|
+
return this.oidcSecurityService.isAuthenticated().pipe(map((authenticated) => {
|
|
9288
|
+
if (authenticated) {
|
|
9289
|
+
return true;
|
|
9290
|
+
}
|
|
9291
|
+
this.oidcSecurityService.authorize(returnUrl);
|
|
9292
|
+
return false;
|
|
9293
|
+
}));
|
|
7541
9294
|
}
|
|
7542
9295
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AuthGuardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7543
9296
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: AuthGuardService }); }
|
|
@@ -7546,6 +9299,103 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7546
9299
|
type: Injectable
|
|
7547
9300
|
}] });
|
|
7548
9301
|
|
|
9302
|
+
/**
|
|
9303
|
+
* Reads the rights the current user has on a module instance.
|
|
9304
|
+
*
|
|
9305
|
+
* Results are cached per instance and dropped whenever the authenticated user changes.
|
|
9306
|
+
*/
|
|
9307
|
+
class ModuleInstanceRightsService {
|
|
9308
|
+
static { this.readRight = 'read'; }
|
|
9309
|
+
constructor() {
|
|
9310
|
+
this.menuApi = inject(MenuApi);
|
|
9311
|
+
this.securityService = inject(SecurityService);
|
|
9312
|
+
this.cache = new Map();
|
|
9313
|
+
this.cachedIdentity = undefined;
|
|
9314
|
+
this.securityService.payload.subscribe((payload) => {
|
|
9315
|
+
// Rights depend on both the user and the roles of the current session.
|
|
9316
|
+
const roles = payload?.realm_access?.roles ?? [];
|
|
9317
|
+
const identity = `${payload?.preferred_username ?? ''}|${[...roles].sort().join(',')}`;
|
|
9318
|
+
if (identity !== this.cachedIdentity) {
|
|
9319
|
+
this.cachedIdentity = identity;
|
|
9320
|
+
this.clearCache();
|
|
9321
|
+
}
|
|
9322
|
+
});
|
|
9323
|
+
}
|
|
9324
|
+
/**
|
|
9325
|
+
* Gets the rights of the current user on the given module instance.
|
|
9326
|
+
*/
|
|
9327
|
+
getRights(moduleInstanceId) {
|
|
9328
|
+
const cached = this.cache.get(moduleInstanceId);
|
|
9329
|
+
if (cached) {
|
|
9330
|
+
return cached;
|
|
9331
|
+
}
|
|
9332
|
+
const request = this.menuApi
|
|
9333
|
+
.getModuleInstanceRights({ id: moduleInstanceId })
|
|
9334
|
+
.then((rights) => rights ?? [])
|
|
9335
|
+
.catch((error) => {
|
|
9336
|
+
this.cache.delete(moduleInstanceId);
|
|
9337
|
+
throw error;
|
|
9338
|
+
});
|
|
9339
|
+
this.cache.set(moduleInstanceId, request);
|
|
9340
|
+
return request;
|
|
9341
|
+
}
|
|
9342
|
+
/**
|
|
9343
|
+
* Checks whether the current user has the `read` right on the given module instance.
|
|
9344
|
+
*/
|
|
9345
|
+
async canRead(moduleInstanceId) {
|
|
9346
|
+
const rights = await this.getRights(moduleInstanceId);
|
|
9347
|
+
return rights.includes(ModuleInstanceRightsService.readRight);
|
|
9348
|
+
}
|
|
9349
|
+
/**
|
|
9350
|
+
* Drops every cached result, for example after module security was changed.
|
|
9351
|
+
*/
|
|
9352
|
+
clearCache() {
|
|
9353
|
+
this.cache.clear();
|
|
9354
|
+
}
|
|
9355
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ModuleInstanceRightsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
9356
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ModuleInstanceRightsService }); }
|
|
9357
|
+
}
|
|
9358
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: ModuleInstanceRightsService, decorators: [{
|
|
9359
|
+
type: Injectable
|
|
9360
|
+
}], ctorParameters: () => [] });
|
|
9361
|
+
|
|
9362
|
+
/**
|
|
9363
|
+
* Guards module routes against direct navigation without the required rights.
|
|
9364
|
+
*
|
|
9365
|
+
* - Routes flagged with `data: { requireAdmin: true }` require the `admin` role.
|
|
9366
|
+
* - Routes carrying an `:id` segment require the `read` right on that module instance.
|
|
9367
|
+
* - Everything else is left to {@link AuthGuardService}.
|
|
9368
|
+
*
|
|
9369
|
+
* Denied navigation is redirected to the access denied page. This is a UX guard only:
|
|
9370
|
+
* the backend checks the same rights on every module endpoint.
|
|
9371
|
+
*/
|
|
9372
|
+
const moduleAccessGuard = async (route) => {
|
|
9373
|
+
const router = inject(Router);
|
|
9374
|
+
const securityService = inject(SecurityService);
|
|
9375
|
+
const rightsService = inject(ModuleInstanceRightsService);
|
|
9376
|
+
const accessDenied = router.parseUrl('/access');
|
|
9377
|
+
if (route.data?.requireAdmin) {
|
|
9378
|
+
// Wait for the session payload so a direct URL entry does not read roles before they are loaded.
|
|
9379
|
+
await firstValueFrom(securityService.payload.pipe(filter((payload) => payload != null), take(1)));
|
|
9380
|
+
return securityService.isAdmin() ? true : accessDenied;
|
|
9381
|
+
}
|
|
9382
|
+
const routeId = route.paramMap.get('id');
|
|
9383
|
+
if (routeId == null) {
|
|
9384
|
+
return true;
|
|
9385
|
+
}
|
|
9386
|
+
const moduleInstanceId = Number(routeId);
|
|
9387
|
+
if (!Number.isFinite(moduleInstanceId)) {
|
|
9388
|
+
return accessDenied;
|
|
9389
|
+
}
|
|
9390
|
+
try {
|
|
9391
|
+
return (await rightsService.canRead(moduleInstanceId)) ? true : accessDenied;
|
|
9392
|
+
}
|
|
9393
|
+
catch (error) {
|
|
9394
|
+
console.error('Failed to load module instance rights', error);
|
|
9395
|
+
return accessDenied;
|
|
9396
|
+
}
|
|
9397
|
+
};
|
|
9398
|
+
|
|
7549
9399
|
/**
|
|
7550
9400
|
* Prime-ng table filter service
|
|
7551
9401
|
*/
|
|
@@ -7618,13 +9468,55 @@ function replaceDefaults(themes) {
|
|
|
7618
9468
|
return provideAppThemes(themes, { mode: 'replaceDefaults' });
|
|
7619
9469
|
}
|
|
7620
9470
|
|
|
9471
|
+
const defaultTheme = [
|
|
9472
|
+
{
|
|
9473
|
+
id: 'Oip',
|
|
9474
|
+
label: 'Oip',
|
|
9475
|
+
preset: definePreset(Aura, {
|
|
9476
|
+
components: {
|
|
9477
|
+
toolbar: {
|
|
9478
|
+
colorScheme: {
|
|
9479
|
+
light: {
|
|
9480
|
+
root: {
|
|
9481
|
+
borderRadius: '0.7rem'
|
|
9482
|
+
}
|
|
9483
|
+
},
|
|
9484
|
+
dark: {
|
|
9485
|
+
root: {
|
|
9486
|
+
borderRadius: '0.7rem'
|
|
9487
|
+
}
|
|
9488
|
+
}
|
|
9489
|
+
}
|
|
9490
|
+
}
|
|
9491
|
+
}
|
|
9492
|
+
}),
|
|
9493
|
+
primaryColors: {
|
|
9494
|
+
rose: primitive['red']
|
|
9495
|
+
},
|
|
9496
|
+
surfaceColors: {
|
|
9497
|
+
zinc: {
|
|
9498
|
+
0: '#ffffff',
|
|
9499
|
+
50: '#fafafa',
|
|
9500
|
+
100: '#f4f4f5',
|
|
9501
|
+
200: '#e4e4e7',
|
|
9502
|
+
300: '#d4d4d8',
|
|
9503
|
+
400: '#a1a1aa',
|
|
9504
|
+
500: '#71717a',
|
|
9505
|
+
600: '#52525b',
|
|
9506
|
+
700: '#3f3f46',
|
|
9507
|
+
800: '#27272a',
|
|
9508
|
+
900: '#18181b',
|
|
9509
|
+
950: '#09090b'
|
|
9510
|
+
}
|
|
9511
|
+
}
|
|
9512
|
+
}
|
|
9513
|
+
];
|
|
9514
|
+
|
|
7621
9515
|
const langIntercept = (req, next) => {
|
|
7622
9516
|
const layoutService = inject(LayoutService);
|
|
7623
9517
|
const securityService = inject(SecurityService);
|
|
7624
9518
|
const lang = layoutService.language() ? layoutService.language() : 'en';
|
|
7625
|
-
const headers = req.headers
|
|
7626
|
-
.set('Accept-language', lang)
|
|
7627
|
-
.set('X-Timezone', layoutService.timeZone());
|
|
9519
|
+
const headers = req.headers.set('Accept-language', lang).set('X-Timezone', layoutService.timeZone());
|
|
7628
9520
|
const reqWithCredentials = req.clone({
|
|
7629
9521
|
headers,
|
|
7630
9522
|
withCredentials: true
|
|
@@ -7649,12 +9541,14 @@ function provideOip() {
|
|
|
7649
9541
|
{ provide: LocationStrategy, useClass: PathLocationStrategy },
|
|
7650
9542
|
{ provide: SecurityService, useClass: BffSecurityService },
|
|
7651
9543
|
AuthGuardService,
|
|
9544
|
+
ModuleInstanceRightsService,
|
|
7652
9545
|
MessageService,
|
|
7653
9546
|
UserService,
|
|
7654
9547
|
NotificationService,
|
|
7655
9548
|
UserProfileApi,
|
|
7656
9549
|
SecurityApi,
|
|
7657
9550
|
NotificationApi,
|
|
9551
|
+
MenuApi,
|
|
7658
9552
|
importProvidersFrom([
|
|
7659
9553
|
TranslateModule.forRoot({
|
|
7660
9554
|
loader: {
|
|
@@ -7673,10 +9567,9 @@ function provideOip() {
|
|
|
7673
9567
|
class FolderModuleApi extends HttpClient {
|
|
7674
9568
|
constructor() {
|
|
7675
9569
|
super(...arguments);
|
|
7676
|
-
this.getModuleInstanceSettings = (
|
|
9570
|
+
this.getModuleInstanceSettings = (params = {}) => this.request({
|
|
7677
9571
|
path: `/api/folder-module/get-module-instance-settings`,
|
|
7678
9572
|
method: "GET",
|
|
7679
|
-
query: query,
|
|
7680
9573
|
secure: true,
|
|
7681
9574
|
format: "json",
|
|
7682
9575
|
...params,
|
|
@@ -7695,10 +9588,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7695
9588
|
class IframeModuleApi extends HttpClient {
|
|
7696
9589
|
constructor() {
|
|
7697
9590
|
super(...arguments);
|
|
7698
|
-
this.getModuleInstanceSettings = (
|
|
9591
|
+
this.getModuleInstanceSettings = (params = {}) => this.request({
|
|
7699
9592
|
path: `/api/iframe-module/get-module-instance-settings`,
|
|
7700
9593
|
method: "GET",
|
|
7701
|
-
query: query,
|
|
7702
9594
|
secure: true,
|
|
7703
9595
|
format: "json",
|
|
7704
9596
|
...params,
|
|
@@ -7717,5 +9609,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
7717
9609
|
* Generated bundle index. Do not edit.
|
|
7718
9610
|
*/
|
|
7719
9611
|
|
|
7720
|
-
export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AppTopbarApplicationSwitcherComponent, ApplicationRegistryService, ApplicationsApi, ApplicationsComponent, AuthGuardService, BaseModuleComponent, BffSecurityService, ConfigComponent, ContentType, DbMigrationComponent, DiscussionComponent, ErrorComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, MsgService, NotfoundComponent, NotificationApi, NotificationService, ProfileComponent, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserService, convertToPrimeNgDateFormat, langIntercept, mergeWithDefaults, provideAppThemes, provideLogoComponent, provideOip, replaceDefaults };
|
|
9612
|
+
export { APP_THEME_PRESETS, APP_THEME_PRESETS_MERGE_MODE, AccessComponent, AppConfiguratorComponent, AppFloatingConfiguratorComponent, AppLayoutComponent, AppModulesComponent, AppTopbar, AppTopbarApplicationSwitcherComponent, ApplicationRegistryService, ApplicationsApi, ApplicationsComponent, AuthGuardService, BaseModuleComponent, BffSecurityService, ConfigComponent, ContentType, CustomElementExtensionModuleHostComponent, DbMigrationComponent, DiscussionComponent, ErrorComponent, ExtensionLoaderService, ExtensionModuleHostComponent, FolderModuleApi, FooterComponent, HttpClient, IframeModuleApi, IframeModuleComponent, L10nService, LOGO_COMPONENT_TOKEN, LayoutService, LogoComponent, LogoService, MenuComponent, MenuService, ModuleInstanceRightsService, MsgService, NotfoundComponent, NotificationApi, NotificationService, OIP_EXTENSION_EVENTS, ProfileComponent, SecurityApi, SecurityComponent, SecurityService, SidebarComponent, TableFilterService, TopBarService, UnauthorizedComponent, UserNotificationsComponent, UserProfileApi, UserService, convertToPrimeNgDateFormat, defaultTheme, emitOipContextChange, emitOipError, emitOipNavigate, emitOipNotify, emitOipSettingsChange, emitOipTitleChange, langIntercept, mergeWithDefaults, moduleAccessGuard, provideAppThemes, provideLogoComponent, provideOip, replaceDefaults };
|
|
7721
9613
|
//# sourceMappingURL=oip-common.mjs.map
|