@myrmidon/auth-jwt-admin 9.0.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,36 +1,35 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, input, output, computed, effect, ChangeDetectionStrategy, Component, signal } from '@angular/core';
3
- import * as i1 from '@angular/forms';
4
- import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
2
+ import { inject, Injectable, input, output, computed, effect, ChangeDetectionStrategy, Component, signal, resource } from '@angular/core';
3
+ import { form, required, email, validateAsync, pattern, maxLength, validate, FormField, FormRoot, disabled } from '@angular/forms/signals';
4
+ import { BehaviorSubject, tap, firstValueFrom } from 'rxjs';
5
5
  import { MatSnackBar } from '@angular/material/snack-bar';
6
- import { retry, map, catchError, take } from 'rxjs/operators';
7
- import * as i3 from '@angular/material/form-field';
6
+ import * as i2 from '@angular/material/form-field';
8
7
  import { MatFormFieldModule } from '@angular/material/form-field';
9
- import * as i2 from '@angular/material/button';
8
+ import * as i1 from '@angular/material/button';
10
9
  import { MatButtonModule } from '@angular/material/button';
11
- import * as i4 from '@angular/material/icon';
10
+ import * as i3 from '@angular/material/icon';
12
11
  import { MatIconModule } from '@angular/material/icon';
13
- import * as i5 from '@angular/material/input';
12
+ import * as i4 from '@angular/material/input';
14
13
  import { MatInputModule } from '@angular/material/input';
15
- import * as i6 from '@angular/material/progress-spinner';
14
+ import * as i5 from '@angular/material/progress-spinner';
16
15
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
17
16
  import { HttpClient, HttpParams } from '@angular/common/http';
17
+ import { retry, map, catchError } from 'rxjs/operators';
18
18
  import { ErrorService, EnvService } from '@myrmidon/ngx-tools';
19
- import { BehaviorSubject, tap } from 'rxjs';
20
19
  import { PagedListStore } from '@myrmidon/paged-data-browsers';
21
- import * as i6$1 from '@angular/material/tooltip';
20
+ import * as i6 from '@angular/material/tooltip';
22
21
  import { MatTooltipModule } from '@angular/material/tooltip';
23
22
  import * as i4$1 from '@angular/material/paginator';
24
23
  import { MatPaginatorModule } from '@angular/material/paginator';
25
24
  import * as i7 from '@angular/common';
26
25
  import { CommonModule } from '@angular/common';
27
- import * as i2$1 from '@angular/material/expansion';
26
+ import * as i2$2 from '@angular/material/expansion';
28
27
  import { MatExpansionModule } from '@angular/material/expansion';
29
28
  import * as i5$1 from '@angular/material/progress-bar';
30
29
  import { MatProgressBarModule } from '@angular/material/progress-bar';
31
30
  import { AuthJwtService, GravatarService } from '@myrmidon/auth-jwt-login';
32
31
  import { DialogService } from '@myrmidon/ngx-mat-tools';
33
- import * as i3$1 from '@angular/material/checkbox';
32
+ import * as i2$1 from '@angular/material/checkbox';
34
33
  import { MatCheckboxModule } from '@angular/material/checkbox';
35
34
 
36
35
  /**
@@ -223,10 +222,10 @@ class AuthJwtAccountService {
223
222
  .delete(this._env.get('apiUrl') + 'accounts/' + name)
224
223
  .pipe(catchError(this._error.handleError));
225
224
  }
226
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AuthJwtAccountService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
227
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' }); }
225
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtAccountService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
226
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' }); }
228
227
  }
229
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AuthJwtAccountService, decorators: [{
228
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtAccountService, decorators: [{
230
229
  type: Injectable,
231
230
  args: [{
232
231
  providedIn: 'root',
@@ -234,55 +233,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImpor
234
233
  }] });
235
234
 
236
235
  /**
237
- * Password validators.
236
+ * Password validators as pure predicate functions returning Signal Forms
237
+ * compatible ValidationError objects ({ kind: string }).
238
238
  */
239
239
  class PasswordValidators {
240
- /** "Standard" password validator for my API services. */
241
240
  static standard() {
242
- return (control) => {
243
- if (!control.value) {
241
+ return (value) => {
242
+ if (!value)
244
243
  return null;
245
- }
246
- if (control.value.length < 8) {
247
- return {
248
- passwordtooshort: true,
249
- };
250
- }
251
- if (!/.*[A-Z].*/.test(control.value)) {
252
- return {
253
- noupperinpassword: true,
254
- };
255
- }
256
- if (!/.*[a-z].*/.test(control.value)) {
257
- return {
258
- nolowerinpassword: true,
259
- };
260
- }
261
- if (!/.*[A-Z].*/.test(control.value)) {
262
- return {
263
- noupperinpassword: true,
264
- };
265
- }
266
- if (!/.*[-`~!@#$%^&*()_+=\[\]{};:'",.<>/?|\\].*/.test(control.value)) {
267
- return {
268
- nosymbolinpassword: true,
269
- };
270
- }
244
+ if (value.length < 8)
245
+ return { kind: 'passwordtooshort' };
246
+ if (!/.*[A-Z].*/.test(value))
247
+ return { kind: 'noupperinpassword' };
248
+ if (!/.*[a-z].*/.test(value))
249
+ return { kind: 'nolowerinpassword' };
250
+ if (!/.*[-`~!@#$%^&*()_+=\[\]{};:'",.<>/?|\\].*/.test(value))
251
+ return { kind: 'nosymbolinpassword' };
271
252
  return null;
272
253
  };
273
254
  }
274
- static areEqual(controlName, otherControlName) {
275
- return (control) => {
276
- const g = control;
277
- const a = g.controls[controlName];
278
- const b = g.controls[otherControlName];
279
- return a.value !== b.value
280
- ? {
281
- areequal: true,
282
- }
283
- : null;
284
- };
285
- }
286
255
  }
287
256
 
288
257
  class UserListRepository {
@@ -398,10 +367,10 @@ class UserListRepository {
398
367
  });
399
368
  return promise;
400
369
  }
401
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserListRepository, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
402
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserListRepository, providedIn: 'root' }); }
370
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListRepository, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
371
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListRepository, providedIn: 'root' }); }
403
372
  }
404
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserListRepository, decorators: [{
373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListRepository, decorators: [{
405
374
  type: Injectable,
406
375
  args: [{ providedIn: 'root' }]
407
376
  }], ctorParameters: () => [] });
