@yuuvis/user-management-app 1.0.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.
@@ -0,0 +1,706 @@
1
+ import * as i1$2 from '@angular/common';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, Component, Injectable, signal, linkedSignal, Inject, Input, HostBinding, ViewChild } from '@angular/core';
5
+ import * as i1 from '@angular/router';
6
+ import { RouterModule } from '@angular/router';
7
+ import * as i2 from '@yuuvis/client-core';
8
+ import { TranslateService, TranslateModule, BackendService, ApiBase, Logger, NotificationService, UserService } from '@yuuvis/client-core';
9
+ import { Title } from '@angular/platform-browser';
10
+ import { ShellService } from '@yuuvis/client-shell-core';
11
+ import * as i2$1 from '@angular/material/button';
12
+ import { MatButtonModule } from '@angular/material/button';
13
+ import * as i7 from '@angular/material/icon';
14
+ import { MatIconModule } from '@angular/material/icon';
15
+ import * as i4$2 from '@angular/material/tooltip';
16
+ import { MatTooltipModule } from '@angular/material/tooltip';
17
+ import { MatSortModule } from '@angular/material/sort';
18
+ import * as i6 from '@angular/material/paginator';
19
+ import { MatPaginatorModule } from '@angular/material/paginator';
20
+ import * as i5$1 from '@angular/material/table';
21
+ import { MatTableModule } from '@angular/material/table';
22
+ import { HttpParams } from '@angular/common/http';
23
+ import { map, switchMap, of } from 'rxjs';
24
+ import { ConfirmService, BusyOverlayDirective, DialogComponent, ClickDoubleDirective } from '@yuuvis/client-framework/common';
25
+ import { SimpleSearchComponent } from '@yuuvis/client-framework/simple-search';
26
+ import * as i8 from '@yuuvis/client-shell';
27
+ import { YuvClientShellModule } from '@yuuvis/client-shell';
28
+ import * as i1$1 from '@angular/forms';
29
+ import { ReactiveFormsModule, FormBuilder, FormControl, Validators } from '@angular/forms';
30
+ import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
31
+ import * as i3 from '@angular/material/form-field';
32
+ import { MatFormFieldModule } from '@angular/material/form-field';
33
+ import { YmtButtonDirective } from '@yuuvis/material';
34
+ import * as i4 from '@angular/material/slide-toggle';
35
+ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
36
+ import * as i5 from '@angular/material/input';
37
+ import { MatInputModule } from '@angular/material/input';
38
+ import { SelectionModel } from '@angular/cdk/collections';
39
+ import * as i9$1 from '@yuuvis/client-framework/master-details';
40
+ import { YuvMasterDetailsModule } from '@yuuvis/client-framework/master-details';
41
+ import * as i3$1 from '@angular/material/card';
42
+ import { MatCardModule } from '@angular/material/card';
43
+ import { MatCheckboxModule } from '@angular/material/checkbox';
44
+ import * as i4$1 from '@angular/material/chips';
45
+ import { MatChipsModule } from '@angular/material/chips';
46
+ import * as i9 from '@angular/material/tabs';
47
+ import { MatTabsModule } from '@angular/material/tabs';
48
+ import * as i10 from '@yuuvis/client-framework/overflow-menu';
49
+ import { YuvOverflowMenuModule } from '@yuuvis/client-framework/overflow-menu';
50
+
51
+ const APP_ID = 'io.yuuvis.app.user-management';
52
+ const APP_ICONS = {
53
+ refresh: 'refresh',
54
+ stateActive: 'account_circle',
55
+ stateInactive: 'account_circle_off',
56
+ actionCreateNewUser: 'add',
57
+ actionEditUser: 'person_edit',
58
+ actionActivateUser: 'person_check',
59
+ actionDeactivateUser: 'person_off',
60
+ actionDeleteUser: 'delete',
61
+ };
62
+
63
+ class YuvUserManagementComponent {
64
+ #shell = inject(ShellService);
65
+ #titleService = inject(Title);
66
+ #translateService = inject(TranslateService);
67
+ #app = this.#shell.getApp(APP_ID);
68
+ appName = this.#app?.title;
69
+ appIcon = this.#app?.iconName;
70
+ ngOnInit() {
71
+ // Browser-Tab-Titel lokalisiert setzen
72
+ const translatedTitle = this.appName.startsWith('yuv.')
73
+ ? this.#translateService.instant(this.appName)
74
+ : this.appName;
75
+ this.#titleService.setTitle(translatedTitle);
76
+ }
77
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: YuvUserManagementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
78
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: YuvUserManagementComponent, isStandalone: true, selector: "ymusrmgmt-root", ngImport: i0, template: "<section class=\"usrmgmt-main__content\" [attr.aria-label]=\"'yuv.app.user-management.content.aria.label' | translate\">\n <router-outlet></router-outlet>\n</section>\n\n<router-outlet name=\"modal\"></router-outlet>\n", styles: [":host{display:flex;flex-flow:column;height:100%}:host .usrmgmt-main__content{flex:1;overflow-y:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
79
+ }
80
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: YuvUserManagementComponent, decorators: [{
81
+ type: Component,
82
+ args: [{ selector: 'ymusrmgmt-root', standalone: true, imports: [
83
+ CommonModule,
84
+ RouterModule,
85
+ TranslateModule,
86
+ ], template: "<section class=\"usrmgmt-main__content\" [attr.aria-label]=\"'yuv.app.user-management.content.aria.label' | translate\">\n <router-outlet></router-outlet>\n</section>\n\n<router-outlet name=\"modal\"></router-outlet>\n", styles: [":host{display:flex;flex-flow:column;height:100%}:host .usrmgmt-main__content{flex:1;overflow-y:hidden}\n"] }]
87
+ }] });
88
+
89
+ class YuvUserManagementService {
90
+ static DEFAULT_PAGE_SIZE = 15;
91
+ #backendService = inject(BackendService);
92
+ #translateService = inject(TranslateService);
93
+ #confirmService = inject(ConfirmService);
94
+ fetchUsers(page = 0, search) {
95
+ const filterParams = new HttpParams()
96
+ .set('page', page)
97
+ .set('size', YuvUserManagementService.DEFAULT_PAGE_SIZE)
98
+ .set('sort', 'username%2Casc')
99
+ .set('search', search || '');
100
+ return this.#backendService
101
+ .get(`/tenant-management/api/idm/users?${filterParams}`, ApiBase.none);
102
+ }
103
+ createUser(createUserRequest, withInvitation) {
104
+ const createParams = new HttpParams()
105
+ .set('withInvitation', withInvitation || false)
106
+ .set('temporaryPassword', true);
107
+ return this.#backendService
108
+ .post(`/tenant-management/api/admin/users?${createParams}`, createUserRequest, ApiBase.none, { responseType: 'text' })
109
+ .pipe(map((createdUserId) => createdUserId));
110
+ }
111
+ editUser(userId, updateUserRequest) {
112
+ return this.#backendService
113
+ .put(`/tenant-management/api/admin/users/${userId}`, updateUserRequest, ApiBase.none);
114
+ }
115
+ deleteUser(user) {
116
+ return this.#confirmService
117
+ .confirm({
118
+ title: this.#translateService.instant('yuv.app.user-management.users.action.delete.label'),
119
+ message: this.#translateService.instant('yuv.app.user-management.users.action.delete.confirm.message', { username: user.username }),
120
+ })
121
+ .pipe(switchMap((confirmed) => {
122
+ if (confirmed) {
123
+ return this.#backendService
124
+ .delete(`/tenant-management/api/admin/users/${user.id}`, ApiBase.none)
125
+ .pipe(map(() => true));
126
+ }
127
+ else
128
+ return of(false);
129
+ }));
130
+ }
131
+ getUserDetails(id) {
132
+ const queryParams = new HttpParams()
133
+ .set('briefRepresentation', false);
134
+ return this.#backendService
135
+ .get(`/tenant-management/api/idm/users/${id}?${queryParams}`, ApiBase.none);
136
+ }
137
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: YuvUserManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
138
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: YuvUserManagementService, providedIn: 'root' });
139
+ }
140
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: YuvUserManagementService, decorators: [{
141
+ type: Injectable,
142
+ args: [{
143
+ providedIn: 'root',
144
+ }]
145
+ }] });
146
+
147
+ const components$1 = [BusyOverlayDirective, YmtButtonDirective, DialogComponent];
148
+ const modules$1 = [
149
+ CommonModule,
150
+ ReactiveFormsModule,
151
+ TranslateModule,
152
+ MatFormFieldModule,
153
+ MatSlideToggleModule,
154
+ MatInputModule
155
+ ];
156
+ class CreateUserComponent {
157
+ #fb = inject(FormBuilder);
158
+ #userManagementService = inject(YuvUserManagementService);
159
+ #dialogRef = inject((MatDialogRef));
160
+ #translateService = inject(TranslateService);
161
+ #logger = inject(Logger);
162
+ busy = signal(false);
163
+ error = signal(undefined);
164
+ username = new FormControl('', [Validators.required, Validators.minLength(3), Validators.maxLength(255), Validators.pattern('^[a-zA-Z0-9._-]*$')]);
165
+ email = new FormControl('', [Validators.required, Validators.email]);
166
+ firstname = new FormControl('', [Validators.minLength(1), Validators.maxLength(255), Validators.pattern("^[^#!<>&/%=;*§$()[\\]{}]*$")]);
167
+ lastname = new FormControl('', [Validators.minLength(1), Validators.maxLength(255), Validators.pattern("^[^#!<>&/%=;*§$()[\\]{}]*$")]);
168
+ enabled = new FormControl(true, []);
169
+ form = this.#fb.group({
170
+ username: this.username,
171
+ email: this.email,
172
+ firstname: this.firstname,
173
+ lastname: this.lastname,
174
+ enabled: this.enabled
175
+ });
176
+ changedInput = signal(undefined);
177
+ disabledSubmit = linkedSignal({
178
+ source: this.changedInput,
179
+ computation: () => {
180
+ return this.busy() || this.form.invalid;
181
+ }
182
+ });
183
+ createUser() {
184
+ let createdUserId;
185
+ const createParams = this.form.value;
186
+ this.busy.set(true);
187
+ this.error.set(undefined);
188
+ const createUserRequest = {
189
+ username: createParams.username,
190
+ email: createParams.email,
191
+ firstName: createParams.firstname ? createParams.firstname : null,
192
+ lastName: createParams.lastname ? createParams.lastname : null,
193
+ enabled: createParams.enabled,
194
+ roles: ["YUUVIS_DEFAULT"]
195
+ };
196
+ this.#userManagementService
197
+ .createUser(createUserRequest, true)
198
+ .subscribe({
199
+ error: (e) => {
200
+ switch (e.status) {
201
+ case 409: {
202
+ const errorMsg = JSON.parse(e.error).message;
203
+ if (errorMsg === "User exists with same username") {
204
+ this.error.set(this.#translateService.instant("yuv.app.user-management.users.action.create.error.usernameExists"));
205
+ }
206
+ else if (errorMsg === "User exists with same email") {
207
+ this.error.set(this.#translateService.instant("yuv.app.user-management.users.action.create.error.emailExists"));
208
+ }
209
+ else {
210
+ this.error.set(this.#translateService.instant("yuv.app.user-management.users.action.create.error.unknown"));
211
+ }
212
+ break;
213
+ }
214
+ default:
215
+ this.error.set(this.#translateService.instant("yuv.app.user-management.users.action.create.error.unknown"));
216
+ }
217
+ this.#logger.error(`Failed to create user with username ${createUserRequest.username}`, e);
218
+ this.busy.set(false);
219
+ },
220
+ next: (userId) => {
221
+ createdUserId = userId;
222
+ },
223
+ complete: () => {
224
+ this.busy.set(false);
225
+ this.#dialogRef.close(createdUserId);
226
+ },
227
+ });
228
+ }
229
+ close() {
230
+ this.#dialogRef.close();
231
+ }
232
+ ngAfterViewInit() {
233
+ this.form.valueChanges.subscribe((value) => {
234
+ this.changedInput.set(value);
235
+ });
236
+ }
237
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CreateUserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
238
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: CreateUserComponent, isStandalone: true, selector: "ymusrmgmt-create-user", host: { properties: { "class.busy": "!busy()" } }, ngImport: i0, template: "<yuv-dialog [yuvBusyOverlay]=\"busy()\" [headertitel]=\"'yuv.app.user-management.users.action.create.label' | translate\">\n <main class=\"yuv-dialog-content\">\n <form [formGroup]=\"form\">\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.username\" | translate }}</mat-label>\n <input matInput [formControl]=\"username\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.email\" | translate}}</mat-label>\n <input matInput [formControl]=\"email\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.firstname\" | translate}}</mat-label>\n <input matInput [formControl]=\"firstname\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.lastname\" | translate}}</mat-label>\n <input matInput [formControl]=\"lastname\" type=\"text\"/>\n </mat-form-field>\n <div class=\"yuv-form-field\" id=\"enabledPropDiv\">\n <mat-slide-toggle formControlName=\"enabled\">\n {{ form.get('enabled')?.value ? ('yuv.app.user-management.users.object.property.enabled' | translate) : ('yuv.app.user-management.users.object.property.disabled' | translate) }}\n </mat-slide-toggle>\n </div>\n @if (error()) {\n <p class=\"error\">{{ error() }}</p>\n }\n </form>\n </main>\n <footer>\n <button ymtButton=\"secondary\" [disabled]=\"busy()\" (click)=\"close()\">\n {{ \"yuv.app.user-management.users.action.button.cancel\" | translate }}\n </button>\n <button ymtButton=\"primary\" [disabled]=\"disabledSubmit()\" (click)=\"createUser()\">\n {{ 'yuv.app.user-management.users.action.button.create' | translate }}\n </button>\n </footer>\n</yuv-dialog>\n", styles: [":host{display:block;position:relative}:host main form{padding:var(--ymt-spacing-m)}:host main form .yuv-form-field{width:100%;margin:var(--ymt-spacing-xs) 0}:host main form .error{color:var(--ymt-on-danger-container);background-color:var(--ymt-danger-container);padding:var(--ymt-spacing-m);border-radius:var(--ymt-corner-xs)}:host main form #enabledPropDiv{display:flex;justify-content:center;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i4.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: BusyOverlayDirective, selector: "[yuvBusyOverlay]", inputs: ["yuvBusyOverlay", "yuvBusyOverlayConfig"] }, { kind: "directive", type: YmtButtonDirective, selector: "button[ymtButton], a[ymtButton]", inputs: ["ymtButton", "disabled", "aria-disabled", "disableRipple", "disabledInteractive", "button-size"] }, { kind: "component", type: DialogComponent, selector: "yuv-dialog", inputs: ["headertitel"] }] });
239
+ }
240
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CreateUserComponent, decorators: [{
241
+ type: Component,
242
+ args: [{ selector: 'ymusrmgmt-create-user', standalone: true, imports: [...modules$1, ...components$1], host: {
243
+ '[class.busy]': '!busy()',
244
+ }, template: "<yuv-dialog [yuvBusyOverlay]=\"busy()\" [headertitel]=\"'yuv.app.user-management.users.action.create.label' | translate\">\n <main class=\"yuv-dialog-content\">\n <form [formGroup]=\"form\">\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.username\" | translate }}</mat-label>\n <input matInput [formControl]=\"username\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.email\" | translate}}</mat-label>\n <input matInput [formControl]=\"email\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.firstname\" | translate}}</mat-label>\n <input matInput [formControl]=\"firstname\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.lastname\" | translate}}</mat-label>\n <input matInput [formControl]=\"lastname\" type=\"text\"/>\n </mat-form-field>\n <div class=\"yuv-form-field\" id=\"enabledPropDiv\">\n <mat-slide-toggle formControlName=\"enabled\">\n {{ form.get('enabled')?.value ? ('yuv.app.user-management.users.object.property.enabled' | translate) : ('yuv.app.user-management.users.object.property.disabled' | translate) }}\n </mat-slide-toggle>\n </div>\n @if (error()) {\n <p class=\"error\">{{ error() }}</p>\n }\n </form>\n </main>\n <footer>\n <button ymtButton=\"secondary\" [disabled]=\"busy()\" (click)=\"close()\">\n {{ \"yuv.app.user-management.users.action.button.cancel\" | translate }}\n </button>\n <button ymtButton=\"primary\" [disabled]=\"disabledSubmit()\" (click)=\"createUser()\">\n {{ 'yuv.app.user-management.users.action.button.create' | translate }}\n </button>\n </footer>\n</yuv-dialog>\n", styles: [":host{display:block;position:relative}:host main form{padding:var(--ymt-spacing-m)}:host main form .yuv-form-field{width:100%;margin:var(--ymt-spacing-xs) 0}:host main form .error{color:var(--ymt-on-danger-container);background-color:var(--ymt-danger-container);padding:var(--ymt-spacing-m);border-radius:var(--ymt-corner-xs)}:host main form #enabledPropDiv{display:flex;justify-content:center;align-items:center}\n"] }]
245
+ }] });
246
+
247
+ const components = [BusyOverlayDirective, YmtButtonDirective, DialogComponent];
248
+ const modules = [
249
+ CommonModule,
250
+ ReactiveFormsModule,
251
+ TranslateModule,
252
+ MatFormFieldModule,
253
+ MatInputModule,
254
+ ];
255
+ class EditUserComponent {
256
+ data;
257
+ #fb = inject(FormBuilder);
258
+ #userManagementService = inject(YuvUserManagementService);
259
+ #dialogRef = inject((MatDialogRef));
260
+ #translateService = inject(TranslateService);
261
+ #logger = inject(Logger);
262
+ busy = signal(false);
263
+ error = signal(undefined);
264
+ username = new FormControl('');
265
+ email = new FormControl('', [Validators.required, Validators.email]);
266
+ firstName = new FormControl('', [Validators.minLength(1), Validators.maxLength(255), Validators.pattern("^[^#!<>&/%=;*§$()[\\]{}]*$")]);
267
+ lastName = new FormControl('', [Validators.minLength(1), Validators.maxLength(255), Validators.pattern("^[^#!<>&/%=;*§$()[\\]{}]*$")]);
268
+ form = this.#fb.group({
269
+ username: this.username,
270
+ email: this.email,
271
+ firstName: this.firstName,
272
+ lastName: this.lastName,
273
+ });
274
+ changedInput = signal(undefined);
275
+ disabledSubmit = linkedSignal({
276
+ source: this.changedInput,
277
+ computation: () => {
278
+ return this.busy() || this.form.invalid || !this.isDataChanged();
279
+ }
280
+ });
281
+ constructor(data) {
282
+ this.data = data;
283
+ this.form.patchValue({
284
+ username: this.data.user.username,
285
+ firstName: this.data.user.firstName,
286
+ lastName: this.data.user.lastName,
287
+ email: this.data.user.email
288
+ });
289
+ }
290
+ ngAfterViewInit() {
291
+ this.form.valueChanges.subscribe((value) => {
292
+ this.changedInput.set(value);
293
+ });
294
+ }
295
+ isDataChanged() {
296
+ const isDataUnchanged = Object.keys(this.form.value).every((key) => this.isEquals(key));
297
+ return !isDataUnchanged;
298
+ }
299
+ isEquals(key) {
300
+ const oldVal = this.data.user?.[key];
301
+ const newVal = this.form.get(key)?.value;
302
+ return oldVal === newVal;
303
+ }
304
+ editUser() {
305
+ const editParams = this.form.value;
306
+ this.busy.set(true);
307
+ this.error.set(undefined);
308
+ const updateUserRequest = {
309
+ email: editParams.email,
310
+ firstName: editParams.firstName ? editParams.firstName : null,
311
+ lastName: editParams.lastName ? editParams.lastName : null
312
+ };
313
+ this.#userManagementService
314
+ .editUser(this.data.user.id, updateUserRequest)
315
+ .subscribe({
316
+ error: (e) => {
317
+ switch (e.status) {
318
+ case 409: {
319
+ this.error.set(this.#translateService.instant("yuv.app.user-management.users.action.create.error.emailExists"));
320
+ break;
321
+ }
322
+ default:
323
+ this.error.set(this.#translateService.instant("yuv.app.user-management.users.action.edit.error.unknown"));
324
+ }
325
+ this.#logger.error(`Failed to update user with id ${this.data.user.id}`, e);
326
+ this.busy.set(false);
327
+ },
328
+ complete: () => {
329
+ this.busy.set(false);
330
+ this.#dialogRef.close(this.data.user.id);
331
+ },
332
+ });
333
+ }
334
+ close() {
335
+ this.#dialogRef.close();
336
+ }
337
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: EditUserComponent, deps: [{ token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
338
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: EditUserComponent, isStandalone: true, selector: "ymusrmgmt-edit-user", host: { properties: { "class.busy": "!busy()" } }, ngImport: i0, template: "<yuv-dialog [yuvBusyOverlay]=\"busy()\" [headertitel]=\"'yuv.app.user-management.users.action.edit.label' | translate\">\n <main class=\"yuv-dialog-content\">\n <form [formGroup]=\"form\">\n <mat-form-field class=\"yuv-form-field readonly-field\">\n <mat-label class=\"readonly-label\">{{\"yuv.app.user-management.users.object.property.username\" | translate }}</mat-label>\n <input matInput [formControl]=\"username\" type=\"text\" [attr.tabindex]=\"-1\" readonly/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.email\" | translate}}</mat-label>\n <input matInput [formControl]=\"email\" type=\"text\" #emailField/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.firstname\" | translate}}</mat-label>\n <input matInput [formControl]=\"firstName\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.lastname\" | translate}}</mat-label>\n <input matInput [formControl]=\"lastName\" type=\"text\"/>\n </mat-form-field>\n @if (error()) {\n <p class=\"error\">{{ error() }}</p>\n }\n </form>\n </main>\n <footer>\n <button ymtButton=\"secondary\" [disabled]=\"busy()\" (click)=\"close()\">\n {{ \"yuv.app.user-management.users.action.button.cancel\" | translate }}\n </button>\n <button ymtButton=\"primary\" [disabled]=\"disabledSubmit()\" (click)=\"editUser()\">\n {{ 'yuv.app.user-management.users.action.button.save' | translate }}\n </button>\n </footer>\n</yuv-dialog>\n", styles: [":host{display:block;position:relative}:host main form{padding:var(--ymt-spacing-m)}:host main form .yuv-form-field{width:100%;margin:var(--ymt-spacing-xs) 0}:host main form .readonly-field{opacity:.5;pointer-events:none}:host main form .readonly-label{pointer-events:none}:host main form .error{color:var(--ymt-on-danger-container);background-color:var(--ymt-danger-container);padding:var(--ymt-spacing-m);border-radius:var(--ymt-corner-xs)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: BusyOverlayDirective, selector: "[yuvBusyOverlay]", inputs: ["yuvBusyOverlay", "yuvBusyOverlayConfig"] }, { kind: "directive", type: YmtButtonDirective, selector: "button[ymtButton], a[ymtButton]", inputs: ["ymtButton", "disabled", "aria-disabled", "disableRipple", "disabledInteractive", "button-size"] }, { kind: "component", type: DialogComponent, selector: "yuv-dialog", inputs: ["headertitel"] }] });
339
+ }
340
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: EditUserComponent, decorators: [{
341
+ type: Component,
342
+ args: [{ selector: 'ymusrmgmt-edit-user', standalone: true, imports: [...modules, ...components], host: {
343
+ '[class.busy]': '!busy()',
344
+ }, template: "<yuv-dialog [yuvBusyOverlay]=\"busy()\" [headertitel]=\"'yuv.app.user-management.users.action.edit.label' | translate\">\n <main class=\"yuv-dialog-content\">\n <form [formGroup]=\"form\">\n <mat-form-field class=\"yuv-form-field readonly-field\">\n <mat-label class=\"readonly-label\">{{\"yuv.app.user-management.users.object.property.username\" | translate }}</mat-label>\n <input matInput [formControl]=\"username\" type=\"text\" [attr.tabindex]=\"-1\" readonly/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.email\" | translate}}</mat-label>\n <input matInput [formControl]=\"email\" type=\"text\" #emailField/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.firstname\" | translate}}</mat-label>\n <input matInput [formControl]=\"firstName\" type=\"text\"/>\n </mat-form-field>\n <mat-form-field class=\"yuv-form-field\">\n <mat-label>{{\"yuv.app.user-management.users.object.property.lastname\" | translate}}</mat-label>\n <input matInput [formControl]=\"lastName\" type=\"text\"/>\n </mat-form-field>\n @if (error()) {\n <p class=\"error\">{{ error() }}</p>\n }\n </form>\n </main>\n <footer>\n <button ymtButton=\"secondary\" [disabled]=\"busy()\" (click)=\"close()\">\n {{ \"yuv.app.user-management.users.action.button.cancel\" | translate }}\n </button>\n <button ymtButton=\"primary\" [disabled]=\"disabledSubmit()\" (click)=\"editUser()\">\n {{ 'yuv.app.user-management.users.action.button.save' | translate }}\n </button>\n </footer>\n</yuv-dialog>\n", styles: [":host{display:block;position:relative}:host main form{padding:var(--ymt-spacing-m)}:host main form .yuv-form-field{width:100%;margin:var(--ymt-spacing-xs) 0}:host main form .readonly-field{opacity:.5;pointer-events:none}:host main form .readonly-label{pointer-events:none}:host main form .error{color:var(--ymt-on-danger-container);background-color:var(--ymt-danger-container);padding:var(--ymt-spacing-m);border-radius:var(--ymt-corner-xs)}\n"] }]
345
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
346
+ type: Inject,
347
+ args: [MAT_DIALOG_DATA]
348
+ }] }] });
349
+
350
+ class UserDetailsComponent {
351
+ userService;
352
+ formBuilder;
353
+ userDetails = signal(undefined);
354
+ userDetailsForm;
355
+ currentUserId;
356
+ set userId(value) {
357
+ this.currentUserId = value;
358
+ this.loadUserDetails();
359
+ }
360
+ loadUserDetails() {
361
+ if (this.currentUserId) {
362
+ this.userService.getUserDetails(this.currentUserId).subscribe(user => {
363
+ this.userDetails.set(user);
364
+ this.userDetailsForm.patchValue({
365
+ id: user.id,
366
+ username: user.username,
367
+ firstName: user.firstName,
368
+ lastName: user.lastName,
369
+ email: user.email,
370
+ enabled: user.enabled
371
+ });
372
+ });
373
+ }
374
+ else {
375
+ this.userDetails.set(undefined);
376
+ }
377
+ }
378
+ /**
379
+ * Refresh the user details by reloading the data from the server
380
+ */
381
+ refresh() {
382
+ this.loadUserDetails();
383
+ }
384
+ constructor(userService, formBuilder) {
385
+ this.userService = userService;
386
+ this.formBuilder = formBuilder;
387
+ this.userDetailsForm = this.formBuilder.group({
388
+ id: [{ value: '' }],
389
+ username: [{ value: '' }],
390
+ firstName: [{ value: '' }],
391
+ lastName: [{ value: '' }],
392
+ email: [{ value: '' }],
393
+ enabled: [{ value: false, disabled: true }]
394
+ });
395
+ }
396
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: UserDetailsComponent, deps: [{ token: YuvUserManagementService }, { token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
397
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: UserDetailsComponent, isStandalone: true, selector: "ymusrmgmt-user-details", inputs: { userId: "userId" }, ngImport: i0, template: " \n <mat-tab-group>\n <mat-tab>\n <ng-template mat-tab-label>\n <mat-icon>person</mat-icon>\n {{('yuv.app.user-management.users.details.title' | translate)}}\n </ng-template>\n <mat-card class=\"user-details-card\">\n <mat-card-content>\n @let currentUserDetails = userDetails();\n @if (currentUserDetails) {\n <form [formGroup]=\"userDetailsForm\" class=\"user-details-form\">\n <mat-form-field appearance=\"outline\">\n <mat-label>{{('yuv.app.user-management.users.object.property.id' | translate)}}</mat-label>\n <input matInput formControlName=\"id\" readonly>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.username' | translate)}}</mat-label>\n <input matInput formControlName=\"username\" readonly>\n <mat-icon matPrefix>account_box</mat-icon>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.email' | translate)}}</mat-label>\n <input matInput formControlName=\"email\" readonly>\n <mat-icon matPrefix>email</mat-icon>\n </mat-form-field> \n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.firstname' | translate)}}</mat-label>\n <input matInput formControlName=\"firstName\" readonly>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.lastname' | translate)}}</mat-label>\n <input matInput formControlName=\"lastName\" readonly>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.groups' | translate)}}</mat-label>\n <mat-chip-grid #groupChipGrid>\n @if (currentUserDetails.groups) {\n @for (group of currentUserDetails.groups.sort(); track group) {\n <mat-chip-row [editable]=\"false\"><div class=\"chip\">{{group}}</div></mat-chip-row>\n }\n }\n <input [matChipInputFor]=\"groupChipGrid\" readonly/>\n </mat-chip-grid>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.roles' | translate)}}</mat-label>\n <mat-chip-grid #roleChipGrid>\n @if (currentUserDetails.roles) {\n @for (role of currentUserDetails.roles.sort(); track role) {\n <mat-chip-row [editable]=\"false\"><div class=\"chip\">{{role}}</div></mat-chip-row>\n }\n }\n <input [matChipInputFor]=\"roleChipGrid\" readonly/>\n </mat-chip-grid>\n </mat-form-field>\n <mat-slide-toggle formControlName=\"enabled\">\n {{ userDetailsForm.get('enabled')?.value ? ('yuv.app.user-management.users.object.property.enabled' | translate) :\n ('yuv.app.user-management.users.object.property.disabled' | translate) }}\n </mat-slide-toggle> \n </form>\n } @else {\n <p>{{('yuv.app.user-management.users.details.empty' | translate)}}</p>\n }\n </mat-card-content>\n </mat-card>\n </mat-tab>\n </mat-tab-group>", styles: [":host{height:100%;overflow:hidden;display:flex;flex-flow:column}:host .user-details-card{margin:var(--ymt-spacing-m)}:host .user-details-form{display:grid;gap:var(--ymt-spacing-m)}:host .user-details-form mat-chip-row{overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$1.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i4$1.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i4$1.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: i4$1.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i4.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "directive", type: i9.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i9.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i9.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
398
+ }
399
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: UserDetailsComponent, decorators: [{
400
+ type: Component,
401
+ args: [{ selector: 'ymusrmgmt-user-details', imports: [
402
+ MatCardModule,
403
+ MatChipsModule,
404
+ MatFormFieldModule,
405
+ MatInputModule,
406
+ MatIconModule,
407
+ MatCheckboxModule,
408
+ MatSlideToggleModule,
409
+ MatTabsModule,
410
+ ReactiveFormsModule,
411
+ TranslateModule
412
+ ], template: " \n <mat-tab-group>\n <mat-tab>\n <ng-template mat-tab-label>\n <mat-icon>person</mat-icon>\n {{('yuv.app.user-management.users.details.title' | translate)}}\n </ng-template>\n <mat-card class=\"user-details-card\">\n <mat-card-content>\n @let currentUserDetails = userDetails();\n @if (currentUserDetails) {\n <form [formGroup]=\"userDetailsForm\" class=\"user-details-form\">\n <mat-form-field appearance=\"outline\">\n <mat-label>{{('yuv.app.user-management.users.object.property.id' | translate)}}</mat-label>\n <input matInput formControlName=\"id\" readonly>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.username' | translate)}}</mat-label>\n <input matInput formControlName=\"username\" readonly>\n <mat-icon matPrefix>account_box</mat-icon>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.email' | translate)}}</mat-label>\n <input matInput formControlName=\"email\" readonly>\n <mat-icon matPrefix>email</mat-icon>\n </mat-form-field> \n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.firstname' | translate)}}</mat-label>\n <input matInput formControlName=\"firstName\" readonly>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.lastname' | translate)}}</mat-label>\n <input matInput formControlName=\"lastName\" readonly>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.groups' | translate)}}</mat-label>\n <mat-chip-grid #groupChipGrid>\n @if (currentUserDetails.groups) {\n @for (group of currentUserDetails.groups.sort(); track group) {\n <mat-chip-row [editable]=\"false\"><div class=\"chip\">{{group}}</div></mat-chip-row>\n }\n }\n <input [matChipInputFor]=\"groupChipGrid\" readonly/>\n </mat-chip-grid>\n </mat-form-field>\n <mat-form-field>\n <mat-label>{{('yuv.app.user-management.users.object.property.roles' | translate)}}</mat-label>\n <mat-chip-grid #roleChipGrid>\n @if (currentUserDetails.roles) {\n @for (role of currentUserDetails.roles.sort(); track role) {\n <mat-chip-row [editable]=\"false\"><div class=\"chip\">{{role}}</div></mat-chip-row>\n }\n }\n <input [matChipInputFor]=\"roleChipGrid\" readonly/>\n </mat-chip-grid>\n </mat-form-field>\n <mat-slide-toggle formControlName=\"enabled\">\n {{ userDetailsForm.get('enabled')?.value ? ('yuv.app.user-management.users.object.property.enabled' | translate) :\n ('yuv.app.user-management.users.object.property.disabled' | translate) }}\n </mat-slide-toggle> \n </form>\n } @else {\n <p>{{('yuv.app.user-management.users.details.empty' | translate)}}</p>\n }\n </mat-card-content>\n </mat-card>\n </mat-tab>\n </mat-tab-group>", styles: [":host{height:100%;overflow:hidden;display:flex;flex-flow:column}:host .user-details-card{margin:var(--ymt-spacing-m)}:host .user-details-form{display:grid;gap:var(--ymt-spacing-m)}:host .user-details-form mat-chip-row{overflow:hidden}\n"] }]
413
+ }], ctorParameters: () => [{ type: YuvUserManagementService }, { type: i1$1.FormBuilder }], propDecorators: { userId: [{
414
+ type: Input
415
+ }] } });
416
+
417
+ class YuvUsersPageComponent {
418
+ layoutSettingsID = APP_ID + '#root.layout.settings';
419
+ #logger = inject(Logger);
420
+ #userManagementService = inject(YuvUserManagementService);
421
+ #translateService = inject(TranslateService);
422
+ #dialog = inject(MatDialog);
423
+ #notificationService = inject(NotificationService);
424
+ #userService = inject(UserService);
425
+ #confirmService = inject(ConfirmService);
426
+ userDetailsComponent;
427
+ actions = [];
428
+ pagination;
429
+ busy = signal(false);
430
+ displayedColumns = ['state', 'name', 'firstName', 'lastName', 'email', 'id'];
431
+ icons = {
432
+ ...APP_ICONS,
433
+ };
434
+ dataSource = signal([]);
435
+ selection = signal(new SelectionModel(false, undefined));
436
+ enableDetails = signal(false);
437
+ layoutOptions = signal({
438
+ masterSize: 80,
439
+ detailsSize: 20,
440
+ });
441
+ #query = { term: '' };
442
+ #updateActions(selectedUser) {
443
+ if (!selectedUser) {
444
+ this.actions = [];
445
+ return;
446
+ }
447
+ const currentUser = this.#userService.getCurrentUser();
448
+ const editAction = {
449
+ id: 'yuv.app.users.action.edit',
450
+ icon: APP_ICONS.actionEditUser,
451
+ label: this.#translateService.instant('yuv.app.user-management.users.action.edit.label'),
452
+ callback: () => this.editSelectedUser(),
453
+ };
454
+ const activateAction = {
455
+ id: 'yuv.app.users.action.activate',
456
+ icon: APP_ICONS.actionActivateUser,
457
+ label: this.#translateService.instant('yuv.app.user-management.users.action.activate.label'),
458
+ disabled: selectedUser.id === currentUser.id || selectedUser.enabled,
459
+ callback: () => this.activateSelectedUser(),
460
+ };
461
+ const deactivateAction = {
462
+ id: 'yuv.app.users.action.deactivate',
463
+ icon: APP_ICONS.actionDeactivateUser,
464
+ label: this.#translateService.instant('yuv.app.user-management.users.action.deactivate.label'),
465
+ disabled: selectedUser.id === currentUser.id || !selectedUser.enabled,
466
+ callback: () => this.deactivateSelectedUser(),
467
+ };
468
+ const deleteAction = {
469
+ id: 'yuv.app.users.action.delete',
470
+ icon: APP_ICONS.actionDeleteUser,
471
+ label: this.#translateService.instant('yuv.app.user-management.users.action.delete.label'),
472
+ disabled: selectedUser.id === currentUser.id,
473
+ callback: () => this.deleteSelectedUser(),
474
+ };
475
+ this.actions = [editAction, activateAction, deactivateAction, deleteAction];
476
+ }
477
+ createNewUser() {
478
+ this.#logger.debug('Create new user ...');
479
+ this.#dialog.open(CreateUserComponent, {
480
+ width: '400px',
481
+ maxWidth: '90vw',
482
+ }).afterClosed().subscribe((createdUserId) => {
483
+ if (createdUserId) {
484
+ this.#logger.debug("New user created with ID: " + createdUserId);
485
+ this.#notificationService.success(this.#translateService.instant('yuv.app.user-management.users.action.create.success'));
486
+ this.refresh();
487
+ }
488
+ });
489
+ }
490
+ editSelectedUser() {
491
+ const selected = this.selection().hasValue() ? this.selection().selected[0] : undefined;
492
+ if (selected) {
493
+ this.#logger.debug(`Edit selected user with id '${selected.id}'...`);
494
+ this.#dialog.open(EditUserComponent, {
495
+ width: '600px',
496
+ maxWidth: '90vw',
497
+ data: {
498
+ user: selected
499
+ },
500
+ }).afterClosed().subscribe((editedUserId) => {
501
+ if (editedUserId) {
502
+ this.#logger.debug("User edited with ID: " + editedUserId);
503
+ this.#notificationService.success(this.#translateService.instant('yuv.app.user-management.users.action.edit.success', { username: selected.username }));
504
+ this.refresh();
505
+ }
506
+ });
507
+ }
508
+ }
509
+ activateSelectedUser() {
510
+ this.updateUserEnabledState(true);
511
+ }
512
+ deactivateSelectedUser() {
513
+ this.updateUserEnabledState(false);
514
+ }
515
+ updateUserEnabledState(enabled) {
516
+ const selected = this.selection().hasValue() ? this.selection().selected[0] : undefined;
517
+ if (!selected)
518
+ return;
519
+ const action = enabled ? 'activate' : 'deactivate';
520
+ const updateUserRequest = { enabled };
521
+ const performUpdate = () => {
522
+ this.busy.set(true);
523
+ this.#userManagementService.editUser(selected.id, updateUserRequest).subscribe({
524
+ error: (e) => {
525
+ this.#notificationService.error(this.#translateService.instant(`yuv.app.user-management.users.action.${action}.error`, { username: selected.username }));
526
+ this.#logger.error(`Failed to ${action} user with id ${selected.id}`, e);
527
+ this.busy.set(false);
528
+ },
529
+ complete: () => {
530
+ this.#notificationService.success(this.#translateService.instant(`yuv.app.user-management.users.action.${action}.success`, { username: selected.username }));
531
+ this.busy.set(false);
532
+ this.refresh();
533
+ },
534
+ });
535
+ };
536
+ if (!enabled) {
537
+ this.#confirmService
538
+ .confirm({
539
+ title: this.#translateService.instant('yuv.app.user-management.users.action.deactivate.label'),
540
+ message: this.#translateService.instant('yuv.app.user-management.users.action.deactivate.confirm.message', { username: selected.username }),
541
+ })
542
+ .subscribe({
543
+ next: (confirmed) => {
544
+ if (confirmed) {
545
+ performUpdate();
546
+ }
547
+ }
548
+ });
549
+ }
550
+ else {
551
+ performUpdate();
552
+ }
553
+ }
554
+ deleteSelectedUser() {
555
+ const selected = this.selection().hasValue() ? this.selection().selected[0] : undefined;
556
+ if (selected) {
557
+ this.#logger.debug(`Delete selected user with id '${selected.id}'...`);
558
+ this.#userManagementService.deleteUser(selected).subscribe({
559
+ next: (result) => {
560
+ if (result) {
561
+ this.#notificationService.success(this.#translateService.instant('yuv.app.user-management.users.action.delete.success', { username: selected.username }));
562
+ this.deselect();
563
+ this.refresh();
564
+ }
565
+ },
566
+ error: (e) => {
567
+ this.#logger.error(`Failed to delete user with id '${selected.id}'`, e);
568
+ this.#notificationService.error(this.#translateService.instant('yuv.app.user-management.users.action.delete.error', { username: selected.username }));
569
+ }
570
+ });
571
+ }
572
+ }
573
+ select(row) {
574
+ if (this.selection().isSelected(row)) {
575
+ this.deselect();
576
+ }
577
+ else {
578
+ this.selection().select(row);
579
+ this.#updateActions(row);
580
+ }
581
+ this.enableDetails.set(true);
582
+ }
583
+ deselect() {
584
+ this.selection().clear();
585
+ this.#updateActions(undefined);
586
+ }
587
+ isSelected(row) {
588
+ return this.selection().selected?.some(item => item.id === row.id);
589
+ }
590
+ refresh() {
591
+ this.#loadUserList(this.pagination?.page || 0);
592
+ }
593
+ refreshUserDetails() {
594
+ if (this.userDetailsComponent) {
595
+ this.userDetailsComponent.refresh();
596
+ }
597
+ }
598
+ getPageSize() {
599
+ return YuvUserManagementService.DEFAULT_PAGE_SIZE;
600
+ }
601
+ onChangePage($event) {
602
+ const { pageIndex } = $event;
603
+ this.#loadUserList(pageIndex);
604
+ }
605
+ onQueryChange(q) {
606
+ this.#query.term = q.term || '';
607
+ this.#loadUserList(0);
608
+ }
609
+ ngOnInit() {
610
+ this.#loadUserList(0);
611
+ }
612
+ #loadUserList(page) {
613
+ this.busy.set(true);
614
+ this.#userManagementService.fetchUsers(page, this.#query.term).subscribe({
615
+ next: (response) => {
616
+ console.log(`fetched users: ${response}`);
617
+ this.dataSource.set(response.objects);
618
+ this.pagination = (response.totalNumItems > YuvUserManagementService.DEFAULT_PAGE_SIZE)
619
+ ? {
620
+ total: response.totalNumItems,
621
+ pages: Math.ceil(response.totalNumItems / YuvUserManagementService.DEFAULT_PAGE_SIZE),
622
+ page: page
623
+ } : undefined;
624
+ },
625
+ error: (e) => {
626
+ this.#logger.error('Failed to fetch users', e);
627
+ this.busy.set(false);
628
+ },
629
+ complete: () => {
630
+ const selected = this.selection().hasValue() ? this.selection().selected[0] : undefined;
631
+ if (selected) {
632
+ if (this.dataSource().some(u => u.id === selected.id)) {
633
+ const updatedSelected = this.dataSource().find(u => u.id === selected.id);
634
+ this.select(updatedSelected);
635
+ }
636
+ else {
637
+ this.#userManagementService.getUserDetails(selected.id).subscribe({
638
+ next: (user) => {
639
+ this.select(user);
640
+ },
641
+ error: (e) => {
642
+ this.#logger.error(`Failed to fetch data for selected user with id '${selected.id}'. Deselecting user...`, e);
643
+ this.deselect();
644
+ }
645
+ });
646
+ }
647
+ this.refreshUserDetails();
648
+ }
649
+ else {
650
+ this.deselect();
651
+ }
652
+ this.busy.set(false);
653
+ },
654
+ });
655
+ }
656
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: YuvUsersPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
657
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: YuvUsersPageComponent, isStandalone: true, selector: "ymusrmgmt-users", host: { properties: { "class.busy": "!busy()", "class.pagination": "this.pagination" } }, viewQueries: [{ propertyName: "userDetailsComponent", first: true, predicate: UserDetailsComponent, descendants: true }], ngImport: i0, template: "<ng-template yuvAppHeaderSlot=\"actions\">\n</ng-template>\n\n<ng-template yuvAppHeaderSlot=\"search\">\n <yuv-simple-search (queryChange)=\"onQueryChange($event)\"></yuv-simple-search>\n</ng-template>\n\n<header>\n <nav [attr.aria-label]=\"'yuv.app.user-management.users.naviagtion.aria.label' | translate\">\n <div class=\"primary-actions\">\n <button mat-mini-fab (click)=\"createNewUser()\" [matTooltip]=\"'yuv.app.user-management.users.navigation.add-user.tooltip' | translate\">\n <mat-icon>{{icons.actionCreateNewUser}}</mat-icon> \n </button>\n </div>\n <div class=\"user-actions\">\n <yuv-overflow-menu [menuItems]=\"actions\"></yuv-overflow-menu>\n </div>\n <div class=\"secondary-actions\">\n <button mat-icon-button (click)=\"enableDetails.set(!enableDetails())\" [matTooltip]=\"enableDetails() ? ('yuv.app.user-management.users.navigation.hidedetails.tooltip' | translate) : ('yuv.app.user-management.users.navigation.showdetails.tooltip' | translate)\" [ngClass]=\"{ enabled: enableDetails() }\">\n <mat-icon>dock_to_left</mat-icon>\n </button>\n <button mat-icon-button (click)=\"refresh()\" [matTooltip]=\"'yuv.app.user-management.users.navigation.refresh.tooltip' | translate\">\n <mat-icon>{{icons.refresh}}</mat-icon>\n </button>\n </div>\n </nav>\n</header>\n\n<main [yuvBusyOverlay]=\"busy()\">\n <yuv-master-details\n [gutterSize]=\"1\"\n [detailsActive]=\"enableDetails()\"\n [layoutOptions]=\"layoutOptions()\"\n [layoutSettingsID]=\"layoutSettingsID\"\n [mode]=\"'aside'\">\n\n <ng-template #yuvMasterPane>\n <div class=\"masterPaneContainer\">\n <mat-table [dataSource]=\"dataSource()\" class=\"user-table mat-elevation-z8\" row>\n <ng-container matColumnDef=\"state\">\n <mat-header-cell *matHeaderCellDef />\n <mat-cell *matCellDef=\"let element\"><mat-icon>{{ element.enabled ? icons.stateActive : icons.stateInactive\n }}</mat-icon></mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"name\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.username' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.username}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"firstName\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.firstname' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.firstName}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"lastName\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.lastname' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.lastName}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"email\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.email' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.email}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"id\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.id' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.id}} </mat-cell>\n </ng-container>\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row \n *matRowDef=\"let row; columns: displayedColumns;\" \n (click.single)=\"select(row)\" \n [class.selected-row]=\"this.isSelected(row)\" class=\"user-row\">\n </mat-row>\n </mat-table>\n\n @if (pagination) {\n <mat-paginator class=\"paginator\" [length]=\"pagination.total\" [pageSize]=\"getPageSize()\" aria-label=\"Select page\"\n (page)=\"onChangePage($event)\" hidePageSize></mat-paginator>\n }\n </div>\n\n <ng-template #yuvDetailsPane>\n <div class=\"detailsPaneContainer\">\n <ymusrmgmt-user-details #userDetails [userId]=\"selection().selected.at(0)?.id\" />\n </div>\n </ng-template>\n\n </ng-template>\n </yuv-master-details>\n</main>", styles: [":host{--mat-table-row-item-outline-color: var(--ymt-outline-variant);--split-gutter-background-color: var(--ymt-outline-variant);height:100%;overflow:hidden;display:flex;flex-flow:column}:host header{flex:0 0 auto}:host header>nav{flex:0 0 auto;border-block-end:1px solid var(--ymt-outline-variant);display:grid;grid-template-columns:auto 1fr auto;grid-template-areas:\"primary actions sort secondary\";align-items:center;gap:var(--ymt-spacing-xs);padding:var(--ymt-spacing-xs);min-height:40px;position:relative}:host header>nav .primary-actions{grid-area:primary;overflow-x:auto;border-color:var(--ymt-outline-variant);border-width:0 1px 0 0;border-style:solid;padding-right:10px}:host header>nav .secondary-actions{grid-area:secondary;overflow-x:auto;border-color:var(--ymt-outline-variant);border-width:0 0 0 1px;border-style:solid;padding-left:10px}:host main{height:100%;overflow:hidden;background-color:var(--ymt-surface);display:flex;flex-flow:column}:host main yuv-master-details{height:100%}:host main .user-table{overflow:auto;height:100%}:host main .masterPaneContainer{display:flex;flex-direction:column;height:100%;overflow:hidden}:host main .detailsPaneContainer{display:flex;flex-direction:column;height:100%;overflow:auto}:host .user-row:hover{background-color:var(--ymt-hover-background)}:host .selected-row{background-color:var(--ymt-selection-background)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i6.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "component", type: SimpleSearchComponent, selector: "yuv-simple-search", inputs: ["query"], outputs: ["querySubmit", "clearInput", "targetSelectionChanged", "queryChange", "typeAggregation"] }, { kind: "ngmodule", type: YuvClientShellModule }, { kind: "directive", type: i8.YuvAppHeaderSlotDirective, selector: "ng-template[yuvAppHeaderSlot]", inputs: ["yuvAppHeaderSlot"] }, { kind: "ngmodule", type: YuvMasterDetailsModule }, { kind: "component", type: i9$1.YuvMasterDetailsComponent, selector: "yuv-master-details", inputs: ["detailsActive", "layoutSettingsID", "layoutOptions", "undockableDetails", "panelStyle", "gutterSize", "mode"], outputs: ["detailsActiveChange"] }, { kind: "directive", type: BusyOverlayDirective, selector: "[yuvBusyOverlay]", inputs: ["yuvBusyOverlay", "yuvBusyOverlayConfig"] }, { kind: "directive", type: ClickDoubleDirective, selector: "[click.single],[click.double]", inputs: ["debounceTime"], outputs: ["click.double", "click.single"] }, { kind: "component", type: UserDetailsComponent, selector: "ymusrmgmt-user-details", inputs: ["userId"] }, { kind: "ngmodule", type: YuvOverflowMenuModule }, { kind: "component", type: i10.OverflowMenuComponent, selector: "yuv-overflow-menu", inputs: ["overflowIcon", "groupLabels", "menuItems", "vertical"] }] });
658
+ }
659
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: YuvUsersPageComponent, decorators: [{
660
+ type: Component,
661
+ args: [{ selector: 'ymusrmgmt-users', standalone: true, imports: [
662
+ CommonModule,
663
+ MatButtonModule,
664
+ MatIconModule,
665
+ MatTooltipModule,
666
+ MatTableModule,
667
+ MatPaginatorModule,
668
+ MatSortModule,
669
+ RouterModule,
670
+ TranslateModule,
671
+ SimpleSearchComponent,
672
+ YuvClientShellModule,
673
+ YuvMasterDetailsModule,
674
+ BusyOverlayDirective,
675
+ ClickDoubleDirective,
676
+ UserDetailsComponent,
677
+ YuvClientShellModule,
678
+ YuvOverflowMenuModule
679
+ ], host: {
680
+ '[class.busy]': '!busy()',
681
+ }, template: "<ng-template yuvAppHeaderSlot=\"actions\">\n</ng-template>\n\n<ng-template yuvAppHeaderSlot=\"search\">\n <yuv-simple-search (queryChange)=\"onQueryChange($event)\"></yuv-simple-search>\n</ng-template>\n\n<header>\n <nav [attr.aria-label]=\"'yuv.app.user-management.users.naviagtion.aria.label' | translate\">\n <div class=\"primary-actions\">\n <button mat-mini-fab (click)=\"createNewUser()\" [matTooltip]=\"'yuv.app.user-management.users.navigation.add-user.tooltip' | translate\">\n <mat-icon>{{icons.actionCreateNewUser}}</mat-icon> \n </button>\n </div>\n <div class=\"user-actions\">\n <yuv-overflow-menu [menuItems]=\"actions\"></yuv-overflow-menu>\n </div>\n <div class=\"secondary-actions\">\n <button mat-icon-button (click)=\"enableDetails.set(!enableDetails())\" [matTooltip]=\"enableDetails() ? ('yuv.app.user-management.users.navigation.hidedetails.tooltip' | translate) : ('yuv.app.user-management.users.navigation.showdetails.tooltip' | translate)\" [ngClass]=\"{ enabled: enableDetails() }\">\n <mat-icon>dock_to_left</mat-icon>\n </button>\n <button mat-icon-button (click)=\"refresh()\" [matTooltip]=\"'yuv.app.user-management.users.navigation.refresh.tooltip' | translate\">\n <mat-icon>{{icons.refresh}}</mat-icon>\n </button>\n </div>\n </nav>\n</header>\n\n<main [yuvBusyOverlay]=\"busy()\">\n <yuv-master-details\n [gutterSize]=\"1\"\n [detailsActive]=\"enableDetails()\"\n [layoutOptions]=\"layoutOptions()\"\n [layoutSettingsID]=\"layoutSettingsID\"\n [mode]=\"'aside'\">\n\n <ng-template #yuvMasterPane>\n <div class=\"masterPaneContainer\">\n <mat-table [dataSource]=\"dataSource()\" class=\"user-table mat-elevation-z8\" row>\n <ng-container matColumnDef=\"state\">\n <mat-header-cell *matHeaderCellDef />\n <mat-cell *matCellDef=\"let element\"><mat-icon>{{ element.enabled ? icons.stateActive : icons.stateInactive\n }}</mat-icon></mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"name\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.username' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.username}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"firstName\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.firstname' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.firstName}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"lastName\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.lastname' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.lastName}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"email\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.email' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.email}} </mat-cell>\n </ng-container>\n <ng-container matColumnDef=\"id\">\n <mat-header-cell *matHeaderCellDef>{{'yuv.app.user-management.users.object.property.id' | translate\n }}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\"> {{element.id}} </mat-cell>\n </ng-container>\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row \n *matRowDef=\"let row; columns: displayedColumns;\" \n (click.single)=\"select(row)\" \n [class.selected-row]=\"this.isSelected(row)\" class=\"user-row\">\n </mat-row>\n </mat-table>\n\n @if (pagination) {\n <mat-paginator class=\"paginator\" [length]=\"pagination.total\" [pageSize]=\"getPageSize()\" aria-label=\"Select page\"\n (page)=\"onChangePage($event)\" hidePageSize></mat-paginator>\n }\n </div>\n\n <ng-template #yuvDetailsPane>\n <div class=\"detailsPaneContainer\">\n <ymusrmgmt-user-details #userDetails [userId]=\"selection().selected.at(0)?.id\" />\n </div>\n </ng-template>\n\n </ng-template>\n </yuv-master-details>\n</main>", styles: [":host{--mat-table-row-item-outline-color: var(--ymt-outline-variant);--split-gutter-background-color: var(--ymt-outline-variant);height:100%;overflow:hidden;display:flex;flex-flow:column}:host header{flex:0 0 auto}:host header>nav{flex:0 0 auto;border-block-end:1px solid var(--ymt-outline-variant);display:grid;grid-template-columns:auto 1fr auto;grid-template-areas:\"primary actions sort secondary\";align-items:center;gap:var(--ymt-spacing-xs);padding:var(--ymt-spacing-xs);min-height:40px;position:relative}:host header>nav .primary-actions{grid-area:primary;overflow-x:auto;border-color:var(--ymt-outline-variant);border-width:0 1px 0 0;border-style:solid;padding-right:10px}:host header>nav .secondary-actions{grid-area:secondary;overflow-x:auto;border-color:var(--ymt-outline-variant);border-width:0 0 0 1px;border-style:solid;padding-left:10px}:host main{height:100%;overflow:hidden;background-color:var(--ymt-surface);display:flex;flex-flow:column}:host main yuv-master-details{height:100%}:host main .user-table{overflow:auto;height:100%}:host main .masterPaneContainer{display:flex;flex-direction:column;height:100%;overflow:hidden}:host main .detailsPaneContainer{display:flex;flex-direction:column;height:100%;overflow:auto}:host .user-row:hover{background-color:var(--ymt-hover-background)}:host .selected-row{background-color:var(--ymt-selection-background)!important}\n"] }]
682
+ }], propDecorators: { userDetailsComponent: [{
683
+ type: ViewChild,
684
+ args: [UserDetailsComponent]
685
+ }], pagination: [{
686
+ type: HostBinding,
687
+ args: ['class.pagination']
688
+ }] } });
689
+
690
+ const YuvUserManagementRoutes = [
691
+ {
692
+ path: '',
693
+ component: YuvUserManagementComponent,
694
+ children: [
695
+ { path: 'users', component: YuvUsersPageComponent },
696
+ { path: '', redirectTo: 'users', pathMatch: 'full' }
697
+ ]
698
+ }
699
+ ];
700
+
701
+ /**
702
+ * Generated bundle index. Do not edit.
703
+ */
704
+
705
+ export { YuvUserManagementRoutes, YuvUserManagementService };
706
+ //# sourceMappingURL=yuuvis-user-management-app.mjs.map