@myrmidon/auth-jwt-admin 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/{esm2015/lib/auth-jwt-admin.module.js → esm2020/lib/auth-jwt-admin.module.mjs} +4 -4
  2. package/esm2020/lib/components/auth-jwt-registration/auth-jwt-registration.component.mjs +203 -0
  3. package/{esm2015/lib/components/confirm-dialog/confirm-dialog.component.js → esm2020/lib/components/confirm-dialog/confirm-dialog.component.mjs} +5 -10
  4. package/{esm2015/lib/components/password-strength-bar/password-strength-bar.component.js → esm2020/lib/components/password-strength-bar/password-strength-bar.component.mjs} +5 -9
  5. package/{esm2015/lib/components/state/users.paginator.js → esm2020/lib/components/state/users.paginator.mjs} +0 -0
  6. package/{esm2015/lib/components/state/users.query.js → esm2020/lib/components/state/users.query.mjs} +3 -3
  7. package/esm2020/lib/components/state/users.service.mjs +65 -0
  8. package/{esm2015/lib/components/state/users.store.js → esm2020/lib/components/state/users.store.mjs} +3 -3
  9. package/esm2020/lib/components/user-editor/user-editor.component.mjs +112 -0
  10. package/esm2020/lib/components/user-filter/user-filter.component.mjs +58 -0
  11. package/esm2020/lib/components/user-list/user-list.component.mjs +134 -0
  12. package/{esm2015/lib/services/auth-jwt-account.service.js → esm2020/lib/services/auth-jwt-account.service.mjs} +3 -3
  13. package/{esm2015/lib/services/dialog.service.js → esm2020/lib/services/dialog.service.mjs} +3 -3
  14. package/{esm2015/lib/validators/password.validators.js → esm2020/lib/validators/password.validators.mjs} +0 -0
  15. package/{esm2015/myrmidon-auth-jwt-admin.js → esm2020/myrmidon-auth-jwt-admin.mjs} +0 -0
  16. package/{esm2015/public-api.js → esm2020/public-api.mjs} +0 -0
  17. package/fesm2015/myrmidon-auth-jwt-admin.mjs +1061 -0
  18. package/fesm2015/myrmidon-auth-jwt-admin.mjs.map +1 -0
  19. package/{fesm2015/myrmidon-auth-jwt-admin.js → fesm2020/myrmidon-auth-jwt-admin.mjs} +50 -78
  20. package/fesm2020/myrmidon-auth-jwt-admin.mjs.map +1 -0
  21. package/package.json +22 -9
  22. package/bundles/myrmidon-auth-jwt-admin.umd.js +0 -1466
  23. package/bundles/myrmidon-auth-jwt-admin.umd.js.map +0 -1
  24. package/esm2015/lib/components/auth-jwt-registration/auth-jwt-registration.component.js +0 -207
  25. package/esm2015/lib/components/state/users.service.js +0 -65
  26. package/esm2015/lib/components/user-editor/user-editor.component.js +0 -118
  27. package/esm2015/lib/components/user-filter/user-filter.component.js +0 -63
  28. package/esm2015/lib/components/user-list/user-list.component.js +0 -138
  29. package/fesm2015/myrmidon-auth-jwt-admin.js.map +0 -1