@@ -712,10 +681,10 @@ class PasswordChecklistComponent {
712
681
  checkRule(ruleId) {
713
682
  return this.isRuleSatisfied()(ruleId);
714
683
  }
715
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: PasswordChecklistComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
716
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.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:var(--mat-sys-surface-variant);border-radius:3px;overflow:hidden}.strength-bar{height:100%;transition:width .3s ease,background-color .3s ease;border-radius:3px}.strength-percentage{flex-shrink:0;min-width:3rem;text-align:right}.checklist{font-size:.875rem}.checklist-items{list-style:none;margin:0;padding:0}.checklist-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;transition:color .2s ease}.checklist-icon{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border-radius:50%;font-weight:700;font-size:.75rem;flex-shrink:0;transition:background-color .2s ease,color .2s ease}.checklist-item.satisfied .checklist-icon{background-color:var(--mat-sys-success);color:var(--mat-sys-on-success)}.checklist-item.unsatisfied .checklist-icon{background-color:var(--mat-sys-error);color:var(--mat-sys-on-error)}.checklist-text{flex:1}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}@media(prefers-color-scheme:dark){.strength-bar-container{background-color:var(--mat-sys-surface-variant)}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
684
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordChecklistComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
685
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PasswordChecklistComponent, isStandalone: true, selector: "auth-jwt-password-checklist", inputs: { password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, username: { classPropertyName: "username", publicName: "username", isSignal: true, isRequired: false, transformFunction: null }, email: { classPropertyName: "email", publicName: "email", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, requireUppercase: { classPropertyName: "requireUppercase", publicName: "requireUppercase", isSignal: true, isRequired: false, transformFunction: null }, requireLowercase: { classPropertyName: "requireLowercase", publicName: "requireLowercase", isSignal: true, isRequired: false, transformFunction: null }, requireNumber: { classPropertyName: "requireNumber", publicName: "requireNumber", isSignal: true, isRequired: false, transformFunction: null }, requireSymbol: { classPropertyName: "requireSymbol", publicName: "requireSymbol", isSignal: true, isRequired: false, transformFunction: null }, checkUsername: { classPropertyName: "checkUsername", publicName: "checkUsername", isSignal: true, isRequired: false, transformFunction: null }, checkEmail: { classPropertyName: "checkEmail", publicName: "checkEmail", isSignal: true, isRequired: false, transformFunction: null }, minLengthLabel: { classPropertyName: "minLengthLabel", publicName: "minLengthLabel", isSignal: true, isRequired: false, transformFunction: null }, maxLengthLabel: { classPropertyName: "maxLengthLabel", publicName: "maxLengthLabel", isSignal: true, isRequired: false, transformFunction: null }, uppercaseLabel: { classPropertyName: "uppercaseLabel", publicName: "uppercaseLabel", isSignal: true, isRequired: false, transformFunction: null }, lowercaseLabel: { classPropertyName: "lowercaseLabel", publicName: "lowercaseLabel", isSignal: true, isRequired: false, transformFunction: null }, numberLabel: { classPropertyName: "numberLabel", publicName: "numberLabel", isSignal: true, isRequired: false, transformFunction: null }, symbolLabel: { classPropertyName: "symbolLabel", publicName: "symbolLabel", isSignal: true, isRequired: false, transformFunction: null }, usernameLabel: { classPropertyName: "usernameLabel", publicName: "usernameLabel", isSignal: true, isRequired: false, transformFunction: null }, emailLabel: { classPropertyName: "emailLabel", publicName: "emailLabel", isSignal: true, isRequired: false, transformFunction: null }, noChecklist: { classPropertyName: "noChecklist", publicName: "noChecklist", isSignal: true, isRequired: false, transformFunction: null }, noMeter: { classPropertyName: "noMeter", publicName: "noMeter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validChange: "validChange" }, ngImport: i0, template: "@if (!hidden()) {\r\n<div class=\"password-checklist-container\">\r\n <!-- Strength Meter -->\r\n @if (!noMeter() && password()) {\r\n <div class=\"strength-meter\">\r\n <div class=\"strength-label\">\r\n <small>Strength:</small>\r\n </div>\r\n <div class=\"strength-bar-container\">\r\n <div\r\n class=\"strength-bar\"\r\n [style.width.%]=\"strengthPercent()\"\r\n [style.background-color]=\"strengthColor()\"\r\n ></div>\r\n </div>\r\n <div class=\"strength-percentage\">\r\n <small>{{ strengthPercent() }}%</small>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Checklist -->\r\n @if (!noChecklist() && password() && rules().length > 0) {\r\n <div class=\"checklist\">\r\n <ul class=\"checklist-items\">\r\n @for (rule of rules(); track rule.id) {\r\n <li\r\n class=\"checklist-item\"\r\n [class.satisfied]=\"checkRule(rule.id)\"\r\n [class.unsatisfied]=\"!checkRule(rule.id)\"\r\n >\r\n <span class=\"checklist-icon\">\r\n {{ checkRule(rule.id) ? '\u2713' : '\u2717' }}\r\n </span>\r\n <span class=\"checklist-text\">{{ rule.label }}</span>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n</div>\r\n}\r\n", styles: [".password-checklist-container{margin-top:.5rem}.strength-meter{display:flex;align-items:center;gap:.5rem;margin-bottom:.75rem}.strength-label{flex-shrink:0}.strength-bar-container{position:relative;flex:1;height:6px;background-color:var(--mat-sys-surface-variant);border-radius:3px;overflow:hidden}.strength-bar{height:100%;transition:width .3s ease,background-color .3s ease;border-radius:3px}.strength-percentage{flex-shrink:0;min-width:3rem;text-align:right}.checklist{font-size:.875rem}.checklist-items{list-style:none;margin:0;padding:0}.checklist-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;transition:color .2s ease}.checklist-icon{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border-radius:50%;font-weight:700;font-size:.75rem;flex-shrink:0;transition:background-color .2s ease,color .2s ease}.checklist-item.satisfied .checklist-icon{background-color:var(--mat-sys-success);color:var(--mat-sys-on-success)}.checklist-item.unsatisfied .checklist-icon{background-color:var(--mat-sys-error);color:var(--mat-sys-on-error)}.checklist-text{flex:1}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}@media(prefers-color-scheme:dark){.strength-bar-container{background-color:var(--mat-sys-surface-variant)}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
717
686
  }
718
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: PasswordChecklistComponent, decorators: [{
687
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordChecklistComponent, decorators: [{
719
688
  type: Component,
720
689
  args: [{ selector: 'auth-jwt-password-checklist', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!hidden()) {\r\n<div class=\"password-checklist-container\">\r\n <!-- Strength Meter -->\r\n @if (!noMeter() && password()) {\r\n <div class=\"strength-meter\">\r\n <div class=\"strength-label\">\r\n <small>Strength:</small>\r\n </div>\r\n <div class=\"strength-bar-container\">\r\n <div\r\n class=\"strength-bar\"\r\n [style.width.%]=\"strengthPercent()\"\r\n [style.background-color]=\"strengthColor()\"\r\n ></div>\r\n </div>\r\n <div class=\"strength-percentage\">\r\n <small>{{ strengthPercent() }}%</small>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Checklist -->\r\n @if (!noChecklist() && password() && rules().length > 0) {\r\n <div class=\"checklist\">\r\n <ul class=\"checklist-items\">\r\n @for (rule of rules(); track rule.id) {\r\n <li\r\n class=\"checklist-item\"\r\n [class.satisfied]=\"checkRule(rule.id)\"\r\n [class.unsatisfied]=\"!checkRule(rule.id)\"\r\n >\r\n <span class=\"checklist-icon\">\r\n {{ checkRule(rule.id) ? '\u2713' : '\u2717' }}\r\n </span>\r\n <span class=\"checklist-text\">{{ rule.label }}</span>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n }\r\n</div>\r\n}\r\n", styles: [".password-checklist-container{margin-top:.5rem}.strength-meter{display:flex;align-items:center;gap:.5rem;margin-bottom:.75rem}.strength-label{flex-shrink:0}.strength-bar-container{position:relative;flex:1;height:6px;background-color:var(--mat-sys-surface-variant);border-radius:3px;overflow:hidden}.strength-bar{height:100%;transition:width .3s ease,background-color .3s ease;border-radius:3px}.strength-percentage{flex-shrink:0;min-width:3rem;text-align:right}.checklist{font-size:.875rem}.checklist-items{list-style:none;margin:0;padding:0}.checklist-item{display:flex;align-items:center;gap:.5rem;padding:.25rem 0;transition:color .2s ease}.checklist-icon{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border-radius:50%;font-weight:700;font-size:.75rem;flex-shrink:0;transition:background-color .2s ease,color .2s ease}.checklist-item.satisfied .checklist-icon{background-color:var(--mat-sys-success);color:var(--mat-sys-on-success)}.checklist-item.unsatisfied .checklist-icon{background-color:var(--mat-sys-error);color:var(--mat-sys-on-error)}.checklist-text{flex:1}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}@media(prefers-color-scheme:dark){.strength-bar-container{background-color:var(--mat-sys-surface-variant)}.checklist-item.satisfied .checklist-text{color:var(--mat-sys-success)}.checklist-item.unsatisfied .checklist-text{color:var(--mat-sys-error)}}\n"] }]
721
690
  }], ctorParameters: () => [], propDecorators: { password: [{ type: i0.Input, args: [{ isSignal: true, alias: "password", required: false }] }], username: [{ type: i0.Input, args: [{ isSignal: true, alias: "username", required: false }] }], email: [{ type: i0.Input, args: [{ isSignal: true, alias: "email", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], requireUppercase: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireUppercase", required: false }] }], requireLowercase: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireLowercase", required: false }] }], requireNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireNumber", required: false }] }], requireSymbol: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireSymbol", required: false }] }], checkUsername: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkUsername", required: false }] }], checkEmail: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkEmail", required: false }] }], minLengthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLengthLabel", required: false }] }], maxLengthLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLengthLabel", required: false }] }], uppercaseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "uppercaseLabel", required: false }] }], lowercaseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "lowercaseLabel", required: false }] }], numberLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "numberLabel", required: false }] }], symbolLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "symbolLabel", required: false }] }], usernameLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "usernameLabel", required: false }] }], emailLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "emailLabel", required: false }] }], noChecklist: [{ type: i0.Input, args: [{ isSignal: true, alias: "noChecklist", required: false }] }], noMeter: [{ type: i0.Input, args: [{ isSignal: true, alias: "noMeter", required: false }] }], validChange: [{ type: i0.Output, args: ["validChange"] }] } });
