@myrmidon/auth-jwt-admin 0.1.2 → 1.0.1
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 +11 -11
- 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 +144 -0
- package/esm2020/lib/components/user-editor/user-editor.component.mjs +7 -7
- package/esm2020/lib/components/user-filter/user-filter.component.mjs +16 -19
- package/esm2020/lib/components/user-list/user-list.component.mjs +37 -103
- 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 +190 -224
- package/fesm2015/myrmidon-auth-jwt-admin.mjs.map +1 -1
- package/fesm2020/myrmidon-auth-jwt-admin.mjs +189 -222
- 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,43 +1,44 @@
|
|
|
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 } 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
|
-
import { MatCardModule } from '@angular/material/card';
|
|
40
40
|
import { RouterModule } from '@angular/router';
|
|
41
|
+
import { MatCardModule } from '@angular/material/card';
|
|
41
42
|
|
|
42
43
|
class PasswordValidators {
|
|
43
44
|
/** "Standard" password validator for my API services. */
|
|
@@ -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,155 @@ 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
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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 user, 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
|
+
this._store.update(deleteAllPages());
|
|
551
|
+
// load page 1
|
|
552
|
+
this.loadPage(1, paginationData.perPage);
|
|
553
|
+
});
|
|
554
|
+
// the request status
|
|
555
|
+
this.status$ = this._store.pipe(selectRequestStatus('user-list'));
|
|
556
|
+
// load page 1 and subscribe to pagination
|
|
557
|
+
this.loadPage(1, PAGE_SIZE);
|
|
558
|
+
this.pagination$.subscribe(console.log);
|
|
559
|
+
}
|
|
560
|
+
createStore() {
|
|
561
|
+
const store = createStore({ name: 'user-list' }, withProps({
|
|
562
|
+
filter: {},
|
|
563
|
+
}), withEntities({ idKey: 'userName' }), withActiveId(), withRequestsCache(), withRequestsStatus(), withPagination());
|
|
564
|
+
return store;
|
|
565
|
+
}
|
|
566
|
+
adaptPage(page) {
|
|
567
|
+
// adapt the server page DataPage<T> to Elf pagination
|
|
568
|
+
return {
|
|
569
|
+
currentPage: page.pageNumber,
|
|
570
|
+
perPage: page.pageSize,
|
|
571
|
+
lastPage: page.pageCount,
|
|
572
|
+
total: page.total,
|
|
573
|
+
data: page.items,
|
|
574
|
+
};
|
|
555
575
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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;
|
|
576
|
+
addPage(response) {
|
|
577
|
+
const { data, ...paginationData } = response;
|
|
578
|
+
this._store.update(upsertEntities(data), updatePaginationData(paginationData), setPage(paginationData.currentPage, data.map((c) => c.userName)));
|
|
568
579
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
this._store.
|
|
575
|
-
|
|
580
|
+
loadPage(pageNumber, pageSize) {
|
|
581
|
+
if (!pageSize) {
|
|
582
|
+
pageSize = PAGE_SIZE;
|
|
583
|
+
}
|
|
584
|
+
// if the page exists and page size is the same, just move to it
|
|
585
|
+
if (this._store.query(hasPage(pageNumber)) &&
|
|
586
|
+
pageSize === this._lastPageSize) {
|
|
587
|
+
console.log('Page exists: ' + pageNumber);
|
|
588
|
+
this._store.update(setCurrentPage(pageNumber));
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
// reset cached pages if page size changed
|
|
592
|
+
if (this._lastPageSize !== pageSize) {
|
|
593
|
+
this._store.update(deleteAllPages());
|
|
594
|
+
this._lastPageSize = pageSize;
|
|
595
|
+
}
|
|
596
|
+
// load page from server
|
|
597
|
+
this._store.update(updateRequestStatus('user-list', 'pending'));
|
|
598
|
+
this._loading$.next(true);
|
|
599
|
+
this._accService
|
|
600
|
+
.getUsers(this._store.getValue().filter, pageNumber, pageSize)
|
|
601
|
+
.pipe(take$1(1))
|
|
602
|
+
.subscribe((page) => {
|
|
603
|
+
this._loading$.next(false);
|
|
604
|
+
this.addPage({ ...this.adaptPage(page), data: page.items });
|
|
605
|
+
this._store.update(updateRequestStatus('user-list', 'success'));
|
|
576
606
|
});
|
|
577
607
|
}
|
|
608
|
+
setFilter(filter) {
|
|
609
|
+
this._store.update((state) => ({ ...state, filter: filter }));
|
|
610
|
+
}
|
|
611
|
+
clearCache() {
|
|
612
|
+
this._store.update(deleteAllEntities(), deleteAllPages());
|
|
613
|
+
}
|
|
578
614
|
setActive(name) {
|
|
579
|
-
this._store.
|
|
615
|
+
this._store.update(setActiveId(name));
|
|
580
616
|
}
|
|
581
617
|
updateActive(user) {
|
|
582
618
|
const promise = new Promise((resolve, reject) => {
|
|
583
|
-
this.
|
|
584
|
-
this.
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
619
|
+
this._saving$.next(true);
|
|
620
|
+
this._accService.updateUser(user).subscribe({
|
|
621
|
+
next: (_) => {
|
|
622
|
+
this._saving$.next(false);
|
|
623
|
+
this._store.update(upsertEntities(user));
|
|
624
|
+
resolve(true);
|
|
625
|
+
},
|
|
626
|
+
error: (error) => {
|
|
627
|
+
this._saving$.next(false);
|
|
628
|
+
console.error(`Error updating user ${user.userName}: ` +
|
|
629
|
+
JSON.stringify(error || {}));
|
|
630
|
+
resolve(false);
|
|
631
|
+
},
|
|
596
632
|
});
|
|
597
633
|
});
|
|
598
634
|
return promise;
|
|
599
635
|
}
|
|
600
636
|
deleteUser(name) {
|
|
601
637
|
const promise = new Promise((resolve, reject) => {
|
|
602
|
-
this.
|
|
603
|
-
this.
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
638
|
+
this._saving$.next(true);
|
|
639
|
+
this._accService.deleteUser(name).subscribe({
|
|
640
|
+
next: (_) => {
|
|
641
|
+
this._saving$.next(false);
|
|
642
|
+
this.clearCache();
|
|
643
|
+
this.loadPage(1);
|
|
644
|
+
resolve(true);
|
|
645
|
+
},
|
|
646
|
+
error: (error) => {
|
|
647
|
+
this._saving$.next(false);
|
|
648
|
+
console.error(`Error deleting user ${name}: ` + JSON.stringify(error || {}));
|
|
649
|
+
reject(error);
|
|
650
|
+
},
|
|
613
651
|
});
|
|
614
652
|
});
|
|
615
653
|
return promise;
|
|
616
654
|
}
|
|
617
655
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
656
|
+
UserListRepository.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, deps: [{ token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
657
|
+
UserListRepository.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, providedIn: 'root' });
|
|
658
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListRepository, decorators: [{
|
|
621
659
|
type: Injectable,
|
|
622
660
|
args: [{ providedIn: 'root' }]
|
|
623
|
-
}], ctorParameters: function () { return [{ type:
|
|
661
|
+
}], ctorParameters: function () { return [{ type: AuthJwtAccountService }]; } });
|
|
624
662
|
|
|
625
663
|
class UserFilterComponent {
|
|
626
|
-
constructor(formBuilder,
|
|
627
|
-
this.
|
|
628
|
-
this.filter$ =
|
|
664
|
+
constructor(formBuilder, _repository) {
|
|
665
|
+
this._repository = _repository;
|
|
666
|
+
this.filter$ = _repository.filter$;
|
|
629
667
|
// form
|
|
630
668
|
this.name = formBuilder.control(null);
|
|
631
669
|
this.form = formBuilder.group({
|
|
@@ -638,7 +676,7 @@ class UserFilterComponent {
|
|
|
638
676
|
});
|
|
639
677
|
}
|
|
640
678
|
updateForm(filter) {
|
|
641
|
-
this.name.setValue(filter.name);
|
|
679
|
+
this.name.setValue(filter.name || null);
|
|
642
680
|
this.form.markAsPristine();
|
|
643
681
|
}
|
|
644
682
|
reset() {
|
|
@@ -647,8 +685,6 @@ class UserFilterComponent {
|
|
|
647
685
|
}
|
|
648
686
|
getFilter() {
|
|
649
687
|
return {
|
|
650
|
-
pageNumber: 1,
|
|
651
|
-
pageSize: 20,
|
|
652
688
|
name: this.name.value?.trim(),
|
|
653
689
|
};
|
|
654
690
|
}
|
|
@@ -658,27 +694,18 @@ class UserFilterComponent {
|
|
|
658
694
|
}
|
|
659
695
|
const filter = this.getFilter();
|
|
660
696
|
// update filter in state
|
|
661
|
-
this.
|
|
697
|
+
this._repository.setFilter(filter);
|
|
662
698
|
}
|
|
663
699
|
}
|
|
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: "
|
|
700
|
+
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 });
|
|
701
|
+
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 <div class=\"form-row\">\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 style=\"margin-top: -20px\"\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 </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "directive", type: 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"] }] });
|
|
702
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserFilterComponent, decorators: [{
|
|
667
703
|
type: Component,
|
|
668
|
-
args: [{ selector: 'auth-jwt-user-filter', template: "<form [formGroup]=\"form\" (submit)=\"apply()\" ng-disabled=\"disabled\">\n <mat-form-field>\n
|
|
669
|
-
}], ctorParameters: function () { return [{ type: i1$1.
|
|
704
|
+
args: [{ selector: 'auth-jwt-user-filter', template: "<form [formGroup]=\"form\" (submit)=\"apply()\" ng-disabled=\"disabled\">\n <div class=\"form-row\">\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 style=\"margin-top: -20px\"\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 </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
705
|
+
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: UserListRepository }]; }, propDecorators: { disabled: [{
|
|
670
706
|
type: Input
|
|
671
707
|
}] } });
|
|
672
708
|
|
|
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
709
|
// https://medium.com/@tarik.nzl/making-use-of-dialogs-in-material-2-mddialog-7533d27df41
|
|
683
710
|
class ConfirmDialogComponent {
|
|
684
711
|
constructor(dialogRef, data) {
|
|
@@ -691,9 +718,9 @@ class ConfirmDialogComponent {
|
|
|
691
718
|
}
|
|
692
719
|
ngOnInit() { }
|
|
693
720
|
}
|
|
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: "
|
|
721
|
+
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 });
|
|
722
|
+
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"] }] });
|
|
723
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
|
|
697
724
|
type: Component,
|
|
698
725
|
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
726
|
}], ctorParameters: function () { return [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
|
|
@@ -727,9 +754,9 @@ class DialogService {
|
|
|
727
754
|
return dialogRef.afterClosed();
|
|
728
755
|
}
|
|
729
756
|
}
|
|
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: "
|
|
757
|
+
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 });
|
|
758
|
+
DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: DialogService, providedIn: 'root' });
|
|
759
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: DialogService, decorators: [{
|
|
733
760
|
type: Injectable,
|
|
734
761
|
args: [{
|
|
735
762
|
providedIn: 'root'
|
|
@@ -823,11 +850,11 @@ class UserEditorComponent {
|
|
|
823
850
|
this.userChange.emit(this.getUserFromForm());
|
|
824
851
|
}
|
|
825
852
|
}
|
|
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: "
|
|
853
|
+
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 });
|
|
854
|
+
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 <div class=\"form-row\">\n <!-- email -->\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\n <!-- emailConfirmed -->\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formControl]=\"lockoutEnabled\">lockout enabled</mat-checkbox>\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 <div class=\"form-row\">\n <!-- firstName -->\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\n <!-- lastName -->\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 style=\"width: 16em\">\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 <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user\"\n >\n <mat-icon>check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "directive", type: 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"] }] });
|
|
855
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserEditorComponent, decorators: [{
|
|
829
856
|
type: Component,
|
|
830
|
-
args: [{ selector: 'auth-jwt-user-editor', template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <!-- email -->\n
|
|
857
|
+
args: [{ selector: 'auth-jwt-user-editor', template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <div class=\"form-row\">\n <!-- email -->\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\n <!-- emailConfirmed -->\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formControl]=\"lockoutEnabled\">lockout enabled</mat-checkbox>\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 <div class=\"form-row\">\n <!-- firstName -->\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\n <!-- lastName -->\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 style=\"width: 16em\">\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 <button\n type=\"submit\"\n mat-icon-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user\"\n >\n <mat-icon>check_circle</mat-icon>\n </button>\n </div>\n</form>\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
|
|
831
858
|
}], ctorParameters: function () { return [{ type: i1$1.UntypedFormBuilder }, { type: i2$2.AuthJwtService }]; }, propDecorators: { user: [{
|
|
832
859
|
type: Input
|
|
833
860
|
}], userChange: [{
|
|
@@ -837,77 +864,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.6", ngImpor
|
|
|
837
864
|
}] } });
|
|
838
865
|
|
|
839
866
|
class UserListComponent {
|
|
840
|
-
constructor(
|
|
841
|
-
this.
|
|
842
|
-
this._accountService = _accountService;
|
|
843
|
-
this._usersService = _usersService;
|
|
867
|
+
constructor(_repository, _dialogService, _gravatarService) {
|
|
868
|
+
this._repository = _repository;
|
|
844
869
|
this._dialogService = _dialogService;
|
|
845
870
|
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
|
-
}));
|
|
871
|
+
this.pagination$ = _repository.pagination$;
|
|
872
|
+
this.active$ = _repository.activeUser$;
|
|
873
|
+
this.loading$ = _repository.loading$;
|
|
900
874
|
}
|
|
901
875
|
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);
|
|
876
|
+
this._repository.loadPage(event.pageIndex + 1, event.pageSize);
|
|
911
877
|
}
|
|
912
878
|
deleteUser(user) {
|
|
913
879
|
this._dialogService
|
|
@@ -917,43 +883,44 @@ class UserListComponent {
|
|
|
917
883
|
if (!yes) {
|
|
918
884
|
return;
|
|
919
885
|
}
|
|
920
|
-
this.
|
|
921
|
-
this.
|
|
886
|
+
this._repository.deleteUser(user.userName).finally(() => {
|
|
887
|
+
this._repository.clearCache();
|
|
888
|
+
this._repository.loadPage(1);
|
|
922
889
|
});
|
|
923
890
|
});
|
|
924
891
|
}
|
|
925
892
|
setActiveUser(user) {
|
|
926
|
-
this.
|
|
893
|
+
this._repository.setActive(user?.userName || null);
|
|
927
894
|
}
|
|
928
895
|
resetActiveUser() {
|
|
929
|
-
this.
|
|
896
|
+
this._repository.setActive(null);
|
|
930
897
|
}
|
|
931
898
|
saveActiveUser(user) {
|
|
932
|
-
this.
|
|
933
|
-
|
|
934
|
-
});
|
|
899
|
+
this._repository.updateActive(user);
|
|
900
|
+
this._repository.setActive(null);
|
|
935
901
|
}
|
|
936
902
|
onUserEditorClose() {
|
|
937
|
-
this.
|
|
903
|
+
this._repository.setActive(null);
|
|
938
904
|
}
|
|
939
905
|
getGravatarUrl(email, size = 80) {
|
|
940
906
|
return this._gravatarService.buildGravatarUrl(email, size);
|
|
941
907
|
}
|
|
908
|
+
clearCache() {
|
|
909
|
+
this._repository.clearCache();
|
|
910
|
+
this._repository.loadPage(1);
|
|
911
|
+
}
|
|
942
912
|
}
|
|
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: "
|
|
913
|
+
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 });
|
|
914
|
+
UserListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: UserListComponent, selector: "auth-jwt-user-list", ngImport: i0, template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div style=\"grid-area: filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n <div style=\"grid-area: list\" *ngIf=\"pagination$ | async as pagination\">\n <div *ngIf=\"loading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n <table>\n <thead>\n <td></td>\n <td></td>\n <th>name</th>\n <th class=\"noif-lt-md\">first</th>\n <th class=\"noif-lt-md\">last</th>\n <th class=\"noif-lt-md\">email</th>\n <th>roles</th>\n <th class=\"noif-lt-md\">lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td>\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 <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 class=\"noif-lt-md\">{{ user.firstName }}</td>\n <td class=\"noif-lt-md\">{{ user.lastName }}</td>\n <td class=\"noif-lt-md\">\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td class=\"noif-lt-md\">{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n\n <!-- paginator -->\n <div style=\"grid-area: paginator; justify-content: end\" class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n matTooltip=\"Clear items cache\"\n (click)=\"clearCache()\"\n >\n <mat-icon>autorenew</mat-icon>\n </button>\n\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 </div>\n\n <!-- editor -->\n <div style=\"grid-area: 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}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}div#container{display:grid;grid-template-rows:auto 1fr auto auto;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));grid-template-areas:\"filters\" \"list\" \"paginator\" \"editor\";gap:8px}@media only screen and (max-width: 959px){.noif-lt-md{display:none}}\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" }] });
|
|
915
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: UserListComponent, decorators: [{
|
|
946
916
|
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 }]; } });
|
|
917
|
+
args: [{ selector: 'auth-jwt-user-list', template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div style=\"grid-area: filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n <div style=\"grid-area: list\" *ngIf=\"pagination$ | async as pagination\">\n <div *ngIf=\"loading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n <table>\n <thead>\n <td></td>\n <td></td>\n <th>name</th>\n <th class=\"noif-lt-md\">first</th>\n <th class=\"noif-lt-md\">last</th>\n <th class=\"noif-lt-md\">email</th>\n <th>roles</th>\n <th class=\"noif-lt-md\">lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td>\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 <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 class=\"noif-lt-md\">{{ user.firstName }}</td>\n <td class=\"noif-lt-md\">{{ user.lastName }}</td>\n <td class=\"noif-lt-md\">\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles.join(\" \") }}</td>\n <td class=\"noif-lt-md\">{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n\n <!-- paginator -->\n <div style=\"grid-area: paginator; justify-content: end\" class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n matTooltip=\"Clear items cache\"\n (click)=\"clearCache()\"\n >\n <mat-icon>autorenew</mat-icon>\n </button>\n\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 </div>\n\n <!-- editor -->\n <div style=\"grid-area: 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}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}div#container{display:grid;grid-template-rows:auto 1fr auto auto;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));grid-template-areas:\"filters\" \"list\" \"paginator\" \"editor\";gap:8px}@media only screen and (max-width: 959px){.noif-lt-md{display:none}}\n"] }]
|
|
918
|
+
}], ctorParameters: function () { return [{ type: UserListRepository }, { type: DialogService }, { type: i2$2.GravatarService }]; } });
|
|
952
919
|
|
|
953
920
|
class AuthJwtAdminModule {
|
|
954
921
|
}
|
|
955
|
-
AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
956
|
-
AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
922
|
+
AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
923
|
+
AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, declarations: [AuthJwtRegistrationComponent,
|
|
957
924
|
PasswordStrengthBarComponent,
|
|
958
925
|
UserFilterComponent,
|
|
959
926
|
UserListComponent,
|
|
@@ -980,7 +947,7 @@ AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", vers
|
|
|
980
947
|
PasswordStrengthBarComponent,
|
|
981
948
|
UserFilterComponent,
|
|
982
949
|
UserListComponent] });
|
|
983
|
-
AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
950
|
+
AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, imports: [CommonModule,
|
|
984
951
|
HttpClientModule,
|
|
985
952
|
FormsModule,
|
|
986
953
|
RouterModule,
|
|
@@ -999,7 +966,7 @@ AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", vers
|
|
|
999
966
|
MatTooltipModule,
|
|
1000
967
|
AuthJwtLoginModule,
|
|
1001
968
|
NgToolsModule] });
|
|
1002
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
969
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: AuthJwtAdminModule, decorators: [{
|
|
1003
970
|
type: NgModule,
|
|
1004
971
|
args: [{
|
|
1005
972
|
declarations: [
|