@myrmidon/auth-jwt-admin 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/esm2020/lib/auth-jwt-admin.module.mjs +5 -5
  2. package/esm2020/lib/components/auth-jwt-registration/auth-jwt-registration.component.mjs +6 -6
  3. package/esm2020/lib/components/confirm-dialog/confirm-dialog.component.mjs +3 -3
  4. package/esm2020/lib/components/password-strength-bar/password-strength-bar.component.mjs +3 -3
  5. package/esm2020/lib/components/state/user-list.repository.mjs +147 -0
  6. package/esm2020/lib/components/user-editor/user-editor.component.mjs +7 -7
  7. package/esm2020/lib/components/user-filter/user-filter.component.mjs +15 -18
  8. package/esm2020/lib/components/user-list/user-list.component.mjs +34 -102
  9. package/esm2020/lib/services/auth-jwt-account.service.mjs +7 -7
  10. package/esm2020/lib/services/dialog.service.mjs +3 -3
  11. package/fesm2015/myrmidon-auth-jwt-admin.mjs +188 -221
  12. package/fesm2015/myrmidon-auth-jwt-admin.mjs.map +1 -1
  13. package/fesm2020/myrmidon-auth-jwt-admin.mjs +187 -219
  14. package/fesm2020/myrmidon-auth-jwt-admin.mjs.map +1 -1
  15. package/lib/components/auth-jwt-registration/auth-jwt-registration.component.d.ts +1 -1
  16. package/lib/components/confirm-dialog/confirm-dialog.component.d.ts +1 -1
  17. package/lib/components/password-strength-bar/password-strength-bar.component.d.ts +1 -1
  18. package/lib/components/state/user-list.repository.d.ts +36 -0
  19. package/lib/components/user-editor/user-editor.component.d.ts +1 -1
  20. package/lib/components/user-filter/user-filter.component.d.ts +7 -8
  21. package/lib/components/user-list/user-list.component.d.ts +11 -20
  22. package/lib/services/auth-jwt-account.service.d.ts +1 -3
  23. package/package.json +6 -6
  24. package/esm2020/lib/components/state/users.paginator.mjs +0 -12
  25. package/esm2020/lib/components/state/users.query.mjs +0 -20
  26. package/esm2020/lib/components/state/users.service.mjs +0 -65
  27. package/esm2020/lib/components/state/users.store.mjs +0 -27
  28. package/lib/components/state/users.paginator.d.ts +0 -3
  29. package/lib/components/state/users.query.d.ts +0 -12
  30. package/lib/components/state/users.service.d.ts +0 -19
  31. package/lib/components/state/users.store.d.ts +0 -13
@@ -1,40 +1,42 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, Component, Input, Output, InjectionToken, inject, Optional, Inject, NgModule } from '@angular/core';
2
+ import { Injectable, EventEmitter, Component, Input, Output, Optional, Inject, NgModule } from '@angular/core';
3
3
  import * as i1$1 from '@angular/forms';
4
4
  import { Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
5
- import { retry, catchError, take, startWith, tap, switchMap, map } from 'rxjs/operators';
5
+ import { retry, catchError, take } from 'rxjs/operators';
6
6
  import * as i2$1 from '@angular/material/snack-bar';
7
7
  import { MatSnackBarModule } from '@angular/material/snack-bar';
8
8
  import * as i1 from '@angular/common/http';
9
9
  import { HttpParams, HttpClientModule } from '@angular/common/http';
10
10
  import * as i2 from '@myrmidon/ng-tools';
11
11
  import { NgToolsModule } from '@myrmidon/ng-tools';
12
- import * as i7 from '@angular/common';
12
+ import * as i4 from '@angular/common';
13
13
  import { CommonModule } from '@angular/common';
14
- import * as i4 from '@angular/material/button';
14
+ import * as i5 from '@angular/material/button';
15
15
  import { MatButtonModule } from '@angular/material/button';
16
16
  import * as i6 from '@angular/material/icon';
17
17
  import { MatIconModule } from '@angular/material/icon';
18
- import * as i7$1 from '@angular/material/form-field';
19
- import * as i8 from '@angular/material/input';
18
+ import * as i7 from '@angular/material/input';
20
19
  import { MatInputModule } from '@angular/material/input';
20
+ import * as i8 from '@angular/material/form-field';
21
21
  import * as i9 from '@angular/material/progress-spinner';
22
22
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
23
- import * as i15 from '@datorama/akita';
24
- import { EntityStore, StoreConfig, QueryEntity, PaginatorPlugin } from '@datorama/akita';
25
- import { __decorate } from 'tslib';
26
- import * as i8$1 from '@angular/material/tooltip';
23
+ import { __rest } from 'tslib';
24
+ import { BehaviorSubject, combineLatest, map, debounceTime, take as take$1 } from 'rxjs';
25
+ import { select, createStore, withProps } from '@ngneat/elf';
26
+ import { selectActiveEntity, withEntities, withActiveId, upsertEntities, deleteAllEntities, setActiveId, updateEntities } from '@ngneat/elf-entities';
27
+ import { selectPaginationData, selectCurrentPageEntities, deleteAllPages, withPagination, updatePaginationData, setPage, hasPage, setCurrentPage } from '@ngneat/elf-pagination';
28
+ import { selectRequestStatus, withRequestsCache, withRequestsStatus, updateRequestStatus } from '@ngneat/elf-requests';
29
+ import * as i9$1 from '@angular/material/tooltip';
27
30
  import { MatTooltipModule } from '@angular/material/tooltip';
28
- import { BehaviorSubject, combineLatest } from 'rxjs';
29
31
  import * as i1$2 from '@angular/material/dialog';
30
32
  import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
31
33
  import * as i2$2 from '@myrmidon/auth-jwt-login';
32
34
  import { AuthJwtLoginModule } from '@myrmidon/auth-jwt-login';
33
- import * as i10 from '@angular/material/paginator';
35
+ import * as i7$1 from '@angular/material/paginator';
34
36
  import { MatPaginatorModule } from '@angular/material/paginator';
35
- import * as i11 from '@angular/material/progress-bar';
37
+ import * as i8$1 from '@angular/material/progress-bar';
36
38
  import { MatProgressBarModule } from '@angular/material/progress-bar';
37
- import * as i5 from '@angular/material/checkbox';
39
+ import * as i5$1 from '@angular/material/checkbox';
38
40
  import { MatCheckboxModule } from '@angular/material/checkbox';
39
41
  import { MatCardModule } from '@angular/material/card';
40
42
  import { RouterModule } from '@angular/router';
@@ -148,10 +150,10 @@ class AuthJwtAccountService {
148
150
  })
149
151
  .pipe(retry(3), catchError(this._error.handleError));
150
152
  }