@@ -728,172 +697,115 @@ class AuthJwtRegistrationComponent {
728
697
  this._snackbar = inject(MatSnackBar);
729
698
  this._accountService = inject(AuthJwtAccountService);
730
699
  this._userRepository = inject(UserListRepository);
731
- /**
732
- * True if the registration should be confirmed automatically.
733
- */
700
+ this.formModel = signal({
701
+ email: '',
702
+ name: '',
703
+ firstName: '',
704
+ lastName: '',
705
+ password: '',
706
+ confirmPassword: '',
707
+ }, /* @ts-ignore */
708
+ ...(ngDevMode ? [{ debugName: "formModel" }] : /* istanbul ignore next */ []));
709
+ this.userForm = form(this.formModel, (p) => {
710
+ // email
711
+ required(p.email);
712
+ email(p.email);
713
+ validateAsync(p.email, {
714
+ params: ({ value }) => value() || undefined,
715
+ factory: (emailParam) => resource({
716
+ params: () => emailParam(),
717
+ loader: async ({ params: emailVal }) => firstValueFrom(this._accountService.isEmailRegistered(emailVal)),
718
+ }),
719
+ onSuccess: (result) => result?.isExisting ? { kind: 'uniqueEmail' } : undefined,
720
+ onError: (err) => {
721
+ console.error('Unique email validator error:', err);
722
+ return { kind: 'uniqueEmail' };
723
+ },
724
+ debounce: 300,
725
+ });
726
+ // name
727
+ required(p.name);
728
+ pattern(p.name, /^[a-zA-Z][a-zA-Z0-9]{2,49}$/);
729
+ validateAsync(p.name, {
730
+ params: ({ value }) => value() || undefined,
731
+ factory: (nameParam) => resource({
732
+ params: () => nameParam(),
733
+ loader: async ({ params: nameVal }) => firstValueFrom(this._accountService.isNameRegistered(nameVal)),
734
+ }),
735
+ onSuccess: (result) => result?.isExisting ? { kind: 'uniqueName' } : undefined,
736
+ onError: (err) => {
737
+ console.error('Unique name validator error:', err);
738
+ return { kind: 'uniqueName' };
739
+ },
740
+ debounce: 300,
741
+ });
742
+ // first/last name
743
+ required(p.firstName);
744
+ maxLength(p.firstName, 50);
745
+ required(p.lastName);
746
+ maxLength(p.lastName, 50);
747
+ // password
748
+ required(p.password);
749
+ validate(p.password, ({ value }) => PasswordValidators.standard()(value()));
750
+ // confirmPassword + cross-field match
751
+ required(p.confirmPassword);
752
+ validate(p, ({ value }) => {
753
+ const m = value();
754
+ return m.password !== m.confirmPassword ? { kind: 'areequal' } : null;
755
+ });
756
+ }, {
757
+ submission: {
758
+ action: async () => {
759
+ if (this.busy())
760
+ return;
761
+ const m = this.formModel();
762
+ const model = {
763
+ email: m.email,
764
+ name: m.name,
765
+ firstName: m.firstName,
766
+ lastName: m.lastName,
767
+ password: m.password,
768
+ };
769
+ this.busy.set(true);
770
+ try {
771
+ await firstValueFrom(this._accountService.register(model, this.autoConfirm()));
772
+ this.busy.set(false);
773
+ this._snackbar.open($localize `:auth-jwt-admin:Registration succeeded`, 'OK');
774
+ this._userRepository.reset();
775
+ this.registered.emit();
776
+ }
777
+ catch (error) {
778
+ this.busy.set(false);
779
+ console.error('Registration error' + (error ? JSON.stringify(error) : ''));
780
+ this._snackbar.open($localize `:auth-jwt-admin:Registration error`, 'OK');
781
+ }
782
+ },
783
+ },
784
+ });
734
785
  this.autoConfirm = input(/* @ts-ignore */
735
786
  ...(ngDevMode ? [undefined, { debugName: "autoConfirm" }] : /* istanbul ignore next */ []));
736
- /**
737
- * Emitted when a user was successfully registered. Usually
738
- * you should handle this to move away from the registration
739
- * page.
740
- */
741
787
  this.registered = output();
742
788
  this.busy = signal(undefined, /* @ts-ignore */
743
789
  ...(ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []));
744
790
  this.hidePassword = signal(true, /* @ts-ignore */
745
791
  ...(ngDevMode ? [{ debugName: "hidePassword" }] : /* istanbul ignore next */ []));
746
- const formBuilder = inject(FormBuilder);
747
- // form
748
- this.email = formBuilder.control('', {
749
- validators: [Validators.required, Validators.email],
750
- asyncValidators: this.getUniqueEmailValidator(this._accountService).bind(this),
751
- nonNullable: true,
752
- });
753
- this.name = formBuilder.control('', {
754
- validators: Validators.required,
755
- asyncValidators: this.getUniqueNameValidator(this._accountService).bind(this),
756
- nonNullable: true,
757
- });
758
- this.firstName = formBuilder.control('', {
759
- validators: [Validators.required, Validators.maxLength(50)],
760
- nonNullable: true,
761
- });
762
- this.lastName = formBuilder.control('', {
763
- validators: [Validators.required, Validators.maxLength(50)],
764
- nonNullable: true,
765
- });
766
- // http://stackoverflow.com/questions/35474991/angular-2-form-validating-for-repeat-password
767
- this.password = formBuilder.control('', {
768
- validators: [Validators.required, PasswordValidators.standard()],
769
- nonNullable: true,
770
- });
771
- this.confirmPassword = formBuilder.control('', {
772
- validators: Validators.required,
773
- nonNullable: true,
774
- });
775
- this.form = formBuilder.group({
776
- email: this.email,
777
- name: this.name,
778
- firstName: this.firstName,
779
- lastName: this.lastName,
780
- password: this.password,
781
- confirmPassword: this.confirmPassword,
782
- }, {
783
- validators: [
784
- PasswordValidators.areEqual('password', 'confirmPassword'),
785
- ],
786
- });
787
- }
788
- /**
789
- * Creates a unique name validator. There is no dependency injection at this level,
790
- * but we can use closures. As a matter of fact, we have access to the service instance
791
- * from the component where we register validators. So we will implement a function
792
- * that will accept the service as parameter, and create the actual validation function.
793
- * This function will have access to the service when called during the validation process.
794
- * See http://restlet.com/blog/2016/02/17/implementing-angular2-forms-beyond-basics-part-2/.
795
- */
796
- getUniqueNameValidator(service) {
797
- return (control) => {
798
- return new Promise((resolve, reject) => {
799
- // avoid checking if empty
800
- if (!control.value) {
801
- resolve(null);
802
- }
803
- else {
804
- service.isNameRegistered(control.value).subscribe({
805
- next: (data) => {
806
- if (!data.isExisting) {
807
- resolve(null);
808
- }
809
- else {
810
- resolve({ uniqueName: true });
811
- }
812
- },
813
- error: (error) => {
814
- console.error('Unique name validator error' +
815
- (error ? JSON.stringify(error) : ''));
816
- resolve({ uniqueName: true });
817
- },
818
- });
819
- }
820
- });
821
- };
822
- }
823
- getUniqueEmailValidator(service) {
824
- return (control) => {
825
- return new Promise((resolve, reject) => {
826
- // avoid checking if empty
827
- if (!control.value) {
828
- resolve(null);
829
- }
830
- else {
831
- service.isEmailRegistered(control.value).subscribe({
832
- next: (data) => {
833
- if (!data.isExisting) {
834
- resolve(null);
835
- }
836
- else {
837
- resolve({ uniqueEmail: true });
838
- }
839
- },
840
- error: (error) => {
841
- console.error('Unique email validator error' +
842
- (error ? JSON.stringify(error) : ''));
843
- resolve({ uniqueEmail: true });
844
- },
845
- });
846
- }
847
- });
848
- };
849
- }
850
- onSubmit() {
851
- if (!this.form.valid ||
852
- this.busy() ||
853
- this.name.pending ||
854
- this.email.pending) {
855
- return;
856
- }
857
- const model = {
858
- email: this.email.value,
859
- name: this.name.value,
860
- firstName: this.firstName.value,
861
- lastName: this.lastName.value,
862
- password: this.password.value,
863
- };
864
- this.busy.set(true);
865
- this._accountService
866
- .register(model, this.autoConfirm())
867
- .pipe(take(1))
868
- .subscribe({
869
- next: () => {
870
- this.busy.set(false);
871
- this._snackbar.open($localize `:auth-jwt-admin:Registration succeeded`, 'OK');
872
- this._userRepository.reset();
873
- this.registered.emit();
874
- },
875
- error: (error) => {
876
- this.busy.set(false);
877
- console.error('Registration error' + (error ? JSON.stringify(error) : ''));
878
- this._snackbar.open($localize `:auth-jwt-admin:Registration error`, 'OK');
879
- },
880
- });
881
792
  }
