@myrmidon/auth-jwt-admin 0.1.2 → 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.
- package/esm2020/lib/auth-jwt-admin.module.mjs +5 -5
- package/esm2020/lib/components/auth-jwt-registration/auth-jwt-registration.component.mjs +6 -6
- package/esm2020/lib/components/confirm-dialog/confirm-dialog.component.mjs +3 -3
- package/esm2020/lib/components/password-strength-bar/password-strength-bar.component.mjs +3 -3
- package/esm2020/lib/components/state/user-list.repository.mjs +147 -0
- package/esm2020/lib/components/user-editor/user-editor.component.mjs +7 -7
- package/esm2020/lib/components/user-filter/user-filter.component.mjs +15 -18
- package/esm2020/lib/components/user-list/user-list.component.mjs +34 -102
- package/esm2020/lib/services/auth-jwt-account.service.mjs +7 -7
- package/esm2020/lib/services/dialog.service.mjs +3 -3
- package/fesm2015/myrmidon-auth-jwt-admin.mjs +188 -221
- package/fesm2015/myrmidon-auth-jwt-admin.mjs.map +1 -1
- package/fesm2020/myrmidon-auth-jwt-admin.mjs +187 -219
- package/fesm2020/myrmidon-auth-jwt-admin.mjs.map +1 -1
- package/lib/components/auth-jwt-registration/auth-jwt-registration.component.d.ts +1 -1
- package/lib/components/confirm-dialog/confirm-dialog.component.d.ts +1 -1
- package/lib/components/password-strength-bar/password-strength-bar.component.d.ts +1 -1
- package/lib/components/state/user-list.repository.d.ts +36 -0
- package/lib/components/user-editor/user-editor.component.d.ts +1 -1
- package/lib/components/user-filter/user-filter.component.d.ts +7 -8
- package/lib/components/user-list/user-list.component.d.ts +11 -20
- package/lib/services/auth-jwt-account.service.d.ts +1 -3
- package/package.json +6 -6
- package/esm2020/lib/components/state/users.paginator.mjs +0 -12
- package/esm2020/lib/components/state/users.query.mjs +0 -20
- package/esm2020/lib/components/state/users.service.mjs +0 -65
- package/esm2020/lib/components/state/users.store.mjs +0 -27
- package/lib/components/state/users.paginator.d.ts +0 -3
- package/lib/components/state/users.query.d.ts +0 -12
- package/lib/components/state/users.service.d.ts +0 -19
- package/lib/components/state/users.store.d.ts +0 -13
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, EventEmitter, Component, Input, Output,
|
|
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
|
|
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
|
|
12
|
+
import * as i4 from '@angular/common';
|
|
13
13
|
import { CommonModule } from '@angular/common';
|
|
14
|
-
import * as
|
|
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
|
|
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
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import
|
|
23
|
+
import { BehaviorSubject, combineLatest, map, debounceTime, take as take$1 } from 'rxjs';
|
|
24
|
+
import { select, createStore, withProps } from '@ngneat/elf';
|
|
25
|
+
import { selectActiveEntity, withEntities, withActiveId, upsertEntities, deleteAllEntities, setActiveId, updateEntities } from '@ngneat/elf-entities';
|
|
26
|
+
import { selectPaginationData, selectCurrentPageEntities, deleteAllPages, withPagination, updatePaginationData, setPage, hasPage, setCurrentPage } from '@ngneat/elf-pagination';
|
|
27
|
+
import { selectRequestStatus, withRequestsCache, withRequestsStatus, updateRequestStatus } from '@ngneat/elf-requests';
|
|
28
|
+
import * as i9$1 from '@angular/material/tooltip';
|
|
27
29
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
28
|
-
import { BehaviorSubject, combineLatest } from 'rxjs';
|
|
29
30
|
import * as i1$2 from '@angular/material/dialog';
|
|
30
31
|
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
31
32
|
import * as i2$2 from '@myrmidon/auth-jwt-login';
|
|
32
33
|
import { AuthJwtLoginModule } from '@myrmidon/auth-jwt-login';
|
|
33
|
-
import * as
|
|
34
|
+
import * as i7$1 from '@angular/material/paginator';
|
|
34
35
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
35
|
-
import * as
|
|
36
|
+
import * as i8$1 from '@angular/material/progress-bar';
|
|
36
37
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
37
|
-
import * as i5 from '@angular/material/checkbox';
|
|
38
|
+
import * as i5$1 from '@angular/material/checkbox';
|
|
38
39
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
39
40
|
import { MatCardModule } from '@angular/material/card';
|
|
40
41
|
import { RouterModule } from '@angular/router';
|
|
@@ -148,10 +149,10 @@ class AuthJwtAccountService {
|
|
|
148
149
|
})
|
|
149
150
|
.pipe(retry(3), catchError(this._error.handleError));
|
|
150
151
|
}
|
|
151
|
-
getUsers(filter) {
|
|
152
|
+
getUsers(filter, pageNumber = 1, pageSize = 20) {
|
|
152
153
|
let httpParams = new HttpParams();
|
|
153
|
-
httpParams = httpParams.set('pageNumber',
|
|
154
|
-
httpParams = httpParams.set('pageSize',
|
|
154
|
+
httpParams = httpParams.set('pageNumber', pageNumber.toString());
|
|
155
|
+
httpParams = httpParams.set('pageSize', pageSize.toString());
|
|
155
156
|
if (filter.name) {
|
|
156
157
|
httpParams = httpParams.set('name', filter.name);
|
|
157
158
|
}
|
|
@@ -248,9 +249,9 @@ class AuthJwtAccountService {
|
|
|
248
249
|
.pipe(catchError(this._error.handleError));
|
|
249
250
|
}
|
|
250
251
|
}
|
|
251
|
-
AuthJwtAccountService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
252
|
-
AuthJwtAccountService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
253
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
252
|
+
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 });
|
|
253
|
+
AuthJwtAccountService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' });
|
|
254
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAccountService, decorators: [{
|
|
254
255
|
type: Injectable,
|
|
255
256
|
args: [{
|
|
256
257
|
providedIn: 'root',
|
|
@@ -324,9 +325,9 @@ class PasswordStrengthBarComponent {
|
|
|
324
325
|
}
|
|
325
326
|
}
|
|
326
327
|
}
|
|
327
|
-
PasswordStrengthBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
328
|
-
PasswordStrengthBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
329
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
328
|
+
PasswordStrengthBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
329
|
+
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"] });
|
|
330
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
|
|
330
331
|
type: Component,
|
|
331
332
|
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
333
|
}], ctorParameters: function () { return []; }, propDecorators: { passwordToCheck: [{
|
|
@@ -514,118 +515,158 @@ class AuthJwtRegistrationComponent {
|
|
|
514
515
|
});
|
|
515
516
|
}
|
|
516
517
|
}
|
|
517
|
-
AuthJwtRegistrationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
518
|
-
AuthJwtRegistrationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
519
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
518
|
+
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 });
|
|
519
|
+
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"] }] });
|
|
520
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
|
|
520
521
|
type: Component,
|
|
521
522
|
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
523
|
}], ctorParameters: function () { return [{ type: i1$1.UntypedFormBuilder }, { type: i2$1.MatSnackBar }, { type: AuthJwtAccountService }]; }, propDecorators: { registered: [{
|
|
523
524
|
type: Output
|
|
524
525
|
}] } });
|
|
525
526
|
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
527
|
+
const PAGE_SIZE = 20;
|
|
528
|
+
class UserListRepository {
|
|
529
|
+
constructor(_accService) {
|
|
530
|
+
this._accService = _accService;
|
|
531
|
+
// create store
|
|
532
|
+
this._store = this.createStore();
|
|
533
|
+
this._lastPageSize = PAGE_SIZE;
|
|
534
|
+
this._loading$ = new BehaviorSubject(false);
|
|
535
|
+
this._saving$ = new BehaviorSubject(false);
|
|
536
|
+
this.loading$ = this._loading$.asObservable();
|
|
537
|
+
this.saving$ = this._saving$.asObservable();
|
|
538
|
+
// combine pagination parameters with page data for our consumers
|
|
539
|
+
this.pagination$ = combineLatest([
|
|
540
|
+
this._store.pipe(selectPaginationData()),
|
|
541
|
+
this._store.pipe(selectCurrentPageEntities()),
|
|
542
|
+
]).pipe(map(([pagination, data]) => ({ ...pagination, data })), debounceTime(0));
|
|
543
|
+
// the active document, if required
|
|
544
|
+
this.activeUser$ = this._store.pipe(selectActiveEntity());
|
|
545
|
+
// the filter, if required
|
|
546
|
+
this.filter$ = this._store.pipe(select((state) => state.filter));
|
|
547
|
+
this.filter$.subscribe((filter) => {
|
|
548
|
+
// when filter changed, reset any existing page and move to page 1
|
|
549
|
+
const paginationData = this._store.getValue().pagination;
|
|
550
|
+
console.log('Deleting all pages');
|
|
551
|
+
this._store.update(deleteAllPages());
|
|
552
|
+
// load page 1
|
|
553
|
+
this.loadPage(1, paginationData.perPage);
|
|
554
|
+
});
|
|
555
|
+
// the request status
|
|
556
|
+
this.status$ = this._store.pipe(selectRequestStatus('document'));
|
|
557
|
+
// load page 1 and subscribe to pagination
|
|
558
|
+
this.loadPage(1, PAGE_SIZE);
|
|
559
|
+
this.pagination$.subscribe(console.log);
|
|
560
|
+
}
|
|
561
|
+
createStore() {
|
|
562
|
+
const store = createStore({ name: 'user-list' }, withProps({
|
|
563
|
+
filter: {},
|
|
564
|
+
}), withEntities({ idKey: 'userName' }), withActiveId(), withRequestsCache(), withRequestsStatus(), withPagination());
|
|
565
|
+
return store;
|
|
566
|
+
}
|
|
567
|
+
adaptPage(page) {
|
|
568
|
+
// adapt the server page DataPage<T> to Elf pagination
|
|
569
|
+
return {
|
|
570
|
+
currentPage: page.pageNumber,
|
|
571
|
+
perPage: page.pageSize,
|
|
572
|
+
lastPage: page.pageCount,
|
|
573
|
+
total: page.total,
|
|
574
|
+
data: page.items,
|
|
575
|
+
};
|
|
552
576
|
}
|
|
553
|
-
|
|
554
|
-
|
|
577
|
+
addPage(response) {
|
|
578
|
+
const { data, ...paginationData } = response;
|
|
579
|
+
this._store.update(upsertEntities(data),
|
|
580
|
+
// addEntities(data),
|
|
581
|
+
updatePaginationData(paginationData), setPage(paginationData.currentPage, data.map((c) => c.userName)));
|
|
582
|
+
}
|
|
583
|
+
loadPage(pageNumber, pageSize) {
|
|
584
|
+
if (!pageSize) {
|
|
585
|
+
pageSize = PAGE_SIZE;
|
|
586
|
+
}
|
|
587
|
+
// if the page exists and page size is the same, just move to it
|
|
588
|
+
if (this._store.query(hasPage(pageNumber)) &&
|
|
589
|
+
pageSize === this._lastPageSize) {
|
|
590
|
+
console.log('Page exists: ' + pageNumber);
|
|
591
|
+
this._store.update(setCurrentPage(pageNumber));
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
// reset cached pages if page size changed
|
|
595
|
+
if (this._lastPageSize !== pageSize) {
|
|
596
|
+
this._store.update(deleteAllPages());
|
|
597
|
+
this._lastPageSize = pageSize;
|
|
598
|
+
}
|
|
599
|
+
// load page from server
|
|
600
|
+
this._store.update(updateRequestStatus('document', 'pending'));
|
|
601
|
+
this._loading$.next(true);
|
|
602
|
+
this._accService
|
|
603
|
+
.getUsers(this._store.getValue().filter, pageNumber, pageSize)
|
|
604
|
+
.pipe(take$1(1))
|
|
605
|
+
.subscribe((page) => {
|
|
606
|
+
this._loading$.next(false);
|
|
607
|
+
this.addPage({ ...this.adaptPage(page), data: page.items });
|
|
608
|
+
this._store.update(updateRequestStatus('document', 'success'));
|
|
609
|
+
});
|
|
555
610
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
UsersQuery.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.6", ngImport: i0, type: UsersQuery, providedIn: 'root' });
|
|
559
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.6", 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;
|
|
611
|
+
setFilter(filter) {
|
|
612
|
+
this._store.update((state) => ({ ...state, filter: filter }));
|
|
568
613
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
* @param filter The filter.
|
|
572
|
-
*/
|
|
573
|
-
updateFilter(filter) {
|
|
574
|
-
this._store.update({
|
|
575
|
-
filter: filter,
|
|
576
|
-
});
|
|
614
|
+
clearCache() {
|
|
615
|
+
this._store.update(deleteAllEntities(), deleteAllPages());
|
|
577
616
|
}
|
|
578
617
|
setActive(name) {
|
|
579
|
-
this._store.
|
|
618
|
+
this._store.update(setActiveId(name));
|
|
580
619
|
}
|
|
581
620
|
updateActive(user) {
|
|
582
621
|
const promise = new Promise((resolve, reject) => {
|
|
583
|
-
this.
|
|
584
|
-
this.
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
622
|
+
this._saving$.next(true);
|
|
623
|
+
this._accService.updateUser(user).subscribe({
|
|
624
|
+
next: (_) => {
|
|
625
|
+
this._saving$.next(false);
|
|
626
|
+
this._store.update(updateEntities(user.userName, user));
|
|
627
|
+
resolve(true);
|
|
628
|
+
},
|
|
629
|
+
error: (error) => {
|
|
630
|
+
this._saving$.next(false);
|
|
631
|
+
console.error(`Error updating user ${user.userName}: ` +
|
|
632
|
+
JSON.stringify(error || {}));
|
|
633
|
+
resolve(false);
|
|
634
|
+
},
|
|
596
635
|
});
|
|
597
636
|
});
|
|
598
637
|
return promise;
|
|
599
638
|
}
|
|
600
639
|
deleteUser(name) {
|
|
601
640
|
const promise = new Promise((resolve, reject) => {
|
|
602
|
-
this.
|
|
603
|
-
this.
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
641
|
+
this._saving$.next(true);
|
|
642
|
+
this._accService.deleteUser(name).subscribe({
|
|
643
|
+
next: (_) => {
|
|
644
|
+
this._saving$.next(false);
|
|
645
|
+
this.clearCache();
|
|
646
|
+
this.loadPage(1);
|
|
647
|
+
resolve(true);
|
|
648
|
+
},
|
|
649
|
+
error: (error) => {
|
|
650
|
+
this._saving$.next(false);
|
|
651
|
+
console.error(`Error deleting user ${name}: ` + JSON.stringify(error || {}));
|
|
652
|
+
reject(error);
|
|
653
|
+
},
|
|
613
654
|
});
|
|
614
655
|
});
|
|
615
656
|
return promise;
|
|
616
657
|
}
|
|
617
658
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
659
|
+
UserListRepository.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, deps: [{ token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
660
|
+
UserListRepository.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, providedIn: 'root' });
|
|
661
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, decorators: [{
|
|
621
662
|
type: Injectable,
|
|
622
663
|
args: [{ providedIn: 'root' }]
|
|
623
|
-
}], ctorParameters: function () { return [{ type:
|
|
664
|
+
}], ctorParameters: function () { return [{ type: AuthJwtAccountService }]; } });
|
|
624
665
|
|
|
625
666
|
class UserFilterComponent {
|
|
626
|
-
constructor(formBuilder,
|
|
627
|
-
this.
|
|
628
|
-
this.filter$ =
|
|
667
|
+
constructor(formBuilder, _repository) {
|
|
668
|
+
this._repository = _repository;
|
|
669
|
+
this.filter$ = _repository.filter$;
|
|
629
670
|
// form
|
|
630
671
|
this.name = formBuilder.control(null);
|
|
631
672
|
this.form = formBuilder.group({
|
|
@@ -638,7 +679,7 @@ class UserFilterComponent {
|
|
|
638
679
|
});
|
|
639
680
|
}
|
|
640
681
|
updateForm(filter) {
|
|
641
|
-
this.name.setValue(filter.name);
|
|
682
|
+
this.name.setValue(filter.name || null);
|
|
642
683
|
this.form.markAsPristine();
|
|
643
684
|
}
|
|
644
685
|
reset() {
|
|
@@ -647,8 +688,6 @@ class UserFilterComponent {
|
|
|
647
688
|
}
|
|
648
689
|
getFilter() {
|
|
649
690
|
return {
|
|
650
|
-
pageNumber: 1,
|
|
651
|
-
pageSize: 20,
|
|
652
691
|
name: this.name.value?.trim(),
|
|
653
692
|
};
|
|
654
693
|
}
|
|
@@ -658,27 +697,18 @@ class UserFilterComponent {
|
|
|
658
697
|
}
|
|
659
698
|
const filter = this.getFilter();
|
|
660
699
|
// update filter in state
|
|
661
|
-
this.
|
|
700
|
+
this._repository.setFilter(filter);
|
|
662
701
|
}
|
|
663
702
|
}
|
|
664
|
-
UserFilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
665
|
-
UserFilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
666
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
703
|
+
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 });
|
|
704
|
+
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"] }] });
|
|
705
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserFilterComponent, decorators: [{
|
|
667
706
|
type: Component,
|
|
668
707
|
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" }]
|
|
669
|
-
}], ctorParameters: function () { return [{ type: i1$1.
|
|
708
|
+
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: UserListRepository }]; }, propDecorators: { disabled: [{
|
|
670
709
|
type: Input
|
|
671
710
|
}] } });
|
|
672
711
|
|
|
673
|
-
// create a factory provider for the paginator
|
|
674
|
-
const USERS_PAGINATOR = new InjectionToken('USERS_PAGINATOR', {
|
|
675
|
-
providedIn: 'root',
|
|
676
|
-
factory: () => {
|
|
677
|
-
const query = inject(UsersQuery);
|
|
678
|
-
return new PaginatorPlugin(query).withControls().withRange();
|
|
679
|
-
},
|
|
680
|
-
});
|
|
681
|
-
|
|
682
712
|
// https://medium.com/@tarik.nzl/making-use-of-dialogs-in-material-2-mddialog-7533d27df41
|
|
683
713
|
class ConfirmDialogComponent {
|
|
684
714
|
constructor(dialogRef, data) {
|
|
@@ -691,9 +721,9 @@ class ConfirmDialogComponent {
|
|
|
691
721
|
}
|
|
692
722
|
ngOnInit() { }
|
|
693
723
|
}
|
|
694
|
-
ConfirmDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
695
|
-
ConfirmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
696
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
724
|
+
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 });
|
|
725
|
+
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"] }] });
|
|
726
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
|
|
697
727
|
type: Component,
|
|
698
728
|
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" }]
|
|
699
729
|
}], ctorParameters: function () { return [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
|
|
@@ -727,9 +757,9 @@ class DialogService {
|
|
|
727
757
|
return dialogRef.afterClosed();
|
|
728
758
|
}
|
|
729
759
|
}
|
|
730
|
-
DialogService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
731
|
-
DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
732
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
760
|
+
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 });
|
|
761
|
+
DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: DialogService, providedIn: 'root' });
|
|
762
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: DialogService, decorators: [{
|
|
733
763
|
type: Injectable,
|
|
734
764
|
args: [{
|
|
735
765
|
providedIn: 'root'
|
|
@@ -823,11 +853,11 @@ class UserEditorComponent {
|
|
|
823
853
|
this.userChange.emit(this.getUserFromForm());
|
|
824
854
|
}
|
|
825
855
|
}
|
|
826
|
-
UserEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
827
|
-
UserEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
828
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
856
|
+
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 });
|
|
857
|
+
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 \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 \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"] }] });
|
|
858
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserEditorComponent, decorators: [{
|
|
829
859
|
type: Component,
|
|
830
|
-
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\"
|
|
860
|
+
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 \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 \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" }]
|
|
831
861
|
}], ctorParameters: function () { return [{ type: i1$1.UntypedFormBuilder }, { type: i2$2.AuthJwtService }]; }, propDecorators: { user: [{
|
|
832
862
|
type: Input
|
|
833
863
|
}], userChange: [{
|
|
@@ -837,77 +867,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.6", ngImpor
|
|
|
837
867
|
}] } });
|
|
838
868
|
|
|
839
869
|
class UserListComponent {
|
|
840
|
-
constructor(
|
|
841
|
-
this.
|
|
842
|
-
this._accountService = _accountService;
|
|
843
|
-
this._usersService = _usersService;
|
|
870
|
+
constructor(_repository, _dialogService, _gravatarService) {
|
|
871
|
+
this._repository = _repository;
|
|
844
872
|
this._dialogService = _dialogService;
|
|
845
873
|
this._gravatarService = _gravatarService;
|
|
846
|
-
this.
|
|
847
|
-
this.
|
|
848
|
-
this.
|
|
849
|
-
// https://netbasal.com/manage-your-entities-with-akita-like-a-boss-768732f8d4d1
|
|
850
|
-
this.active$ = userQuery.selectActive();
|
|
851
|
-
this.pagination$ = combineLatest([
|
|
852
|
-
this.paginator.pageChanges,
|
|
853
|
-
this.pageSize.valueChanges.pipe(
|
|
854
|
-
// we are required to emit at least the initial value
|
|
855
|
-
// as combineLatest emits only if ALL observables have emitted
|
|
856
|
-
startWith(20),
|
|
857
|
-
// clear the cache when page size changes
|
|
858
|
-
tap((_) => {
|
|
859
|
-
this.paginator.clearCache();
|
|
860
|
-
})),
|
|
861
|
-
this._filter$.pipe(
|
|
862
|
-
// clear the cache when filters changed
|
|
863
|
-
tap((_) => {
|
|
864
|
-
this.paginator.clearCache();
|
|
865
|
-
})),
|
|
866
|
-
this._refresh$.pipe(
|
|
867
|
-
// clear the cache when forcing refresh
|
|
868
|
-
tap((_) => {
|
|
869
|
-
this.paginator.clearCache();
|
|
870
|
-
})),
|
|
871
|
-
]).pipe(
|
|
872
|
-
// for each emitted value, combine into a filter and use it
|
|
873
|
-
// to request the page from server
|
|
874
|
-
switchMap(([pageNumber, pageSize, filter, refresh]) => {
|
|
875
|
-
// const filter = { ...this._docsQuery.getValue().filter };
|
|
876
|
-
const f = { ...filter };
|
|
877
|
-
f.pageNumber = pageNumber;
|
|
878
|
-
f.pageSize = pageSize;
|
|
879
|
-
const request = this.getRequest(f);
|
|
880
|
-
// update saved filters
|
|
881
|
-
this.paginator.metadata.set('filter', f);
|
|
882
|
-
return this.paginator.getPage(request);
|
|
883
|
-
}));
|
|
884
|
-
}
|
|
885
|
-
ngOnDestroy() {
|
|
886
|
-
this.paginator.destroy();
|
|
887
|
-
}
|
|
888
|
-
getRequest(filter) {
|
|
889
|
-
return () => this._accountService.getUsers(filter).pipe(
|
|
890
|
-
// adapt server results to the paginator plugin
|
|
891
|
-
map((p) => {
|
|
892
|
-
return {
|
|
893
|
-
currentPage: p.pageNumber,
|
|
894
|
-
perPage: p.pageSize,
|
|
895
|
-
lastPage: p.pageCount,
|
|
896
|
-
data: p.items,
|
|
897
|
-
total: p.total,
|
|
898
|
-
};
|
|
899
|
-
}));
|
|
874
|
+
this.pagination$ = _repository.pagination$;
|
|
875
|
+
this.active$ = _repository.activeUser$;
|
|
876
|
+
this.loading$ = _repository.loading$;
|
|
900
877
|
}
|
|
901
878
|
pageChange(event) {
|
|
902
|
-
|
|
903
|
-
this.paginator.setPage(event.pageIndex + 1);
|
|
904
|
-
if (event.pageSize !== this.pageSize.value) {
|
|
905
|
-
this.pageSize.setValue(event.pageSize);
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
refresh() {
|
|
909
|
-
this.paginator.clearCache();
|
|
910
|
-
this._refresh$.next(this._refresh$.value + 1);
|
|
879
|
+
this._repository.loadPage(event.pageIndex + 1, event.pageSize);
|
|
911
880
|
}
|
|
912
881
|
deleteUser(user) {
|
|
913
882
|
this._dialogService
|
|
@@ -917,21 +886,20 @@ class UserListComponent {
|
|
|
917
886
|
if (!yes) {
|
|
918
887
|
return;
|
|
919
888
|
}
|
|
920
|
-
this.
|
|
921
|
-
this.
|
|
889
|
+
this._repository.deleteUser(user.userName).finally(() => {
|
|
890
|
+
this._repository.clearCache();
|
|
891
|
+
this._repository.loadPage(1);
|
|
922
892
|
});
|
|
923
893
|
});
|
|
924
894
|
}
|
|
925
895
|
setActiveUser(user) {
|
|
926
|
-
this.
|
|
896
|
+
this._repository.setActive(user?.userName || null);
|
|
927
897
|
}
|
|
928
898
|
resetActiveUser() {
|
|
929
|
-
this.
|
|
899
|
+
this._repository.setActive(null);
|
|
930
900
|
}
|
|
931
901
|
saveActiveUser(user) {
|
|
932
|
-
this.
|
|
933
|
-
this.refresh();
|
|
934
|
-
});
|
|
902
|
+
this._repository.updateActive(user);
|
|
935
903
|
}
|
|
936
904
|
onUserEditorClose() {
|
|
937
905
|
this.setActiveUser(null);
|
|
@@ -939,21 +907,21 @@ class UserListComponent {
|
|
|
939
907
|
getGravatarUrl(email, size = 80) {
|
|
940
908
|
return this._gravatarService.buildGravatarUrl(email, size);
|
|
941
909
|
}
|
|
910
|
+
clearCache() {
|
|
911
|
+
this._repository.clearCache();
|
|
912
|
+
}
|
|
942
913
|
}
|
|
943
|
-
UserListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
944
|
-
UserListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
945
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
914
|
+
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 });
|
|
915
|
+
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" }] });
|
|
916
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListComponent, decorators: [{
|
|
946
917
|
type: Component,
|
|
947
|
-
args: [{ selector: 'auth-jwt-user-list', template: "<div\
|
|
948
|
-
}], ctorParameters: function () { return [{ type:
|
|
949
|
-
type: Inject,
|
|
950
|
-
args: [USERS_PAGINATOR]
|
|
951
|
-
}] }, { type: UsersQuery }, { type: AuthJwtAccountService }, { type: UsersService }, { type: DialogService }, { type: i2$2.GravatarService }, { type: i1$1.UntypedFormBuilder }]; } });
|
|
918
|
+
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"] }]
|
|
919
|
+
}], ctorParameters: function () { return [{ type: UserListRepository }, { type: DialogService }, { type: i2$2.GravatarService }]; } });
|
|
952
920
|
|
|
953
921
|
class AuthJwtAdminModule {
|
|
954
922
|
}
|
|
955
|
-
AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
956
|
-
AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
923
|
+
AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
924
|
+
AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, declarations: [AuthJwtRegistrationComponent,
|
|
957
925
|
PasswordStrengthBarComponent,
|
|
958
926
|
UserFilterComponent,
|
|
959
927
|
UserListComponent,
|
|
@@ -980,7 +948,7 @@ AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", vers
|
|
|
980
948
|
PasswordStrengthBarComponent,
|
|
981
949
|
UserFilterComponent,
|
|
982
950
|
UserListComponent] });
|
|
983
|
-
AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
951
|
+
AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, imports: [CommonModule,
|
|
984
952
|
HttpClientModule,
|
|
985
953
|
FormsModule,
|
|
986
954
|
RouterModule,
|
|
@@ -999,7 +967,7 @@ AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", vers
|
|
|
999
967
|
MatTooltipModule,
|
|
1000
968
|
AuthJwtLoginModule,
|
|
1001
969
|
NgToolsModule] });
|
|
1002
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
970
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, decorators: [{
|
|
1003
971
|
type: NgModule,
|
|
1004
972
|
args: [{
|
|
1005
973
|
declarations: [
|