151
- getUsers(filter) {
153
+ getUsers(filter, pageNumber = 1, pageSize = 20) {
152
154
  let httpParams = new HttpParams();
153
- httpParams = httpParams.set('pageNumber', filter.pageNumber.toString());
154
- httpParams = httpParams.set('pageSize', filter.pageSize.toString());
155
+ httpParams = httpParams.set('pageNumber', pageNumber.toString());
156
+ httpParams = httpParams.set('pageSize', pageSize.toString());
155
157
  if (filter.name) {
156
158
  httpParams = httpParams.set('name', filter.name);
157
159
  }
@@ -248,9 +250,9 @@ class AuthJwtAccountService {
248
250
  .pipe(catchError(this._error.handleError));
249
251
  }
250
252
  }
251
- AuthJwtAccountService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtAccountService, deps: [{ token: i1.HttpClient }, { token: i2.ErrorService }, { token: i2.EnvService }], target: i0.ɵɵFactoryTarget.Injectable });
252
- AuthJwtAccountService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' });
253
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtAccountService, decorators: [{
253
+ AuthJwtAccountService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAccountService, deps: [{ token: i1.HttpClient }, { token: i2.ErrorService }, { token: i2.EnvService }], target: i0.ɵɵFactoryTarget.Injectable });
254
+ AuthJwtAccountService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' });
255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAccountService, decorators: [{
254
256
  type: Injectable,
255
257
  args: [{
256
258
  providedIn: 'root',
@@ -324,9 +326,9 @@ class PasswordStrengthBarComponent {
324
326
  }
325
327
  }
326
328
  }
327
- PasswordStrengthBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
328
- PasswordStrengthBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.2", type: PasswordStrengthBarComponent, selector: "auth-jwt-password-strength-bar", inputs: { passwordToCheck: "passwordToCheck" }, outputs: { strengthChange: "strengthChange" }, usesOnChanges: true, ngImport: i0, template: "<div id=\"strength\">\n <small>strength:</small>\n <ul id=\"strengthBar\">\n <li class=\"point\" [style.background-color]=\"bars[0]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[1]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[2]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[3]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[4]\"></li>\n </ul>\n</div>\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:#ddd;border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] });
329
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
329
+ PasswordStrengthBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
330
+ PasswordStrengthBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: PasswordStrengthBarComponent, selector: "auth-jwt-password-strength-bar", inputs: { passwordToCheck: "passwordToCheck" }, outputs: { strengthChange: "strengthChange" }, usesOnChanges: true, ngImport: i0, template: "<div id=\"strength\">\n <small>strength:</small>\n <ul id=\"strengthBar\">\n <li class=\"point\" [style.background-color]=\"bars[0]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[1]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[2]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[3]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[4]\"></li>\n </ul>\n</div>\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:#ddd;border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] });
331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
330
332
  type: Component,
331
333
  args: [{ selector: 'auth-jwt-password-strength-bar', template: "<div id=\"strength\">\n <small>strength:</small>\n <ul id=\"strengthBar\">\n <li class=\"point\" [style.background-color]=\"bars[0]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[1]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[2]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[3]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[4]\"></li>\n </ul>\n</div>\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:#ddd;border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] }]
332
334
  }], ctorParameters: function () { return []; }, propDecorators: { passwordToCheck: [{
@@ -514,118 +516,158 @@ class AuthJwtRegistrationComponent {
514
516
  });
515
517
  }
516
518
  }
517
- AuthJwtRegistrationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: i2$1.MatSnackBar }, { token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Component });
518
- AuthJwtRegistrationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.2", type: AuthJwtRegistrationComponent, selector: "auth-jwt-registration", outputs: { registered: "registered" }, ngImport: i0, template: "<div>\n <div>\n <p>\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 3\n characters, nor longer than 50.\n </p>\n <p>\n To promote a decent security level, the password must include at least 8\n characters, uppercase and lowercase letters, digits, and punctuation (like\n dashes, stops, parentheses, etc.).\n </p>\n <p>\n Once registered, the user will receive an email message to the email\n address you specified; he will have to click on the provided link to\n complete the registration process.\n </p>\n </div>\n\n <form role=\"form\" [formGroup]=\"registration\" (submit)=\"onSubmit()\">\n <fieldset>\n <label>register user</label>\n <!-- email -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"email\"\n id=\"email\"\n maxlength=\"256\"\n required\n autofocus\n spellcheck=\"false\"\n placeholder=\"email\"\n formControlName=\"email\"\n />\n <mat-error>{{ getEmailErrorLabel() }}</mat-error>\n <mat-icon *ngIf=\"email.pending\">hourglass</mat-icon>\n </mat-form-field>\n </div>\n\n <!-- name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"name\"\n maxlength=\"50\"\n required\n pattern=\"^[a-zA-Z][a-zA-Z0-9]{2,49}$\"\n spellcheck=\"false\"\n placeholder=\"username\"\n formControlName=\"name\"\n />\n <mat-error>{{ getNameErrorLabel() }}</mat-error>\n <mat-icon *ngIf=\"name.pending\">hourglass</mat-icon>\n </mat-form-field>\n </div>\n\n <!-- first name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"firstName\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"first name\"\n formControlName=\"firstName\"\n />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n class=\"text-danger small\"\n >\n first name required\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- last name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"lastName\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"last name\"\n formControlName=\"lastName\"\n />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') &&\n (lastName.dirty || lastName.touched)\n \"\n class=\"text-danger small\"\n >\n last name required\n </mat-error>\n </mat-form-field>\n </div>\n\n <div [formGroup]=\"passwords\">\n <!-- password -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"password\"\n name=\"password\"\n autocomplete=\"new-password\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"password\"\n formControlName=\"password\"\n />\n <auth-jwt-password-strength-bar [passwordToCheck]=\"password.value\">\n </auth-jwt-password-strength-bar>\n <mat-error>{{ getPasswordErrorLabel() }}</mat-error>\n </mat-form-field>\n </div>\n\n <!-- confirm password -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"password\"\n name=\"confirmPassword\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"confirm password\"\n formControlName=\"confirmPassword\"\n />\n <mat-error\n *ngIf=\"\n passwords.hasError('areEqual') &&\n (confirmPassword.dirty || confirmPassword.touched)\n \"\n >\n password differs from confirmation password\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n\n <button\n mat-raised-button\n type=\"submit\"\n color=\"primary\"\n [disabled]=\"\n !registration.valid || busy || name.pending || email.pending\n \"\n >\n register\n </button>\n <mat-progress-spinner\n diameter=\"20\"\n *ngIf=\"busy\"\n aria-label=\"Busy\"\n ></mat-progress-spinner>\n </fieldset>\n </form>\n</div>\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"], dependencies: [{ kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i7$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i9.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: PasswordStrengthBarComponent, selector: "auth-jwt-password-strength-bar", inputs: ["passwordToCheck"], outputs: ["strengthChange"] }] });
519
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
519
+ AuthJwtRegistrationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: i2$1.MatSnackBar }, { token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Component });
520
+ AuthJwtRegistrationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: AuthJwtRegistrationComponent, selector: "auth-jwt-registration", outputs: { registered: "registered" }, ngImport: i0, template: "<div>\n <div>\n <p>\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 3\n characters, nor longer than 50.\n </p>\n <p>\n To promote a decent security level, the password must include at least 8\n characters, uppercase and lowercase letters, digits, and punctuation (like\n dashes, stops, parentheses, etc.).\n </p>\n <p>\n Once registered, the user will receive an email message to the email\n address you specified; he will have to click on the provided link to\n complete the registration process.\n </p>\n </div>\n\n <form role=\"form\" [formGroup]=\"registration\" (submit)=\"onSubmit()\">\n <fieldset>\n <label>register user</label>\n <!-- email -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"email\"\n id=\"email\"\n maxlength=\"256\"\n required\n autofocus\n spellcheck=\"false\"\n placeholder=\"email\"\n formControlName=\"email\"\n />\n <mat-error>{{ getEmailErrorLabel() }}</mat-error>\n <mat-icon *ngIf=\"email.pending\">hourglass</mat-icon>\n </mat-form-field>\n </div>\n\n <!-- name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"name\"\n maxlength=\"50\"\n required\n pattern=\"^[a-zA-Z][a-zA-Z0-9]{2,49}$\"\n spellcheck=\"false\"\n placeholder=\"username\"\n formControlName=\"name\"\n />\n <mat-error>{{ getNameErrorLabel() }}</mat-error>\n <mat-icon *ngIf=\"name.pending\">hourglass</mat-icon>\n </mat-form-field>\n </div>\n\n <!-- first name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"firstName\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"first name\"\n formControlName=\"firstName\"\n />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n class=\"text-danger small\"\n >\n first name required\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- last name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"lastName\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"last name\"\n formControlName=\"lastName\"\n />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') &&\n (lastName.dirty || lastName.touched)\n \"\n class=\"text-danger small\"\n >\n last name required\n </mat-error>\n </mat-form-field>\n </div>\n\n <div [formGroup]=\"passwords\">\n <!-- password -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"password\"\n name=\"password\"\n autocomplete=\"new-password\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"password\"\n formControlName=\"password\"\n />\n <auth-jwt-password-strength-bar [passwordToCheck]=\"password.value\">\n </auth-jwt-password-strength-bar>\n <mat-error>{{ getPasswordErrorLabel() }}</mat-error>\n </mat-form-field>\n </div>\n\n <!-- confirm password -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"password\"\n name=\"confirmPassword\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"confirm password\"\n formControlName=\"confirmPassword\"\n />\n <mat-error\n *ngIf=\"\n passwords.hasError('areEqual') &&\n (confirmPassword.dirty || confirmPassword.touched)\n \"\n >\n password differs from confirmation password\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n\n <button\n mat-raised-button\n type=\"submit\"\n color=\"primary\"\n [disabled]=\"\n !registration.valid || busy || name.pending || email.pending\n \"\n >\n register\n </button>\n <mat-progress-spinner\n diameter=\"20\"\n *ngIf=\"busy\"\n aria-label=\"Busy\"\n ></mat-progress-spinner>\n </fieldset>\n </form>\n</div>\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i9.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: PasswordStrengthBarComponent, selector: "auth-jwt-password-strength-bar", inputs: ["passwordToCheck"], outputs: ["strengthChange"] }] });
521
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
520
522
  type: Component,