882
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
883
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.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 var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}details{margin:8px}.info{column-width:600px}.error{color:var(--mat-sys-error)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[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"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
793
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
794
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: AuthJwtRegistrationComponent, isStandalone: true, selector: "auth-jwt-registration", inputs: { autoConfirm: { classPropertyName: "autoConfirm", publicName: "autoConfirm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { registered: "registered" }, ngImport: i0, template: "<div>\n <form role=\"form\" [formRoot]=\"userForm\">\n <fieldset>\n <legend i18n=\"auth-jwt-admin\">registration</legend>\n\n <!-- email -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n>email</mat-label>\n <input\n matInput\n type=\"email\"\n id=\"email\"\n autofocus\n spellcheck=\"false\"\n [formField]=\"userForm.email\"\n />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email</mat-error>\n }\n @if (userForm.email().getError('uniqueEmail') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.email().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- name -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">username</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"name\"\n spellcheck=\"false\"\n [formField]=\"userForm.name\"\n />\n @if (userForm.name().getError('required') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username required</mat-error>\n }\n @if (userForm.name().getError('pattern') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid username</mat-error>\n }\n @if (userForm.name().getError('uniqueName') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.name().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- first name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"firstName\"\n spellcheck=\"false\"\n [formField]=\"userForm.firstName\"\n />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">first name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- last name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"lastName\"\n spellcheck=\"false\"\n [formField]=\"userForm.lastName\"\n />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">last name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.password\"\n />\n <button\n type=\"button\"\n mat-icon-button\n matSuffix\n (click)=\"hidePassword.set(!hidePassword())\"\n i18n-aria-label=\"auth-jwt-login\"\n aria-label=\"Hide password\"\n [attr.aria-pressed]=\"hidePassword()\"\n >\n <mat-icon>{{ hidePassword() ? \"visibility_off\" : \"visibility\" }}</mat-icon>\n </button>\n <auth-jwt-password-checklist\n [password]=\"formModel().password\"\n [username]=\"formModel().name\"\n [email]=\"formModel().email\"\n [minLength]=\"8\"\n [requireUppercase]=\"true\"\n [requireLowercase]=\"true\"\n [requireSymbol]=\"true\"\n [minLengthLabel]=\"'At least 8 characters'\"\n [uppercaseLabel]=\"'At least 1 uppercase letter'\"\n [lowercaseLabel]=\"'At least 1 lowercase letter'\"\n [symbolLabel]=\"'At least 1 punctuation/symbol'\"\n />\n @if (userForm.password().getError('required') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">password required</mat-error>\n }\n @if (userForm.password().getError('passwordtooshort') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 8 characters</mat-error>\n }\n @if (userForm.password().getError('noupperinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 uppercase letter</mat-error>\n }\n @if (userForm.password().getError('nolowerinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 lowercase letter</mat-error>\n }\n @if (userForm.password().getError('nosymbolinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 punctuation/symbol</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- confirm password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">confirm password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.confirmPassword\"\n />\n </mat-form-field>\n </div>\n @if (userForm().getError('areequal') && userForm.confirmPassword().touched()) {\n <div i18n=\"auth-jwt-admin\" class=\"error\">\n password differs from confirmation password\n </div>\n }\n\n <button\n i18n=\"auth-jwt-admin\"\n mat-flat-button\n type=\"submit\"\n color=\"primary\"\n class=\"mat-primary\"\n [disabled]=\"!userForm().valid() || busy()\"\n >\n register\n </button>\n @if (busy()) {\n <mat-progress-spinner diameter=\"20\" />\n }\n </fieldset>\n </form>\n\n <details>\n <summary i18n=\"auth-jwt-admin\">Hints</summary>\n <div class=\"info\">\n <p i18n=\"auth-jwt-admin\">\n To register a new user, you must provide his email address, choose a\n password, and choose a username, which must be unique (you will be\n notified if another user has already taken that name). The username must\n include only letters/digits, start with a letter, and be no shorter than\n 3 characters, nor longer than 50.\n </p>\n <p i18n=\"auth-jwt-admin\">\n To promote a decent security level, the password must include at least 8\n characters, uppercase and lowercase letters, digits, and punctuation\n (like dashes, stops, parentheses, etc.).\n </p>\n <p i18n=\"auth-jwt-admin\">\n Once registered, if messaging is enabled on the server side the user\n will receive an email message to the email address you specified; he\n will have to click on the provided link to complete the registration\n process. Otherwise, you should edit the newly created user and confirm\n the email registration.\n </p>\n </div>\n </details>\n</div>\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}details{margin:8px}.info{column-width:600px}.error{color:var(--mat-sys-error)}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "directive", type: FormRoot, selector: "form[formRoot]", inputs: ["formRoot"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: PasswordChecklistComponent, selector: "auth-jwt-password-checklist", inputs: ["password", "username", "email", "hidden", "minLength", "maxLength", "requireUppercase", "requireLowercase", "requireNumber", "requireSymbol", "checkUsername", "checkEmail", "minLengthLabel", "maxLengthLabel", "uppercaseLabel", "lowercaseLabel", "numberLabel", "symbolLabel", "usernameLabel", "emailLabel", "noChecklist", "noMeter"], outputs: ["validChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
884
795
  }
885
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
796
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
886
797
  type: Component,
887
798
  args: [{ selector: 'auth-jwt-registration', imports: [
888
- ReactiveFormsModule,
799
+ FormField,
800
+ FormRoot,
889
801
  MatButtonModule,
890
802
  MatFormFieldModule,
891
803
  MatIconModule,
892
804
  MatInputModule,
893
805
  MatProgressSpinnerModule,
894
806
  PasswordChecklistComponent,
895
- ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div>\r\n <form role=\"form\" [formGroup]=\"form\" (submit)=\"onSubmit()\">\r\n <fieldset>\r\n <legend i18n=\"auth-jwt-admin\">registration</legend>\r\n <!-- email -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n>email</mat-label>\r\n <input\r\n matInput\r\n type=\"email\"\r\n id=\"email\"\r\n maxlength=\"256\"\r\n required\r\n autofocus\r\n spellcheck=\"false\"\r\n [formControl]=\"email\"\r\n />\r\n @if ( $any(email).errors?.required && (email.dirty || email.touched) )\r\n {\r\n <mat-error i18n=\"auth-jwt-admin\">email required</mat-error>\r\n } @if ($any(email).errors?.email && (email.dirty || email.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\">invalid email</mat-error>\r\n } @if ( $any(email).errors?.uniqueEmail && (email.dirty ||\r\n email.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\">email already registered</mat-error>\r\n }\r\n </mat-form-field>\r\n @if (email.pending) {\r\n <mat-icon>hourglass</mat-icon>\r\n }\r\n </div>\r\n\r\n <!-- name -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">username</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"name\"\r\n maxlength=\"50\"\r\n required\r\n pattern=\"^[a-zA-Z][a-zA-Z0-9]{2,49}$\"\r\n spellcheck=\"false\"\r\n [formControl]=\"name\"\r\n />\r\n @if ($any(name).errors?.required && (name.dirty || name.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\">username required</mat-error>\r\n } @if ($any(name).errors?.pattern && (name.dirty || name.touched)) {\r\n <mat-error i18n=\"auth-jwt-admin\">invalid username</mat-error>\r\n } @if ( $any(name).errors?.uniqueName && (name.dirty || name.touched)\r\n ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >username already registered</mat-error\r\n >\r\n }\r\n </mat-form-field>\r\n @if (name.pending) {\r\n <mat-icon>hourglass</mat-icon>\r\n }\r\n </div>\r\n\r\n <!-- first name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"firstName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"firstName\"\r\n />\r\n @if ( firstName.hasError('required') && (firstName.dirty ||\r\n firstName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">\r\n first name required\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- last name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"lastName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"lastName\"\r\n />\r\n @if ( lastName.hasError('required') && (lastName.dirty ||\r\n lastName.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">\r\n last name required\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- <div [formGroup]=\"passwords\"> -->\r\n <!-- password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">password</mat-label>\r\n <input\r\n matInput\r\n [type]=\"hidePassword() ? 'password' : 'text'\"\r\n name=\"password\"\r\n autocomplete=\"new-password\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"password\"\r\n />\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n matSuffix\r\n (click)=\"hidePassword.set(!hidePassword())\"\r\n i18n-aria-label=\"auth-jwt-login\"\r\n aria-label=\"Hide password\"\r\n [attr.aria-pressed]=\"hidePassword()\"\r\n >\r\n <mat-icon>{{\r\n hidePassword() ? \"visibility_off\" : \"visibility\"\r\n }}</mat-icon>\r\n </button>\r\n <auth-jwt-password-checklist\r\n [password]=\"password.value\"\r\n [username]=\"name.value\"\r\n [email]=\"email.value\"\r\n [minLength]=\"8\"\r\n [requireUppercase]=\"true\"\r\n [requireLowercase]=\"true\"\r\n [requireSymbol]=\"true\"\r\n [minLengthLabel]=\"'At least 8 characters'\"\r\n [uppercaseLabel]=\"'At least 1 uppercase letter'\"\r\n [lowercaseLabel]=\"'At least 1 lowercase letter'\"\r\n [symbolLabel]=\"'At least 1 punctuation/symbol'\">\r\n </auth-jwt-password-checklist>\r\n @if ( $any(password).errors?.required && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\">password required</mat-error>\r\n } @if ( $any(password).errors?.passwordtooshort && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\">at least 8 characters</mat-error>\r\n } @if ( $any(password).errors?.noupperinpassword && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >at least 1 uppercase letter</mat-error\r\n >\r\n } @if ( $any(password).errors?.nolowerinpassword && (password.dirty ||\r\n password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >at least 1 lowercase letter</mat-error\r\n >\r\n } @if ( $any(password).errors?.nosymbolinpassword && (password.dirty\r\n || password.touched) ) {\r\n <mat-error i18n=\"auth-jwt-admin\"\r\n >at least 1 punctuation/symbol</mat-error\r\n >\r\n }\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- confirm password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n=\"auth-jwt-admin\">confirm password</mat-label>\r\n <input\r\n matInput\r\n [type]=\"hidePassword() ? 'password' : 'text'\"\r\n name=\"confirmPassword\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"confirmPassword\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n @if (form.errors?.areequal && confirmPassword.touched) {\r\n <div i18n=\"auth-jwt-admin\" class=\"error\">\r\n password differs from confirmation password\r\n </div>\r\n }\r\n\r\n <button\r\n i18n=\"auth-jwt-admin\"\r\n mat-flat-button\r\n type=\"submit\"\r\n color=\"primary\"\r\n class=\"mat-primary\"\r\n [disabled]=\"\r\n form.invalid || form.pristine || busy() || name.pending || email.pending\r\n \"\r\n >\r\n register\r\n </button>\r\n @if (busy()) {\r\n <mat-progress-spinner diameter=\"20\"></mat-progress-spinner>\r\n }\r\n </fieldset>\r\n </form>\r\n\r\n <details>\r\n <summary i18n=\"auth-jwt-admin\">Hints</summary>\r\n <div class=\"info\">\r\n <p i18n=\"auth-jwt-admin\">\r\n To register a new user, you must provide his email address, choose a\r\n password, and choose a username, which must be unique (you will be\r\n notified if another user has already taken that name). The username must\r\n include only letters/digits, start with a letter, and be no shorter than\r\n 3 characters, nor longer than 50.\r\n </p>\r\n <p i18n=\"auth-jwt-admin\">\r\n To promote a decent security level, the password must include at least 8\r\n characters, uppercase and lowercase letters, digits, and punctuation\r\n (like dashes, stops, parentheses, etc.).\r\n </p>\r\n <p i18n=\"auth-jwt-admin\">\r\n Once registered, if messaging is enabled on the server side the user\r\n will receive an email message to the email address you specified; he\r\n will have to click on the provided link to complete the registration\r\n process. Otherwise, you should edit the newly created user and confirm\r\n the email registration.\r\n </p>\r\n </div>\r\n </details>\r\n</div>\r\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}details{margin:8px}.info{column-width:600px}.error{color:var(--mat-sys-error)}\n"] }]
896
- }], ctorParameters: () => [], propDecorators: { autoConfirm: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoConfirm", required: false }] }], registered: [{ type: i0.Output, args: ["registered"] }] } });
807
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<div>\n <form role=\"form\" [formRoot]=\"userForm\">\n <fieldset>\n <legend i18n=\"auth-jwt-admin\">registration</legend>\n\n <!-- email -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n>email</mat-label>\n <input\n matInput\n type=\"email\"\n id=\"email\"\n autofocus\n spellcheck=\"false\"\n [formField]=\"userForm.email\"\n />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email</mat-error>\n }\n @if (userForm.email().getError('uniqueEmail') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.email().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- name -->\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">username</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"name\"\n spellcheck=\"false\"\n [formField]=\"userForm.name\"\n />\n @if (userForm.name().getError('required') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username required</mat-error>\n }\n @if (userForm.name().getError('pattern') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid username</mat-error>\n }\n @if (userForm.name().getError('uniqueName') && (userForm.name().dirty() || userForm.name().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">username already registered</mat-error>\n }\n </mat-form-field>\n @if (userForm.name().pending()) {\n <mat-icon>hourglass</mat-icon>\n }\n </div>\n\n <!-- first name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"firstName\"\n spellcheck=\"false\"\n [formField]=\"userForm.firstName\"\n />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">first name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- last name -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input\n matInput\n type=\"text\"\n id=\"lastName\"\n spellcheck=\"false\"\n [formField]=\"userForm.lastName\"\n />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\" class=\"text-danger small\">last name required</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.password\"\n />\n <button\n type=\"button\"\n mat-icon-button\n matSuffix\n (click)=\"hidePassword.set(!hidePassword())\"\n i18n-aria-label=\"auth-jwt-login\"\n aria-label=\"Hide password\"\n [attr.aria-pressed]=\"hidePassword()\"\n >\n <mat-icon>{{ hidePassword() ? \"visibility_off\" : \"visibility\" }}</mat-icon>\n </button>\n <auth-jwt-password-checklist\n [password]=\"formModel().password\"\n [username]=\"formModel().name\"\n [email]=\"formModel().email\"\n [minLength]=\"8\"\n [requireUppercase]=\"true\"\n [requireLowercase]=\"true\"\n [requireSymbol]=\"true\"\n [minLengthLabel]=\"'At least 8 characters'\"\n [uppercaseLabel]=\"'At least 1 uppercase letter'\"\n [lowercaseLabel]=\"'At least 1 lowercase letter'\"\n [symbolLabel]=\"'At least 1 punctuation/symbol'\"\n />\n @if (userForm.password().getError('required') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">password required</mat-error>\n }\n @if (userForm.password().getError('passwordtooshort') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 8 characters</mat-error>\n }\n @if (userForm.password().getError('noupperinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 uppercase letter</mat-error>\n }\n @if (userForm.password().getError('nolowerinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 lowercase letter</mat-error>\n }\n @if (userForm.password().getError('nosymbolinpassword') && (userForm.password().dirty() || userForm.password().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">at least 1 punctuation/symbol</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- confirm password -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">confirm password</mat-label>\n <input\n matInput\n [type]=\"hidePassword() ? 'password' : 'text'\"\n autocomplete=\"new-password\"\n spellcheck=\"false\"\n [formField]=\"userForm.confirmPassword\"\n />\n </mat-form-field>\n </div>\n @if (userForm().getError('areequal') && userForm.confirmPassword().touched()) {\n <div i18n=\"auth-jwt-admin\" class=\"error\">\n password differs from confirmation password\n </div>\n }\n\n <button\n i18n=\"auth-jwt-admin\"\n mat-flat-button\n type=\"submit\"\n color=\"primary\"\n class=\"mat-primary\"\n [disabled]=\"!userForm().valid() || busy()\"\n >\n register\n </button>\n @if (busy()) {\n <mat-progress-spinner diameter=\"20\" />\n }\n </fieldset>\n </form>\n\n <details>\n <summary i18n=\"auth-jwt-admin\">Hints</summary>\n <div class=\"info\">\n <p i18n=\"auth-jwt-admin\">\n To register a new user, you must provide his email address, choose a\n password, and choose a username, which must be unique (you will be\n notified if another user has already taken that name). The username must\n include only letters/digits, start with a letter, and be no shorter than\n 3 characters, nor longer than 50.\n </p>\n <p i18n=\"auth-jwt-admin\">\n To promote a decent security level, the password must include at least 8\n characters, uppercase and lowercase letters, digits, and punctuation\n (like dashes, stops, parentheses, etc.).\n </p>\n <p i18n=\"auth-jwt-admin\">\n Once registered, if messaging is enabled on the server side the user\n will receive an email message to the email address you specified; he\n will have to click on the provided link to complete the registration\n process. Otherwise, you should edit the newly created user and confirm\n the email registration.\n </p>\n </div>\n </details>\n</div>\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}details{margin:8px}.info{column-width:600px}.error{color:var(--mat-sys-error)}\n"] }]
808
+ }], propDecorators: { autoConfirm: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoConfirm", required: false }] }], registered: [{ type: i0.Output, args: ["registered"] }] } });
897
809
 
898
810
  class PasswordStrengthBarComponent {
899
811
  constructor() {
@@ -965,10 +877,10 @@ class PasswordStrengthBarComponent {
965
877
  }
966
878
  this.bars.set(bars);
967
879
  }
968
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
969
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.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:var(--mat-sys-surface-variant);border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
880
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
881
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: PasswordStrengthBarComponent, isStandalone: true, selector: "auth-jwt-password-strength-bar", inputs: { passwordToCheck: { classPropertyName: "passwordToCheck", publicName: "passwordToCheck", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { strengthChange: "strengthChange" }, usesOnChanges: true, ngImport: i0, template: "<div id=\"strength\">\r\n <small>strength:</small>\r\n <ul id=\"strengthBar\">\r\n <li class=\"point\" [style.background-color]=\"bars()[0]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[1]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[2]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[3]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[4]\"></li>\r\n </ul>\r\n</div>\r\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:var(--mat-sys-surface-variant);border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
970
882
  }
971
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
883
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
972
884
  type: Component,
973
885
  args: [{ selector: 'auth-jwt-password-strength-bar', changeDetection: ChangeDetectionStrategy.Eager, template: "<div id=\"strength\">\r\n <small>strength:</small>\r\n <ul id=\"strengthBar\">\r\n <li class=\"point\" [style.background-color]=\"bars()[0]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[1]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[2]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[3]\"></li>\r\n <li class=\"point\" [style.background-color]=\"bars()[4]\"></li>\r\n </ul>\r\n</div>\r\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:var(--mat-sys-surface-variant);border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] }]
974
886
  }], propDecorators: { passwordToCheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "passwordToCheck", required: false }] }], strengthChange: [{ type: i0.Output, args: ["strengthChange"] }] } });
