@myrmidon/auth-jwt-admin 8.0.2 → 8.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -24
- package/fesm2022/myrmidon-auth-jwt-admin.mjs +369 -92
- package/fesm2022/myrmidon-auth-jwt-admin.mjs.map +1 -1
- package/package.json +9 -9
- package/src/locale/messages.it.xlf +558 -558
- package/src/locale/messages.xlf +494 -494
- package/types/myrmidon-auth-jwt-admin.d.ts +343 -0
- package/index.d.ts +0 -267
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, input, output,
|
|
2
|
+
import { inject, Injectable, input, output, computed, effect, ChangeDetectionStrategy, Component, signal } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
4
|
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
5
5
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
@@ -223,10 +223,10 @@ class AuthJwtAccountService {
|
|
|
223
223
|
.delete(this._env.get('apiUrl') + 'accounts/' + name)
|
|
224
224
|
.pipe(catchError(this._error.handleError));
|
|
225
225
|
}
|
|
226
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
227
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
226
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AuthJwtAccountService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
227
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' }); }
|
|
228
228
|
}
|
|
229
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
229
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AuthJwtAccountService, decorators: [{
|
|
230
230
|
type: Injectable,
|
|
231
231
|
args: [{
|
|
232
232
|
providedIn: 'root',
|
|
@@ -398,89 +398,290 @@ class UserListRepository {
|
|
|
398
398
|
});
|
|
399
399
|
return promise;
|
|
400
400
|
}
|
|
401
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
402
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
401
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserListRepository, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
402
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserListRepository, providedIn: 'root' }); }
|
|
403
403
|
}
|
|
404
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
404
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserListRepository, decorators: [{
|
|
405
405
|
type: Injectable,
|
|
406
406
|
args: [{ providedIn: 'root' }]
|
|
407
407
|
}], ctorParameters: () => [] });
|
|
408
408
|
|
|
409
|
-
|
|
409
|
+
/**
|
|
410
|
+
* Default labels for password rules.
|
|
411
|
+
*/
|
|
412
|
+
const DEFAULT_RULE_LABELS = {
|
|
413
|
+
minLength: 'At least {value} characters',
|
|
414
|
+
maxLength: 'No more than {value} characters',
|
|
415
|
+
hasUppercase: 'Contains uppercase letter',
|
|
416
|
+
hasLowercase: 'Contains lowercase letter',
|
|
417
|
+
hasNumber: 'Contains number',
|
|
418
|
+
hasSymbol: 'Contains symbol',
|
|
419
|
+
noUsername: 'Does not contain username',
|
|
420
|
+
noEmail: 'Does not contain email',
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* A modern, fully reactive password checklist component with strength meter.
|
|
424
|
+
* Uses only signals for state management and is ready for zoneless Angular.
|
|
425
|
+
*/
|
|
426
|
+
class PasswordChecklistComponent {
|
|
410
427
|
constructor() {
|
|
411
|
-
|
|
412
|
-
this.
|
|
413
|
-
this.
|
|
414
|
-
this.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
428
|
+
// Input signals for password and context
|
|
429
|
+
this.password = input('', ...(ngDevMode ? [{ debugName: "password" }] : []));
|
|
430
|
+
this.username = input('', ...(ngDevMode ? [{ debugName: "username" }] : []));
|
|
431
|
+
this.email = input('', ...(ngDevMode ? [{ debugName: "email" }] : []));
|
|
432
|
+
this.hidden = input(false, ...(ngDevMode ? [{ debugName: "hidden" }] : []));
|
|
433
|
+
// Input signals for rule configuration
|
|
434
|
+
this.minLength = input(null, ...(ngDevMode ? [{ debugName: "minLength" }] : []));
|
|
435
|
+
this.maxLength = input(null, ...(ngDevMode ? [{ debugName: "maxLength" }] : []));
|
|
436
|
+
this.requireUppercase = input(false, ...(ngDevMode ? [{ debugName: "requireUppercase" }] : []));
|
|
437
|
+
this.requireLowercase = input(false, ...(ngDevMode ? [{ debugName: "requireLowercase" }] : []));
|
|
438
|
+
this.requireNumber = input(false, ...(ngDevMode ? [{ debugName: "requireNumber" }] : []));
|
|
439
|
+
this.requireSymbol = input(false, ...(ngDevMode ? [{ debugName: "requireSymbol" }] : []));
|
|
440
|
+
this.checkUsername = input(false, ...(ngDevMode ? [{ debugName: "checkUsername" }] : []));
|
|
441
|
+
this.checkEmail = input(false, ...(ngDevMode ? [{ debugName: "checkEmail" }] : []));
|
|
442
|
+
// Input signals for custom labels
|
|
443
|
+
this.minLengthLabel = input(null, ...(ngDevMode ? [{ debugName: "minLengthLabel" }] : []));
|
|
444
|
+
this.maxLengthLabel = input(null, ...(ngDevMode ? [{ debugName: "maxLengthLabel" }] : []));
|
|
445
|
+
this.uppercaseLabel = input(null, ...(ngDevMode ? [{ debugName: "uppercaseLabel" }] : []));
|
|
446
|
+
this.lowercaseLabel = input(null, ...(ngDevMode ? [{ debugName: "lowercaseLabel" }] : []));
|
|
447
|
+
this.numberLabel = input(null, ...(ngDevMode ? [{ debugName: "numberLabel" }] : []));
|
|
448
|
+
this.symbolLabel = input(null, ...(ngDevMode ? [{ debugName: "symbolLabel" }] : []));
|
|
449
|
+
this.usernameLabel = input(null, ...(ngDevMode ? [{ debugName: "usernameLabel" }] : []));
|
|
450
|
+
this.emailLabel = input(null, ...(ngDevMode ? [{ debugName: "emailLabel" }] : []));
|
|
451
|
+
// Input signals for display options
|
|
452
|
+
this.noChecklist = input(false, ...(ngDevMode ? [{ debugName: "noChecklist" }] : []));
|
|
453
|
+
this.noMeter = input(false, ...(ngDevMode ? [{ debugName: "noMeter" }] : []));
|
|
454
|
+
// Output signal for validity
|
|
455
|
+
this.validChange = output();
|
|
456
|
+
// Symbol regex pattern
|
|
457
|
+
this.symbolRegex = /[-`~!@#$%^&*()_+=\[\]{};:'",.<>/?|\\]/;
|
|
458
|
+
// Computed signals for individual rule checks
|
|
459
|
+
this.hasMinLength = computed(() => {
|
|
460
|
+
const min = this.minLength();
|
|
461
|
+
return min === null || this.password().length >= min;
|
|
462
|
+
}, ...(ngDevMode ? [{ debugName: "hasMinLength" }] : []));
|
|
463
|
+
this.hasMaxLength = computed(() => {
|
|
464
|
+
const max = this.maxLength();
|
|
465
|
+
return max === null || this.password().length <= max;
|
|
466
|
+
}, ...(ngDevMode ? [{ debugName: "hasMaxLength" }] : []));
|
|
467
|
+
this.hasUppercase = computed(() => {
|
|
468
|
+
return /[A-Z]/.test(this.password());
|
|
469
|
+
}, ...(ngDevMode ? [{ debugName: "hasUppercase" }] : []));
|
|
470
|
+
this.hasLowercase = computed(() => {
|
|
471
|
+
return /[a-z]/.test(this.password());
|
|
472
|
+
}, ...(ngDevMode ? [{ debugName: "hasLowercase" }] : []));
|
|
473
|
+
this.hasNumber = computed(() => {
|
|
474
|
+
return /[0-9]/.test(this.password());
|
|
475
|
+
}, ...(ngDevMode ? [{ debugName: "hasNumber" }] : []));
|
|
476
|
+
this.hasSymbol = computed(() => {
|
|
477
|
+
return this.symbolRegex.test(this.password());
|
|
478
|
+
}, ...(ngDevMode ? [{ debugName: "hasSymbol" }] : []));
|
|
479
|
+
this.noUsernameInPassword = computed(() => {
|
|
480
|
+
const username = this.username().toLowerCase();
|
|
481
|
+
const pwd = this.password().toLowerCase();
|
|
482
|
+
return !username || !pwd || !pwd.includes(username);
|
|
483
|
+
}, ...(ngDevMode ? [{ debugName: "noUsernameInPassword" }] : []));
|
|
484
|
+
this.noEmailInPassword = computed(() => {
|
|
485
|
+
const email = this.email().toLowerCase();
|
|
486
|
+
const pwd = this.password().toLowerCase();
|
|
487
|
+
return !email || !pwd || !pwd.includes(email);
|
|
488
|
+
}, ...(ngDevMode ? [{ debugName: "noEmailInPassword" }] : []));
|
|
489
|
+
// Computed signal for all rules with their status
|
|
490
|
+
this.rules = computed(() => {
|
|
491
|
+
const rules = [];
|
|
492
|
+
if (this.minLength() !== null) {
|
|
493
|
+
rules.push({
|
|
494
|
+
id: 'minLength',
|
|
495
|
+
label: this.getLabel('minLength', this.minLengthLabel(), this.minLength()),
|
|
496
|
+
enabled: true,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
if (this.maxLength() !== null) {
|
|
500
|
+
rules.push({
|
|
501
|
+
id: 'maxLength',
|
|
502
|
+
label: this.getLabel('maxLength', this.maxLengthLabel(), this.maxLength()),
|
|
503
|
+
enabled: true,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
if (this.requireUppercase()) {
|
|
507
|
+
rules.push({
|
|
508
|
+
id: 'hasUppercase',
|
|
509
|
+
label: this.getLabel('hasUppercase', this.uppercaseLabel()),
|
|
510
|
+
enabled: true,
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
if (this.requireLowercase()) {
|
|
514
|
+
rules.push({
|
|
515
|
+
id: 'hasLowercase',
|
|
516
|
+
label: this.getLabel('hasLowercase', this.lowercaseLabel()),
|
|
517
|
+
enabled: true,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
if (this.requireNumber()) {
|
|
521
|
+
rules.push({
|
|
522
|
+
id: 'hasNumber',
|
|
523
|
+
label: this.getLabel('hasNumber', this.numberLabel()),
|
|
524
|
+
enabled: true,
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
if (this.requireSymbol()) {
|
|
528
|
+
rules.push({
|
|
529
|
+
id: 'hasSymbol',
|
|
530
|
+
label: this.getLabel('hasSymbol', this.symbolLabel()),
|
|
531
|
+
enabled: true,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
if (this.checkUsername()) {
|
|
535
|
+
rules.push({
|
|
536
|
+
id: 'noUsername',
|
|
537
|
+
label: this.getLabel('noUsername', this.usernameLabel()),
|
|
538
|
+
enabled: true,
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
if (this.checkEmail()) {
|
|
542
|
+
rules.push({
|
|
543
|
+
id: 'noEmail',
|
|
544
|
+
label: this.getLabel('noEmail', this.emailLabel()),
|
|
545
|
+
enabled: true,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return rules;
|
|
549
|
+
}, ...(ngDevMode ? [{ debugName: "rules" }] : []));
|
|
550
|
+
// Computed signal to check if a specific rule is satisfied
|
|
551
|
+
this.isRuleSatisfied = computed(() => {
|
|
552
|
+
return (ruleId) => {
|
|
553
|
+
switch (ruleId) {
|
|
554
|
+
case 'minLength':
|
|
555
|
+
return this.hasMinLength();
|
|
556
|
+
case 'maxLength':
|
|
557
|
+
return this.hasMaxLength();
|
|
558
|
+
case 'hasUppercase':
|
|
559
|
+
return this.hasUppercase();
|
|
560
|
+
case 'hasLowercase':
|
|
561
|
+
return this.hasLowercase();
|
|
562
|
+
case 'hasNumber':
|
|
563
|
+
return this.hasNumber();
|
|
564
|
+
case 'hasSymbol':
|
|
565
|
+
return this.hasSymbol();
|
|
566
|
+
case 'noUsername':
|
|
567
|
+
return this.noUsernameInPassword();
|
|
568
|
+
case 'noEmail':
|
|
569
|
+
return this.noEmailInPassword();
|
|
570
|
+
default:
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
}, ...(ngDevMode ? [{ debugName: "isRuleSatisfied" }] : []));
|
|
575
|
+
// Computed signal for overall validity
|
|
576
|
+
this.isValid = computed(() => {
|
|
577
|
+
const rules = this.rules();
|
|
578
|
+
if (rules.length === 0) {
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
const checkFn = this.isRuleSatisfied();
|
|
582
|
+
return rules.every((rule) => checkFn(rule.id));
|
|
583
|
+
}, ...(ngDevMode ? [{ debugName: "isValid" }] : []));
|
|
584
|
+
// Computed signal for password strength (0-100)
|
|
585
|
+
this.strength = computed(() => {
|
|
586
|
+
const pwd = this.password();
|
|
587
|
+
if (!pwd) {
|
|
588
|
+
return 0;
|
|
589
|
+
}
|
|
590
|
+
let score = 0;
|
|
591
|
+
// Length contribution (max 30 points)
|
|
592
|
+
const lengthScore = Math.min(pwd.length * 2, 30);
|
|
593
|
+
score += lengthScore;
|
|
594
|
+
// Character variety (max 40 points, 10 per type)
|
|
595
|
+
const hasLower = /[a-z]/.test(pwd);
|
|
596
|
+
const hasUpper = /[A-Z]/.test(pwd);
|
|
597
|
+
const hasDigit = /[0-9]/.test(pwd);
|
|
598
|
+
const hasSymbol = this.symbolRegex.test(pwd);
|
|
599
|
+
score += hasLower ? 10 : 0;
|
|
600
|
+
score += hasUpper ? 10 : 0;
|
|
601
|
+
score += hasDigit ? 10 : 0;
|
|
602
|
+
score += hasSymbol ? 10 : 0;
|
|
603
|
+
// Entropy bonus (max 30 points)
|
|
604
|
+
const uniqueChars = new Set(pwd).size;
|
|
605
|
+
const entropyScore = Math.min((uniqueChars / pwd.length) * 30, 30);
|
|
606
|
+
score += entropyScore;
|
|
607
|
+
// Penalties
|
|
608
|
+
if (pwd.length < 8) {
|
|
609
|
+
score = Math.min(score, 20);
|
|
610
|
+
}
|
|
611
|
+
const varietyCount = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;
|
|
612
|
+
if (varietyCount === 1) {
|
|
613
|
+
score = Math.min(score, 20);
|
|
614
|
+
}
|
|
615
|
+
else if (varietyCount === 2) {
|
|
616
|
+
score = Math.min(score, 40);
|
|
617
|
+
}
|
|
618
|
+
else if (varietyCount === 3) {
|
|
619
|
+
score = Math.min(score, 70);
|
|
620
|
+
}
|
|
621
|
+
return Math.min(Math.round(score), 100);
|
|
622
|
+
}, ...(ngDevMode ? [{ debugName: "strength" }] : []));
|
|
623
|
+
// Computed signal for strength level (0-4)
|
|
624
|
+
this.strengthLevel = computed(() => {
|
|
625
|
+
const strength = this.strength();
|
|
626
|
+
if (strength <= 20)
|
|
627
|
+
return 0;
|
|
628
|
+
if (strength <= 40)
|
|
629
|
+
return 1;
|
|
630
|
+
if (strength <= 60)
|
|
631
|
+
return 2;
|
|
632
|
+
if (strength <= 80)
|
|
633
|
+
return 3;
|
|
634
|
+
return 4;
|
|
635
|
+
}, ...(ngDevMode ? [{ debugName: "strengthLevel" }] : []));
|
|
636
|
+
// Computed signal for strength color
|
|
637
|
+
this.strengthColor = computed(() => {
|
|
638
|
+
const colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
|
|
639
|
+
return colors[this.strengthLevel()];
|
|
640
|
+
}, ...(ngDevMode ? [{ debugName: "strengthColor" }] : []));
|
|
641
|
+
// Computed signal for strength percentage
|
|
642
|
+
this.strengthPercent = computed(() => {
|
|
643
|
+
return this.strength();
|
|
644
|
+
}, ...(ngDevMode ? [{ debugName: "strengthPercent" }] : []));
|
|
645
|
+
// Effect to emit validity changes
|
|
646
|
+
// This will automatically track the isValid computed signal
|
|
647
|
+
effect(() => {
|
|
648
|
+
const isValid = this.isValid();
|
|
649
|
+
// Emit the validity status whenever it changes
|
|
650
|
+
this.validChange.emit(isValid);
|
|
651
|
+
});
|
|
437
652
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
idx = 1;
|
|
445
|
-
}
|
|
446
|
-
else if (s <= 30) {
|
|
447
|
-
idx = 2;
|
|
448
|
-
}
|
|
449
|
-
else if (s <= 40) {
|
|
450
|
-
idx = 3;
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
idx = 4;
|
|
653
|
+
/**
|
|
654
|
+
* Gets the label for a rule, using custom label if provided, otherwise default.
|
|
655
|
+
*/
|
|
656
|
+
getLabel(ruleId, customLabel, value) {
|
|
657
|
+
if (customLabel) {
|
|
658
|
+
return this.interpolateLabel(customLabel, value);
|
|
454
659
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
col: this._colors[idx],
|
|
458
|
-
};
|
|
660
|
+
const defaultLabel = DEFAULT_RULE_LABELS[ruleId] || ruleId;
|
|
661
|
+
return this.interpolateLabel(defaultLabel, value);
|
|
459
662
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
this.setBarColors(c.idx, c.col);
|
|
467
|
-
this.strengthChange.emit(strength);
|
|
663
|
+
/**
|
|
664
|
+
* Interpolates {value} placeholder in label.
|
|
665
|
+
*/
|
|
666
|
+
interpolateLabel(label, value) {
|
|
667
|
+
if (value !== undefined) {
|
|
668
|
+
return label.replace('{value}', value.toString());
|
|
468
669
|
}
|
|
670
|
+
return label;
|
|
469
671
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
this.bars.set(bars);
|
|
672
|
+
/**
|
|
673
|
+
* Helper method to check if a rule is satisfied (for template use).
|
|
674
|
+
*/
|
|
675
|
+
checkRule(ruleId) {
|
|
676
|
+
return this.isRuleSatisfied()(ruleId);
|
|
476
677
|
}
|
|
477
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
478
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
678
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: PasswordChecklistComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
679
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", 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:#ddd;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:#4caf50;color:#fff}.checklist-item.unsatisfied .checklist-icon{background-color:#f44336;color:#fff}.checklist-text{flex:1}.checklist-item.satisfied .checklist-text{color:#4caf50}.checklist-item.unsatisfied .checklist-text{color:#f44336}@media(prefers-color-scheme:dark){.strength-bar-container{background-color:#444}.checklist-item.satisfied .checklist-text{color:#81c784}.checklist-item.unsatisfied .checklist-text{color:#e57373}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
479
680
|
}
|
|
480
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
681
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: PasswordChecklistComponent, decorators: [{
|
|
481
682
|
type: Component,
|
|
482
|
-
args: [{ selector: 'auth-jwt-password-
|
|
483
|
-
}] });
|
|
683
|
+
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:#ddd;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:#4caf50;color:#fff}.checklist-item.unsatisfied .checklist-icon{background-color:#f44336;color:#fff}.checklist-text{flex:1}.checklist-item.satisfied .checklist-text{color:#4caf50}.checklist-item.unsatisfied .checklist-text{color:#f44336}@media(prefers-color-scheme:dark){.strength-bar-container{background-color:#444}.checklist-item.satisfied .checklist-text{color:#81c784}.checklist-item.unsatisfied .checklist-text{color:#e57373}}\n"] }]
|
|
684
|
+
}], 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"] }] } });
|
|
484
685
|
|
|
485
686
|
/**
|
|
486
687
|
* User registration form.
|
|
@@ -638,10 +839,10 @@ class AuthJwtRegistrationComponent {
|
|
|
638
839
|
},
|
|
639
840
|
});
|
|
640
841
|
}
|
|
641
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
642
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.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-strength-bar [passwordToCheck]=\"password.value\">\r\n </auth-jwt-password-strength-bar>\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 silver;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:red}\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],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: PasswordStrengthBarComponent, selector: "auth-jwt-password-strength-bar", inputs: ["passwordToCheck"], outputs: ["strengthChange"] }] }); }
|
|
842
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
843
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", 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 silver;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:red}\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"] }] }); }
|
|
643
844
|
}
|
|
644
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
845
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
|
|
645
846
|
type: Component,
|
|
646
847
|
args: [{ selector: 'auth-jwt-registration', imports: [
|
|
647
848
|
ReactiveFormsModule,
|
|
@@ -650,9 +851,85 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImpor
|
|
|
650
851
|
MatIconModule,
|
|
651
852
|
MatInputModule,
|
|
652
853
|
MatProgressSpinnerModule,
|
|
653
|
-
|
|
654
|
-
], 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-
|
|
655
|
-
}], ctorParameters: () => [] });
|
|
854
|
+
PasswordChecklistComponent,
|
|
855
|
+
], 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 silver;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:red}\n"] }]
|
|
856
|
+
}], ctorParameters: () => [], propDecorators: { autoConfirm: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoConfirm", required: false }] }], registered: [{ type: i0.Output, args: ["registered"] }] } });
|
|
857
|
+
|
|
858
|
+
class PasswordStrengthBarComponent {
|
|
859
|
+
constructor() {
|
|
860
|
+
this._colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
|
|
861
|
+
this.passwordToCheck = input(...(ngDevMode ? [undefined, { debugName: "passwordToCheck" }] : []));
|
|
862
|
+
this.strengthChange = output();
|
|
863
|
+
this.bars = signal([], ...(ngDevMode ? [{ debugName: "bars" }] : []));
|
|
864
|
+
}
|
|
865
|
+
measureStrength(p) {
|
|
866
|
+
let force = 0;
|
|
867
|
+
const regex = /[$-/:-?{-~!"^_`\[\]]/g; // "
|
|
868
|
+
const lowerLetters = /[a-z]+/.test(p);
|
|
869
|
+
const upperLetters = /[A-Z]+/.test(p);
|
|
870
|
+
const numbers = /[0-9]+/.test(p);
|
|
871
|
+
const symbols = regex.test(p);
|
|
872
|
+
const flags = [lowerLetters, upperLetters, numbers, symbols];
|
|
873
|
+
let passedMatches = 0;
|
|
874
|
+
for (const flag of flags) {
|
|
875
|
+
passedMatches += flag === true ? 1 : 0;
|
|
876
|
+
}
|
|
877
|
+
force += 2 * p.length + (p.length >= 10 ? 1 : 0);
|
|
878
|
+
force += passedMatches * 10;
|
|
879
|
+
// penalty (short password)
|
|
880
|
+
force = p.length <= 6 ? Math.min(force, 10) : force;
|
|
881
|
+
// penalty (poor letiety of characters)
|
|
882
|
+
force = passedMatches === 1 ? Math.min(force, 10) : force;
|
|
883
|
+
force = passedMatches === 2 ? Math.min(force, 20) : force;
|
|
884
|
+
force = passedMatches === 3 ? Math.min(force, 40) : force;
|
|
885
|
+
return force;
|
|
886
|
+
}
|
|
887
|
+
getColor(s) {
|
|
888
|
+
let idx = 0;
|
|
889
|
+
if (s <= 10) {
|
|
890
|
+
idx = 0;
|
|
891
|
+
}
|
|
892
|
+
else if (s <= 20) {
|
|
893
|
+
idx = 1;
|
|
894
|
+
}
|
|
895
|
+
else if (s <= 30) {
|
|
896
|
+
idx = 2;
|
|
897
|
+
}
|
|
898
|
+
else if (s <= 40) {
|
|
899
|
+
idx = 3;
|
|
900
|
+
}
|
|
901
|
+
else {
|
|
902
|
+
idx = 4;
|
|
903
|
+
}
|
|
904
|
+
return {
|
|
905
|
+
idx: idx + 1,
|
|
906
|
+
col: this._colors[idx],
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
ngOnChanges(changes) {
|
|
910
|
+
const password = changes['passwordToCheck'].currentValue;
|
|
911
|
+
this.setBarColors(5, '#DDD');
|
|
912
|
+
if (password) {
|
|
913
|
+
const strength = this.measureStrength(password);
|
|
914
|
+
const c = this.getColor(strength);
|
|
915
|
+
this.setBarColors(c.idx, c.col);
|
|
916
|
+
this.strengthChange.emit(strength);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
setBarColors(count, col) {
|
|
920
|
+
const bars = this.bars();
|
|
921
|
+
for (let n = 0; n < count; n++) {
|
|
922
|
+
bars[n] = col;
|
|
923
|
+
}
|
|
924
|
+
this.bars.set(bars);
|
|
925
|
+
}
|
|
926
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
927
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.0", 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:#ddd;border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] }); }
|
|
928
|
+
}
|
|
929
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
|
|
930
|
+
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:#ddd;border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] }]
|
|
932
|
+
}], propDecorators: { passwordToCheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "passwordToCheck", required: false }] }], strengthChange: [{ type: i0.Output, args: ["strengthChange"] }] } });
|
|
656
933
|
|
|
657
934
|
/**
|
|
658
935
|
* Users filter.
|
|
@@ -713,10 +990,10 @@ class UserFilterComponent {
|
|
|
713
990
|
this._filter = this.getFilter();
|
|
714
991
|
this.filterChange.emit(this._filter);
|
|
715
992
|
}
|
|
716
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
717
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
993
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
994
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.0", 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 [formGroup]=\"form\" (submit)=\"apply()\">\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">name or ID</mat-label>\r\n <input matInput [formControl]=\"name\" />\r\n <button\r\n mat-icon-button\r\n matSuffix\r\n type=\"button\"\r\n (click)=\"reset()\"\r\n i18n-matTooltip=\"auth-jwt-admin\"\r\n matTooltip=\"Reset filters\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n\r\n <button\r\n id=\"apply\"\r\n type=\"submit\"\r\n mat-icon-button\r\n [disabled]=\"disabled()\"\r\n i18n-matTooltip=\"auth-jwt-admin\"\r\n matTooltip=\"Apply filters\"\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}#apply{margin-top:-20px}\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: 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.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: MatTooltipModule }, { kind: "directive", type: i6$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
718
995
|
}
|
|
719
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
996
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserFilterComponent, decorators: [{
|
|
720
997
|
type: Component,
|
|
721
998
|
args: [{ selector: 'auth-jwt-user-filter', imports: [
|
|
722
999
|
ReactiveFormsModule,
|
|
@@ -726,7 +1003,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImpor
|
|
|
726
1003
|
MatInputModule,
|
|
727
1004
|
MatTooltipModule,
|
|
728
1005
|
], template: "<form [formGroup]=\"form\" (submit)=\"apply()\">\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">name or ID</mat-label>\r\n <input matInput [formControl]=\"name\" />\r\n <button\r\n mat-icon-button\r\n matSuffix\r\n type=\"button\"\r\n (click)=\"reset()\"\r\n i18n-matTooltip=\"auth-jwt-admin\"\r\n matTooltip=\"Reset filters\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <mat-icon class=\"mat-warn\">clear</mat-icon>\r\n </button>\r\n </mat-form-field>\r\n\r\n <button\r\n id=\"apply\"\r\n type=\"submit\"\r\n mat-icon-button\r\n [disabled]=\"disabled()\"\r\n i18n-matTooltip=\"auth-jwt-admin\"\r\n matTooltip=\"Apply filters\"\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}#apply{margin-top:-20px}\n"] }]
|
|
729
|
-
}], ctorParameters: () => [] });
|
|
1006
|
+
}], 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"] }] } });
|
|
730
1007
|
|
|
731
1008
|
/**
|
|
732
1009
|
* User editor form.
|
|
@@ -831,10 +1108,10 @@ class UserEditorComponent {
|
|
|
831
1108
|
}
|
|
832
1109
|
this.userChange.emit(this.getUserFromForm());
|
|
833
1110
|
}
|
|
834
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
835
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1111
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1112
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", 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"] }] }); }
|
|
836
1113
|
}
|
|
837
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserEditorComponent, decorators: [{
|
|
838
1115
|
type: Component,
|
|
839
1116
|
args: [{ selector: 'auth-jwt-user-editor', imports: [
|
|
840
1117
|
ReactiveFormsModule,
|
|
@@ -845,7 +1122,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImpor
|
|
|
845
1122
|
MatInputModule,
|
|
846
1123
|
MatTooltipModule,
|
|
847
1124
|
], 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"] }]
|
|
848
|
-
}], ctorParameters: () => [] });
|
|
1125
|
+
}], 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"] }] } });
|
|
849
1126
|
|
|
850
1127
|
/**
|
|
851
1128
|
* List of users.
|
|
@@ -897,10 +1174,10 @@ class UserListComponent {
|
|
|
897
1174
|
getGravatarUrl(email, options) {
|
|
898
1175
|
return this._gravatarService.buildGravatarUrl(email, options);
|
|
899
1176
|
}
|
|
900
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
901
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
1177
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1178
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", 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: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:400}td{padding:0 8px}td.fit-width{width:1px;white-space:nowrap}table{width:100%;border-collapse:collapse}fieldset{border:1px solid silver;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: ReactiveFormsModule }, { 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: MatExpansionModule }, { kind: "component", type: i2$1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { 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: "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$1.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" }] }); }
|
|
902
1179
|
}
|
|
903
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: UserListComponent, decorators: [{
|
|
904
1181
|
type: Component,
|
|
905
1182
|
args: [{ selector: 'auth-jwt-user-list', imports: [
|
|
906
1183
|
CommonModule,
|
|
@@ -914,7 +1191,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImpor
|
|
|
914
1191
|
MatTooltipModule,
|
|
915
1192
|
UserEditorComponent,
|
|
916
1193
|
UserFilterComponent,
|
|
917
|
-
], template: "<div id=\"container\">\
|
|
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: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:400}td{padding:0 8px}td.fit-width{width:1px;white-space:nowrap}table{width:100%;border-collapse:collapse}fieldset{border:1px solid silver;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"] }]
|
|
918
1195
|
}], ctorParameters: () => [] });
|
|
919
1196
|
|
|
920
1197
|
/*
|
|
@@ -925,5 +1202,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImpor
|
|
|
925
1202
|
* Generated bundle index. Do not edit.
|
|
926
1203
|
*/
|
|
927
1204
|
|
|
928
|
-
export { AuthJwtAccountService, AuthJwtRegistrationComponent, PasswordStrengthBarComponent, PasswordValidators, UserFilterComponent, UserListComponent, UserListRepository };
|
|
1205
|
+
export { AuthJwtAccountService, AuthJwtRegistrationComponent, DEFAULT_RULE_LABELS, PasswordChecklistComponent, PasswordStrengthBarComponent, PasswordValidators, UserFilterComponent, UserListComponent, UserListRepository };
|
|
929
1206
|
//# sourceMappingURL=myrmidon-auth-jwt-admin.mjs.map
|