521
523
  args: [{ selector: 'auth-jwt-registration', template: "<div>\n <div>\n <p>\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 3\n characters, nor longer than 50.\n </p>\n <p>\n To promote a decent security level, the password must include at least 8\n characters, uppercase and lowercase letters, digits, and punctuation (like\n dashes, stops, parentheses, etc.).\n </p>\n <p>\n Once registered, the user will receive an email message to the email\n address you specified; he will have to click on the provided link to\n complete the registration process.\n </p>\n </div>\n\n <form role=\"form\" [formGroup]=\"registration\" (submit)=\"onSubmit()\">\n <fieldset>\n <label>register user</label>\n <!-- email -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"email\"\n id=\"email\"\n maxlength=\"256\"\n required\n autofocus\n spellcheck=\"false\"\n placeholder=\"email\"\n formControlName=\"email\"\n />\n <mat-error>{{ getEmailErrorLabel() }}</mat-error>\n <mat-icon *ngIf=\"email.pending\">hourglass</mat-icon>\n </mat-form-field>\n </div>\n\n <!-- name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"name\"\n maxlength=\"50\"\n required\n pattern=\"^[a-zA-Z][a-zA-Z0-9]{2,49}$\"\n spellcheck=\"false\"\n placeholder=\"username\"\n formControlName=\"name\"\n />\n <mat-error>{{ getNameErrorLabel() }}</mat-error>\n <mat-icon *ngIf=\"name.pending\">hourglass</mat-icon>\n </mat-form-field>\n </div>\n\n <!-- first name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"firstName\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"first name\"\n formControlName=\"firstName\"\n />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n class=\"text-danger small\"\n >\n first name required\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- last name -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"text\"\n id=\"lastName\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"last name\"\n formControlName=\"lastName\"\n />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') &&\n (lastName.dirty || lastName.touched)\n \"\n class=\"text-danger small\"\n >\n last name required\n </mat-error>\n </mat-form-field>\n </div>\n\n <div [formGroup]=\"passwords\">\n <!-- password -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"password\"\n name=\"password\"\n autocomplete=\"new-password\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"password\"\n formControlName=\"password\"\n />\n <auth-jwt-password-strength-bar [passwordToCheck]=\"password.value\">\n </auth-jwt-password-strength-bar>\n <mat-error>{{ getPasswordErrorLabel() }}</mat-error>\n </mat-form-field>\n </div>\n\n <!-- confirm password -->\n <div>\n <mat-form-field>\n <input\n matInput\n type=\"password\"\n name=\"confirmPassword\"\n maxlength=\"50\"\n required\n spellcheck=\"false\"\n placeholder=\"confirm password\"\n formControlName=\"confirmPassword\"\n />\n <mat-error\n *ngIf=\"\n passwords.hasError('areEqual') &&\n (confirmPassword.dirty || confirmPassword.touched)\n \"\n >\n password differs from confirmation password\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n\n <button\n mat-raised-button\n type=\"submit\"\n color=\"primary\"\n [disabled]=\"\n !registration.valid || busy || name.pending || email.pending\n \"\n >\n register\n </button>\n <mat-progress-spinner\n diameter=\"20\"\n *ngIf=\"busy\"\n aria-label=\"Busy\"\n ></mat-progress-spinner>\n </fieldset>\n </form>\n</div>\n", styles: ["mat-form-field{width:400px}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"] }]
522
524
  }], ctorParameters: function () { return [{ type: i1$1.UntypedFormBuilder }, { type: i2$1.MatSnackBar }, { type: AuthJwtAccountService }]; }, propDecorators: { registered: [{
523
525
  type: Output
524
526
  }] } });
525
527
 