@@ -978,75 +890,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImpor
978
890
  */
979
891
  class UserFilterComponent {
980
892
  constructor() {
981
- /**
982
- * The filter.
983
- */
984
893
  this.filter = input(/* @ts-ignore */
985
894
  ...(ngDevMode ? [undefined, { debugName: "filter" }] : /* istanbul ignore next */ []));
986
- /**
987
- * Whether the filter is disabled.
988
- */
989
895
  this.disabled = input(/* @ts-ignore */
990
896
  ...(ngDevMode ? [undefined, { debugName: "disabled" }] : /* istanbul ignore next */ []));
991
- /**
992
- * Event emitted when the filter changes.
993
- */
994
897
  this.filterChange = output();
995
- const formBuilder = inject(FormBuilder);
996
- // form
997
- this.name = formBuilder.control(null);
998
- this.form = formBuilder.group({
999
- name: this.name,
1000
- });
1001
- // update form when filter changes
1002
- effect(() => {
1003
- this.updateForm(this.filter() || undefined);
898
+ this.formModel = signal({ name: '' }, /* @ts-ignore */
899
+ ...(ngDevMode ? [{ debugName: "formModel" }] : /* istanbul ignore next */ []));
900
+ this.userForm = form(this.formModel, (p) => {
901
+ disabled(p.name, { when: () => this.disabled() ?? false });
902
+ }, {
903
+ submission: {
904
+ action: async () => {
905
+ const name = this.formModel().name.trim();
906
+ this.filterChange.emit({ name: name || undefined });
907
+ },
908
+ },
1004
909
  });
1005
- // disable form when disabled
1006
910
  effect(() => {
1007
- if (this.disabled()) {
1008
- this.form.disable();
1009
- }
1010
- else {
1011
- this.form.enable();
1012
- }
911
+ const filter = this.filter();
912
+ this.formModel.set({ name: filter?.name || '' });
1013
913
  });
1014
914
  }
1015
- updateForm(filter) {
1016
- if (!filter) {
1017
- this.form.reset();
1018
- return;
1019
- }
1020
- this.name.setValue(filter.name || null);
1021
- this.form.markAsPristine();
1022
- }
1023
- getFilter() {
1024
- return {
1025
- name: this.name.value?.trim(),
1026
- };
1027
- }
1028
915
  reset() {
1029
- this.form.reset();
1030
- this._filter = {};
1031
- this.filterChange.emit(this._filter);
916
+ this.formModel.set({ name: '' });
917
+ this.filterChange.emit({});
1032
918
  }
1033
- apply() {
1034
- this._filter = this.getFilter();
1035
- this.filterChange.emit(this._filter);
1036
- }
1037
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1038
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.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]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[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"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
919
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
920
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: UserFilterComponent, isStandalone: true, selector: "auth-jwt-user-filter", inputs: { filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange" }, ngImport: i0, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">name or ID</mat-label>\n <input matInput [formField]=\"userForm.name\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Reset filters\"\n [disabled]=\"disabled()\"\n >\n <mat-icon class=\"mat-warn\">clear</mat-icon>\n </button>\n </mat-form-field>\n\n <button\n id=\"apply\"\n type=\"submit\"\n mat-icon-button\n [disabled]=\"disabled()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Apply filters\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#apply{margin-top:-20px}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "directive", type: FormRoot, selector: "form[formRoot]", inputs: ["formRoot"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1039
921
  }
1040
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserFilterComponent, decorators: [{
922
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserFilterComponent, decorators: [{
1041
923
  type: Component,
1042
924
  args: [{ selector: 'auth-jwt-user-filter', imports: [
1043
- ReactiveFormsModule,
925
+ FormField,
926
+ FormRoot,
1044
927
  MatButtonModule,
1045
928
  MatFormFieldModule,
1046
929
  MatIconModule,
1047
930
  MatInputModule,
1048
931
  MatTooltipModule,
1049
- ], changeDetection: ChangeDetectionStrategy.Eager, 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"] }]
932
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">name or ID</mat-label>\n <input matInput [formField]=\"userForm.name\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Reset filters\"\n [disabled]=\"disabled()\"\n >\n <mat-icon class=\"mat-warn\">clear</mat-icon>\n </button>\n </mat-form-field>\n\n <button\n id=\"apply\"\n type=\"submit\"\n mat-icon-button\n [disabled]=\"disabled()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Apply filters\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}#apply{margin-top:-20px}\n"] }]
1050
933
  }], ctorParameters: () => [], propDecorators: { filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }] } });