@@ -0,0 +1,1061 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, EventEmitter, Component, Input, Output, InjectionToken, inject, Optional, Inject, NgModule } from '@angular/core';
3
+ import * as i1$1 from '@angular/forms';
4
+ import { Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
5
+ import { retry, catchError, take, startWith, tap, switchMap, map } from 'rxjs/operators';
6
+ import * as i2$1 from '@angular/material/snack-bar';
7
+ import { MatSnackBarModule } from '@angular/material/snack-bar';
8
+ import * as i1 from '@angular/common/http';
9
+ import { HttpParams, HttpClientModule } from '@angular/common/http';
10
+ import * as i2 from '@myrmidon/ng-tools';
11
+ import { NgToolsModule } from '@myrmidon/ng-tools';
12
+ import * as i4 from '@angular/material/form-field';
13
+ import * as i6 from '@angular/material/icon';
14
+ import { MatIconModule } from '@angular/material/icon';
15
+ import * as i5 from '@angular/material/button';
16
+ import { MatButtonModule } from '@angular/material/button';
17
+ import * as i8 from '@angular/material/progress-spinner';
18
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
19
+ import * as i7 from '@angular/material/input';
20
+ import { MatInputModule } from '@angular/material/input';
21
+ import * as i13 from '@angular/common';
22
+ import { CommonModule } from '@angular/common';
23
+ import * as i15 from '@datorama/akita';
24
+ import { EntityStore, StoreConfig, QueryEntity, PaginatorPlugin } from '@datorama/akita';
25
+ import { __decorate } from 'tslib';
26
+ import * as i8$1 from '@angular/material/tooltip';
27
+ import { MatTooltipModule } from '@angular/material/tooltip';
28
+ import { BehaviorSubject, combineLatest } from 'rxjs';
29
+ import * as i1$2 from '@angular/material/dialog';
30
+ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
31
+ import * as i2$2 from '@myrmidon/auth-jwt-login';
32
+ import { AuthJwtLoginModule } from '@myrmidon/auth-jwt-login';
33
+ import * as i8$2 from '@angular/material/progress-bar';
34
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
35
+ import * as i11 from '@angular/material/paginator';
36
+ import { MatPaginatorModule } from '@angular/material/paginator';
37
+ import * as i4$1 from '@angular/material/checkbox';
38
+ import { MatCheckboxModule } from '@angular/material/checkbox';
39
+ import { MatCardModule } from '@angular/material/card';
40
+ import { RouterModule } from '@angular/router';
41
+
42
+ class PasswordValidators {
43
+ /** "Standard" password validator for my API services. */
44
+ static standard() {
45
+ return (control) => {
46
+ if (!control.value) {
47
+ return null;
48
+ }
49
+ if (control.value.length < 8) {
50
+ return {
51
+ passwordTooShort: true,
52
+ };
53
+ }
54
+ if (!/.*[A-Z].*/.test(control.value)) {
55
+ return {
56
+ noUpperInPassword: true,
57
+ };
58
+ }
59
+ if (!/.*[a-z].*/.test(control.value)) {
60
+ return {
61
+ noLowerInPassword: true,
62
+ };
63
+ }
64
+ if (!/.*[A-Z].*/.test(control.value)) {
65
+ return {
66
+ noUpperInPassword: true,
67
+ };
68
+ }
69
+ if (!/.*[-`~!@#$%^&*()_+=\[\]{};:'",.<>/?|\\].*/.test(control.value)) {
70
+ return {
71
+ noSymbolInPassword: true,
72
+ };
73
+ }
74
+ return null;
75
+ };
76
+ }
77
+ }
78
+
79
+ class AuthJwtAccountService {
80
+ constructor(_http, _error, _env) {
81
+ this._http = _http;
82
+ this._error = _error;
83
+ this._env = _env;
84
+ }
85
+ /**
86
+ * Checks if the specified email address is registered on the server.
87
+ * @param email email address to test.
88
+ * @returns result.
89
+ */
90
+ isEmailRegistered(email) {
91
+ return this._http.get(this._env.get('apiUrl') +
92
+ 'accounts/emailexists/' +
93
+ encodeURIComponent(email));
94
+ }
95
+ /**
96
+ * Checks if the specified user's given name is registered on the server.
97
+ * This name is a nickname chosen by users during registration, and is the key
98
+ * used for referencing users when talking to the server.
99
+ * @param name name to test.
100
+ * @returns result.
101
+ */
102
+ isNameRegistered(name) {
103
+ return this._http.get(this._env.get('apiUrl') +
104
+ 'accounts/nameexists/' +
105
+ encodeURIComponent(name));
106
+ }
107
+ /**
108
+ * Register the user with the specified registration data.
109
+ * @param registration The registration data.
110
+ */
111
+ register(registration) {
112
+ // const options = {
113
+ // headers: this.createAuthHeaders({
114
+ // 'Content-Type': 'application/json',
115
+ // }),
116
+ // };
117
+ return this._http.post(this._env.get('apiUrl') + 'accounts/register', registration
118
+ // options
119
+ );
120
+ }
121
+ /**
122
+ * Resend the confirmation email to the specified address.
123
+ * @param email address.
124
+ */
125
+ resendConfirmEmail(email) {
126
+ // const options = {
127
+ // headers: this.createAuthHeaders({
128
+ // 'Content-Type': 'application/json',
129
+ // }),
130
+ // };
131
+ return this._http.get(this._env.get('apiUrl') +
132
+ 'accounts/resendconfirm/' +
133
+ encodeURIComponent(email)
134
+ // options
135
+ );
136
+ }
137
+ /**
138
+ * Request a password reset for the specified email address.
139
+ * @param email Email address.
140
+ */
141
+ requestPasswordReset(email) {
142
+ return this._http.post(this._env.get('apiUrl') + 'accounts/resetpassword/request', { email });
143
+ }
144
+ getAllUsers() {
145
+ return this._http
146
+ .get(this._env.get('apiUrl') + 'users', {
147
+ params: new HttpParams().set('pageNumber', '1'),
148
+ })
149
+ .pipe(retry(3), catchError(this._error.handleError));
150
+ }
151
+ getUsers(filter) {
152
+ let httpParams = new HttpParams();
153
+ httpParams = httpParams.set('pageNumber', filter.pageNumber.toString());
154
+ httpParams = httpParams.set('pageSize', filter.pageSize.toString());
155
+ if (filter.name) {
156
+ httpParams = httpParams.set('name', filter.name);
157
+ }
158
+ return this._http
159
+ .get(this._env.get('apiUrl') + 'users', {
160
+ params: httpParams,
161
+ })
162
+ .pipe(retry(3), catchError(this._error.handleError));
163
+ }
164
+ /**
165
+ * Get the top N users matching the specified name filter.
166
+ * @param nameFilter The user name filter.
167
+ * @param limit The maximum number of users to get.
168
+ */
169
+ getTopUsers(nameFilter, limit = 10) {
170
+ let httpParams = new HttpParams();
171
+ httpParams = httpParams.set('pageNumber', '1');
172
+ httpParams = httpParams.set('pageSize', limit.toString());
173
+ if (nameFilter) {
174
+ httpParams = httpParams.set('name', nameFilter);
175
+ }
176
+ const options = httpParams.keys().length > 0
177
+ ? {
178
+ params: httpParams,
179
+ }
180
+ : {};
181
+ return this._http
182
+ .get(this._env.get('apiUrl') + 'users', options)
183
+ .pipe(retry(3), catchError(this._error.handleError));
184
+ }
185
+ /**
186
+ * Get information about all the users listed in the specified names.
187
+ * @param names User(s) names.
188
+ */
189
+ getUsersFromNames(names) {
190
+ let httpParams = new HttpParams();
191
+ if (names && names.length > 0) {
192
+ httpParams = httpParams.set('names', names.join(','));
193
+ }
194
+ const options = httpParams.keys().length > 0
195
+ ? {
196
+ params: httpParams,
197
+ }
198
+ : {};
199
+ return this._http
200
+ .get(this._env.get('apiUrl') + 'users-from-names', options)
201
+ .pipe(retry(3), catchError(this._error.handleError));
202
+ }
203
+ /**
204
+ * Get data about the specified user.
205
+ * @param name The user name.
206
+ */
207
+ getUser(name) {
208
+ return this._http
209
+ .get(this._env.get('apiUrl') + 'users/' + name)
210
+ .pipe(retry(3), catchError(this._error.handleError));
211
+ }
212
+ /**
213
+ * Update the editable data for the specified user.
214
+ * @param user The user to update.
215
+ */
216
+ updateUser(user) {
217
+ return this._http
218
+ .put(this._env.get('apiUrl') + 'users', user)
219
+ .pipe(catchError(this._error.handleError));
220
+ }
221
+ /**
222
+ * Request a password reset email for the specified email address.
223
+ * @param email The email address to receive the reset message.
224
+ */
225
+ resetPassword(email) {
226
+ return this._http
227
+ .post(this._env.get('apiUrl') + 'accounts/resetpassword/request', {
228
+ email: email,
229
+ })
230
+ .pipe(catchError(this._error.handleError));
231
+ }
232
+ /**
233
+ * Change the password.
234
+ * @param change The password change data.
235
+ */
236
+ changePassword(change) {
237
+ return this._http
238
+ .post(this._env.get('apiUrl') + 'accounts/changepassword', change)
239
+ .pipe(catchError(this._error.handleError));
240
+ }
241
+ /**
242
+ * Delete the user with the specified username.
243
+ * @param name The user name.
244
+ */
245
+ deleteUser(name) {
246
+ return this._http
247
+ .delete(this._env.get('apiUrl') + 'accounts/' + name)
248
+ .pipe(catchError(this._error.handleError));
249
+ }
250
+ }
251
+ AuthJwtAccountService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtAccountService, deps: [{ token: i1.HttpClient }, { token: i2.ErrorService }, { token: i2.EnvService }], target: i0.ɵɵFactoryTarget.Injectable });
252
+ AuthJwtAccountService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' });
253
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtAccountService, decorators: [{
254
+ type: Injectable,
255
+ args: [{
256
+ providedIn: 'root',
257
+ }]
258
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i2.ErrorService }, { type: i2.EnvService }]; } });
259
+
260
+ class PasswordStrengthBarComponent {
261
+ constructor() {
262
+ this._colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
263
+ this.strengthChange = new EventEmitter();
264
+ this.strengthChange = new EventEmitter();
265
+ this.bars = [];
266
+ }
267
+ measureStrength(p) {
268
+ let force = 0;
269
+ const regex = /[$-/:-?{-~!"^_`\[\]]/g; // "
270
+ const lowerLetters = /[a-z]+/.test(p);
271
+ const upperLetters = /[A-Z]+/.test(p);
272
+ const numbers = /[0-9]+/.test(p);
273
+ const symbols = regex.test(p);
274
+ const flags = [lowerLetters, upperLetters, numbers, symbols];
275
+ let passedMatches = 0;
276
+ for (const flag of flags) {
277
+ passedMatches += flag === true ? 1 : 0;
278
+ }
279
+ force += 2 * p.length + (p.length >= 10 ? 1 : 0);
280
+ force += passedMatches * 10;
281
+ // penalty (short password)
282
+ force = p.length <= 6 ? Math.min(force, 10) : force;
283
+ // penalty (poor letiety of characters)
284
+ force = passedMatches === 1 ? Math.min(force, 10) : force;
285
+ force = passedMatches === 2 ? Math.min(force, 20) : force;
286
+ force = passedMatches === 3 ? Math.min(force, 40) : force;
287
+ return force;
288
+ }
289
+ getColor(s) {
290
+ let idx = 0;
291
+ if (s <= 10) {
292
+ idx = 0;
293
+ }
294
+ else if (s <= 20) {
295
+ idx = 1;
296
+ }
297
+ else if (s <= 30) {
298
+ idx = 2;
299
+ }
300
+ else if (s <= 40) {
301
+ idx = 3;
302
+ }
303
+ else {
304
+ idx = 4;
305
+ }
306
+ return {
307
+ idx: idx + 1,
308
+ col: this._colors[idx],
309
+ };
310
+ }
311
+ ngOnChanges(changes) {
312
+ const password = changes['passwordToCheck'].currentValue;
313
+ this.setBarColors(5, '#DDD');
314
+ if (password) {
315
+ const strength = this.measureStrength(password);
316
+ const c = this.getColor(strength);
317
+ this.setBarColors(c.idx, c.col);
318
+ this.strengthChange.emit(strength);
319
+ }
320
+ }
321
+ setBarColors(count, col) {
322
+ for (let n = 0; n < count; n++) {
323
+ this.bars[n] = col;
324
+ }
325
+ }
326
+ }
327
+ PasswordStrengthBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
328
+ PasswordStrengthBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.5", type: PasswordStrengthBarComponent, selector: "auth-jwt-password-strength-bar", inputs: { passwordToCheck: "passwordToCheck" }, outputs: { strengthChange: "strengthChange" }, usesOnChanges: true, ngImport: i0, template: "<div id=\"strength\">\n <small>strength:</small>\n <ul id=\"strengthBar\">\n <li class=\"point\" [style.background-color]=\"bars[0]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[1]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[2]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[3]\"></li>\n <li class=\"point\" [style.background-color]=\"bars[4]\"></li>\n </ul>\n</div>\n", styles: ["ul#strengthBar{display:inline;list-style:none;margin:0 0 0 15px;padding:0;vertical-align:2px}li.point:last{margin:0!important}li.point{background:#ddd;border-radius:2px;display:inline-block;height:5px;margin-right:1px;width:20px}\n"] });
329
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
330
+ type: Component,
331
+ 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
+ }], ctorParameters: function () { return []; }, propDecorators: { passwordToCheck: [{
333
+ type: Input
334
+ }], strengthChange: [{
335
+ type: Output
336
+ }] } });
337
+
338
+ class AuthJwtRegistrationComponent {
339
+ constructor(formBuilder, _snackbar, _accountService) {
340
+ this._snackbar = _snackbar;
341
+ this._accountService = _accountService;
342
+ this.registered = new EventEmitter();
343
+ // form
344
+ this.email = formBuilder.control('', [Validators.required, Validators.email], this.getUniqueEmailValidator(this._accountService).bind(this));
345
+ this.name = formBuilder.control('', Validators.required, this.getUniqueNameValidator(this._accountService).bind(this));
346
+ this.firstName = formBuilder.control('', [
347
+ Validators.required,
348
+ Validators.maxLength(50),
349
+ ]);
350
+ this.lastName = formBuilder.control('', [
351
+ Validators.required,
352
+ Validators.maxLength(50),
353
+ ]);
354
+ // http://stackoverflow.com/questions/35474991/angular-2-form-validating-for-repeat-password
355
+ this.password = formBuilder.control('', Validators.compose([Validators.required, PasswordValidators.standard]));
356
+ this.confirmPassword = formBuilder.control('', Validators.required);
357
+ this.passwords = formBuilder.group({
358
+ password: this.password,
359
+ confirmPassword: this.confirmPassword,
360
+ }, { validator: this.areEqual.bind(this) });
361
+ this.registration = formBuilder.group({
362
+ email: this.email,
363
+ name: this.name,
364
+ firstName: this.firstName,
365
+ lastName: this.lastName,
366
+ passwords: this.passwords,
367
+ });
368
+ }
369
+ areEqual(group) {
370
+ if (this.password.value === this.confirmPassword.value) {
371
+ return null;
372
+ }
373
+ return {
374
+ areEqual: true,
375
+ };
376
+ }
377
+ /**
378
+ * Creates a unique name validator. There is no dependency injection at this level,
379
+ * but we can use closures. As a matter of fact, we have access to the service instance
380
+ * from the component where we register validators. So we will implement a function
381
+ * that will accept the service as parameter, and create the actual validation function.
382
+ * This function will have access to the service when called during the validation process.
383
+ * See http://restlet.com/blog/2016/02/17/implementing-angular2-forms-beyond-basics-part-2/.
384
+ */
385
+ getUniqueNameValidator(service) {
386
+ return (control) => {
387
+ return new Promise((resolve, reject) => {
388
+ // avoid checking if empty
389
+ if (!control.value) {
390
+ resolve(null);
391
+ }
392
+ else {
393
+ service.isNameRegistered(control.value).subscribe((data) => {
394
+ if (!data.isExisting) {
395
+ resolve(null);
396
+ }
397
+ else {
398
+ resolve({ uniqueName: true });
399
+ }
400
+ }, (err) => {
401
+ resolve({ uniqueName: true });
402
+ });
403
+ }
404
+ });
405
+ };
406
+ }
407
+ getUniqueEmailValidator(service) {
408
+ return (control) => {
409
+ return new Promise((resolve, reject) => {
410
+ // avoid checking if empty
411
+ if (!control.value) {
412
+ resolve(null);
413
+ }
414
+ else {
415
+ service.isEmailRegistered(control.value).subscribe((data) => {
416
+ if (!data.isExisting) {
417
+ resolve(null);
418
+ }
419
+ else {
420
+ resolve({ uniqueEmail: true });
421
+ }
422
+ }, (err) => {
423
+ resolve({ uniqueEmail: true });
424
+ });
425
+ }
426
+ });
427
+ };
428
+ }
429
+ ngOnInit() { }
430
+ getEmailErrorLabel() {
431
+ if (!this.email.dirty) {
432
+ return null;
433
+ }
434
+ if (this.email.hasError('required')) {
435
+ return 'email address required';
436
+ }
437
+ if (this.email.hasError('email')) {
438
+ return 'invalid email address';
439
+ }
440
+ if (this.email.hasError('uniqueEmail') && !this.email.pending) {
441
+ return 'email address already registered';
442
+ }
443
+ return null;
444
+ }
445
+ getNameErrorLabel() {
446
+ if (!this.name.dirty) {
447
+ return null;
448
+ }
449
+ if (this.name.hasError('required')) {
450
+ return 'username required';
451
+ }
452
+ if (this.name.hasError('pattern')) {
453
+ return 'invalid username';
454
+ }
455
+ if (this.name.hasError('uniqueName') && !this.name.pending) {
456
+ return 'username already taken';
457
+ }
458
+ return null;
459
+ }
460
+ getPasswordErrorLabel() {
461
+ if (!this.password.dirty) {
462
+ return null;
463
+ }
464
+ if (this.password.hasError('required')) {
465
+ return 'password required';
466
+ }
467
+ if (this.password.hasError('passwordTooShort')) {
468
+ let s = 'at least 8 characters';
469
+ if (this.password.value) {
470
+ s += ` (now ${this.password.value.length})`;
471
+ }
472
+ return s;
473
+ }
474
+ if (this.password.hasError('noUpperInPassword')) {
475
+ return 'at least 1 uppercase letter';
476
+ }
477
+ if (this.password.hasError('noLowerInPassword')) {
478
+ return 'at least 1 lowercase letter';
479
+ }
480
+ if (this.password.hasError('noSymbolInPassword')) {
481
+ return 'at least 1 punctuation or symbol';
482
+ }
483
+ return null;
484
+ }
485
+ onSubmit() {
486
+ if (!this.registration.valid ||
487
+ this.busy ||
488
+ this.name.pending ||
489
+ this.email.pending) {
490
+ return;
491
+ }
492
+ const model = {
493
+ email: this.email.value,
494
+ name: this.name.value,
495
+ firstName: this.firstName.value,
496
+ lastName: this.lastName.value,
497
+ password: this.password.value,
498
+ };
499
+ this.busy = true;
500
+ this._accountService
501
+ .register(model)
502
+ .pipe(take(1))
503
+ .subscribe(() => {
504
+ this.busy = false;
505
+ this._snackbar.open('Registration succeeded', 'OK');
506
+ // this.registration.reset();
507
+ // this.registration.clearValidators();
508
+ // this.registration.markAsPristine();
509
+ this.registered.emit();
510
+ }, (error) => {
511
+ this.busy = false;
512
+ console.error(error);
513
+ this._snackbar.open('Registration error', 'OK');
514
+ });
515
+ }
516
+ }
517
+ AuthJwtRegistrationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2$1.MatSnackBar }, { token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Component });
518
+ AuthJwtRegistrationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.5", 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"], components: [{ type: i4.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: PasswordStrengthBarComponent, selector: "auth-jwt-password-strength-bar", inputs: ["passwordToCheck"], outputs: ["strengthChange"] }, { type: i5.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { 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"] }, { 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]" }, { type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.MatError, selector: "mat-error", inputs: ["id"] }, { type: i13.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }] });
519
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
520
+ type: Component,
521
+ 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
+ }], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: i2$1.MatSnackBar }, { type: AuthJwtAccountService }]; }, propDecorators: { registered: [{
523
+ type: Output
524
+ }] } });
525
+
526
+ const initialState = {
527
+ filter: {
528
+ pageNumber: 1,
529
+ pageSize: 20,
530
+ },
531
+ active: null
532
+ };
533
+ let UsersStore = class UsersStore extends EntityStore {
534
+ constructor() {
535
+ super(initialState);
536
+ }
537
+ };
538
+ UsersStore.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
539
+ UsersStore.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersStore, providedIn: 'root' });
540
+ UsersStore = __decorate([
541
+ StoreConfig({ name: 'Users', idKey: 'userName', resettable: true })
542
+ ], UsersStore);
543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersStore, decorators: [{
544
+ type: Injectable,
545
+ args: [{ providedIn: 'root' }]
546
+ }], ctorParameters: function () { return []; } });
547
+
548
+ class UsersQuery extends QueryEntity {
549
+ constructor(_store) {
550
+ super(_store);
551
+ this._store = _store;
552
+ }
553
+ selectFilter() {
554
+ return this.select((state) => state.filter);
555
+ }
556
+ }
557
+ UsersQuery.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersQuery, deps: [{ token: UsersStore }], target: i0.ɵɵFactoryTarget.Injectable });
558
+ UsersQuery.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersQuery, providedIn: 'root' });
559
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", 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;
568
+ }
569
+ /**
570
+ * Update the filter in the store.
571
+ * @param filter The filter.
572
+ */
573
+ updateFilter(filter) {
574
+ this._store.update({
575
+ filter: filter,
576
+ });
577
+ }
578
+ setActive(name) {
579
+ this._store.setActive(name);
580
+ }
581
+ updateActive(user) {
582
+ const promise = new Promise((resolve, reject) => {
583
+ this._store.setLoading(true);
584
+ this._accountService.updateUser(user).subscribe((_) => {
585
+ this._store.setLoading(false);
586
+ this._store.setError(null);
587
+ this._store.updateActive((u) => {
588
+ return Object.assign({}, user);
589
+ });
590
+ resolve(true);
591
+ }, (error) => {
592
+ console.error(error);
593
+ this._store.setLoading(false);
594
+ this._store.setError('Error updating user');
595
+ resolve(false);
596
+ });
597
+ });
598
+ return promise;
599
+ }
600
+ deleteUser(name) {
601
+ const promise = new Promise((resolve, reject) => {
602
+ this._store.setLoading(true);
603
+ this._accountService.deleteUser(name).subscribe((_) => {
604
+ this._store.setLoading(false);
605
+ this._store.setError(null);
606
+ this._store.remove(name);
607
+ resolve(true);
608
+ }, (error) => {
609
+ console.error(error);
610
+ this._store.setLoading(false);
611
+ this._store.setError('Error deleting user');
612
+ reject(error);
613
+ });
614
+ });
615
+ return promise;
616
+ }
617
+ }
618
+ UsersService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersService, deps: [{ token: UsersStore }, { token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Injectable });
619
+ UsersService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersService, providedIn: 'root' });
620
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UsersService, decorators: [{
621
+ type: Injectable,
622
+ args: [{ providedIn: 'root' }]
623
+ }], ctorParameters: function () { return [{ type: UsersStore }, { type: AuthJwtAccountService }]; } });
624
+
625
+ class UserFilterComponent {
626
+ constructor(formBuilder, query, _corporaService) {
627
+ this._corporaService = _corporaService;
628
+ this.filter$ = query.selectFilter();
629
+ // form
630
+ this.name = formBuilder.control(null);
631
+ this.form = formBuilder.group({
632
+ name: this.name,
633
+ });
634
+ }
635
+ ngOnInit() {
636
+ this.filter$.subscribe((f) => {
637
+ this.updateForm(f);
638
+ });
639
+ }
640
+ updateForm(filter) {
641
+ this.name.setValue(filter.name);
642
+ this.form.markAsPristine();
643
+ }
644
+ reset() {
645
+ this.form.reset();
646
+ this.apply();
647
+ }
648
+ getFilter() {
649
+ var _a;
650
+ return {
651
+ pageNumber: 1,
652
+ pageSize: 20,
653
+ name: (_a = this.name.value) === null || _a === void 0 ? void 0 : _a.trim(),
654
+ };
655
+ }
656
+ apply() {
657
+ if (this.form.invalid) {
658
+ return;
659
+ }
660
+ const filter = this.getFilter();
661
+ // update filter in state
662
+ this._corporaService.updateFilter(filter);
663
+ }
664
+ }
665
+ UserFilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UserFilterComponent, deps: [{ token: i1$1.FormBuilder }, { token: UsersQuery }, { token: UsersService }], target: i0.ɵɵFactoryTarget.Component });
666
+ UserFilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.5", 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: [""], components: [{ type: i4.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i5.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { 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"] }, { 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]" }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i4.MatSuffix, selector: "[matSuffix]" }, { type: i8$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
667
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UserFilterComponent, decorators: [{
668
+ type: Component,
669
+ 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", styles: [""] }]
670
+ }], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: UsersQuery }, { type: UsersService }]; }, propDecorators: { disabled: [{
671
+ type: Input
672
+ }] } });
673
+
674
+ // create a factory provider for the paginator
675
+ const USERS_PAGINATOR = new InjectionToken('USERS_PAGINATOR', {
676
+ providedIn: 'root',
677
+ factory: () => {
678
+ const query = inject(UsersQuery);
679
+ return new PaginatorPlugin(query).withControls().withRange();
680
+ },
681
+ });
682
+
683
+ // https://medium.com/@tarik.nzl/making-use-of-dialogs-in-material-2-mddialog-7533d27df41
684
+ class ConfirmDialogComponent {
685
+ constructor(dialogRef, data) {
686
+ this.dialogRef = dialogRef;
687
+ this.data = data;
688
+ this.title = 'Confirm';
689
+ this.prompt = 'Confirm operation?';
690
+ this.ok = 'yes';
691
+ this.cancel = 'no';
692
+ }
693
+ ngOnInit() { }
694
+ }
695
+ ConfirmDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: ConfirmDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
696
+ ConfirmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.5", 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: [""], components: [{ type: i5.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
697
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
698
+ type: Component,
699
+ 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", styles: [""] }]
700
+ }], ctorParameters: function () {
701
+ return [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
702
+ type: Optional
703
+ }, {
704
+ type: Inject,
705
+ args: [MAT_DIALOG_DATA]
706
+ }] }];
707
+ } });
708
+
709
+ // https://medium.com/@tarik.nzl/making-use-of-dialogs-in-material-2-mddialog-7533d27df41
710
+ /**
711
+ * This service acts as a wrapper for MatDialog to simplify the process of calling
712
+ * the dialog and subscribing to it. What it will do is create an Instance of
713
+ * MatDialog with our custom component (ConfirmDialogComponent). Then it will set
714
+ * any public properties it needs to by setting the properties on the
715
+ * componentInstance object. It will return the observable afterClosed()
716
+ * to the caller so they can subscribe to it. This will emit an event whenever
717
+ * the dialog is closed.
718
+ */
719
+ class DialogService {
720
+ constructor(dialog) {
721
+ this.dialog = dialog;
722
+ }
723
+ confirm(title, prompt, ok = 'yes', cancel = 'no') {
724
+ let dialogRef;
725
+ dialogRef = this.dialog.open(ConfirmDialogComponent);
726
+ dialogRef.componentInstance.title = title;
727
+ dialogRef.componentInstance.prompt = prompt;
728
+ dialogRef.componentInstance.ok = ok;
729
+ dialogRef.componentInstance.cancel = cancel;
730
+ return dialogRef.afterClosed();
731
+ }
732
+ }
733
+ DialogService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: DialogService, deps: [{ token: i1$2.MatDialog }], target: i0.ɵɵFactoryTarget.Injectable });
734
+ DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: DialogService, providedIn: 'root' });
735
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: DialogService, decorators: [{
736
+ type: Injectable,
737
+ args: [{
738
+ providedIn: 'root'
739
+ }]
740
+ }], ctorParameters: function () { return [{ type: i1$2.MatDialog }]; } });
741
+
742
+ class UserEditorComponent {
743
+ constructor(formBuilder, _authService) {
744
+ this._authService = _authService;
745
+ // events
746
+ this.userChange = new EventEmitter();
747
+ this.editorClose = new EventEmitter();
748
+ // form
749
+ this.email = formBuilder.control(null, [
750
+ Validators.required,
751
+ Validators.email,
752
+ ]);
753
+ this.emailConfirmed = formBuilder.control(false);
754
+ this.lockoutEnabled = formBuilder.control(false);
755
+ this.firstName = formBuilder.control(null, [
756
+ Validators.required,
757
+ Validators.maxLength(50),
758
+ ]);
759
+ this.lastName = formBuilder.control(null, [
760
+ Validators.required,
761
+ Validators.maxLength(50),
762
+ ]);
763
+ this.roles = formBuilder.control(null, Validators.maxLength(200));
764
+ this.form = formBuilder.group({
765
+ email: this.email,
766
+ emailConfirmed: this.emailConfirmed,
767
+ lockoutEnabled: this.lockoutEnabled,
768
+ firstName: this.firstName,
769
+ lastName: this.lastName,
770
+ roles: this.roles,
771
+ });
772
+ }
773
+ set user(value) {
774
+ this._user = value;
775
+ this.updateForm(value);
776
+ }
777
+ get user() {
778
+ return this._user;
779
+ }
780
+ ngOnInit() { }
781
+ updateForm(user) {
782
+ var _a;
783
+ if (!user) {
784
+ this.form.reset();
785
+ }
786
+ else {
787
+ this.email.setValue(user.email);
788
+ this.emailConfirmed.setValue(user.emailConfirmed);
789
+ this.lockoutEnabled.setValue(user.lockoutEnabled);
790
+ this.firstName.setValue(user.firstName);
791
+ this.lastName.setValue(user.lastName);
792
+ if (((_a = user.roles) === null || _a === void 0 ? void 0 : _a.length) > 0) {
793
+ this.roles.setValue(user.roles.join(' '));
794
+ }
795
+ else {
796
+ this.roles.setValue(null);
797
+ }
798
+ }
799
+ }
800
+ getUserFromForm() {
801
+ var _a;
802
+ return {
803
+ userName: ((_a = this._user) === null || _a === void 0 ? void 0 : _a.userName) || '',
804
+ email: this.email.value,
805
+ emailConfirmed: this.emailConfirmed.value,
806
+ lockoutEnabled: this.lockoutEnabled.value,
807
+ firstName: this.firstName.value,
808
+ lastName: this.lastName.value,
809
+ roles: this.roles.value
810
+ ? this.roles.value.split(' ').filter((s) => s)
811
+ : [],
812
+ };
813
+ }
814
+ endLockout() {
815
+ if (this.unlocked) {
816
+ return;
817
+ }
818
+ this._user.lockoutEnd = this._authService.getUTCDate();
819
+ this.unlocked = true;
820
+ }
821
+ close() {
822
+ this.editorClose.emit();
823
+ }
824
+ save() {
825
+ if (this.form.invalid) {
826
+ return;
827
+ }
828
+ this.userChange.emit(this.getUserFromForm());
829
+ }
830
+ }
831
+ UserEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UserEditorComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2$2.AuthJwtService }], target: i0.ɵɵFactoryTarget.Component });
832
+ UserEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.5", type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: { user: "user" }, outputs: { userChange: "userChange", editorClose: "editorClose" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <!-- email -->\n <div>\n <mat-form-field>\n <input type=\"text\" matInput [formControl]=\"email\" placeholder=\"email\" />\n <mat-error\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n *ngIf=\"email.hasError('pattern') && (email.dirty || email.touched)\"\n >\n invalid email address\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- emailConfirmed -->\n <div>\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div>\n <mat-checkbox [formControl]=\"lockoutEnabled\"\n >lockout enabled</mat-checkbox\n >\n &nbsp;\n <button\n mat-stroked-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n matTooltip=\"Unlock this user if locked\"\n >\n unlock\n </button>\n </div>\n\n <!-- firstName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"firstName\"\n placeholder=\"first name\"\n />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n *ngIf=\"\n firstName.hasError('maxlength') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- lastName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"lastName\"\n placeholder=\"last name\"\n />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n *ngIf=\"\n lastName.hasError('maxlength') && (lastName.dirty || lastName.touched)\n \"\n >\n last name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"roles\"\n placeholder=\"roles (separated by space)\"\n />\n <mat-error\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button mat-icon-button color=\"warn\" matTooltip=\"Close\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n </button>\n &nbsp;\n <button\n type=\"submit\"\n mat-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user data\"\n >\n <mat-icon>check_circle</mat-icon> save\n </button>\n </div>\n</form>\n", styles: [""], components: [{ type: i4.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i5.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { 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"] }, { 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]" }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i13.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.MatError, selector: "mat-error", inputs: ["id"] }, { type: i8$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
833
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UserEditorComponent, decorators: [{
834
+ type: Component,
835
+ args: [{ selector: 'auth-jwt-user-editor', template: "<form [formGroup]=\"form\" (submit)=\"save()\">\n <!-- email -->\n <div>\n <mat-form-field>\n <input type=\"text\" matInput [formControl]=\"email\" placeholder=\"email\" />\n <mat-error\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n *ngIf=\"email.hasError('pattern') && (email.dirty || email.touched)\"\n >\n invalid email address\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- emailConfirmed -->\n <div>\n <mat-checkbox [formControl]=\"emailConfirmed\"\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div>\n <mat-checkbox [formControl]=\"lockoutEnabled\"\n >lockout enabled</mat-checkbox\n >\n &nbsp;\n <button\n mat-stroked-button\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n matTooltip=\"Unlock this user if locked\"\n >\n unlock\n </button>\n </div>\n\n <!-- firstName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"firstName\"\n placeholder=\"first name\"\n />\n <mat-error\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n *ngIf=\"\n firstName.hasError('maxlength') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- lastName -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"lastName\"\n placeholder=\"last name\"\n />\n <mat-error\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n *ngIf=\"\n lastName.hasError('maxlength') && (lastName.dirty || lastName.touched)\n \"\n >\n last name too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- roles -->\n <div>\n <mat-form-field>\n <input\n type=\"text\"\n matInput\n [formControl]=\"roles\"\n placeholder=\"roles (separated by space)\"\n />\n <mat-error\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button mat-icon-button color=\"warn\" matTooltip=\"Close\" (click)=\"close()\">\n <mat-icon>cancel</mat-icon>\n </button>\n &nbsp;\n <button\n type=\"submit\"\n mat-button\n color=\"primary\"\n [disabled]=\"form.invalid\"\n matTooltip=\"Save user data\"\n >\n <mat-icon>check_circle</mat-icon> save\n </button>\n </div>\n</form>\n", styles: [""] }]
836
+ }], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: i2$2.AuthJwtService }]; }, propDecorators: { user: [{
837
+ type: Input
838
+ }], userChange: [{
839
+ type: Output
840
+ }], editorClose: [{
841
+ type: Output
842
+ }] } });
843
+
844
+ class UserListComponent {
845
+ constructor(paginator, userQuery, _accountService, _usersService, _dialogService, _gravatarService, formBuilder) {
846
+ this.paginator = paginator;
847
+ this._accountService = _accountService;
848
+ this._usersService = _usersService;
849
+ this._dialogService = _dialogService;
850
+ this._gravatarService = _gravatarService;
851
+ this.pageSize = formBuilder.control(20);
852
+ this._refresh$ = new BehaviorSubject(0);
853
+ this._filter$ = userQuery.selectFilter();
854
+ // https://netbasal.com/manage-your-entities-with-akita-like-a-boss-768732f8d4d1
855
+ this.active$ = userQuery.selectActive();
856
+ this.pagination$ = combineLatest([
857
+ this.paginator.pageChanges,
858
+ this.pageSize.valueChanges.pipe(
859
+ // we are required to emit at least the initial value
860
+ // as combineLatest emits only if ALL observables have emitted
861
+ startWith(20),
862
+ // clear the cache when page size changes
863
+ tap((_) => {
864
+ this.paginator.clearCache();
865
+ })),
866
+ this._filter$.pipe(
867
+ // clear the cache when filters changed
868
+ tap((_) => {
869
+ this.paginator.clearCache();
870
+ })),
871
+ this._refresh$.pipe(
872
+ // clear the cache when forcing refresh
873
+ tap((_) => {
874
+ this.paginator.clearCache();
875
+ })),
876
+ ]).pipe(
877
+ // for each emitted value, combine into a filter and use it
878
+ // to request the page from server
879
+ switchMap(([pageNumber, pageSize, filter, refresh]) => {
880
+ // const filter = { ...this._docsQuery.getValue().filter };
881
+ const f = Object.assign({}, filter);
882
+ f.pageNumber = pageNumber;
883
+ f.pageSize = pageSize;
884
+ const request = this.getRequest(f);
885
+ // update saved filters
886
+ this.paginator.metadata.set('filter', f);
887
+ return this.paginator.getPage(request);
888
+ }));
889
+ }
890
+ ngOnDestroy() {
891
+ this.paginator.destroy();
892
+ }
893
+ getRequest(filter) {
894
+ return () => this._accountService.getUsers(filter).pipe(
895
+ // adapt server results to the paginator plugin
896
+ map((p) => {
897
+ return {
898
+ currentPage: p.pageNumber,
899
+ perPage: p.pageSize,
900
+ lastPage: p.pageCount,
901
+ data: p.items,
902
+ total: p.total,
903
+ };
904
+ }));
905
+ }
906
+ pageChange(event) {
907
+ // https://material.angular.io/components/paginator/api
908
+ this.paginator.setPage(event.pageIndex + 1);
909
+ if (event.pageSize !== this.pageSize.value) {
910
+ this.pageSize.setValue(event.pageSize);
911
+ }
912
+ }
913
+ refresh() {
914
+ this.paginator.clearCache();
915
+ this._refresh$.next(this._refresh$.value + 1);
916
+ }
917
+ deleteUser(user) {
918
+ this._dialogService
919
+ .confirm('Confirm', `Delete User ${user.userName}?`)
920
+ .pipe(take(1))
921
+ .subscribe((yes) => {
922
+ if (!yes) {
923
+ return;
924
+ }
925
+ this._usersService.deleteUser(user.userName).finally(() => {
926
+ this.refresh();
927
+ });
928
+ });
929
+ }
930
+ setActiveUser(user) {
931
+ this._usersService.setActive((user === null || user === void 0 ? void 0 : user.userName) || null);
932
+ }
933
+ resetActiveUser() {
934
+ this._usersService.setActive(null);
935
+ }
936
+ saveActiveUser(user) {
937
+ this._usersService.updateActive(user).finally(() => {
938
+ this.refresh();
939
+ });
940
+ }
941
+ onUserEditorClose() {
942
+ this.setActiveUser(null);
943
+ }
944
+ getGravatarUrl(email, size = 80) {
945
+ return this._gravatarService.buildGravatarUrl(email, size);
946
+ }
947
+ }
948
+ UserListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UserListComponent, deps: [{ token: USERS_PAGINATOR }, { token: UsersQuery }, { token: AuthJwtAccountService }, { token: UsersService }, { token: DialogService }, { token: i2$2.GravatarService }, { token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
949
+ UserListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.5", type: UserListComponent, selector: "auth-jwt-user-list", ngImport: i0, template: "<div\n gdAreas=\"filters | progress | list | pager | editor\"\n gdRows=\"80px 64px 2fr 40px 1fr\"\n gdColumns=\"1fr\"\n gdGap=\"8px\"\n>\n <div>\n <!-- filters -->\n <div gdArea=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- progress -->\n <div *ngIf=\"paginator.isLoading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n\n <!-- list -->\n <div gdArea=\"list\" *ngIf=\"pagination$ | async as pagination\">\n <table>\n <thead>\n <td></td>\n <td></td>\n <td></td>\n <th>name</th>\n <th>first</th>\n <th>last</th>\n <th>email</th>\n <th>roles</th>\n <th>lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Edit {{ user.userName }}\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon>mode_edit</mat-icon>\n </button>\n </td>\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Delete {{ user.userName }}\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n [src]=\"getGravatarUrl(user.email, 32)\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td>{{ user.firstName }}</td>\n <td>{{ user.lastName }}</td>\n <td>\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles?.join(\" \") }}</td>\n <td>{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n <!-- pagination -->\n <mat-paginator\n gdArea=\"pager\"\n gdAlignColumns=\"center\"\n gdAlignRows=\"start\"\n [length]=\"pagination.total\"\n [pageSize]=\"pageSize?.value\"\n [pageSizeOptions]=\"[20, 50, 75, 100]\"\n [pageIndex]=\"pagination.currentPage - 1\"\n [showFirstLastButtons]=\"true\"\n (page)=\"pageChange($event)\"\n ></mat-paginator>\n </div>\n </div>\n\n <!-- editor -->\n <div gdArea=\"editor\" *ngIf=\"active$ | async as active\">\n <fieldset>\n <legend>{{ active.userName }}</legend>\n <auth-jwt-user-editor\n [user]=\"active\"\n (userChange)=\"saveActiveUser($event)\"\n (editorClose)=\"resetActiveUser()\"\n ></auth-jwt-user-editor>\n </fieldset>\n </div>\n</div>\n", styles: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:normal}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"], components: [{ type: UserFilterComponent, selector: "auth-jwt-user-filter", inputs: ["disabled"] }, { type: i8$2.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { type: i5.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i11.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { type: UserEditorComponent, selector: "auth-jwt-user-editor", inputs: ["user"], outputs: ["userChange", "editorClose"] }], directives: [{ type: i13.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i13.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }], pipes: { "async": i13.AsyncPipe } });
950
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: UserListComponent, decorators: [{
951
+ type: Component,
952
+ args: [{ selector: 'auth-jwt-user-list', template: "<div\n gdAreas=\"filters | progress | list | pager | editor\"\n gdRows=\"80px 64px 2fr 40px 1fr\"\n gdColumns=\"1fr\"\n gdGap=\"8px\"\n>\n <div>\n <!-- filters -->\n <div gdArea=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- progress -->\n <div *ngIf=\"paginator.isLoading$ | async\" gdArea=\"progress\">\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n\n <!-- list -->\n <div gdArea=\"list\" *ngIf=\"pagination$ | async as pagination\">\n <table>\n <thead>\n <td></td>\n <td></td>\n <td></td>\n <th>name</th>\n <th>first</th>\n <th>last</th>\n <th>email</th>\n <th>roles</th>\n <th>lock end</th>\n </thead>\n <tbody>\n <tr *ngFor=\"let user of pagination.data\">\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Edit {{ user.userName }}\"\n color=\"primary\"\n (click)=\"setActiveUser(user)\"\n >\n <mat-icon>mode_edit</mat-icon>\n </button>\n </td>\n <td class=\"command\">\n <button\n mat-icon-button\n type=\"button\"\n matTooltip=\"Delete {{ user.userName }}\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n [src]=\"getGravatarUrl(user.email, 32)\"\n [alt]=\"user.userName\"\n />\n </td>\n <td>{{ user.userName }}</td>\n <td>{{ user.firstName }}</td>\n <td>{{ user.lastName }}</td>\n <td>\n <a [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n </td>\n <td>{{ user.roles?.join(\" \") }}</td>\n <td>{{ user.lockoutEnd }}</td>\n </tr>\n </tbody>\n </table>\n <!-- pagination -->\n <mat-paginator\n gdArea=\"pager\"\n gdAlignColumns=\"center\"\n gdAlignRows=\"start\"\n [length]=\"pagination.total\"\n [pageSize]=\"pageSize?.value\"\n [pageSizeOptions]=\"[20, 50, 75, 100]\"\n [pageIndex]=\"pagination.currentPage - 1\"\n [showFirstLastButtons]=\"true\"\n (page)=\"pageChange($event)\"\n ></mat-paginator>\n </div>\n </div>\n\n <!-- editor -->\n <div gdArea=\"editor\" *ngIf=\"active$ | async as active\">\n <fieldset>\n <legend>{{ active.userName }}</legend>\n <auth-jwt-user-editor\n [user]=\"active\"\n (userChange)=\"saveActiveUser($event)\"\n (editorClose)=\"resetActiveUser()\"\n ></auth-jwt-user-editor>\n </fieldset>\n </div>\n</div>\n", styles: ["tr:nth-child(odd){background-color:#f8f8f8}th{padding:0 8px;text-align:left;color:silver;font-weight:normal}td{padding:0 8px}td.command{width:24px}table{width:100%;border-collapse:collapse}fieldset{border:1px solid silver;border-radius:8px;padding:16px}\n"] }]
953
+ }], ctorParameters: function () {
954
+ return [{ type: i15.PaginatorPlugin, decorators: [{
955
+ type: Inject,
956
+ args: [USERS_PAGINATOR]
957
+ }] }, { type: UsersQuery }, { type: AuthJwtAccountService }, { type: UsersService }, { type: DialogService }, { type: i2$2.GravatarService }, { type: i1$1.FormBuilder }];
958
+ } });
959
+
960
+ class AuthJwtAdminModule {
961
+ }
962
+ AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtAdminModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
963
+ AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtAdminModule, declarations: [AuthJwtRegistrationComponent,
964
+ PasswordStrengthBarComponent,
965
+ UserFilterComponent,
966
+ UserListComponent,
967
+ ConfirmDialogComponent,
968
+ UserEditorComponent], imports: [CommonModule,
969
+ HttpClientModule,
970
+ FormsModule,
971
+ RouterModule,
972
+ ReactiveFormsModule,
973
+ // material
974
+ MatButtonModule,
975
+ MatCardModule,
976
+ MatCheckboxModule,
977
+ MatDialogModule,
978
+ MatIconModule,
979
+ MatInputModule,
980
+ MatPaginatorModule,
981
+ MatProgressBarModule,
982
+ MatProgressSpinnerModule,
983
+ MatSnackBarModule,
984
+ MatTooltipModule,
985
+ AuthJwtLoginModule,
986
+ NgToolsModule], exports: [AuthJwtRegistrationComponent,
987
+ PasswordStrengthBarComponent,
988
+ UserFilterComponent,
989
+ UserListComponent] });
990
+ AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtAdminModule, imports: [[
991
+ CommonModule,
992
+ HttpClientModule,
993
+ FormsModule,
994
+ RouterModule,
995
+ ReactiveFormsModule,
996
+ // material
997
+ MatButtonModule,
998
+ MatCardModule,
999
+ MatCheckboxModule,
1000
+ MatDialogModule,
1001
+ MatIconModule,
1002
+ MatInputModule,
1003
+ MatPaginatorModule,
1004
+ MatProgressBarModule,
1005
+ MatProgressSpinnerModule,
1006
+ MatSnackBarModule,
1007
+ MatTooltipModule,
1008
+ AuthJwtLoginModule,
1009
+ NgToolsModule
1010
+ ]] });
1011
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.5", ngImport: i0, type: AuthJwtAdminModule, decorators: [{
1012
+ type: NgModule,
1013
+ args: [{
1014
+ declarations: [
1015
+ AuthJwtRegistrationComponent,
1016
+ PasswordStrengthBarComponent,
1017
+ UserFilterComponent,
1018
+ UserListComponent,
1019
+ ConfirmDialogComponent,
1020
+ UserEditorComponent,
1021
+ ],
1022
+ imports: [
1023
+ CommonModule,
1024
+ HttpClientModule,
1025
+ FormsModule,
1026
+ RouterModule,
1027
+ ReactiveFormsModule,
1028
+ // material
1029
+ MatButtonModule,
1030
+ MatCardModule,
1031
+ MatCheckboxModule,
1032
+ MatDialogModule,
1033
+ MatIconModule,
1034
+ MatInputModule,
1035
+ MatPaginatorModule,
1036
+ MatProgressBarModule,
1037
+ MatProgressSpinnerModule,
1038
+ MatSnackBarModule,
1039
+ MatTooltipModule,
1040
+ AuthJwtLoginModule,
1041
+ NgToolsModule
1042
+ ],
1043
+ exports: [
1044
+ AuthJwtRegistrationComponent,
1045
+ PasswordStrengthBarComponent,
1046
+ UserFilterComponent,
1047
+ UserListComponent
1048
+ ],
1049
+ }]
1050
+ }] });
1051
+
1052
+ /*
1053
+ * Public API Surface of auth-jwt-admin
1054
+ */
1055
+
1056
+ /**
1057
+ * Generated bundle index. Do not edit.
1058
+ */
1059
+
1060
+ export { AuthJwtAccountService, AuthJwtAdminModule, AuthJwtRegistrationComponent, PasswordStrengthBarComponent, PasswordValidators, UserFilterComponent, UserListComponent };
1061
+ //# sourceMappingURL=myrmidon-auth-jwt-admin.mjs.map