526
- const initialState = {
527
- filter: {
528
- pageNumber: 1,
529
- pageSize: 20,
530
- },
531
- active: null
532
- };
533
- let UsersStore = class UsersStore extends EntityStore {
534
- constructor() {
535
- super(initialState);
536
- }
537
- };
538
- UsersStore.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
539
- UsersStore.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersStore, providedIn: 'root' });
540
- UsersStore = __decorate([
541
- StoreConfig({ name: 'Users', idKey: 'userName', resettable: true })
542
- ], UsersStore);
543
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersStore, decorators: [{
544
- type: Injectable,
545
- args: [{ providedIn: 'root' }]
546
- }], ctorParameters: function () { return []; } });
547
-
548
- class UsersQuery extends QueryEntity {
549
- constructor(_store) {
550
- super(_store);
551
- this._store = _store;
552
- }
553
- selectFilter() {
554
- return this.select((state) => state.filter);
528
+ const PAGE_SIZE = 20;
529
+ class UserListRepository {
530
+ constructor(_accService) {
531
+ this._accService = _accService;
532
+ // create store
533
+ this._store = this.createStore();
534
+ this._lastPageSize = PAGE_SIZE;
535
+ this._loading$ = new BehaviorSubject(false);
536
+ this._saving$ = new BehaviorSubject(false);
537
+ this.loading$ = this._loading$.asObservable();
538
+ this.saving$ = this._saving$.asObservable();
539
+ // combine pagination parameters with page data for our consumers
540
+ this.pagination$ = combineLatest([
541
+ this._store.pipe(selectPaginationData()),
542
+ this._store.pipe(selectCurrentPageEntities()),
543
+ ]).pipe(map(([pagination, data]) => (Object.assign(Object.assign({}, pagination), { data }))), debounceTime(0));
544
+ // the active document, if required
545
+ this.activeUser$ = this._store.pipe(selectActiveEntity());
546
+ // the filter, if required
547
+ this.filter$ = this._store.pipe(select((state) => state.filter));
548
+ this.filter$.subscribe((filter) => {
549
+ // when filter changed, reset any existing page and move to page 1
550
+ const paginationData = this._store.getValue().pagination;
551
+ console.log('Deleting all pages');
552
+ this._store.update(deleteAllPages());
553
+ // load page 1
554
+ this.loadPage(1, paginationData.perPage);
555
+ });
556
+ // the request status
557
+ this.status$ = this._store.pipe(selectRequestStatus('document'));
558
+ // load page 1 and subscribe to pagination
559
+ this.loadPage(1, PAGE_SIZE);
560
+ this.pagination$.subscribe(console.log);
561
+ }
562
+ createStore() {
563
+ const store = createStore({ name: 'user-list' }, withProps({
564
+ filter: {},
565
+ }), withEntities({ idKey: 'userName' }), withActiveId(), withRequestsCache(), withRequestsStatus(), withPagination());
566
+ return store;
567
+ }
568
+ adaptPage(page) {
569
+ // adapt the server page DataPage<T> to Elf pagination
570
+ return {
571
+ currentPage: page.pageNumber,
572
+ perPage: page.pageSize,
573
+ lastPage: page.pageCount,
574
+ total: page.total,
575
+ data: page.items,
576
+ };
555
577
  }
556
- }
557
- UsersQuery.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersQuery, deps: [{ token: UsersStore }], target: i0.ɵɵFactoryTarget.Injectable });
558
- UsersQuery.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersQuery, providedIn: 'root' });
559
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersQuery, decorators: [{
560
- type: Injectable,
561
- args: [{ providedIn: 'root' }]
562
- }], ctorParameters: function () { return [{ type: UsersStore }]; } });
563
-
564
- class UsersService {
565
- constructor(_store, _accountService) {
566
- this._store = _store;
567
- this._accountService = _accountService;
578
+ addPage(response) {
579
+ const { data } = response, paginationData = __rest(response, ["data"]);
580
+ this._store.update(upsertEntities(data),
581
+ // addEntities(data),
582
+ updatePaginationData(paginationData), setPage(paginationData.currentPage, data.map((c) => c.userName)));
568
583
  }
569
- /**
570
- * Update the filter in the store.
571
- * @param filter The filter.
572
- */
573
- updateFilter(filter) {
574
- this._store.update({
575
- filter: filter,
584
+ loadPage(pageNumber, pageSize) {
585
+ if (!pageSize) {
586
+ pageSize = PAGE_SIZE;
587
+ }
588
+ // if the page exists and page size is the same, just move to it
589
+ if (this._store.query(hasPage(pageNumber)) &&
590
+ pageSize === this._lastPageSize) {
591
+ console.log('Page exists: ' + pageNumber);
592
+ this._store.update(setCurrentPage(pageNumber));
593
+ return;
594
+ }
595
+ // reset cached pages if page size changed
596
+ if (this._lastPageSize !== pageSize) {
597
+ this._store.update(deleteAllPages());
598
+ this._lastPageSize = pageSize;
599
+ }
600
+ // load page from server
601
+ this._store.update(updateRequestStatus('document', 'pending'));
602
+ this._loading$.next(true);
603
+ this._accService
604
+ .getUsers(this._store.getValue().filter, pageNumber, pageSize)
605
+ .pipe(take$1(1))
606
+ .subscribe((page) => {
607
+ this._loading$.next(false);
608
+ this.addPage(Object.assign(Object.assign({}, this.adaptPage(page)), { data: page.items }));
609
+ this._store.update(updateRequestStatus('document', 'success'));
576
610
  });
577
611
  }
612
+ setFilter(filter) {
613
+ this._store.update((state) => (Object.assign(Object.assign({}, state), { filter: filter })));
614
+ }
615
+ clearCache() {
616
+ this._store.update(deleteAllEntities(), deleteAllPages());
617
+ }
578
618
  setActive(name) {
579
- this._store.setActive(name);
619
+ this._store.update(setActiveId(name));
580
620
  }
581
621
  updateActive(user) {
582
622
  const promise = new Promise((resolve, reject) => {
583
- this._store.setLoading(true);
584
- this._accountService.updateUser(user).subscribe((_) => {
585
- this._store.setLoading(false);
586
- this._store.setError(null);
587
- this._store.updateActive((u) => {
588
- return Object.assign({}, user);
589
- });
590
- resolve(true);
591
- }, (error) => {
592
- console.error(error);
593
- this._store.setLoading(false);
594
- this._store.setError('Error updating user');
595
- resolve(false);
623
+ this._saving$.next(true);
624
+ this._accService.updateUser(user).subscribe({
625
+ next: (_) => {
626
+ this._saving$.next(false);
627
+ this._store.update(updateEntities(user.userName, user));
628
+ resolve(true);
629
+ },
630
+ error: (error) => {
631
+ this._saving$.next(false);
632
+ console.error(`Error updating user ${user.userName}: ` +
633
+ JSON.stringify(error || {}));
634
+ resolve(false);
635
+ },
596
636
  });
597
637
  });
598
638
  return promise;
599
639
  }
600
640
  deleteUser(name) {
601
641
  const promise = new Promise((resolve, reject) => {
602
- this._store.setLoading(true);
603
- this._accountService.deleteUser(name).subscribe((_) => {
604
- this._store.setLoading(false);
605
- this._store.setError(null);
606
- this._store.remove(name);
607
- resolve(true);
608
- }, (error) => {
609
- console.error(error);
610
- this._store.setLoading(false);
611
- this._store.setError('Error deleting user');
612
- reject(error);
642
+ this._saving$.next(true);
643
+ this._accService.deleteUser(name).subscribe({
644
+ next: (_) => {
645
+ this._saving$.next(false);
646
+ this.clearCache();
647
+ this.loadPage(1);
648
+ resolve(true);
649
+ },
650
+ error: (error) => {
651
+ this._saving$.next(false);
652
+ console.error(`Error deleting user ${name}: ` + JSON.stringify(error || {}));
653
+ reject(error);
654
+ },
613
655
  });
614
656
  });
615
657
  return promise;
616
658
  }
617
659
  }
618
- UsersService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersService, deps: [{ token: UsersStore }, { token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Injectable });
619
- UsersService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersService, providedIn: 'root' });
620
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UsersService, decorators: [{
660
+ UserListRepository.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, deps: [{ token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Injectable });
661
+ UserListRepository.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, providedIn: 'root' });
662
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, decorators: [{
621
663
  type: Injectable,
622
664
  args: [{ providedIn: 'root' }]
623
- }], ctorParameters: function () { return [{ type: UsersStore }, { type: AuthJwtAccountService }]; } });
665
+ }], ctorParameters: function () { return [{ type: AuthJwtAccountService }]; } });
624
666
 