1051
934
 
1052
935
  /**
@@ -1055,86 +938,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImpor
1055
938
  class UserEditorComponent {
1056
939
  constructor() {
1057
940
  this._authService = inject(AuthJwtService);
941
+ this.formModel = signal({
942
+ email: '',
943
+ emailConfirmed: false,
944
+ lockoutEnabled: false,
945
+ firstName: '',
946
+ lastName: '',
947
+ roles: '',
948
+ }, /* @ts-ignore */
949
+ ...(ngDevMode ? [{ debugName: "formModel" }] : /* istanbul ignore next */ []));
950
+ this.userForm = form(this.formModel, (p) => {
951
+ required(p.email);
952
+ email(p.email);
953
+ required(p.firstName);
954
+ maxLength(p.firstName, 50);
955
+ required(p.lastName);
956
+ maxLength(p.lastName, 50);
957
+ maxLength(p.roles, 200);
958
+ }, {
959
+ submission: {
960
+ action: async () => {
961
+ this.userChange.emit(this.getUserFromForm());
962
+ },
963
+ },
964
+ });
1058
965
  this.unlocked = signal(undefined, /* @ts-ignore */
1059
966
  ...(ngDevMode ? [{ debugName: "unlocked" }] : /* istanbul ignore next */ []));
1060
- /**
1061
- * The user to edit.
1062
- */
1063
967
  this.user = input(undefined, /* @ts-ignore */
1064
968
  ...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
1065
- /**
1066
- * Emitted when user changes.
1067
- */
1068
969
  this.userChange = output();
1069
- /**
1070
- * Emitted when the user requests to close the user editor.
1071
- */
1072
970
  this.editorClose = output();
1073
- const formBuilder = inject(FormBuilder);
1074
- // form
1075
- this.email = formBuilder.control(null, [
1076
- Validators.required,
1077
- Validators.email,
1078
- ]);
1079
- this.emailConfirmed = formBuilder.control(false, {
1080
- nonNullable: true,
1081
- });
1082
- this.lockoutEnabled = formBuilder.control(false, {
1083
- nonNullable: true,
1084
- });
1085
- this.firstName = formBuilder.control(null, [
1086
- Validators.required,
1087
- Validators.maxLength(50),
1088
- ]);
1089
- this.lastName = formBuilder.control(null, [
1090
- Validators.required,
1091
- Validators.maxLength(50),
1092
- ]);
1093
- this.roles = formBuilder.control(null, Validators.maxLength(200));
1094
- this.form = formBuilder.group({
1095
- email: this.email,
1096
- emailConfirmed: this.emailConfirmed,
1097
- lockoutEnabled: this.lockoutEnabled,
1098
- firstName: this.firstName,
1099
- lastName: this.lastName,
1100
- roles: this.roles,
1101
- });
1102
- // update form when user changes
1103
971
  effect(() => {
1104
972
  this.updateForm(this.user() || undefined);
1105
973
  });
1106
974
  }
