@myrmidon/auth-jwt-admin 8.0.4 → 10.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.
|
@@ -1,36 +1,35 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, input, output, computed, effect, ChangeDetectionStrategy, Component, signal } from '@angular/core';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import { inject, Injectable, input, output, computed, effect, ChangeDetectionStrategy, Component, signal, resource } from '@angular/core';
|
|
3
|
+
import { form, required, email, validateAsync, pattern, maxLength, validate, FormField, FormRoot, disabled } from '@angular/forms/signals';
|
|
4
|
+
import { BehaviorSubject, tap, firstValueFrom } from 'rxjs';
|
|
5
5
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
6
|
-
import
|
|
7
|
-
import * as i3 from '@angular/material/form-field';
|
|
6
|
+
import * as i2 from '@angular/material/form-field';
|
|
8
7
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
9
|
-
import * as
|
|
8
|
+
import * as i1 from '@angular/material/button';
|
|
10
9
|
import { MatButtonModule } from '@angular/material/button';
|
|
11
|
-
import * as
|
|
10
|
+
import * as i3 from '@angular/material/icon';
|
|
12
11
|
import { MatIconModule } from '@angular/material/icon';
|
|
13
|
-
import * as
|
|
12
|
+
import * as i4 from '@angular/material/input';
|
|
14
13
|
import { MatInputModule } from '@angular/material/input';
|
|
15
|
-
import * as
|
|
14
|
+
import * as i5 from '@angular/material/progress-spinner';
|
|
16
15
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
17
16
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
17
|
+
import { retry, map, catchError } from 'rxjs/operators';
|
|
18
18
|
import { ErrorService, EnvService } from '@myrmidon/ngx-tools';
|
|
19
|
-
import { BehaviorSubject, tap } from 'rxjs';
|
|
20
19
|
import { PagedListStore } from '@myrmidon/paged-data-browsers';
|
|
21
|
-
import * as i6
|
|
20
|
+
import * as i6 from '@angular/material/tooltip';
|
|
22
21
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
23
22
|
import * as i4$1 from '@angular/material/paginator';
|
|
24
23
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
25
24
|
import * as i7 from '@angular/common';
|
|
26
25
|
import { CommonModule } from '@angular/common';
|
|
27
|
-
import * as i2$
|
|
26
|
+
import * as i2$2 from '@angular/material/expansion';
|
|
28
27
|
import { MatExpansionModule } from '@angular/material/expansion';
|
|
29
28
|
import * as i5$1 from '@angular/material/progress-bar';
|
|
30
29
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
31
30
|
import { AuthJwtService, GravatarService } from '@myrmidon/auth-jwt-login';
|
|
32
31
|
import { DialogService } from '@myrmidon/ngx-mat-tools';
|
|
33
|
-
import * as
|
|
32
|
+
import * as i2$1 from '@angular/material/checkbox';
|
|
34
33
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
35
34
|
|
|
36
35
|
/**
|
|
@@ -223,10 +222,10 @@ class AuthJwtAccountService {
|
|
|
223
222
|
.delete(this._env.get('apiUrl') + 'accounts/' + name)
|
|
224
223
|
.pipe(catchError(this._error.handleError));
|
|
225
224
|
}
|
|
226
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
227
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
225
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtAccountService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
226
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' }); }
|
|
228
227
|
}
|
|
229
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
228
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtAccountService, decorators: [{
|
|
230
229
|
type: Injectable,
|
|
231
230
|
args: [{
|
|
232
231
|
providedIn: 'root',
|
|
@@ -234,55 +233,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
234
233
|
}] });
|
|
235
234
|
|
|
236
235
|
/**
|
|
237
|
-
* Password validators
|
|
236
|
+
* Password validators as pure predicate functions returning Signal Forms
|
|
237
|
+
* compatible ValidationError objects ({ kind: string }).
|
|
238
238
|
*/
|
|
239
239
|
class PasswordValidators {
|
|
240
|
-
/** "Standard" password validator for my API services. */
|
|
241
240
|
static standard() {
|
|
242
|
-
return (
|
|
243
|
-
if (!
|
|
241
|
+
return (value) => {
|
|
242
|
+
if (!value)
|
|
244
243
|
return null;
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (!/.*[
|
|
252
|
-
return {
|
|
253
|
-
noupperinpassword: true,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
if (!/.*[a-z].*/.test(control.value)) {
|
|
257
|
-
return {
|
|
258
|
-
nolowerinpassword: true,
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
if (!/.*[A-Z].*/.test(control.value)) {
|
|
262
|
-
return {
|
|
263
|
-
noupperinpassword: true,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
if (!/.*[-`~!@#$%^&*()_+=\[\]{};:'",.<>/?|\\].*/.test(control.value)) {
|
|
267
|
-
return {
|
|
268
|
-
nosymbolinpassword: true,
|
|
269
|
-
};
|
|
270
|
-
}
|
|
244
|
+
if (value.length < 8)
|
|
245
|
+
return { kind: 'passwordtooshort' };
|
|
246
|
+
if (!/.*[A-Z].*/.test(value))
|
|
247
|
+
return { kind: 'noupperinpassword' };
|
|
248
|
+
if (!/.*[a-z].*/.test(value))
|
|
249
|
+
return { kind: 'nolowerinpassword' };
|
|
250
|
+
if (!/.*[-`~!@#$%^&*()_+=\[\]{};:'",.<>/?|\\].*/.test(value))
|
|
251
|
+
return { kind: 'nosymbolinpassword' };
|
|
271
252
|
return null;
|
|
272
253
|
};
|
|
273
254
|
}
|
|
274
|
-
static areEqual(controlName, otherControlName) {
|
|
275
|
-
return (control) => {
|
|
276
|
-
const g = control;
|
|
277
|
-
const a = g.controls[controlName];
|
|
278
|
-
const b = g.controls[otherControlName];
|
|
279
|
-
return a.value !== b.value
|
|
280
|
-
? {
|
|
281
|
-
areequal: true,
|
|
282
|
-
}
|
|
283
|
-
: null;
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
255
|
}
|
|
287
256
|
|
|
288
257
|
class UserListRepository {
|
|
@@ -398,10 +367,10 @@ class UserListRepository {
|
|
|
398
367
|
});
|
|
399
368
|
return promise;
|
|
400
369
|
}
|
|
401
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
402
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
370
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListRepository, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
371
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListRepository, providedIn: 'root' }); }
|
|
403
372
|
}
|
|
404
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
373
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListRepository, decorators: [{
|
|
405
374
|
type: Injectable,
|
|
406
375
|
args: [{ providedIn: 'root' }]
|
|
407
376
|
}], ctorParameters: () => [] });
|
|
@@ -426,31 +395,53 @@ const DEFAULT_RULE_LABELS = {
|
|
|
426
395
|
class PasswordChecklistComponent {
|
|
427
396
|
constructor() {
|
|
428
397
|
// Input signals for password and context
|
|
429
|
-
this.password = input('',
|
|
430
|
-
|
|
431
|
-
this.
|
|
432
|
-
|
|
398
|
+
this.password = input('', /* @ts-ignore */
|
|
399
|
+
...(ngDevMode ? [{ debugName: "password" }] : /* istanbul ignore next */ []));
|
|
400
|
+
this.username = input('', /* @ts-ignore */
|
|
401
|
+
...(ngDevMode ? [{ debugName: "username" }] : /* istanbul ignore next */ []));
|
|
402
|
+
this.email = input('', /* @ts-ignore */
|
|
403
|
+
...(ngDevMode ? [{ debugName: "email" }] : /* istanbul ignore next */ []));
|
|
404
|
+
this.hidden = input(false, /* @ts-ignore */
|
|
405
|
+
...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
|
|
433
406
|
// Input signals for rule configuration
|
|
434
|
-
this.minLength = input(null,
|
|
435
|
-
|
|
436
|
-
this.
|
|
437
|
-
|
|
438
|
-
this.
|
|
439
|
-
|
|
440
|
-
this.
|
|
441
|
-
|
|
407
|
+
this.minLength = input(null, /* @ts-ignore */
|
|
408
|
+
...(ngDevMode ? [{ debugName: "minLength" }] : /* istanbul ignore next */ []));
|
|
409
|
+
this.maxLength = input(null, /* @ts-ignore */
|
|
410
|
+
...(ngDevMode ? [{ debugName: "maxLength" }] : /* istanbul ignore next */ []));
|
|
411
|
+
this.requireUppercase = input(false, /* @ts-ignore */
|
|
412
|
+
...(ngDevMode ? [{ debugName: "requireUppercase" }] : /* istanbul ignore next */ []));
|
|
413
|
+
this.requireLowercase = input(false, /* @ts-ignore */
|
|
414
|
+
...(ngDevMode ? [{ debugName: "requireLowercase" }] : /* istanbul ignore next */ []));
|
|
415
|
+
this.requireNumber = input(false, /* @ts-ignore */
|
|
416
|
+
...(ngDevMode ? [{ debugName: "requireNumber" }] : /* istanbul ignore next */ []));
|
|
417
|
+
this.requireSymbol = input(false, /* @ts-ignore */
|
|
418
|
+
...(ngDevMode ? [{ debugName: "requireSymbol" }] : /* istanbul ignore next */ []));
|
|
419
|
+
this.checkUsername = input(false, /* @ts-ignore */
|
|
420
|
+
...(ngDevMode ? [{ debugName: "checkUsername" }] : /* istanbul ignore next */ []));
|
|
421
|
+
this.checkEmail = input(false, /* @ts-ignore */
|
|
422
|
+
...(ngDevMode ? [{ debugName: "checkEmail" }] : /* istanbul ignore next */ []));
|
|
442
423
|
// Input signals for custom labels
|
|
443
|
-
this.minLengthLabel = input(null,
|
|
444
|
-
|
|
445
|
-
this.
|
|
446
|
-
|
|
447
|
-
this.
|
|
448
|
-
|
|
449
|
-
this.
|
|
450
|
-
|
|
424
|
+
this.minLengthLabel = input(null, /* @ts-ignore */
|
|
425
|
+
...(ngDevMode ? [{ debugName: "minLengthLabel" }] : /* istanbul ignore next */ []));
|
|
426
|
+
this.maxLengthLabel = input(null, /* @ts-ignore */
|
|
427
|
+
...(ngDevMode ? [{ debugName: "maxLengthLabel" }] : /* istanbul ignore next */ []));
|
|
428
|
+
this.uppercaseLabel = input(null, /* @ts-ignore */
|
|
429
|
+
...(ngDevMode ? [{ debugName: "uppercaseLabel" }] : /* istanbul ignore next */ []));
|
|
430
|
+
this.lowercaseLabel = input(null, /* @ts-ignore */
|
|
431
|
+
...(ngDevMode ? [{ debugName: "lowercaseLabel" }] : /* istanbul ignore next */ []));
|
|
432
|
+
this.numberLabel = input(null, /* @ts-ignore */
|
|
433
|
+
...(ngDevMode ? [{ debugName: "numberLabel" }] : /* istanbul ignore next */ []));
|
|
434
|
+
this.symbolLabel = input(null, /* @ts-ignore */
|
|
435
|
+
...(ngDevMode ? [{ debugName: "symbolLabel" }] : /* istanbul ignore next */ []));
|
|
436
|
+
this.usernameLabel = input(null, /* @ts-ignore */
|
|
437
|
+
...(ngDevMode ? [{ debugName: "usernameLabel" }] : /* istanbul ignore next */ []));
|
|
438
|
+
this.emailLabel = input(null, /* @ts-ignore */
|
|
439
|
+
...(ngDevMode ? [{ debugName: "emailLabel" }] : /* istanbul ignore next */ []));
|
|
451
440
|
// Input signals for display options
|
|
452
|
-
this.noChecklist = input(false,
|
|
453
|
-
|
|
441
|
+
this.noChecklist = input(false, /* @ts-ignore */
|
|
442
|
+
...(ngDevMode ? [{ debugName: "noChecklist" }] : /* istanbul ignore next */ []));
|
|
443
|
+
this.noMeter = input(false, /* @ts-ignore */
|
|
444
|
+
...(ngDevMode ? [{ debugName: "noMeter" }] : /* istanbul ignore next */ []));
|
|
454
445
|
// Output signal for validity
|
|
455
446
|
this.validChange = output();
|
|
456
447
|
// Symbol regex pattern
|
|
@@ -459,33 +450,41 @@ class PasswordChecklistComponent {
|
|
|
459
450
|
this.hasMinLength = computed(() => {
|
|
460
451
|
const min = this.minLength();
|
|
461
452
|
return min === null || this.password().length >= min;
|
|
462
|
-
},
|
|
453
|
+
}, /* @ts-ignore */
|
|
454
|
+
...(ngDevMode ? [{ debugName: "hasMinLength" }] : /* istanbul ignore next */ []));
|
|
463
455
|
this.hasMaxLength = computed(() => {
|
|
464
456
|
const max = this.maxLength();
|
|
465
457
|
return max === null || this.password().length <= max;
|
|
466
|
-
},
|
|
458
|
+
}, /* @ts-ignore */
|
|
459
|
+
...(ngDevMode ? [{ debugName: "hasMaxLength" }] : /* istanbul ignore next */ []));
|
|
467
460
|
this.hasUppercase = computed(() => {
|
|
468
461
|
return /[A-Z]/.test(this.password());
|
|
469
|
-
},
|
|
462
|
+
}, /* @ts-ignore */
|
|
463
|
+
...(ngDevMode ? [{ debugName: "hasUppercase" }] : /* istanbul ignore next */ []));
|
|
470
464
|
this.hasLowercase = computed(() => {
|
|
471
465
|
return /[a-z]/.test(this.password());
|
|
472
|
-
},
|
|
466
|
+
}, /* @ts-ignore */
|
|
467
|
+
...(ngDevMode ? [{ debugName: "hasLowercase" }] : /* istanbul ignore next */ []));
|
|
473
468
|
this.hasNumber = computed(() => {
|
|
474
469
|
return /[0-9]/.test(this.password());
|
|
475
|
-
},
|
|
470
|
+
}, /* @ts-ignore */
|
|
471
|
+
...(ngDevMode ? [{ debugName: "hasNumber" }] : /* istanbul ignore next */ []));
|
|
476
472
|
this.hasSymbol = computed(() => {
|
|
477
473
|
return this.symbolRegex.test(this.password());
|
|
478
|
-
},
|
|
474
|
+
}, /* @ts-ignore */
|
|
475
|
+
...(ngDevMode ? [{ debugName: "hasSymbol" }] : /* istanbul ignore next */ []));
|
|
479
476
|
this.noUsernameInPassword = computed(() => {
|
|
480
477
|
const username = this.username().toLowerCase();
|
|
481
478
|
const pwd = this.password().toLowerCase();
|
|
482
479
|
return !username || !pwd || !pwd.includes(username);
|
|
483
|
-
},
|
|
480
|
+
}, /* @ts-ignore */
|
|
481
|
+
...(ngDevMode ? [{ debugName: "noUsernameInPassword" }] : /* istanbul ignore next */ []));
|
|
484
482
|
this.noEmailInPassword = computed(() => {
|
|
485
483
|
const email = this.email().toLowerCase();
|
|
486
484
|
const pwd = this.password().toLowerCase();
|
|
487
485
|
return !email || !pwd || !pwd.includes(email);
|
|
488
|
-
},
|
|
486
|
+
}, /* @ts-ignore */
|
|
487
|
+
...(ngDevMode ? [{ debugName: "noEmailInPassword" }] : /* istanbul ignore next */ []));
|
|
489
488
|
// Computed signal for all rules with their status
|
|
490
489
|
this.rules = computed(() => {
|
|
491
490
|
const rules = [];
|
|
@@ -546,7 +545,8 @@ class PasswordChecklistComponent {
|
|
|
546
545
|
});
|
|
547
546
|
}
|
|
548
547
|
return rules;
|
|
549
|
-
},
|
|
548
|
+
}, /* @ts-ignore */
|
|
549
|
+
...(ngDevMode ? [{ debugName: "rules" }] : /* istanbul ignore next */ []));
|
|
550
550
|
// Computed signal to check if a specific rule is satisfied
|
|
551
551
|
this.isRuleSatisfied = computed(() => {
|
|
552
552
|
return (ruleId) => {
|
|
@@ -571,7 +571,8 @@ class PasswordChecklistComponent {
|
|
|
571
571
|
return false;
|
|
572
572
|
}
|
|
573
573
|
};
|
|
574
|
-
},
|
|
574
|
+
}, /* @ts-ignore */
|
|
575
|
+
...(ngDevMode ? [{ debugName: "isRuleSatisfied" }] : /* istanbul ignore next */ []));
|
|
575
576
|
// Computed signal for overall validity
|
|
576
577
|
this.isValid = computed(() => {
|
|
577
578
|
const rules = this.rules();
|
|
@@ -580,7 +581,8 @@ class PasswordChecklistComponent {
|
|
|
580
581
|
}
|
|
581
582
|
const checkFn = this.isRuleSatisfied();
|
|
582
583
|
return rules.every((rule) => checkFn(rule.id));
|
|
583
|
-
},
|
|
584
|
+
}, /* @ts-ignore */
|
|
585
|
+
...(ngDevMode ? [{ debugName: "isValid" }] : /* istanbul ignore next */ []));
|
|
584
586
|
// Computed signal for password strength (0-100)
|
|
585
587
|
this.strength = computed(() => {
|
|
586
588
|
const pwd = this.password();
|
|
@@ -619,7 +621,8 @@ class PasswordChecklistComponent {
|
|
|
619
621
|
score = Math.min(score, 70);
|
|
620
622
|
}
|
|
621
623
|
return Math.min(Math.round(score), 100);
|
|
622
|
-
},
|
|
624
|
+
}, /* @ts-ignore */
|
|
625
|
+
...(ngDevMode ? [{ debugName: "strength" }] : /* istanbul ignore next */ []));
|
|
623
626
|
// Computed signal for strength level (0-4)
|
|
624
627
|
this.strengthLevel = computed(() => {
|
|
625
628
|
const strength = this.strength();
|
|
@@ -632,16 +635,19 @@ class PasswordChecklistComponent {
|
|
|
632
635
|
if (strength <= 80)
|
|
633
636
|
return 3;
|
|
634
637
|
return 4;
|
|
635
|
-
},
|
|
638
|
+
}, /* @ts-ignore */
|
|
639
|
+
...(ngDevMode ? [{ debugName: "strengthLevel" }] : /* istanbul ignore next */ []));
|
|
636
640
|
// Computed signal for strength color
|
|
637
641
|
this.strengthColor = computed(() => {
|
|
638
642
|
const colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
|
|
639
643
|
return colors[this.strengthLevel()];
|
|
640
|
-
},
|
|
644
|
+
}, /* @ts-ignore */
|
|
645
|
+
...(ngDevMode ? [{ debugName: "strengthColor" }] : /* istanbul ignore next */ []));
|
|
641
646
|
// Computed signal for strength percentage
|
|
642
647
|
this.strengthPercent = computed(() => {
|
|
643
648
|
return this.strength();
|
|
644
|
-
},
|
|
649
|
+
}, /* @ts-ignore */
|
|
650
|
+
...(ngDevMode ? [{ debugName: "strengthPercent" }] : /* istanbul ignore next */ []));
|
|
645
651
|
// Effect to emit validity changes
|
|
646
652
|
// This will automatically track the isValid computed signal
|
|
647
653
|
effect(() => {
|
|
@@ -675,10 +681,10 @@ class PasswordChecklistComponent {
|
|
|
675
681
|
checkRule(ruleId) {
|
|
676
682
|
return this.isRuleSatisfied()(ruleId);
|
|
677
683
|
}
|
|
678
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
679
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
684
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordChecklistComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
685
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PasswordChecklistComponent, isStandalone: true, selector: "auth-jwt-password-checklist", inputs: { password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, username: { classPropertyName: "username", publicName: "username", isSignal: true, isRequired: false, transformFunction: null }, email: { classPropertyName: "email", publicName: "email", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, requireUppercase: { classPropertyName: "requireUppercase", publicName: "requireUppercase", isSignal: true, isRequired: false, transformFunction: null }, requireLowercase: { classPropertyName: "requireLowercase", publicName: "requireLowercase", isSignal: true, isRequired: false, transformFunction: null }, requireNumber: { classPropertyName: "requireNumber", publicName: "requireNumber", isSignal: true, isRequired: false, transformFunction: null }, requireSymbol: { classPropertyName: "requireSymbol", publicName: "requireSymbol", isSignal: true, isRequired: false, transformFunction: null }, checkUsername: { classPropertyName: "checkUsername", publicName: "checkUsername", isSignal: true, isRequired: false, transformFunction: null }, checkEmail: { classPropertyName: "checkEmail", publicName: "checkEmail", isSignal: true, isRequired: false, transformFunction: null }, minLengthLabel: { classPropertyName: "minLengthLabel", publicName: "minLengthLabel", isSignal: true, isRequired: false, transformFunction: null }, maxLengthLabel: { classPropertyName: "maxLengthLabel", publicName: "maxLengthLabel", isSignal: true, isRequired: false, transformFunction: null }, uppercaseLabel: { classPropertyName: "uppercaseLabel", publicName: "uppercaseLabel", isSignal: true, isRequired: false, transformFunction: null }, lowercaseLabel: { classPropertyName: "lowercaseLabel", publicName: "lowercaseLabel", isSignal: true, isRequired: false, transformFunction: null }, numberLabel: { classPropertyName: "numberLabel", publicName: "numberLabel", isSignal: true, isRequired: false, transformFunction: null }, symbolLabel: { classPropertyName: "symbolLabel", publicName: "symbolLabel", isSignal: true, isRequired: false, transformFunction: null }, usernameLabel: { classPropertyName: "usernameLabel", publicName: "usernameLabel", isSignal: true, isRequired: false, transformFunction: null }, emailLabel: { classPropertyName: "emailLabel", publicName: "emailLabel", isSignal: true, isRequired: false, transformFunction: null }, noChecklist: { classPropertyName: "noChecklist", publicName: "noChecklist", isSignal: true, isRequired: false, transformFunction: null }, noMeter: { classPropertyName: "noMeter", publicName: "noMeter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validChange: "validChange" }, ngImport: i0, template: "@if (!hidden()) {\r\n<div class=\"password-checklist-container\">\r\n <!-- Strength Meter -->\r\n @if (!noMeter() && password()) {\r\n <div class=\"strength-meter\">\r\n <div class=\"strength-label\">\r\n <small>Strength:</small>\r\n </div>\r\n <div class=\"strength-bar-container\">\r\n <div\r\n class=\"strength-bar\"\r\n [style.width.%]=\"strengthPercent()\"\r\n [style.background-color]=\"strengthColor()\"\r\n ></div>\r\n </div>\r\n <div class=\"strength-percentage\">\r\n <small>{{ strengthPercent() }}%</small>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Checklist -->\r\n @if (!noChecklist() && password() && rules().length > 0) {\r\n <div class=\"checklist\">\r\n <ul class=\"checklist-items\">\r\n @for (rule of rules(); track rule.id) {\r\n <li\r\n class=\"checklist-item\"\r\n [class.satisfied]=\"checkRule(rule.id)\"\r\n [class.unsatisfied]=\"!checkRule(rule.id)\"\r\n >\r\n <span class=\"checklist-icon\">\r\n {{ checkRule(rule.id) ? '\u2713' : '\u2717' }}\r\n </span>\r\n <span class=\"checklist-text\">{{ rule.label }}</span>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n</div>\r\n}\r\n", styles: [".password-checklist-container{margin-top:.5rem}.strength-meter{display:flex;align-items:center;gap:.5rem;margin-bottom:.75rem}.strength-label{flex-shrink:0}.strength-bar-container{position:relative;flex:1;height:6px;background-color:var(--mat-sys-surface-variant);border-radius:3px;overflow:hidden}.strength-bar{height:100%;transition:width .3s ease,background-color .3s ease;border-radius:3px}.strength-percentage{flex-shrink:0;min-width:3rem;text-align:right}.checklist{font-size:.875rem}.checklist-items{list-style:none;margin:0;padding:0}.checklist-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;transition:color .2s ease}.checklist-icon{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border-radius:50%;font-weight:700;font-size:.75rem;flex-shrink:0;transition:background-color .2s ease,color .2s ease}.checklist-item.satisfied .checklist-icon{background-color:var(--mat-sys-success);color:var(--mat-sys-on-success)}.checklist-item.unsatisfied .checklist-icon{background-color:var(--mat-sys-error);color:var(--mat-sys-on-error)}.checklist-text{flex:1}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}@media(prefers-color-scheme:dark){.strength-bar-container{background-color:var(--mat-sys-surface-variant)}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
680
686
|
}
|
|
681
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
687
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordChecklistComponent, decorators: [{
|
|
682
688
|
type: Component,
|
|
683
689
|
args: [{ selector: 'auth-jwt-password-checklist', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!hidden()) {\r\n<div class=\"password-checklist-container\">\r\n <!-- Strength Meter -->\r\n @if (!noMeter() && password()) {\r\n <div class=\"strength-meter\">\r\n <div class=\"strength-label\">\r\n <small>Strength:</small>\r\n </div>\r\n <div class=\"strength-bar-container\">\r\n <div\r\n class=\"strength-bar\"\r\n [style.width.%]=\"strengthPercent()\"\r\n [style.background-color]=\"strengthColor()\"\r\n ></div>\r\n </div>\r\n <div class=\"strength-percentage\">\r\n <small>{{ strengthPercent() }}%</small>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Checklist -->\r\n @if (!noChecklist() && password() && rules().length > 0) {\r\n <div class=\"checklist\">\r\n <ul class=\"checklist-items\">\r\n @for (rule of rules(); track rule.id) {\r\n <li\r\n class=\"checklist-item\"\r\n [class.satisfied]=\"checkRule(rule.id)\"\r\n [class.unsatisfied]=\"!checkRule(rule.id)\"\r\n >\r\n <span class=\"checklist-icon\">\r\n {{ checkRule(rule.id) ? '\u2713' : '\u2717' }}\r\n </span>\r\n <span class=\"checklist-text\">{{ rule.label }}</span>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n</div>\r\n}\r\n", styles: [".password-checklist-container{margin-top:.5rem}.strength-meter{display:flex;align-items:center;gap:.5rem;margin-bottom:.75rem}.strength-label{flex-shrink:0}.strength-bar-container{position:relative;flex:1;height:6px;background-color:var(--mat-sys-surface-variant);border-radius:3px;overflow:hidden}.strength-bar{height:100%;transition:width .3s ease,background-color .3s ease;border-radius:3px}.strength-percentage{flex-shrink:0;min-width:3rem;text-align:right}.checklist{font-size:.875rem}.checklist-items{list-style:none;margin:0;padding:0}.checklist-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;transition:color .2s ease}.checklist-icon{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border-radius:50%;font-weight:700;font-size:.75rem;flex-shrink:0;transition:background-color .2s ease,color .2s ease}.checklist-item.satisfied .checklist-icon{background-color:var(--mat-sys-success);color:var(--mat-sys-on-success)}.checklist-item.unsatisfied .checklist-icon{background-color:var(--mat-sys-error);color:var(--mat-sys-on-error)}.checklist-text{flex:1}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}@media(prefers-color-scheme:dark){.strength-bar-container{background-color:var(--mat-sys-surface-variant)}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}}\n"] }]
|
|
684
690
|
}], ctorParameters: () => [], propDecorators: { password: [{ type: i0.Input, args: [{ isSignal: true, alias: "password", required: false }] }], username: [{ type: i0.Input, args: [{ isSignal: true, alias: "username", required: false }] }], email: [{ type: i0.Input, args: [{ isSignal: true, alias: "email", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], requireUppercase: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireUppercase", required: false }] }], requireLowercase: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireLowercase", required: false }] }], requireNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireNumber", required: false }] }], requireSymbol: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireSymbol", required: false }] }], checkUsername: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkUsername", required: false }] }], checkEmail: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkEmail", required: false }] }], minLengthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLengthLabel", required: false }] }], maxLengthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLengthLabel", required: false }] }], uppercaseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "uppercaseLabel", required: false }] }], lowercaseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "lowercaseLabel", required: false }] }], numberLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "numberLabel", required: false }] }], symbolLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "symbolLabel", required: false }] }], usernameLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "usernameLabel", required: false }] }], emailLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailLabel", required: false }] }], noChecklist: [{ type: i0.Input, args: [{ isSignal: true, alias: "noChecklist", required: false }] }], noMeter: [{ type: i0.Input, args: [{ isSignal: true, alias: "noMeter", required: false }] }], validChange: [{ type: i0.Output, args: ["validChange"] }] } });
|
|
@@ -691,176 +697,124 @@ class AuthJwtRegistrationComponent {
|
|
|
691
697
|
this._snackbar = inject(MatSnackBar);
|
|
692
698
|
this._accountService = inject(AuthJwtAccountService);
|
|
693
699
|
this._userRepository = inject(UserListRepository);
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
this.
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
validators: [Validators.required, Validators.maxLength(50)],
|
|
720
|
-
nonNullable: true,
|
|
721
|
-
});
|
|
722
|
-
this.lastName = formBuilder.control('', {
|
|
723
|
-
validators: [Validators.required, Validators.maxLength(50)],
|
|
724
|
-
nonNullable: true,
|
|
725
|
-
});
|
|
726
|
-
// http://stackoverflow.com/questions/35474991/angular-2-form-validating-for-repeat-password
|
|
727
|
-
this.password = formBuilder.control('', {
|
|
728
|
-
validators: [Validators.required, PasswordValidators.standard()],
|
|
729
|
-
nonNullable: true,
|
|
730
|
-
});
|
|
731
|
-
this.confirmPassword = formBuilder.control('', {
|
|
732
|
-
validators: Validators.required,
|
|
733
|
-
nonNullable: true,
|
|
734
|
-
});
|
|
735
|
-
this.form = formBuilder.group({
|
|
736
|
-
email: this.email,
|
|
737
|
-
name: this.name,
|
|
738
|
-
firstName: this.firstName,
|
|
739
|
-
lastName: this.lastName,
|
|
740
|
-
password: this.password,
|
|
741
|
-
confirmPassword: this.confirmPassword,
|
|
742
|
-
}, {
|
|
743
|
-
validators: [
|
|
744
|
-
PasswordValidators.areEqual('password', 'confirmPassword'),
|
|
745
|
-
],
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Creates a unique name validator. There is no dependency injection at this level,
|
|
750
|
-
* but we can use closures. As a matter of fact, we have access to the service instance
|
|
751
|
-
* from the component where we register validators. So we will implement a function
|
|
752
|
-
* that will accept the service as parameter, and create the actual validation function.
|
|
753
|
-
* This function will have access to the service when called during the validation process.
|
|
754
|
-
* See http://restlet.com/blog/2016/02/17/implementing-angular2-forms-beyond-basics-part-2/.
|
|
755
|
-
*/
|
|
756
|
-
getUniqueNameValidator(service) {
|
|
757
|
-
return (control) => {
|
|
758
|
-
return new Promise((resolve, reject) => {
|
|
759
|
-
// avoid checking if empty
|
|
760
|
-
if (!control.value) {
|
|
761
|
-
resolve(null);
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
service.isNameRegistered(control.value).subscribe({
|
|
765
|
-
next: (data) => {
|
|
766
|
-
if (!data.isExisting) {
|
|
767
|
-
resolve(null);
|
|
768
|
-
}
|
|
769
|
-
else {
|
|
770
|
-
resolve({ uniqueName: true });
|
|
771
|
-
}
|
|
772
|
-
},
|
|
773
|
-
error: (error) => {
|
|
774
|
-
console.error('Unique name validator error' +
|
|
775
|
-
(error ? JSON.stringify(error) : ''));
|
|
776
|
-
resolve({ uniqueName: true });
|
|
777
|
-
},
|
|
778
|
-
});
|
|
779
|
-
}
|
|
700
|
+
this.formModel = signal({
|
|
701
|
+
email: '',
|
|
702
|
+
name: '',
|
|
703
|
+
firstName: '',
|
|
704
|
+
lastName: '',
|
|
705
|
+
password: '',
|
|
706
|
+
confirmPassword: '',
|
|
707
|
+
}, /* @ts-ignore */
|
|
708
|
+
...(ngDevMode ? [{ debugName: "formModel" }] : /* istanbul ignore next */ []));
|
|
709
|
+
this.userForm = form(this.formModel, (p) => {
|
|
710
|
+
// email
|
|
711
|
+
required(p.email);
|
|
712
|
+
email(p.email);
|
|
713
|
+
validateAsync(p.email, {
|
|
714
|
+
params: ({ value }) => value() || undefined,
|
|
715
|
+
factory: (emailParam) => resource({
|
|
716
|
+
params: () => emailParam(),
|
|
717
|
+
loader: async ({ params: emailVal }) => firstValueFrom(this._accountService.isEmailRegistered(emailVal)),
|
|
718
|
+
}),
|
|
719
|
+
onSuccess: (result) => result?.isExisting ? { kind: 'uniqueEmail' } : undefined,
|
|
720
|
+
onError: (err) => {
|
|
721
|
+
console.error('Unique email validator error:', err);
|
|
722
|
+
return { kind: 'uniqueEmail' };
|
|
723
|
+
},
|
|
724
|
+
debounce: 300,
|
|
780
725
|
});
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
else {
|
|
797
|
-
resolve({ uniqueEmail: true });
|
|
798
|
-
}
|
|
799
|
-
},
|
|
800
|
-
error: (error) => {
|
|
801
|
-
console.error('Unique email validator error' +
|
|
802
|
-
(error ? JSON.stringify(error) : ''));
|
|
803
|
-
resolve({ uniqueEmail: true });
|
|
804
|
-
},
|
|
805
|
-
});
|
|
806
|
-
}
|
|
726
|
+
// name
|
|
727
|
+
required(p.name);
|
|
728
|
+
pattern(p.name, /^[a-zA-Z][a-zA-Z0-9]{2,49}$/);
|
|
729
|
+
validateAsync(p.name, {
|
|
730
|
+
params: ({ value }) => value() || undefined,
|
|
731
|
+
factory: (nameParam) => resource({
|
|
732
|
+
params: () => nameParam(),
|
|
733
|
+
loader: async ({ params: nameVal }) => firstValueFrom(this._accountService.isNameRegistered(nameVal)),
|
|
734
|
+
}),
|
|
735
|
+
onSuccess: (result) => result?.isExisting ? { kind: 'uniqueName' } : undefined,
|
|
736
|
+
onError: (err) => {
|
|
737
|
+
console.error('Unique name validator error:', err);
|
|
738
|
+
return { kind: 'uniqueName' };
|
|
739
|
+
},
|
|
740
|
+
debounce: 300,
|
|
807
741
|
});
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
742
|
+
// first/last name
|
|
743
|
+
required(p.firstName);
|
|
744
|
+
maxLength(p.firstName, 50);
|
|
745
|
+
required(p.lastName);
|
|
746
|
+
maxLength(p.lastName, 50);
|
|
747
|
+
// password
|
|
748
|
+
required(p.password);
|
|
749
|
+
validate(p.password, ({ value }) => PasswordValidators.standard()(value()));
|
|
750
|
+
// confirmPassword + cross-field match
|
|
751
|
+
required(p.confirmPassword);
|
|
752
|
+
validate(p, ({ value }) => {
|
|
753
|
+
const m = value();
|
|
754
|
+
return m.password !== m.confirmPassword ? { kind: 'areequal' } : null;
|
|
755
|
+
});
|
|
756
|
+
}, {
|
|
757
|
+
submission: {
|
|
758
|
+
action: async () => {
|
|
759
|
+
if (this.busy())
|
|
760
|
+
return;
|
|
761
|
+
const m = this.formModel();
|
|
762
|
+
const model = {
|
|
763
|
+
email: m.email,
|
|
764
|
+
name: m.name,
|
|
765
|
+
firstName: m.firstName,
|
|
766
|
+
lastName: m.lastName,
|
|
767
|
+
password: m.password,
|
|
768
|
+
};
|
|
769
|
+
this.busy.set(true);
|
|
770
|
+
try {
|
|
771
|
+
await firstValueFrom(this._accountService.register(model, this.autoConfirm()));
|
|
772
|
+
this.busy.set(false);
|
|
773
|
+
this._snackbar.open($localize `:auth-jwt-admin:Registration succeeded`, 'OK');
|
|
774
|
+
this._userRepository.reset();
|
|
775
|
+
this.registered.emit();
|
|
776
|
+
}
|
|
777
|
+
catch (error) {
|
|
778
|
+
this.busy.set(false);
|
|
779
|
+
console.error('Registration error' + (error ? JSON.stringify(error) : ''));
|
|
780
|
+
this._snackbar.open($localize `:auth-jwt-admin:Registration error`, 'OK');
|
|
781
|
+
}
|
|
782
|
+
},
|
|
839
783
|
},
|
|
840
784
|
});
|
|
785
|
+
this.autoConfirm = input(/* @ts-ignore */
|
|
786
|
+
...(ngDevMode ? [undefined, { debugName: "autoConfirm" }] : /* istanbul ignore next */ []));
|
|
787
|
+
this.registered = output();
|
|
788
|
+
this.busy = signal(undefined, /* @ts-ignore */
|
|
789
|
+
...(ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []));
|
|
790
|
+
this.hidePassword = signal(true, /* @ts-ignore */
|
|
791
|
+
...(ngDevMode ? [{ debugName: "hidePassword" }] : /* istanbul ignore next */ []));
|
|
841
792
|
}
|
|
842
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
843
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: AuthJwtRegistrationComponent, isStandalone: true, selector: "auth-jwt-registration", inputs: { autoConfirm: { classPropertyName: "autoConfirm", publicName: "autoConfirm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { registered: "registered" }, ngImport: i0, template: "<div>\r\n <form role=\"form\" [formGroup]=\"form\" (submit)=\"onSubmit()\">\r\n <fieldset>\r\n <legend i18n=\"auth-jwt-admin\">registration</legend>\r\n <!-- email -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n>email</mat-label>\r\n <input\r\n matInput\r\n type=\"email\"\r\n id=\"email\"\r\n maxlength=\"256\"\r\n required\r\n autofocus\r\n spellcheck=\"false\"\r\n [formControl]=\"email\"\r\n />\r\n @if ( $any(email).errors?.required && (email.dirty || email.touched) )\r\n {\r\n <mat-error i18n=\"auth-jwt-admin\">email required</mat-error>\r\n } @if ($any(email).errors?.email && (email.dirty || email.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\">invalid email</mat-error>\r\n } @if ( $any(email).errors?.uniqueEmail && (email.dirty ||\r\n email.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\">email already registered</mat-error>\r\n }\r\n </mat-form-field>\r\n @if (email.pending) {\r\n <mat-icon>hourglass</mat-icon>\r\n }\r\n </div>\r\n\r\n <!-- name -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">username</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"name\"\r\n maxlength=\"50\"\r\n required\r\n pattern=\"^[a-zA-Z][a-zA-Z0-9]{2,49}$\"\r\n spellcheck=\"false\"\r\n [formControl]=\"name\"\r\n />\r\n @if ($any(name).errors?.required && (name.dirty || name.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\">username required</mat-error>\r\n } @if ($any(name).errors?.pattern && (name.dirty || name.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\">invalid username</mat-error>\r\n } @if ( $any(name).errors?.uniqueName && (name.dirty || name.touched)\r\n ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >username already registered</mat-error\r\n >\r\n }\r\n </mat-form-field>\r\n @if (name.pending) {\r\n <mat-icon>hourglass</mat-icon>\r\n }\r\n </div>\r\n\r\n <!-- first name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"firstName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"firstName\"\r\n />\r\n @if ( firstName.hasError('required') && (firstName.dirty ||\r\n firstName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">\r\n first name required\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- last name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"lastName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"lastName\"\r\n />\r\n @if ( lastName.hasError('required') && (lastName.dirty ||\r\n lastName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">\r\n last name required\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- <div [formGroup]=\"passwords\"> -->\r\n <!-- password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">password</mat-label>\r\n <input\r\n matInput\r\n [type]=\"hidePassword() ? 'password' : 'text'\"\r\n name=\"password\"\r\n autocomplete=\"new-password\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"password\"\r\n />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n (click)=\"hidePassword.set(!hidePassword())\"\r\n i18n-aria-label=\"auth-jwt-login\"\r\n aria-label=\"Hide password\"\r\n [attr.aria-pressed]=\"hidePassword()\"\r\n >\r\n <mat-icon>{{\r\n hidePassword() ? \"visibility_off\" : \"visibility\"\r\n }}</mat-icon>\r\n </button>\r\n <auth-jwt-password-checklist\r\n [password]=\"password.value\"\r\n [username]=\"name.value\"\r\n [email]=\"email.value\"\r\n [minLength]=\"8\"\r\n [requireUppercase]=\"true\"\r\n [requireLowercase]=\"true\"\r\n [requireSymbol]=\"true\"\r\n [minLengthLabel]=\"'At least 8 characters'\"\r\n [uppercaseLabel]=\"'At least 1 uppercase letter'\"\r\n [lowercaseLabel]=\"'At least 1 lowercase letter'\"\r\n [symbolLabel]=\"'At least 1 punctuation/symbol'\">\r\n </auth-jwt-password-checklist>\r\n @if ( $any(password).errors?.required && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\">password required</mat-error>\r\n } @if ( $any(password).errors?.passwordtooshort && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\">at least 8 characters</mat-error>\r\n } @if ( $any(password).errors?.noupperinpassword && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >at least 1 uppercase letter</mat-error\r\n >\r\n } @if ( $any(password).errors?.nolowerinpassword && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >at least 1 lowercase letter</mat-error\r\n >\r\n } @if ( $any(password).errors?.nosymbolinpassword && (password.dirty\r\n || password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >at least 1 punctuation/symbol</mat-error\r\n >\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- confirm password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">confirm password</mat-label>\r\n <input\r\n matInput\r\n [type]=\"hidePassword() ? 'password' : 'text'\"\r\n name=\"confirmPassword\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"confirmPassword\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n @if (form.errors?.areequal && confirmPassword.touched) {\r\n <div i18n=\"auth-jwt-admin\" class=\"error\">\r\n password differs from confirmation password\r\n </div>\r\n }\r\n\r\n <button\r\n i18n=\"auth-jwt-admin\"\r\n mat-flat-button\r\n type=\"submit\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n [disabled]=\"\r\n form.invalid || form.pristine || busy() || name.pending || email.pending\r\n \"\r\n >\r\n register\r\n </button>\r\n @if (busy()) {\r\n <mat-progress-spinner diameter=\"20\"></mat-progress-spinner>\r\n }\r\n </fieldset>\r\n </form>\r\n\r\n <details>\r\n <summary i18n=\"auth-jwt-admin\">Hints</summary>\r\n <div class=\"info\">\r\n <p i18n=\"auth-jwt-admin\">\r\n To register a new user, you must provide his email address, choose a\r\n password, and choose a username, which must be unique (you will be\r\n notified if another user has already taken that name). The username must\r\n include only letters/digits, start with a letter, and be no shorter than\r\n 3 characters, nor longer than 50.\r\n </p>\r\n <p i18n=\"auth-jwt-admin\">\r\n To promote a decent security level, the password must include at least 8\r\n characters, uppercase and lowercase letters, digits, and punctuation\r\n (like dashes, stops, parentheses, etc.).\r\n </p>\r\n <p i18n=\"auth-jwt-admin\">\r\n Once registered, if messaging is enabled on the server side the user\r\n will receive an email message to the email address you specified; he\r\n will have to click on the provided link to complete the registration\r\n process. Otherwise, you should edit the newly created user and confirm\r\n the email registration.\r\n </p>\r\n </div>\r\n </details>\r\n</div>\r\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}details{margin:8px}.info{column-width:600px}.error{color:var(--mat-sys-error)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { 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.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: MatProgressSpinnerModule }, { kind: "component", type: i6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: PasswordChecklistComponent, selector: "auth-jwt-password-checklist", inputs: ["password", "username", "email", "hidden", "minLength", "maxLength", "requireUppercase", "requireLowercase", "requireNumber", "requireSymbol", "checkUsername", "checkEmail", "minLengthLabel", "maxLengthLabel", "uppercaseLabel", "lowercaseLabel", "numberLabel", "symbolLabel", "usernameLabel", "emailLabel", "noChecklist", "noMeter"], outputs: ["validChange"] }] }); }
|
|
793
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
794
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: AuthJwtRegistrationComponent, isStandalone: true, selector: "auth-jwt-registration", inputs: { autoConfirm: { classPropertyName: "autoConfirm", publicName: "autoConfirm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { registered: "registered" }, ngImport: i0, template: "<div>\n <form role=\"form\" [formRoot]=\"userForm\">\n <fieldset>\n <legend i18n=\"auth-jwt-admin\">registration</legend>\n\n <!-- email -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n>email</mat-label>\n <input\n matInput\n type=\"email\"\n id=\"email\"\n autofocus\n spellcheck=\"false\"\n [formField]=\"userForm.email\"\n />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email</mat-error>\n }\n @if (userForm.email().getError('uniqueEmail') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.email().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- name -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">username</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"name\"\n spellcheck=\"false\"\n [formField]=\"userForm.name\"\n />\n @if (userForm.name().getError('required') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username required</mat-error>\n }\n @if (userForm.name().getError('pattern') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid username</mat-error>\n }\n @if (userForm.name().getError('uniqueName') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.name().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- first name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"firstName\"\n spellcheck=\"false\"\n [formField]=\"userForm.firstName\"\n />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">first name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- last name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"lastName\"\n spellcheck=\"false\"\n [formField]=\"userForm.lastName\"\n />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">last name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.password\"\n />\n <button\n type=\"button\"\n mat-icon-button\n matSuffix\n (click)=\"hidePassword.set(!hidePassword())\"\n i18n-aria-label=\"auth-jwt-login\"\n aria-label=\"Hide password\"\n [attr.aria-pressed]=\"hidePassword()\"\n >\n <mat-icon>{{ hidePassword() ? \"visibility_off\" : \"visibility\" }}</mat-icon>\n </button>\n <auth-jwt-password-checklist\n [password]=\"formModel().password\"\n [username]=\"formModel().name\"\n [email]=\"formModel().email\"\n [minLength]=\"8\"\n [requireUppercase]=\"true\"\n [requireLowercase]=\"true\"\n [requireSymbol]=\"true\"\n [minLengthLabel]=\"'At least 8 characters'\"\n [uppercaseLabel]=\"'At least 1 uppercase letter'\"\n [lowercaseLabel]=\"'At least 1 lowercase letter'\"\n [symbolLabel]=\"'At least 1 punctuation/symbol'\"\n />\n @if (userForm.password().getError('required') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">password required</mat-error>\n }\n @if (userForm.password().getError('passwordtooshort') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 8 characters</mat-error>\n }\n @if (userForm.password().getError('noupperinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 uppercase letter</mat-error>\n }\n @if (userForm.password().getError('nolowerinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 lowercase letter</mat-error>\n }\n @if (userForm.password().getError('nosymbolinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 punctuation/symbol</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- confirm password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">confirm password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.confirmPassword\"\n />\n </mat-form-field>\n </div>\n @if (userForm().getError('areequal') && userForm.confirmPassword().touched()) {\n <div i18n=\"auth-jwt-admin\" class=\"error\">\n password differs from confirmation password\n </div>\n }\n\n <button\n i18n=\"auth-jwt-admin\"\n mat-flat-button\n type=\"submit\"\n color=\"primary\"\n class=\"mat-primary\"\n [disabled]=\"!userForm().valid() || busy()\"\n >\n register\n </button>\n @if (busy()) {\n <mat-progress-spinner diameter=\"20\" />\n }\n </fieldset>\n </form>\n\n <details>\n <summary i18n=\"auth-jwt-admin\">Hints</summary>\n <div class=\"info\">\n <p i18n=\"auth-jwt-admin\">\n To register a new user, you must provide his email address, choose a\n password, and choose a username, which must be unique (you will be\n notified if another user has already taken that name). The username must\n include only letters/digits, start with a letter, and be no shorter than\n 3 characters, nor longer than 50.\n </p>\n <p i18n=\"auth-jwt-admin\">\n To promote a decent security level, the password must include at least 8\n characters, uppercase and lowercase letters, digits, and punctuation\n (like dashes, stops, parentheses, etc.).\n </p>\n <p i18n=\"auth-jwt-admin\">\n Once registered, if messaging is enabled on the server side the user\n will receive an email message to the email address you specified; he\n will have to click on the provided link to complete the registration\n process. Otherwise, you should edit the newly created user and confirm\n the email registration.\n </p>\n </div>\n </details>\n</div>\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}details{margin:8px}.info{column-width:600px}.error{color:var(--mat-sys-error)}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "directive", type: FormRoot, selector: "form[formRoot]", inputs: ["formRoot"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: MatProgressSpinnerModule }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: PasswordChecklistComponent, selector: "auth-jwt-password-checklist", inputs: ["password", "username", "email", "hidden", "minLength", "maxLength", "requireUppercase", "requireLowercase", "requireNumber", "requireSymbol", "checkUsername", "checkEmail", "minLengthLabel", "maxLengthLabel", "uppercaseLabel", "lowercaseLabel", "numberLabel", "symbolLabel", "usernameLabel", "emailLabel", "noChecklist", "noMeter"], outputs: ["validChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
844
795
|
}
|
|
845
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
796
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
|
|
846
797
|
type: Component,
|
|
847
798
|
args: [{ selector: 'auth-jwt-registration', imports: [
|
|
848
|
-
|
|
799
|
+
FormField,
|
|
800
|
+
FormRoot,
|
|
849
801
|
MatButtonModule,
|
|
850
802
|
MatFormFieldModule,
|
|
851
803
|
MatIconModule,
|
|
852
804
|
MatInputModule,
|
|
853
805
|
MatProgressSpinnerModule,
|
|
854
806
|
PasswordChecklistComponent,
|
|
855
|
-
], template: "<div>\
|
|
856
|
-
}],
|
|
807
|
+
], changeDetection: ChangeDetectionStrategy.Eager, template: "<div>\n <form role=\"form\" [formRoot]=\"userForm\">\n <fieldset>\n <legend i18n=\"auth-jwt-admin\">registration</legend>\n\n <!-- email -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n>email</mat-label>\n <input\n matInput\n type=\"email\"\n id=\"email\"\n autofocus\n spellcheck=\"false\"\n [formField]=\"userForm.email\"\n />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email</mat-error>\n }\n @if (userForm.email().getError('uniqueEmail') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.email().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- name -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">username</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"name\"\n spellcheck=\"false\"\n [formField]=\"userForm.name\"\n />\n @if (userForm.name().getError('required') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username required</mat-error>\n }\n @if (userForm.name().getError('pattern') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid username</mat-error>\n }\n @if (userForm.name().getError('uniqueName') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.name().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- first name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"firstName\"\n spellcheck=\"false\"\n [formField]=\"userForm.firstName\"\n />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">first name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- last name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"lastName\"\n spellcheck=\"false\"\n [formField]=\"userForm.lastName\"\n />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">last name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.password\"\n />\n <button\n type=\"button\"\n mat-icon-button\n matSuffix\n (click)=\"hidePassword.set(!hidePassword())\"\n i18n-aria-label=\"auth-jwt-login\"\n aria-label=\"Hide password\"\n [attr.aria-pressed]=\"hidePassword()\"\n >\n <mat-icon>{{ hidePassword() ? \"visibility_off\" : \"visibility\" }}</mat-icon>\n </button>\n <auth-jwt-password-checklist\n [password]=\"formModel().password\"\n [username]=\"formModel().name\"\n [email]=\"formModel().email\"\n [minLength]=\"8\"\n [requireUppercase]=\"true\"\n [requireLowercase]=\"true\"\n [requireSymbol]=\"true\"\n [minLengthLabel]=\"'At least 8 characters'\"\n [uppercaseLabel]=\"'At least 1 uppercase letter'\"\n [lowercaseLabel]=\"'At least 1 lowercase letter'\"\n [symbolLabel]=\"'At least 1 punctuation/symbol'\"\n />\n @if (userForm.password().getError('required') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">password required</mat-error>\n }\n @if (userForm.password().getError('passwordtooshort') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 8 characters</mat-error>\n }\n @if (userForm.password().getError('noupperinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 uppercase letter</mat-error>\n }\n @if (userForm.password().getError('nolowerinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 lowercase letter</mat-error>\n }\n @if (userForm.password().getError('nosymbolinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 punctuation/symbol</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- confirm password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">confirm password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.confirmPassword\"\n />\n </mat-form-field>\n </div>\n @if (userForm().getError('areequal') && userForm.confirmPassword().touched()) {\n <div i18n=\"auth-jwt-admin\" class=\"error\">\n password differs from confirmation password\n </div>\n }\n\n <button\n i18n=\"auth-jwt-admin\"\n mat-flat-button\n type=\"submit\"\n color=\"primary\"\n class=\"mat-primary\"\n [disabled]=\"!userForm().valid() || busy()\"\n >\n register\n </button>\n @if (busy()) {\n <mat-progress-spinner diameter=\"20\" />\n }\n </fieldset>\n </form>\n\n <details>\n <summary i18n=\"auth-jwt-admin\">Hints</summary>\n <div class=\"info\">\n <p i18n=\"auth-jwt-admin\">\n To register a new user, you must provide his email address, choose a\n password, and choose a username, which must be unique (you will be\n notified if another user has already taken that name). The username must\n include only letters/digits, start with a letter, and be no shorter than\n 3 characters, nor longer than 50.\n </p>\n <p i18n=\"auth-jwt-admin\">\n To promote a decent security level, the password must include at least 8\n characters, uppercase and lowercase letters, digits, and punctuation\n (like dashes, stops, parentheses, etc.).\n </p>\n <p i18n=\"auth-jwt-admin\">\n Once registered, if messaging is enabled on the server side the user\n will receive an email message to the email address you specified; he\n will have to click on the provided link to complete the registration\n process. Otherwise, you should edit the newly created user and confirm\n the email registration.\n </p>\n </div>\n </details>\n</div>\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}details{margin:8px}.info{column-width:600px}.error{color:var(--mat-sys-error)}\n"] }]
|
|
808
|
+
}], propDecorators: { autoConfirm: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoConfirm", required: false }] }], registered: [{ type: i0.Output, args: ["registered"] }] } });
|
|
857
809
|
|
|
858
810
|
class PasswordStrengthBarComponent {
|
|
859
811
|
constructor() {
|
|
860
812
|
this._colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
|
|
861
|
-
this.passwordToCheck = input(
|
|
813
|
+
this.passwordToCheck = input(/* @ts-ignore */
|
|
814
|
+
...(ngDevMode ? [undefined, { debugName: "passwordToCheck" }] : /* istanbul ignore next */ []));
|
|
862
815
|
this.strengthChange = output();
|
|
863
|
-
this.bars = signal([],
|
|
816
|
+
this.bars = signal([], /* @ts-ignore */
|
|
817
|
+
...(ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []));
|
|
864
818
|
}
|
|
865
819
|
measureStrength(p) {
|
|
866
820
|
let force = 0;
|
|
@@ -923,12 +877,12 @@ class PasswordStrengthBarComponent {
|
|
|
923
877
|
}
|
|
924
878
|
this.bars.set(bars);
|
|
925
879
|
}
|
|
926
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
927
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
880
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
881
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: PasswordStrengthBarComponent, isStandalone: true, selector: "auth-jwt-password-strength-bar", inputs: { passwordToCheck: { classPropertyName: "passwordToCheck", publicName: "passwordToCheck", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { strengthChange: "strengthChange" }, usesOnChanges: true, ngImport: i0, template: "<div id=\"strength\">\r\n <small>strength:</small>\r\n <ul id=\"strengthBar\">\r\n <li class=\"point\" [style.background-color]=\"bars()[0]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[1]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[2]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[3]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[4]\"></li>\r\n </ul>\r\n</div>\r\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:var(--mat-sys-surface-variant);border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
928
882
|
}
|
|
929
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
883
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
|
|
930
884
|
type: Component,
|
|
931
|
-
args: [{ selector: 'auth-jwt-password-strength-bar', template: "<div id=\"strength\">\r\n <small>strength:</small>\r\n <ul id=\"strengthBar\">\r\n <li class=\"point\" [style.background-color]=\"bars()[0]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[1]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[2]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[3]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[4]\"></li>\r\n </ul>\r\n</div>\r\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:var(--mat-sys-surface-variant);border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] }]
|
|
885
|
+
args: [{ selector: 'auth-jwt-password-strength-bar', changeDetection: ChangeDetectionStrategy.Eager, template: "<div id=\"strength\">\r\n <small>strength:</small>\r\n <ul id=\"strengthBar\">\r\n <li class=\"point\" [style.background-color]=\"bars()[0]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[1]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[2]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[3]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[4]\"></li>\r\n </ul>\r\n</div>\r\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:var(--mat-sys-surface-variant);border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] }]
|
|
932
886
|
}], propDecorators: { passwordToCheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "passwordToCheck", required: false }] }], strengthChange: [{ type: i0.Output, args: ["strengthChange"] }] } });
|
|
933
887
|
|
|
934
888
|
/**
|
|
@@ -936,73 +890,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
936
890
|
*/
|
|
937
891
|
class UserFilterComponent {
|
|
938
892
|
constructor() {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
/**
|
|
944
|
-
* Whether the filter is disabled.
|
|
945
|
-
*/
|
|
946
|
-
this.disabled = input(...(ngDevMode ? [undefined, { debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
947
|
-
/**
|
|
948
|
-
* Event emitted when the filter changes.
|
|
949
|
-
*/
|
|
893
|
+
this.filter = input(/* @ts-ignore */
|
|
894
|
+
...(ngDevMode ? [undefined, { debugName: "filter" }] : /* istanbul ignore next */ []));
|
|
895
|
+
this.disabled = input(/* @ts-ignore */
|
|
896
|
+
...(ngDevMode ? [undefined, { debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
950
897
|
this.filterChange = output();
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
this.
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
898
|
+
this.formModel = signal({ name: '' }, /* @ts-ignore */
|
|
899
|
+
...(ngDevMode ? [{ debugName: "formModel" }] : /* istanbul ignore next */ []));
|
|
900
|
+
this.userForm = form(this.formModel, (p) => {
|
|
901
|
+
disabled(p.name, { when: () => this.disabled() ?? false });
|
|
902
|
+
}, {
|
|
903
|
+
submission: {
|
|
904
|
+
action: async () => {
|
|
905
|
+
const name = this.formModel().name.trim();
|
|
906
|
+
this.filterChange.emit({ name: name || undefined });
|
|
907
|
+
},
|
|
908
|
+
},
|
|
960
909
|
});
|
|
961
|
-
// disable form when disabled
|
|
962
910
|
effect(() => {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
966
|
-
else {
|
|
967
|
-
this.form.enable();
|
|
968
|
-
}
|
|
911
|
+
const filter = this.filter();
|
|
912
|
+
this.formModel.set({ name: filter?.name || '' });
|
|
969
913
|
});
|
|
970
914
|
}
|
|
971
|
-
updateForm(filter) {
|
|
972
|
-
if (!filter) {
|
|
973
|
-
this.form.reset();
|
|
974
|
-
return;
|
|
975
|
-
}
|
|
976
|
-
this.name.setValue(filter.name || null);
|
|
977
|
-
this.form.markAsPristine();
|
|
978
|
-
}
|
|
979
|
-
getFilter() {
|
|
980
|
-
return {
|
|
981
|
-
name: this.name.value?.trim(),
|
|
982
|
-
};
|
|
983
|
-
}
|
|
984
915
|
reset() {
|
|
985
|
-
this.
|
|
986
|
-
this.
|
|
987
|
-
this.filterChange.emit(this._filter);
|
|
988
|
-
}
|
|
989
|
-
apply() {
|
|
990
|
-
this._filter = this.getFilter();
|
|
991
|
-
this.filterChange.emit(this._filter);
|
|
916
|
+
this.formModel.set({ name: '' });
|
|
917
|
+
this.filterChange.emit({});
|
|
992
918
|
}
|
|
993
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
994
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
919
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
920
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: UserFilterComponent, isStandalone: true, selector: "auth-jwt-user-filter", inputs: { filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange" }, ngImport: i0, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">name or ID</mat-label>\n <input matInput [formField]=\"userForm.name\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Reset filters\"\n [disabled]=\"disabled()\"\n >\n <mat-icon class=\"mat-warn\">clear</mat-icon>\n </button>\n </mat-form-field>\n\n <button\n id=\"apply\"\n type=\"submit\"\n mat-icon-button\n [disabled]=\"disabled()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Apply filters\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#apply{margin-top:-20px}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "directive", type: FormRoot, selector: "form[formRoot]", inputs: ["formRoot"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
995
921
|
}
|
|
996
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
922
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserFilterComponent, decorators: [{
|
|
997
923
|
type: Component,
|
|
998
924
|
args: [{ selector: 'auth-jwt-user-filter', imports: [
|
|
999
|
-
|
|
925
|
+
FormField,
|
|
926
|
+
FormRoot,
|
|
1000
927
|
MatButtonModule,
|
|
1001
928
|
MatFormFieldModule,
|
|
1002
929
|
MatIconModule,
|
|
1003
930
|
MatInputModule,
|
|
1004
931
|
MatTooltipModule,
|
|
1005
|
-
], template: "<form [
|
|
932
|
+
], changeDetection: ChangeDetectionStrategy.Eager, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">name or ID</mat-label>\n <input matInput [formField]=\"userForm.name\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Reset filters\"\n [disabled]=\"disabled()\"\n >\n <mat-icon class=\"mat-warn\">clear</mat-icon>\n </button>\n </mat-form-field>\n\n <button\n id=\"apply\"\n type=\"submit\"\n mat-icon-button\n [disabled]=\"disabled()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Apply filters\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#apply{margin-top:-20px}\n"] }]
|
|
1006
933
|
}], ctorParameters: () => [], propDecorators: { filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }] } });
|
|
1007
934
|
|
|
1008
935
|
/**
|
|
@@ -1011,84 +938,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
1011
938
|
class UserEditorComponent {
|
|
1012
939
|
constructor() {
|
|
1013
940
|
this._authService = inject(AuthJwtService);
|
|
1014
|
-
this.
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
941
|
+
this.formModel = signal({
|
|
942
|
+
email: '',
|
|
943
|
+
emailConfirmed: false,
|
|
944
|
+
lockoutEnabled: false,
|
|
945
|
+
firstName: '',
|
|
946
|
+
lastName: '',
|
|
947
|
+
roles: '',
|
|
948
|
+
}, /* @ts-ignore */
|
|
949
|
+
...(ngDevMode ? [{ debugName: "formModel" }] : /* istanbul ignore next */ []));
|
|
950
|
+
this.userForm = form(this.formModel, (p) => {
|
|
951
|
+
required(p.email);
|
|
952
|
+
email(p.email);
|
|
953
|
+
required(p.firstName);
|
|
954
|
+
maxLength(p.firstName, 50);
|
|
955
|
+
required(p.lastName);
|
|
956
|
+
maxLength(p.lastName, 50);
|
|
957
|
+
maxLength(p.roles, 200);
|
|
958
|
+
}, {
|
|
959
|
+
submission: {
|
|
960
|
+
action: async () => {
|
|
961
|
+
this.userChange.emit(this.getUserFromForm());
|
|
962
|
+
},
|
|
963
|
+
},
|
|
964
|
+
});
|
|
965
|
+
this.unlocked = signal(undefined, /* @ts-ignore */
|
|
966
|
+
...(ngDevMode ? [{ debugName: "unlocked" }] : /* istanbul ignore next */ []));
|
|
967
|
+
this.user = input(undefined, /* @ts-ignore */
|
|
968
|
+
...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
1022
969
|
this.userChange = output();
|
|
1023
|
-
/**
|
|
1024
|
-
* Emitted when the user requests to close the user editor.
|
|
1025
|
-
*/
|
|
1026
970
|
this.editorClose = output();
|
|
1027
|
-
const formBuilder = inject(FormBuilder);
|
|
1028
|
-
// form
|
|
1029
|
-
this.email = formBuilder.control(null, [
|
|
1030
|
-
Validators.required,
|
|
1031
|
-
Validators.email,
|
|
1032
|
-
]);
|
|
1033
|
-
this.emailConfirmed = formBuilder.control(false, {
|
|
1034
|
-
nonNullable: true,
|
|
1035
|
-
});
|
|
1036
|
-
this.lockoutEnabled = formBuilder.control(false, {
|
|
1037
|
-
nonNullable: true,
|
|
1038
|
-
});
|
|
1039
|
-
this.firstName = formBuilder.control(null, [
|
|
1040
|
-
Validators.required,
|
|
1041
|
-
Validators.maxLength(50),
|
|
1042
|
-
]);
|
|
1043
|
-
this.lastName = formBuilder.control(null, [
|
|
1044
|
-
Validators.required,
|
|
1045
|
-
Validators.maxLength(50),
|
|
1046
|
-
]);
|
|
1047
|
-
this.roles = formBuilder.control(null, Validators.maxLength(200));
|
|
1048
|
-
this.form = formBuilder.group({
|
|
1049
|
-
email: this.email,
|
|
1050
|
-
emailConfirmed: this.emailConfirmed,
|
|
1051
|
-
lockoutEnabled: this.lockoutEnabled,
|
|
1052
|
-
firstName: this.firstName,
|
|
1053
|
-
lastName: this.lastName,
|
|
1054
|
-
roles: this.roles,
|
|
1055
|
-
});
|
|
1056
|
-
// update form when user changes
|
|
1057
971
|
effect(() => {
|
|
1058
972
|
this.updateForm(this.user() || undefined);
|
|
1059
973
|
});
|
|
1060
974
|
}
|
|
1061
975
|
updateForm(user) {
|
|
1062
976
|
if (!user) {
|
|
1063
|
-
this.
|
|
977
|
+
this.formModel.set({
|
|
978
|
+
email: '',
|
|
979
|
+
emailConfirmed: false,
|
|
980
|
+
lockoutEnabled: false,
|
|
981
|
+
firstName: '',
|
|
982
|
+
lastName: '',
|
|
983
|
+
roles: '',
|
|
984
|
+
});
|
|
1064
985
|
}
|
|
1065
986
|
else {
|
|
1066
|
-
this.
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
}
|
|
1074
|
-
else {
|
|
1075
|
-
this.roles.setValue(null);
|
|
1076
|
-
}
|
|
987
|
+
this.formModel.set({
|
|
988
|
+
email: user.email,
|
|
989
|
+
emailConfirmed: user.emailConfirmed || false,
|
|
990
|
+
lockoutEnabled: user.lockoutEnabled || false,
|
|
991
|
+
firstName: user.firstName || '',
|
|
992
|
+
lastName: user.lastName || '',
|
|
993
|
+
roles: user.roles?.length > 0 ? user.roles.join(' ') : '',
|
|
994
|
+
});
|
|
1077
995
|
this.unlocked.set(user.lockoutEnabled &&
|
|
1078
996
|
(!user.lockoutEnd || user.lockoutEnd < this._authService.getUTCDate()));
|
|
1079
997
|
}
|
|
1080
998
|
}
|
|
1081
999
|
getUserFromForm() {
|
|
1000
|
+
const m = this.formModel();
|
|
1082
1001
|
return {
|
|
1083
1002
|
userName: this.user()?.userName || '',
|
|
1084
|
-
email:
|
|
1085
|
-
emailConfirmed:
|
|
1086
|
-
lockoutEnabled:
|
|
1087
|
-
firstName:
|
|
1088
|
-
lastName:
|
|
1089
|
-
roles:
|
|
1090
|
-
? this.roles.value.split(' ').filter((s) => s)
|
|
1091
|
-
: [],
|
|
1003
|
+
email: m.email || '',
|
|
1004
|
+
emailConfirmed: m.emailConfirmed,
|
|
1005
|
+
lockoutEnabled: m.lockoutEnabled,
|
|
1006
|
+
firstName: m.firstName || '',
|
|
1007
|
+
lastName: m.lastName || '',
|
|
1008
|
+
roles: m.roles.trim() ? m.roles.split(' ').filter((s) => s) : [],
|
|
1092
1009
|
};
|
|
1093
1010
|
}
|
|
1094
1011
|
endLockout() {
|
|
@@ -1102,26 +1019,21 @@ class UserEditorComponent {
|
|
|
1102
1019
|
close() {
|
|
1103
1020
|
this.editorClose.emit();
|
|
1104
1021
|
}
|
|
1105
|
-
|
|
1106
|
-
if (this.form.
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
this.userChange.emit(this.getUserFromForm());
|
|
1110
|
-
}
|
|
1111
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: UserEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1112
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: UserEditorComponent, isStandalone: true, selector: "auth-jwt-user-editor", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { userChange: "userChange", editorClose: "editorClose" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\r\n <div class=\"form-row\">\r\n <!-- email -->\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">email</mat-label>\r\n <input type=\"text\" matInput [formControl]=\"email\" />\r\n @if (email.hasError('required') && (email.dirty || email.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\"> email address required </mat-error>\r\n } @if (email.hasError('pattern') && (email.dirty || email.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\"> invalid email address </mat-error>\r\n }\r\n </mat-form-field>\r\n\r\n <!-- emailConfirmed -->\r\n <mat-checkbox [formControl]=\"emailConfirmed\" i18n=\"auth-jwt-admin\"\r\n >email address confirmed</mat-checkbox\r\n >\r\n </div>\r\n\r\n <!-- lockoutEnabled -->\r\n <div class=\"form-row\">\r\n <mat-checkbox [formControl]=\"lockoutEnabled\" i18n=\"auth-jwt-admin\"\r\n >lockout enabled</mat-checkbox\r\n >\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n (click)=\"endLockout()\"\r\n [disabled]=\"unlocked()\"\r\n i18n-matTooltip=\"auth-jwt-admin\"\r\n matTooltip=\"Unlock this user if locked\"\r\n >\r\n <mat-icon class=\"mat-primary\">lock_open</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"form-row\">\r\n <!-- firstName -->\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\r\n <input type=\"text\" matInput [formControl]=\"firstName\" />\r\n @if ( firstName.hasError('required') && (firstName.dirty ||\r\n firstName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"> first name required </mat-error>\r\n } @if ( firstName.hasError('maxlength') && (firstName.dirty ||\r\n firstName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"> first name too long </mat-error>\r\n }\r\n </mat-form-field>\r\n\r\n <!-- lastName -->\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\r\n <input type=\"text\" matInput [formControl]=\"lastName\" />\r\n @if ( lastName.hasError('required') && (lastName.dirty ||\r\n lastName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"> last name required </mat-error>\r\n } @if ( lastName.hasError('maxlength') && (lastName.dirty ||\r\n lastName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"> last name too long </mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- roles -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">roles</mat-label>\r\n <input type=\"text\" matInput [formControl]=\"roles\" />\r\n @if (roles.hasError('maxlength') && (roles.dirty || roles.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\"> too long </mat-error>\r\n }\r\n <mat-hint i18n>roles (separated by space)</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- buttons -->\r\n <br />\r\n <div>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n i18n-matTooltip=\"auth-jwt-admin\"\r\n matTooltip=\"Close\"\r\n (click)=\"close()\"\r\n >\r\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\r\n </button>\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n color=\"primary\"\r\n [disabled]=\"form.invalid\"\r\n i18n-matTooltip=\"auth-jwt-admin\"\r\n matTooltip=\"Save user\"\r\n >\r\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\r\n </button>\r\n </div>\r\n</form>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { 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.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: MatTooltipModule }, { kind: "directive", type: i6$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
1022
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1023
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: UserEditorComponent, isStandalone: true, selector: "auth-jwt-user-editor", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { userChange: "userChange", editorClose: "editorClose" }, ngImport: i0, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <!-- email -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">email</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.email\" />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email address required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email address</mat-error>\n }\n </mat-form-field>\n\n <!-- emailConfirmed -->\n <mat-checkbox [formField]=\"userForm.emailConfirmed\" i18n=\"auth-jwt-admin\">\n email address confirmed\n </mat-checkbox>\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formField]=\"userForm.lockoutEnabled\" i18n=\"auth-jwt-admin\">\n lockout enabled\n </mat-checkbox>\n <button\n type=\"button\"\n mat-icon-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Unlock this user if locked\"\n >\n <mat-icon class=\"mat-primary\">lock_open</mat-icon>\n </button>\n </div>\n\n <div class=\"form-row\">\n <!-- firstName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.firstName\" />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name required</mat-error>\n }\n @if (userForm.firstName().getError('maxLength') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name too long</mat-error>\n }\n </mat-form-field>\n\n <!-- lastName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.lastName\" />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name required</mat-error>\n }\n @if (userForm.lastName().getError('maxLength') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name too long</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">roles</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.roles\" />\n @if (userForm.roles().getError('maxLength') && (userForm.roles().dirty() || userForm.roles().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">too long</mat-error>\n }\n <mat-hint i18n>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button\n type=\"button\"\n mat-icon-button\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Close\"\n (click)=\"close()\"\n >\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\n </button>\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"!userForm().valid()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Save user\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "directive", type: FormRoot, selector: "form[formRoot]", inputs: ["formRoot"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i2$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.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: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
1113
1024
|
}
|
|
1114
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1025
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserEditorComponent, decorators: [{
|
|
1115
1026
|
type: Component,
|
|
1116
1027
|
args: [{ selector: 'auth-jwt-user-editor', imports: [
|
|
1117
|
-
|
|
1028
|
+
FormField,
|
|
1029
|
+
FormRoot,
|
|
1118
1030
|
MatButtonModule,
|
|
1119
1031
|
MatCheckboxModule,
|
|
1120
1032
|
MatFormFieldModule,
|
|
1121
1033
|
MatIconModule,
|
|
1122
1034
|
MatInputModule,
|
|
1123
1035
|
MatTooltipModule,
|
|
1124
|
-
], template: "<form [
|
|
1036
|
+
], changeDetection: ChangeDetectionStrategy.Eager, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <!-- email -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">email</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.email\" />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email address required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email address</mat-error>\n }\n </mat-form-field>\n\n <!-- emailConfirmed -->\n <mat-checkbox [formField]=\"userForm.emailConfirmed\" i18n=\"auth-jwt-admin\">\n email address confirmed\n </mat-checkbox>\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formField]=\"userForm.lockoutEnabled\" i18n=\"auth-jwt-admin\">\n lockout enabled\n </mat-checkbox>\n <button\n type=\"button\"\n mat-icon-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Unlock this user if locked\"\n >\n <mat-icon class=\"mat-primary\">lock_open</mat-icon>\n </button>\n </div>\n\n <div class=\"form-row\">\n <!-- firstName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.firstName\" />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name required</mat-error>\n }\n @if (userForm.firstName().getError('maxLength') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name too long</mat-error>\n }\n </mat-form-field>\n\n <!-- lastName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.lastName\" />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name required</mat-error>\n }\n @if (userForm.lastName().getError('maxLength') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name too long</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">roles</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.roles\" />\n @if (userForm.roles().getError('maxLength') && (userForm.roles().dirty() || userForm.roles().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">too long</mat-error>\n }\n <mat-hint i18n>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button\n type=\"button\"\n mat-icon-button\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Close\"\n (click)=\"close()\"\n >\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\n </button>\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"!userForm().valid()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Save user\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
1125
1037
|
}], ctorParameters: () => [], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }], userChange: [{ type: i0.Output, args: ["userChange"] }], editorClose: [{ type: i0.Output, args: ["editorClose"] }] } });
|
|
1126
1038
|
|
|
1127
1039
|
/**
|
|
@@ -1174,14 +1086,13 @@ class UserListComponent {
|
|
|
1174
1086
|
getGravatarUrl(email, options) {
|
|
1175
1087
|
return this._gravatarService.buildGravatarUrl(email, options);
|
|
1176
1088
|
}
|
|
1177
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1178
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1089
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1090
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: UserListComponent, isStandalone: true, selector: "auth-jwt-user-list", ngImport: i0, template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div id=\"filters\">\n <auth-jwt-user-filter\n [filter]=\"filter$ | async\"\n (filterChange)=\"onFilterChange($event)\"\n ></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n @if (page$ | async; as page) {\n <div id=\"list\">\n @if (loading$ | async) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n <table>\n <thead>\n <td></td>\n <td></td>\n <th i18n=\"auth-jwt-admin\">name</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">first</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">last</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">email</th>\n <th i18n=\"auth-jwt-admin\">roles</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">lock end</th>\n </thead>\n <tbody>\n @for (user of page.items; track user) {\n <tr>\n <td class=\"fit-width\">\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Edit this user\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon class=\"mat-primary\">mode_edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Delete this user\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\n </button>\n </td>\n <td class=\"fit-width\">\n <img\n alt=\"avatar\"\n [src]=\"getGravatarUrl(user.email, { size: '32' })\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td class=\"noif-lt-md\">{{ user.firstName }}</td>\n <td class=\"noif-lt-md\">{{ user.lastName }}</td>\n <td class=\"noif-lt-md\">\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td class=\"noif-lt-md\">{{ user.lockoutEnd }}</td>\n </tr>\n }\n </tbody>\n </table>\n <!-- paginator -->\n <div class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matmatTooltip=\"auth-jwt-admin\"\n matTooltip=\"Refresh list\"\n (click)=\"reset()\"\n >\n <mat-icon class=\"mat-warn\">autorenew</mat-icon>\n </button>\n <mat-paginator\n [length]=\"page.total\"\n [pageIndex]=\"page.pageNumber - 1\"\n [pageSize]=\"page.pageSize\"\n [pageSizeOptions]=\"[5, 10, 20, 50, 100]\"\n (page)=\"onPageChange($event)\"\n [showFirstLastButtons]=\"true\"\n ></mat-paginator>\n </div>\n </div>\n }\n </div>\n\n <!-- editor -->\n <mat-expansion-panel\n id=\"editor\"\n [expanded]=\"active$ | async\"\n [disabled]=\"!(active$ | async)\"\n >\n @if (active$ | async; as active) {\n <div>\n <fieldset>\n <legend>{{ active.userName }}</legend>\n <auth-jwt-user-editor\n [user]=\"active\"\n (userChange)=\"saveActiveUser($event)\"\n (editorClose)=\"resetActiveUser()\"\n ></auth-jwt-user-editor>\n </fieldset>\n </div>\n }\n </mat-expansion-panel>\n</div>\n", styles: ["table{width:100%;border-collapse:collapse}tbody tr:nth-child(odd){background-color:var(--mat-sys-surface-container)}th{text-align:left;font-weight:400;color:var(--mat-sys-on-surface-variant)}tbody tr:hover{background-color:var(--mat-sys-surface-container-high)}td.fit-width{width:1px;white-space:nowrap}tbody tr.selected{background-color:var(--mat-sys-secondary-container);color:var(--mat-sys-on-secondary-container)}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}div#filters{grid-area:filters}div#list{grid-area:list}div#editor{grid-area:editor}div#container{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:1fr;grid-template-areas:\"filters\" \"list\" \"editor\";gap:8px}@media only screen and (max-width:959px){.noif-lt-md{display:none}}@media only screen and (min-width:1920px){div#container{grid-template-rows:auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"filters filters\" \"list editor\"}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i2$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i4$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i5$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: ["user"], outputs: ["userChange", "editorClose"] }, { kind: "component", type: UserFilterComponent, selector: "auth-jwt-user-filter", inputs: ["filter", "disabled"], outputs: ["filterChange"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
1179
1091
|
}
|
|
1180
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1092
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListComponent, decorators: [{
|
|
1181
1093
|
type: Component,
|
|
1182
1094
|
args: [{ selector: 'auth-jwt-user-list', imports: [
|
|
1183
1095
|
CommonModule,
|
|
1184
|
-
ReactiveFormsModule,
|
|
1185
1096
|
MatButtonModule,
|
|
1186
1097
|
MatExpansionModule,
|
|
1187
1098
|
MatIconModule,
|
|
@@ -1191,7 +1102,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
1191
1102
|
MatTooltipModule,
|
|
1192
1103
|
UserEditorComponent,
|
|
1193
1104
|
UserFilterComponent,
|
|
1194
|
-
], template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div id=\"filters\">\n <auth-jwt-user-filter\n [filter]=\"filter$ | async\"\n (filterChange)=\"onFilterChange($event)\"\n ></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n @if (page$ | async; as page) {\n <div id=\"list\">\n @if (loading$ | async) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n <table>\n <thead>\n <td></td>\n <td></td>\n <th i18n=\"auth-jwt-admin\">name</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">first</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">last</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">email</th>\n <th i18n=\"auth-jwt-admin\">roles</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">lock end</th>\n </thead>\n <tbody>\n @for (user of page.items; track user) {\n <tr>\n <td class=\"fit-width\">\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Edit this user\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon class=\"mat-primary\">mode_edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Delete this user\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\n </button>\n </td>\n <td class=\"fit-width\">\n <img\n alt=\"avatar\"\n [src]=\"getGravatarUrl(user.email, { size: '32' })\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td class=\"noif-lt-md\">{{ user.firstName }}</td>\n <td class=\"noif-lt-md\">{{ user.lastName }}</td>\n <td class=\"noif-lt-md\">\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td class=\"noif-lt-md\">{{ user.lockoutEnd }}</td>\n </tr>\n }\n </tbody>\n </table>\n <!-- paginator -->\n <div class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matmatTooltip=\"auth-jwt-admin\"\n matTooltip=\"Refresh list\"\n (click)=\"reset()\"\n >\n <mat-icon class=\"mat-warn\">autorenew</mat-icon>\n </button>\n <mat-paginator\n [length]=\"page.total\"\n [pageIndex]=\"page.pageNumber - 1\"\n [pageSize]=\"page.pageSize\"\n [pageSizeOptions]=\"[5, 10, 20, 50, 100]\"\n (page)=\"onPageChange($event)\"\n [showFirstLastButtons]=\"true\"\n ></mat-paginator>\n </div>\n </div>\n }\n </div>\n\n <!-- editor -->\n <mat-expansion-panel\n id=\"editor\"\n [expanded]=\"active$ | async\"\n [disabled]=\"!(active$ | async)\"\n >\n @if (active$ | async; as active) {\n <div>\n <fieldset>\n <legend>{{ active.userName }}</legend>\n <auth-jwt-user-editor\n [user]=\"active\"\n (userChange)=\"saveActiveUser($event)\"\n (editorClose)=\"resetActiveUser()\"\n ></auth-jwt-user-editor>\n </fieldset>\n </div>\n }\n </mat-expansion-panel>\n</div>\n", styles: ["table{width:100%;border-collapse:collapse}tbody tr:nth-child(odd){background-color:var(--mat-sys-surface-container)}th{text-align:left;font-weight:400;color:var(--mat-sys-on-surface-variant)}tbody tr:hover{background-color:var(--mat-sys-surface-container-high)}td.fit-width{width:1px;white-space:nowrap}tbody tr.selected{background-color:var(--mat-sys-secondary-container);color:var(--mat-sys-on-secondary-container)}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}div#filters{grid-area:filters}div#list{grid-area:list}div#editor{grid-area:editor}div#container{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:1fr;grid-template-areas:\"filters\" \"list\" \"editor\";gap:8px}@media only screen and (max-width:959px){.noif-lt-md{display:none}}@media only screen and (min-width:1920px){div#container{grid-template-rows:auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"filters filters\" \"list editor\"}}\n"] }]
|
|
1105
|
+
], changeDetection: ChangeDetectionStrategy.Eager, template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div id=\"filters\">\n <auth-jwt-user-filter\n [filter]=\"filter$ | async\"\n (filterChange)=\"onFilterChange($event)\"\n ></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n @if (page$ | async; as page) {\n <div id=\"list\">\n @if (loading$ | async) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n <table>\n <thead>\n <td></td>\n <td></td>\n <th i18n=\"auth-jwt-admin\">name</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">first</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">last</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">email</th>\n <th i18n=\"auth-jwt-admin\">roles</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">lock end</th>\n </thead>\n <tbody>\n @for (user of page.items; track user) {\n <tr>\n <td class=\"fit-width\">\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Edit this user\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon class=\"mat-primary\">mode_edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Delete this user\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\n </button>\n </td>\n <td class=\"fit-width\">\n <img\n alt=\"avatar\"\n [src]=\"getGravatarUrl(user.email, { size: '32' })\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td class=\"noif-lt-md\">{{ user.firstName }}</td>\n <td class=\"noif-lt-md\">{{ user.lastName }}</td>\n <td class=\"noif-lt-md\">\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td class=\"noif-lt-md\">{{ user.lockoutEnd }}</td>\n </tr>\n }\n </tbody>\n </table>\n <!-- paginator -->\n <div class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matmatTooltip=\"auth-jwt-admin\"\n matTooltip=\"Refresh list\"\n (click)=\"reset()\"\n >\n <mat-icon class=\"mat-warn\">autorenew</mat-icon>\n </button>\n <mat-paginator\n [length]=\"page.total\"\n [pageIndex]=\"page.pageNumber - 1\"\n [pageSize]=\"page.pageSize\"\n [pageSizeOptions]=\"[5, 10, 20, 50, 100]\"\n (page)=\"onPageChange($event)\"\n [showFirstLastButtons]=\"true\"\n ></mat-paginator>\n </div>\n </div>\n }\n </div>\n\n <!-- editor -->\n <mat-expansion-panel\n id=\"editor\"\n [expanded]=\"active$ | async\"\n [disabled]=\"!(active$ | async)\"\n >\n @if (active$ | async; as active) {\n <div>\n <fieldset>\n <legend>{{ active.userName }}</legend>\n <auth-jwt-user-editor\n [user]=\"active\"\n (userChange)=\"saveActiveUser($event)\"\n (editorClose)=\"resetActiveUser()\"\n ></auth-jwt-user-editor>\n </fieldset>\n </div>\n }\n </mat-expansion-panel>\n</div>\n", styles: ["table{width:100%;border-collapse:collapse}tbody tr:nth-child(odd){background-color:var(--mat-sys-surface-container)}th{text-align:left;font-weight:400;color:var(--mat-sys-on-surface-variant)}tbody tr:hover{background-color:var(--mat-sys-surface-container-high)}td.fit-width{width:1px;white-space:nowrap}tbody tr.selected{background-color:var(--mat-sys-secondary-container);color:var(--mat-sys-on-secondary-container)}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}div#filters{grid-area:filters}div#list{grid-area:list}div#editor{grid-area:editor}div#container{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:1fr;grid-template-areas:\"filters\" \"list\" \"editor\";gap:8px}@media only screen and (max-width:959px){.noif-lt-md{display:none}}@media only screen and (min-width:1920px){div#container{grid-template-rows:auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"filters filters\" \"list editor\"}}\n"] }]
|
|
1195
1106
|
}], ctorParameters: () => [] });
|
|
1196
1107
|
|
|
1197
1108
|
/*
|