625
667
  class UserFilterComponent {
626
- constructor(formBuilder, query, _corporaService) {
627
- this._corporaService = _corporaService;
628
- this.filter$ = query.selectFilter();
668
+ constructor(formBuilder, _repository) {
669
+ this._repository = _repository;
670
+ this.filter$ = _repository.filter$;
629
671
  // form
630
672
  this.name = formBuilder.control(null);
631
673
  this.form = formBuilder.group({
@@ -638,7 +680,7 @@ class UserFilterComponent {
638
680
  });
639
681
  }
640
682
  updateForm(filter) {
641
- this.name.setValue(filter.name);
683
+ this.name.setValue(filter.name || null);
642
684
  this.form.markAsPristine();
643
685
  }
644
686
  reset() {
@@ -648,8 +690,6 @@ class UserFilterComponent {
648
690
  getFilter() {
649
691
  var _a;
650
692
  return {
651
- pageNumber: 1,
652
- pageSize: 20,
653
693
  name: (_a = this.name.value) === null || _a === void 0 ? void 0 : _a.trim(),
654
694
  };
655
695
  }
@@ -659,27 +699,18 @@ class UserFilterComponent {
659
699
  }
660
700
  const filter = this.getFilter();
661
701
  // update filter in state
662
- this._corporaService.updateFilter(filter);
702
+ this._repository.setFilter(filter);
663
703
  }
664
704
  }
665
- UserFilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UserFilterComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: UsersQuery }, { token: UsersService }], target: i0.ɵɵFactoryTarget.Component });
666
- UserFilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.2", type: UserFilterComponent, selector: "auth-jwt-user-filter", inputs: { disabled: "disabled" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"apply()\" ng-disabled=\"disabled\">\n <mat-form-field>\n <input matInput [formControl]=\"name\" placeholder=\"name or ID\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n color=\"warn\"\n matTooltip=\"Reset filters\"\n [disabled]=\"disabled\"\n >\n <mat-icon>clear</mat-icon>\n </button>\n </mat-form-field>\n\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"disabled\"\n matTooltip=\"Apply filters\"\n >\n <mat-icon>check_circle</mat-icon>\n </button>\n</form>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i7$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i7$1.MatSuffix, selector: "[matSuffix]" }, { kind: "directive", type: i8.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i8$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
667
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UserFilterComponent, decorators: [{
705
+ UserFilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserFilterComponent, deps: [{ token: i1$1.FormBuilder }, { token: UserListRepository }], target: i0.ɵɵFactoryTarget.Component });
706
+ UserFilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: UserFilterComponent, selector: "auth-jwt-user-filter", inputs: { disabled: "disabled" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"apply()\" ng-disabled=\"disabled\">\n <mat-form-field>\n <input matInput [formControl]=\"name\" placeholder=\"name or ID\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n color=\"warn\"\n matTooltip=\"Reset filters\"\n [disabled]=\"disabled\"\n >\n <mat-icon>clear</mat-icon>\n </button>\n </mat-form-field>\n\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"disabled\"\n matTooltip=\"Apply filters\"\n >\n <mat-icon>check_circle</mat-icon>\n </button>\n</form>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]" }, { kind: "directive", type: i9$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
707
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserFilterComponent, decorators: [{
668
708
  type: Component,
669
709
  args: [{ selector: 'auth-jwt-user-filter', template: "<form [formGroup]=\"form\" (submit)=\"apply()\" ng-disabled=\"disabled\">\n <mat-form-field>\n <input matInput [formControl]=\"name\" placeholder=\"name or ID\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n color=\"warn\"\n matTooltip=\"Reset filters\"\n [disabled]=\"disabled\"\n >\n <mat-icon>clear</mat-icon>\n </button>\n </mat-form-field>\n\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"disabled\"\n matTooltip=\"Apply filters\"\n >\n <mat-icon>check_circle</mat-icon>\n </button>\n</form>\n" }]
670
- }], ctorParameters: function () { return [{ type: i1$1.UntypedFormBuilder }, { type: UsersQuery }, { type: UsersService }]; }, propDecorators: { disabled: [{
710
+ }], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: UserListRepository }]; }, propDecorators: { disabled: [{
671
711
  type: Input
672
712
  }] } });
673
713
 
674
- // create a factory provider for the paginator
675
- const USERS_PAGINATOR = new InjectionToken('USERS_PAGINATOR', {
676
- providedIn: 'root',
677
- factory: () => {
678
- const query = inject(UsersQuery);
679
- return new PaginatorPlugin(query).withControls().withRange();
680
- },
681
- });
682
-
683
714
  // https://medium.com/@tarik.nzl/making-use-of-dialogs-in-material-2-mddialog-7533d27df41
684
715
  class ConfirmDialogComponent {
685
716
  constructor(dialogRef, data) {
@@ -692,9 +723,9 @@ class ConfirmDialogComponent {
692
723
  }
693
724
  ngOnInit() { }
694
725
  }
695
- ConfirmDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: ConfirmDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
696
- ConfirmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.2", type: ConfirmDialogComponent, selector: "ng-component", ngImport: i0, template: "<h1 mat-dialog-title>{{ title }}</h1>\r\n<mat-dialog-content>\r\n {{ prompt }}\r\n</mat-dialog-content>\r\n<mat-dialog-actions>\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"warn\"\r\n (click)=\"dialogRef.close(true)\"\r\n >\r\n {{ ok }}\r\n </button>\r\n <button type=\"button\" mat-button (click)=\"dialogRef.close()\">\r\n {{ cancel }}\r\n </button>\r\n</mat-dialog-actions>\r\n", styles: [""], dependencies: [{ kind: "component", type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }] });
697
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
726
+ ConfirmDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: ConfirmDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
727
+ ConfirmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: ConfirmDialogComponent, selector: "ng-component", ngImport: i0, template: "<h1 mat-dialog-title>{{ title }}</h1>\r\n<mat-dialog-content>\r\n {{ prompt }}\r\n</mat-dialog-content>\r\n<mat-dialog-actions>\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"warn\"\r\n (click)=\"dialogRef.close(true)\"\r\n >\r\n {{ ok }}\r\n </button>\r\n <button type=\"button\" mat-button (click)=\"dialogRef.close()\">\r\n {{ cancel }}\r\n </button>\r\n</mat-dialog-actions>\r\n", styles: [""], dependencies: [{ kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }] });
728
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
698
729
  type: Component,
699
730
  args: [{ template: "<h1 mat-dialog-title>{{ title }}</h1>\r\n<mat-dialog-content>\r\n {{ prompt }}\r\n</mat-dialog-content>\r\n<mat-dialog-actions>\r\n <button\r\n type=\"button\"\r\n mat-raised-button\r\n color=\"warn\"\r\n (click)=\"dialogRef.close(true)\"\r\n >\r\n {{ ok }}\r\n </button>\r\n <button type=\"button\" mat-button (click)=\"dialogRef.close()\">\r\n {{ cancel }}\r\n </button>\r\n</mat-dialog-actions>\r\n" }]
700
731
  }], ctorParameters: function () {
@@ -730,9 +761,9 @@ class DialogService {
730
761
  return dialogRef.afterClosed();
731
762
  }
732
763
  }