1107
975
  updateForm(user) {
1108
976
  if (!user) {
1109
- this.form.reset();
977
+ this.formModel.set({
978
+ email: '',
979
+ emailConfirmed: false,
980
+ lockoutEnabled: false,
981
+ firstName: '',
982
+ lastName: '',
983
+ roles: '',
984
+ });
1110
985
  }
1111
986
  else {
1112
- this.email.setValue(user.email);
1113
- this.emailConfirmed.setValue(user.emailConfirmed || false);
1114
- this.lockoutEnabled.setValue(user.lockoutEnabled || false);
1115
- this.firstName.setValue(user.firstName || '');
1116
- this.lastName.setValue(user.lastName || '');
1117
- if (user.roles?.length > 0) {
1118
- this.roles.setValue(user.roles.join(' '));
1119
- }
1120
- else {
1121
- this.roles.setValue(null);
1122
- }
987
+ this.formModel.set({
988
+ email: user.email,
989
+ emailConfirmed: user.emailConfirmed || false,
990
+ lockoutEnabled: user.lockoutEnabled || false,
991
+ firstName: user.firstName || '',
992
+ lastName: user.lastName || '',
993
+ roles: user.roles?.length > 0 ? user.roles.join(' ') : '',
994
+ });
1123
995
  this.unlocked.set(user.lockoutEnabled &&
1124
996
  (!user.lockoutEnd || user.lockoutEnd < this._authService.getUTCDate()));
1125
997
  }
1126
998
  }
1127
999
  getUserFromForm() {
1000
+ const m = this.formModel();
1128
1001
  return {
1129
1002
  userName: this.user()?.userName || '',
1130
- email: this.email.value || '',
1131
- emailConfirmed: this.emailConfirmed.value,
1132
- lockoutEnabled: this.lockoutEnabled.value,
1133
- firstName: this.firstName.value || '',
1134
- lastName: this.lastName.value || '',
1135
- roles: this.roles.value
1136
- ? this.roles.value.split(' ').filter((s) => s)
1137
- : [],
1003
+ email: m.email || '',
1004
+ emailConfirmed: m.emailConfirmed,
1005
+ lockoutEnabled: m.lockoutEnabled,
1006
+ firstName: m.firstName || '',
1007
+ lastName: m.lastName || '',
1008
+ roles: m.roles.trim() ? m.roles.split(' ').filter((s) => s) : [],
1138
1009
  };
1139
1010
  }
1140
1011
  endLockout() {
@@ -1148,26 +1019,21 @@ class UserEditorComponent {
1148
1019
  close() {
1149
1020
  this.editorClose.emit();
1150
1021
  }
1151
- save() {
1152
- if (this.form.invalid) {
1153
- return;
1154
- }
1155
- this.userChange.emit(this.getUserFromForm());
1156
- }
1157
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1158
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.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]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[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"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1022
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1023
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: UserEditorComponent, isStandalone: true, selector: "auth-jwt-user-editor", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { userChange: "userChange", editorClose: "editorClose" }, ngImport: i0, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <!-- email -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">email</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.email\" />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email address required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email address</mat-error>\n }\n </mat-form-field>\n\n <!-- emailConfirmed -->\n <mat-checkbox [formField]=\"userForm.emailConfirmed\" i18n=\"auth-jwt-admin\">\n email address confirmed\n </mat-checkbox>\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formField]=\"userForm.lockoutEnabled\" i18n=\"auth-jwt-admin\">\n lockout enabled\n </mat-checkbox>\n <button\n type=\"button\"\n mat-icon-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Unlock this user if locked\"\n >\n <mat-icon class=\"mat-primary\">lock_open</mat-icon>\n </button>\n </div>\n\n <div class=\"form-row\">\n <!-- firstName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.firstName\" />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name required</mat-error>\n }\n @if (userForm.firstName().getError('maxLength') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name too long</mat-error>\n }\n </mat-form-field>\n\n <!-- lastName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.lastName\" />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name required</mat-error>\n }\n @if (userForm.lastName().getError('maxLength') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name too long</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">roles</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.roles\" />\n @if (userForm.roles().getError('maxLength') && (userForm.roles().dirty() || userForm.roles().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">too long</mat-error>\n }\n <mat-hint i18n>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button\n type=\"button\"\n mat-icon-button\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Close\"\n (click)=\"close()\"\n >\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\n </button>\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"!userForm().valid()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Save user\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "directive", type: FormRoot, selector: "form[formRoot]", inputs: ["formRoot"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i2$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1159
1024
  }
1160
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserEditorComponent, decorators: [{
1025
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserEditorComponent, decorators: [{
1161
1026
  type: Component,
1162
1027
  args: [{ selector: 'auth-jwt-user-editor', imports: [
1163
- ReactiveFormsModule,
1028
+ FormField,
1029
+ FormRoot,
1164
1030
  MatButtonModule,
1165
1031
  MatCheckboxModule,
1166
1032
  MatFormFieldModule,
1167
1033
  MatIconModule,
1168
1034
  MatInputModule,
1169
1035
  MatTooltipModule,
1170
- ], changeDetection: ChangeDetectionStrategy.Eager, 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"] }]
1036
+ ], changeDetection: ChangeDetectionStrategy.Eager, template: "<form [formRoot]=\"userForm\">\n <div class=\"form-row\">\n <!-- email -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">email</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.email\" />\n @if (userForm.email().getError('required') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">email address required</mat-error>\n }\n @if (userForm.email().getError('email') && (userForm.email().dirty() || userForm.email().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">invalid email address</mat-error>\n }\n </mat-form-field>\n\n <!-- emailConfirmed -->\n <mat-checkbox [formField]=\"userForm.emailConfirmed\" i18n=\"auth-jwt-admin\">\n email address confirmed\n </mat-checkbox>\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formField]=\"userForm.lockoutEnabled\" i18n=\"auth-jwt-admin\">\n lockout enabled\n </mat-checkbox>\n <button\n type=\"button\"\n mat-icon-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Unlock this user if locked\"\n >\n <mat-icon class=\"mat-primary\">lock_open</mat-icon>\n </button>\n </div>\n\n <div class=\"form-row\">\n <!-- firstName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">first name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.firstName\" />\n @if (userForm.firstName().getError('required') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name required</mat-error>\n }\n @if (userForm.firstName().getError('maxLength') && (userForm.firstName().dirty() || userForm.firstName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">first name too long</mat-error>\n }\n </mat-form-field>\n\n <!-- lastName -->\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">last name</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.lastName\" />\n @if (userForm.lastName().getError('required') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name required</mat-error>\n }\n @if (userForm.lastName().getError('maxLength') && (userForm.lastName().dirty() || userForm.lastName().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">last name too long</mat-error>\n }\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <mat-label i18n=\"auth-jwt-admin\">roles</mat-label>\n <input type=\"text\" matInput [formField]=\"userForm.roles\" />\n @if (userForm.roles().getError('maxLength') && (userForm.roles().dirty() || userForm.roles().touched())) {\n <mat-error i18n=\"auth-jwt-admin\">too long</mat-error>\n }\n <mat-hint i18n>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button\n type=\"button\"\n mat-icon-button\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Close\"\n (click)=\"close()\"\n >\n <mat-icon class=\"mat-warn\">cancel</mat-icon>\n </button>\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"!userForm().valid()\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Save user\"\n >\n <mat-icon class=\"mat-primary\">check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
1171
1037
  }], ctorParameters: () => [], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }], userChange: [{ type: i0.Output, args: ["userChange"] }], editorClose: [{ type: i0.Output, args: ["editorClose"] }] } });
1172
1038
 
1173
1039
  /**
@@ -1220,14 +1086,13 @@ class UserListComponent {
1220
1086
  getGravatarUrl(email, options) {
1221
1087
  return this._gravatarService.buildGravatarUrl(email, options);
1222
1088
  }
1223
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1224
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.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: ["table{width:100%;border-collapse:collapse}tbody tr:nth-child(odd){background-color:var(--mat-sys-surface-container)}th{text-align:left;font-weight:400;color:var(--mat-sys-on-surface-variant)}tbody tr:hover{background-color:var(--mat-sys-surface-container-high)}td.fit-width{width:1px;white-space:nowrap}tbody tr.selected{background-color:var(--mat-sys-secondary-container);color:var(--mat-sys-on-secondary-container)}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}div#filters{grid-area:filters}div#list{grid-area:list}div#editor{grid-area:editor}div#container{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:1fr;grid-template-areas:\"filters\" \"list\" \"editor\";gap:8px}@media only screen and (max-width:959px){.noif-lt-md{display:none}}@media only screen and (min-width:1920px){div#container{grid-template-rows:auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"filters filters\" \"list editor\"}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: 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" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1089
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1090
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: UserListComponent, isStandalone: true, selector: "auth-jwt-user-list", ngImport: i0, template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div id=\"filters\">\n <auth-jwt-user-filter\n [filter]=\"filter$ | async\"\n (filterChange)=\"onFilterChange($event)\"\n ></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n @if (page$ | async; as page) {\n <div id=\"list\">\n @if (loading$ | async) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n <table>\n <thead>\n <td></td>\n <td></td>\n <th i18n=\"auth-jwt-admin\">name</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">first</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">last</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">email</th>\n <th i18n=\"auth-jwt-admin\">roles</th>\n <th i18n=\"auth-jwt-admin\" class=\"noif-lt-md\">lock end</th>\n </thead>\n <tbody>\n @for (user of page.items; track user) {\n <tr>\n <td class=\"fit-width\">\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Edit this user\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon class=\"mat-primary\">mode_edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n i18n-matTooltip=\"auth-jwt-admin\"\n matTooltip=\"Delete this user\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\n </button>\n </td>\n <td class=\"fit-width\">\n <img\n alt=\"avatar\"\n [src]=\"getGravatarUrl(user.email, { size: '32' })\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td class=\"noif-lt-md\">{{ user.firstName }}</td>\n <td class=\"noif-lt-md\">{{ user.lastName }}</td>\n <td class=\"noif-lt-md\">\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td class=\"noif-lt-md\">{{ user.lockoutEnd }}</td>\n </tr>\n }\n </tbody>\n </table>\n <!-- paginator -->\n <div class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matmatTooltip=\"auth-jwt-admin\"\n matTooltip=\"Refresh list\"\n (click)=\"reset()\"\n >\n <mat-icon class=\"mat-warn\">autorenew</mat-icon>\n </button>\n <mat-paginator\n [length]=\"page.total\"\n [pageIndex]=\"page.pageNumber - 1\"\n [pageSize]=\"page.pageSize\"\n [pageSizeOptions]=\"[5, 10, 20, 50, 100]\"\n (page)=\"onPageChange($event)\"\n [showFirstLastButtons]=\"true\"\n ></mat-paginator>\n </div>\n </div>\n }\n </div>\n\n <!-- editor -->\n <mat-expansion-panel\n id=\"editor\"\n [expanded]=\"active$ | async\"\n [disabled]=\"!(active$ | async)\"\n >\n @if (active$ | async; as active) {\n <div>\n <fieldset>\n <legend>{{ active.userName }}</legend>\n <auth-jwt-user-editor\n [user]=\"active\"\n (userChange)=\"saveActiveUser($event)\"\n (editorClose)=\"resetActiveUser()\"\n ></auth-jwt-user-editor>\n </fieldset>\n </div>\n }\n </mat-expansion-panel>\n</div>\n", styles: ["table{width:100%;border-collapse:collapse}tbody tr:nth-child(odd){background-color:var(--mat-sys-surface-container)}th{text-align:left;font-weight:400;color:var(--mat-sys-on-surface-variant)}tbody tr:hover{background-color:var(--mat-sys-surface-container-high)}td.fit-width{width:1px;white-space:nowrap}tbody tr.selected{background-color:var(--mat-sys-secondary-container);color:var(--mat-sys-on-secondary-container)}fieldset{border:1px solid var(--mat-sys-on-surface-variant);border-radius:8px;padding:16px}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}div#filters{grid-area:filters}div#list{grid-area:list}div#editor{grid-area:editor}div#container{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:1fr;grid-template-areas:\"filters\" \"list\" \"editor\";gap:8px}@media only screen and (max-width:959px){.noif-lt-md{display:none}}@media only screen and (min-width:1920px){div#container{grid-template-rows:auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"filters filters\" \"list editor\"}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i2$2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i4$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i5$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i6.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: ["user"], outputs: ["userChange", "editorClose"] }, { kind: "component", type: UserFilterComponent, selector: "auth-jwt-user-filter", inputs: ["filter", "disabled"], outputs: ["filterChange"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
1225
1091
  }
1226
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: UserListComponent, decorators: [{
1092
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: UserListComponent, decorators: [{
1227
1093
  type: Component,
1228
1094
  args: [{ selector: 'auth-jwt-user-list', imports: [
1229
1095
  CommonModule,
1230
- ReactiveFormsModule,
1231
1096
  MatButtonModule,
1232
1097
  MatExpansionModule,
1233
1098
  MatIconModule,