733
- DialogService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: DialogService, deps: [{ token: i1$2.MatDialog }], target: i0.ɵɵFactoryTarget.Injectable });
734
- DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: DialogService, providedIn: 'root' });
735
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: DialogService, decorators: [{
764
+ DialogService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: DialogService, deps: [{ token: i1$2.MatDialog }], target: i0.ɵɵFactoryTarget.Injectable });
765
+ DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: DialogService, providedIn: 'root' });
766
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: DialogService, decorators: [{
736
767
  type: Injectable,
737
768
  args: [{
738
769
  providedIn: 'root'
@@ -828,11 +859,11 @@ class UserEditorComponent {
828
859
  this.userChange.emit(this.getUserFromForm());
829
860
  }
830
861
  }
831
- UserEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UserEditorComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: i2$2.AuthJwtService }], target: i0.ɵɵFactoryTarget.Component });
832
- UserEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.2", type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: { user: "user" }, outputs: { userChange: "userChange", editorClose: "editorClose" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <!-- email -->\n <div>\n <mat-form-field>\n <input type=\"text\" matInput [formControl]=\"email\" placeholder=\"email\" />\n <mat-error\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n *ngIf=\"email.hasError('pattern') && (email.dirty || email.touched)\"\n >\n invalid email address\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- emailConfirmed -->\n <div>\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div>\n <mat-checkbox [formControl]=\"lockoutEnabled\"\n >lockout enabled</mat-checkbox\n >\n &nbsp;\n <button\n mat-stroked-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n matTooltip=\"Unlock this user if locked\"\n >\n unlock\n </button>\n </div>\n\n <!-- firstName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"firstName\"\n placeholder=\"first name\"\n />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n *ngIf=\"\n firstName.hasError('maxlength') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- lastName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"lastName\"\n placeholder=\"last name\"\n />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n *ngIf=\"\n lastName.hasError('maxlength') && (lastName.dirty || lastName.touched)\n \"\n >\n last name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"roles\"\n placeholder=\"roles (separated by space)\"\n />\n <mat-error\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button mat-icon-button color=\"warn\" matTooltip=\"Close\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n </button>\n &nbsp;\n <button\n type=\"submit\"\n mat-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user data\"\n >\n <mat-icon>check_circle</mat-icon> save\n </button>\n </div>\n</form>\n", styles: [""], dependencies: [{ kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i5.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i7$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i8$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
833
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UserEditorComponent, decorators: [{
862
+ UserEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserEditorComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: i2$2.AuthJwtService }], target: i0.ɵɵFactoryTarget.Component });
863
+ UserEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: { user: "user" }, outputs: { userChange: "userChange", editorClose: "editorClose" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <!-- email -->\n <div>\n <mat-form-field>\n <mat-label>email</mat-label>\n <input type=\"text\" matInput [formControl]=\"email\" />\n <mat-error\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n *ngIf=\"email.hasError('pattern') && (email.dirty || email.touched)\"\n >\n invalid email address\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- emailConfirmed -->\n <div>\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div>\n <mat-checkbox [formControl]=\"lockoutEnabled\">lockout enabled</mat-checkbox>\n &nbsp;\n <button\n mat-icon-button\n color=\"primary\"\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n matTooltip=\"Unlock this user if locked\"\n >\n <mat-icon>lock_open</mat-icon>\n </button>\n </div>\n\n <!-- firstName -->\n <div>\n <mat-form-field>\n <mat-label>first name</mat-label>\n <input type=\"text\" matInput [formControl]=\"firstName\" />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n *ngIf=\"\n firstName.hasError('maxlength') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- lastName -->\n <div>\n <mat-form-field>\n <mat-label>last name</mat-label>\n <input type=\"text\" matInput [formControl]=\"lastName\" />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n *ngIf=\"\n lastName.hasError('maxlength') && (lastName.dirty || lastName.touched)\n \"\n >\n last name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <mat-label>roles</mat-label>\n <input type=\"text\" matInput [formControl]=\"roles\" />\n <mat-error\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n <mat-hint>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button mat-icon-button color=\"warn\" matTooltip=\"Close\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n </button>\n &nbsp;\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user data\"\n >\n <mat-icon>check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [""], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i5$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatLabel, selector: "mat-label" }, { kind: "directive", type: i8.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i8.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i9$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
864
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserEditorComponent, decorators: [{
834
865
  type: Component,
835
- args: [{ selector: 'auth-jwt-user-editor', template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <!-- email -->\n <div>\n <mat-form-field>\n <input type=\"text\" matInput [formControl]=\"email\" placeholder=\"email\" />\n <mat-error\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n *ngIf=\"email.hasError('pattern') && (email.dirty || email.touched)\"\n >\n invalid email address\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- emailConfirmed -->\n <div>\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div>\n <mat-checkbox [formControl]=\"lockoutEnabled\"\n >lockout enabled</mat-checkbox\n >\n &nbsp;\n <button\n mat-stroked-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n matTooltip=\"Unlock this user if locked\"\n >\n unlock\n </button>\n </div>\n\n <!-- firstName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"firstName\"\n placeholder=\"first name\"\n />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n *ngIf=\"\n firstName.hasError('maxlength') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- lastName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"lastName\"\n placeholder=\"last name\"\n />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n *ngIf=\"\n lastName.hasError('maxlength') && (lastName.dirty || lastName.touched)\n \"\n >\n last name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"roles\"\n placeholder=\"roles (separated by space)\"\n />\n <mat-error\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button mat-icon-button color=\"warn\" matTooltip=\"Close\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n </button>\n &nbsp;\n <button\n type=\"submit\"\n mat-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user data\"\n >\n <mat-icon>check_circle</mat-icon> save\n </button>\n </div>\n</form>\n" }]
866
+ args: [{ selector: 'auth-jwt-user-editor', template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <!-- email -->\n <div>\n <mat-form-field>\n <mat-label>email</mat-label>\n <input type=\"text\" matInput [formControl]=\"email\" />\n <mat-error\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n *ngIf=\"email.hasError('pattern') && (email.dirty || email.touched)\"\n >\n invalid email address\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- emailConfirmed -->\n <div>\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div>\n <mat-checkbox [formControl]=\"lockoutEnabled\">lockout enabled</mat-checkbox>\n &nbsp;\n <button\n mat-icon-button\n color=\"primary\"\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n matTooltip=\"Unlock this user if locked\"\n >\n <mat-icon>lock_open</mat-icon>\n </button>\n </div>\n\n <!-- firstName -->\n <div>\n <mat-form-field>\n <mat-label>first name</mat-label>\n <input type=\"text\" matInput [formControl]=\"firstName\" />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n *ngIf=\"\n firstName.hasError('maxlength') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- lastName -->\n <div>\n <mat-form-field>\n <mat-label>last name</mat-label>\n <input type=\"text\" matInput [formControl]=\"lastName\" />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n *ngIf=\"\n lastName.hasError('maxlength') && (lastName.dirty || lastName.touched)\n \"\n >\n last name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <mat-label>roles</mat-label>\n <input type=\"text\" matInput [formControl]=\"roles\" />\n <mat-error\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n <mat-hint>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button mat-icon-button color=\"warn\" matTooltip=\"Close\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n </button>\n &nbsp;\n <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user data\"\n >\n <mat-icon>check_circle</mat-icon>\n </button>\n </div>\n</form>\n" }]
836
867
  }], ctorParameters: function () { return [{ type: i1$1.UntypedFormBuilder }, { type: i2$2.AuthJwtService }]; }, propDecorators: { user: [{
837
868
  type: Input
838
869
  }], userChange: [{
@@ -842,77 +873,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImpor
842
873
  }] } });
843
874
 
844
875
  class UserListComponent {
845
- constructor(paginator, userQuery, _accountService, _usersService, _dialogService, _gravatarService, formBuilder) {
846
- this.paginator = paginator;
847
- this._accountService = _accountService;
848
- this._usersService = _usersService;
876
+ constructor(_repository, _dialogService, _gravatarService) {
877
+ this._repository = _repository;
849
878
  this._dialogService = _dialogService;
850
879
  this._gravatarService = _gravatarService;
851
- this.pageSize = formBuilder.control(20);
852
- this._refresh$ = new BehaviorSubject(0);
853
- this._filter$ = userQuery.selectFilter();
854
- // https://netbasal.com/manage-your-entities-with-akita-like-a-boss-768732f8d4d1
855
- this.active$ = userQuery.selectActive();
856
- this.pagination$ = combineLatest([
857
- this.paginator.pageChanges,
858
- this.pageSize.valueChanges.pipe(
859
- // we are required to emit at least the initial value
860
- // as combineLatest emits only if ALL observables have emitted
861
- startWith(20),
862
- // clear the cache when page size changes
863
- tap((_) => {
864
- this.paginator.clearCache();
865
- })),
866
- this._filter$.pipe(
867
- // clear the cache when filters changed
868
- tap((_) => {
869
- this.paginator.clearCache();
870
- })),
871
- this._refresh$.pipe(
872
- // clear the cache when forcing refresh
873
- tap((_) => {
874
- this.paginator.clearCache();
875
- })),
876
- ]).pipe(
877
- // for each emitted value, combine into a filter and use it
878
- // to request the page from server
879
- switchMap(([pageNumber, pageSize, filter, refresh]) => {
880
- // const filter = { ...this._docsQuery.getValue().filter };
881
- const f = Object.assign({}, filter);
882
- f.pageNumber = pageNumber;
883
- f.pageSize = pageSize;
884
- const request = this.getRequest(f);
885
- // update saved filters
886
- this.paginator.metadata.set('filter', f);
887
- return this.paginator.getPage(request);
888
- }));
889
- }
890
- ngOnDestroy() {
891
- this.paginator.destroy();
892
- }
893
- getRequest(filter) {
894
- return () => this._accountService.getUsers(filter).pipe(
895
- // adapt server results to the paginator plugin
896
- map((p) => {
897
- return {
898
- currentPage: p.pageNumber,
899
- perPage: p.pageSize,
900
- lastPage: p.pageCount,
901
- data: p.items,
902
- total: p.total,
903
- };
904
- }));
880
+ this.pagination$ = _repository.pagination$;
881
+ this.active$ = _repository.activeUser$;
882
+ this.loading$ = _repository.loading$;
905
883
  }
906
884
  pageChange(event) {
907
- // https://material.angular.io/components/paginator/api
908
- this.paginator.setPage(event.pageIndex + 1);
909
- if (event.pageSize !== this.pageSize.value) {
910
- this.pageSize.setValue(event.pageSize);
911
- }
912
- }
913
- refresh() {
914
- this.paginator.clearCache();
915
- this._refresh$.next(this._refresh$.value + 1);
885
+ this._repository.loadPage(event.pageIndex + 1, event.pageSize);
916
886
  }
917
887
  deleteUser(user) {
918
888
  this._dialogService
@@ -922,21 +892,20 @@ class UserListComponent {
922
892
  if (!yes) {
923
893
  return;
924
894
  }
925
- this._usersService.deleteUser(user.userName).finally(() => {
926
- this.refresh();
895
+ this._repository.deleteUser(user.userName).finally(() => {
896
+ this._repository.clearCache();
897
+ this._repository.loadPage(1);
927
898
  });
928
899
  });
929
900
  }
930
901
  setActiveUser(user) {
931
- this._usersService.setActive((user === null || user === void 0 ? void 0 : user.userName) || null);
902
+ this._repository.setActive((user === null || user === void 0 ? void 0 : user.userName) || null);
932
903
  }
933
904
  resetActiveUser() {
934
- this._usersService.setActive(null);
905
+ this._repository.setActive(null);
935
906
  }
936
907
  saveActiveUser(user) {
937
- this._usersService.updateActive(user).finally(() => {
938
- this.refresh();
939
- });
908
+ this._repository.updateActive(user);
940
909
  }
941
910
  onUserEditorClose() {
942
911
  this.setActiveUser(null);
@@ -944,23 +913,21 @@ class UserListComponent {
944
913
  getGravatarUrl(email, size = 80) {
945
914
  return this._gravatarService.buildGravatarUrl(email, size);
946
915
  }
916
+ clearCache() {
917
+ this._repository.clearCache();
918
+ }
947
919
  }
948
- UserListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UserListComponent, deps: [{ token: USERS_PAGINATOR }, { token: UsersQuery }, { token: AuthJwtAccountService }, { token: UsersService }, { token: DialogService }, { token: i2$2.GravatarService }, { token: i1$1.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component });
949
- UserListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.2", type: UserListComponent, selector: "auth-jwt-user-list", ngImport: i0, template: "<div\n gdAreas=\"filters | progress | list | pager | editor\"\n gdRows=\"80px 64px 2fr 40px 1fr\"\n gdColumns=\"1fr\"\n gdGap=\"8px\"\n>\n <div>\n <!-- filters -->\n <div gdArea=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- progress -->\n <div *ngIf=\"paginator.isLoading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n\n <!-- list -->\n <div gdArea=\"list\" *ngIf=\"pagination$ | async as pagination\">\n <table>\n <thead>\n <td></td>\n <td></td>\n <td></td>\n <th>name</th>\n <th>first</th>\n <th>last</th>\n <th>email</th>\n <th>roles</th>\n <th>lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Edit {{ user.userName }}\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon>mode_edit</mat-icon>\n </button>\n </td>\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Delete {{ user.userName }}\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n [src]=\"getGravatarUrl(user.email, 32)\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td>{{ user.firstName }}</td>\n <td>{{ user.lastName }}</td>\n <td>\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td>{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n <!-- pagination -->\n <mat-paginator\n gdArea=\"pager\"\n gdAlignColumns=\"center\"\n gdAlignRows=\"start\"\n [length]=\"pagination.total\"\n [pageSize]=\"pageSize.value\"\n [pageSizeOptions]=\"[20, 50, 75, 100]\"\n [pageIndex]=\"pagination.currentPage - 1\"\n [showFirstLastButtons]=\"true\"\n (page)=\"pageChange($event)\"\n ></mat-paginator>\n </div>\n </div>\n\n <!-- editor -->\n <div gdArea=\"editor\" *ngIf=\"active$ | async as active\">\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</div>\n", styles: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:400}td{padding:0 8px}td.command{width:24px}table{width:100%;border-collapse:collapse}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"], dependencies: [{ kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i10.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: i11.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "directive", type: i8$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "component", type: UserFilterComponent, selector: "auth-jwt-user-filter", inputs: ["disabled"] }, { kind: "component", type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: ["user"], outputs: ["userChange", "editorClose"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }] });
950
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: UserListComponent, decorators: [{
920
+ UserListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListComponent, deps: [{ token: UserListRepository }, { token: DialogService }, { token: i2$2.GravatarService }], target: i0.ɵɵFactoryTarget.Component });
921
+ UserListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: UserListComponent, selector: "auth-jwt-user-list", ngImport: i0, template: "<div\n gdAreas=\"filters | progress | list | pager | editor\"\n gdRows=\"80px 64px 2fr 40px 1fr\"\n gdColumns=\"1fr\"\n gdGap=\"8px\"\n>\n <div>\n <!-- filters -->\n <div gdArea=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- progress -->\n <div *ngIf=\"loading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n\n <!-- list -->\n <div gdArea=\"list\" *ngIf=\"pagination$ | async as pagination\">\n <table>\n <thead>\n <td></td>\n <td></td>\n <td></td>\n <th>name</th>\n <th>first</th>\n <th>last</th>\n <th>email</th>\n <th>roles</th>\n <th>lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Edit {{ user.userName }}\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon>mode_edit</mat-icon>\n </button>\n </td>\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Delete {{ user.userName }}\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n [src]=\"getGravatarUrl(user.email, 32)\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td>{{ user.firstName }}</td>\n <td>{{ user.lastName }}</td>\n <td>\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td>{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n <!-- pagination -->\n <mat-paginator\n gdArea=\"pager\"\n gdAlignColumns=\"center\"\n gdAlignRows=\"start\"\n [length]=\"pagination.total\"\n [pageSize]=\"pagination.perPage\"\n [pageSizeOptions]=\"[20, 50, 75, 100]\"\n [pageIndex]=\"pagination.currentPage - 1\"\n [showFirstLastButtons]=\"true\"\n (page)=\"pageChange($event)\"\n ></mat-paginator>\n </div>\n </div>\n\n <!-- editor -->\n <div gdArea=\"editor\" *ngIf=\"active$ | async as active\">\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</div>\n", styles: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:400}td{padding:0 8px}td.command{width:24px}table{width:100%;border-collapse:collapse}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i7$1.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: i8$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "directive", type: i9$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "component", type: UserFilterComponent, selector: "auth-jwt-user-filter", inputs: ["disabled"] }, { kind: "component", type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: ["user"], outputs: ["userChange", "editorClose"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }] });
922
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListComponent, decorators: [{
951
923
  type: Component,
952
- args: [{ selector: 'auth-jwt-user-list', template: "<div\n gdAreas=\"filters | progress | list | pager | editor\"\n gdRows=\"80px 64px 2fr 40px 1fr\"\n gdColumns=\"1fr\"\n gdGap=\"8px\"\n>\n <div>\n <!-- filters -->\n <div gdArea=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- progress -->\n <div *ngIf=\"paginator.isLoading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n\n <!-- list -->\n <div gdArea=\"list\" *ngIf=\"pagination$ | async as pagination\">\n <table>\n <thead>\n <td></td>\n <td></td>\n <td></td>\n <th>name</th>\n <th>first</th>\n <th>last</th>\n <th>email</th>\n <th>roles</th>\n <th>lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Edit {{ user.userName }}\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon>mode_edit</mat-icon>\n </button>\n </td>\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Delete {{ user.userName }}\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n [src]=\"getGravatarUrl(user.email, 32)\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td>{{ user.firstName }}</td>\n <td>{{ user.lastName }}</td>\n <td>\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td>{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n <!-- pagination -->\n <mat-paginator\n gdArea=\"pager\"\n gdAlignColumns=\"center\"\n gdAlignRows=\"start\"\n [length]=\"pagination.total\"\n [pageSize]=\"pageSize.value\"\n [pageSizeOptions]=\"[20, 50, 75, 100]\"\n [pageIndex]=\"pagination.currentPage - 1\"\n [showFirstLastButtons]=\"true\"\n (page)=\"pageChange($event)\"\n ></mat-paginator>\n </div>\n </div>\n\n <!-- editor -->\n <div gdArea=\"editor\" *ngIf=\"active$ | async as active\">\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</div>\n", styles: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:400}td{padding:0 8px}td.command{width:24px}table{width:100%;border-collapse:collapse}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"] }]
953
- }], ctorParameters: function () {
954
- return [{ type: i15.PaginatorPlugin, decorators: [{
955
- type: Inject,
956
- args: [USERS_PAGINATOR]
957
- }] }, { type: UsersQuery }, { type: AuthJwtAccountService }, { type: UsersService }, { type: DialogService }, { type: i2$2.GravatarService }, { type: i1$1.UntypedFormBuilder }];
958
- } });
924
+ args: [{ selector: 'auth-jwt-user-list', template: "<div\n gdAreas=\"filters | progress | list | pager | editor\"\n gdRows=\"80px 64px 2fr 40px 1fr\"\n gdColumns=\"1fr\"\n gdGap=\"8px\"\n>\n <div>\n <!-- filters -->\n <div gdArea=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- progress -->\n <div *ngIf=\"loading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n\n <!-- list -->\n <div gdArea=\"list\" *ngIf=\"pagination$ | async as pagination\">\n <table>\n <thead>\n <td></td>\n <td></td>\n <td></td>\n <th>name</th>\n <th>first</th>\n <th>last</th>\n <th>email</th>\n <th>roles</th>\n <th>lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Edit {{ user.userName }}\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon>mode_edit</mat-icon>\n </button>\n </td>\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Delete {{ user.userName }}\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n [src]=\"getGravatarUrl(user.email, 32)\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td>{{ user.firstName }}</td>\n <td>{{ user.lastName }}</td>\n <td>\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td>{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n <!-- pagination -->\n <mat-paginator\n gdArea=\"pager\"\n gdAlignColumns=\"center\"\n gdAlignRows=\"start\"\n [length]=\"pagination.total\"\n [pageSize]=\"pagination.perPage\"\n [pageSizeOptions]=\"[20, 50, 75, 100]\"\n [pageIndex]=\"pagination.currentPage - 1\"\n [showFirstLastButtons]=\"true\"\n (page)=\"pageChange($event)\"\n ></mat-paginator>\n </div>\n </div>\n\n <!-- editor -->\n <div gdArea=\"editor\" *ngIf=\"active$ | async as active\">\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</div>\n", styles: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:400}td{padding:0 8px}td.command{width:24px}table{width:100%;border-collapse:collapse}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"] }]
925
+ }], ctorParameters: function () { return [{ type: UserListRepository }, { type: DialogService }, { type: i2$2.GravatarService }]; } });
959
926
 
960
927
  class AuthJwtAdminModule {
961
928
  }
962
- AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtAdminModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
963
- AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtAdminModule, declarations: [AuthJwtRegistrationComponent,
929
+ AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
930
+ AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, declarations: [AuthJwtRegistrationComponent,
964
931
  PasswordStrengthBarComponent,
965
932
  UserFilterComponent,
966
933
  UserListComponent,
@@ -987,7 +954,7 @@ AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", vers
987
954
  PasswordStrengthBarComponent,
988
955
  UserFilterComponent,
989
956
  UserListComponent] });
990
- AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtAdminModule, imports: [CommonModule,
957
+ AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, imports: [CommonModule,
991
958
  HttpClientModule,
992
959
  FormsModule,
993
960
  RouterModule,
@@ -1006,7 +973,7 @@ AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", vers
1006
973
  MatTooltipModule,
1007
974
  AuthJwtLoginModule,
1008
975
  NgToolsModule] });
1009
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.2", ngImport: i0, type: AuthJwtAdminModule, decorators: [{
976
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, decorators: [{
1010
977
  type: NgModule,
1011
978
  args: [{
1012
979
  declarations: [