@myrmidon/auth-jwt-admin 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/esm2022/lib/auth-jwt-admin.module.mjs +120 -0
  2. package/esm2022/lib/components/auth-jwt-registration/auth-jwt-registration.component.mjs +165 -0
  3. package/esm2022/lib/components/confirm-dialog/confirm-dialog.component.mjs +30 -0
  4. package/esm2022/lib/components/password-strength-bar/password-strength-bar.component.mjs +81 -0
  5. package/esm2022/lib/components/state/user-list.repository.mjs +145 -0
  6. package/esm2022/lib/components/user-editor/user-editor.component.mjs +113 -0
  7. package/esm2022/lib/components/user-filter/user-filter.component.mjs +56 -0
  8. package/{esm2020 → esm2022}/lib/components/user-list/user-list.component.mjs +71 -70
  9. package/esm2022/lib/services/auth-jwt-account.service.mjs +182 -0
  10. package/esm2022/lib/services/dialog.service.mjs +38 -0
  11. package/{esm2020 → esm2022}/lib/validators/password.validators.mjs +48 -48
  12. package/{esm2020 → esm2022}/myrmidon-auth-jwt-admin.mjs +4 -4
  13. package/{esm2020 → esm2022}/public-api.mjs +11 -11
  14. package/{fesm2020 → fesm2022}/myrmidon-auth-jwt-admin.mjs +919 -919
  15. package/{fesm2020 → fesm2022}/myrmidon-auth-jwt-admin.mjs.map +1 -1
  16. package/index.d.ts +5 -5
  17. package/lib/auth-jwt-admin.module.d.ts +30 -30
  18. package/lib/components/auth-jwt-registration/auth-jwt-registration.component.d.ts +37 -37
  19. package/lib/components/confirm-dialog/confirm-dialog.component.d.ts +15 -15
  20. package/lib/components/password-strength-bar/password-strength-bar.component.d.ts +17 -17
  21. package/lib/components/state/user-list.repository.d.ts +36 -36
  22. package/lib/components/user-editor/user-editor.component.d.ts +29 -29
  23. package/lib/components/user-filter/user-filter.component.d.ts +21 -21
  24. package/lib/components/user-list/user-list.component.d.ts +29 -29
  25. package/lib/services/auth-jwt-account.service.d.ts +114 -114
  26. package/lib/services/dialog.service.d.ts +19 -19
  27. package/lib/validators/password.validators.d.ts +6 -6
  28. package/package.json +24 -17
  29. package/public-api.d.ts +8 -8
  30. package/esm2020/lib/auth-jwt-admin.module.mjs +0 -119
  31. package/esm2020/lib/components/auth-jwt-registration/auth-jwt-registration.component.mjs +0 -164
  32. package/esm2020/lib/components/confirm-dialog/confirm-dialog.component.mjs +0 -29
  33. package/esm2020/lib/components/password-strength-bar/password-strength-bar.component.mjs +0 -80
  34. package/esm2020/lib/components/state/user-list.repository.mjs +0 -144
  35. package/esm2020/lib/components/user-editor/user-editor.component.mjs +0 -112
  36. package/esm2020/lib/components/user-filter/user-filter.component.mjs +0 -55
  37. package/esm2020/lib/services/auth-jwt-account.service.mjs +0 -181
  38. package/esm2020/lib/services/dialog.service.mjs +0 -37
  39. package/fesm2015/myrmidon-auth-jwt-admin.mjs +0 -998
  40. package/fesm2015/myrmidon-auth-jwt-admin.mjs.map +0 -1
@@ -1,998 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, Component, Input, Output, 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 } 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/common';
13
- import { CommonModule } from '@angular/common';
14
- import * as i5 from '@angular/material/button';
15
- import { MatButtonModule } from '@angular/material/button';
16
- import * as i6 from '@angular/material/icon';
17
- import { MatIconModule } from '@angular/material/icon';
18
- import * as i7 from '@angular/material/input';
19
- import { MatInputModule } from '@angular/material/input';
20
- import * as i8 from '@angular/material/form-field';
21
- import * as i9 from '@angular/material/progress-spinner';
22
- import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
23
- import { __rest } from 'tslib';
24
- import { BehaviorSubject, combineLatest, map, debounceTime, take as take$1 } from 'rxjs';
25
- import { select, createStore, withProps } from '@ngneat/elf';
26
- import { selectActiveEntity, withEntities, withActiveId, upsertEntities, deleteAllEntities, setActiveId } from '@ngneat/elf-entities';
27
- import { selectPaginationData, selectCurrentPageEntities, deleteAllPages, withPagination, updatePaginationData, setPage, hasPage, setCurrentPage } from '@ngneat/elf-pagination';
28
- import { selectRequestStatus, withRequestsCache, withRequestsStatus, updateRequestStatus } from '@ngneat/elf-requests';
29
- import * as i7$1 from '@angular/material/tooltip';
30
- import { MatTooltipModule } from '@angular/material/tooltip';
31
- import '@angular/localize/init';
32
- import * as i1$2 from '@angular/material/dialog';
33
- import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
34
- import * as i2$2 from '@myrmidon/auth-jwt-login';
35
- import { AuthJwtLoginModule } from '@myrmidon/auth-jwt-login';
36
- import * as i6$1 from '@angular/material/expansion';
37
- import { MatExpansionModule } from '@angular/material/expansion';
38
- import * as i8$1 from '@angular/material/paginator';
39
- import { MatPaginatorModule } from '@angular/material/paginator';
40
- import * as i9$1 from '@angular/material/progress-bar';
41
- import { MatProgressBarModule } from '@angular/material/progress-bar';
42
- import * as i5$1 from '@angular/material/checkbox';
43
- import { MatCheckboxModule } from '@angular/material/checkbox';
44
- import { RouterModule } from '@angular/router';
45
- import { MatCardModule } from '@angular/material/card';
46
-
47
- class PasswordValidators {
48
- /** "Standard" password validator for my API services. */
49
- static standard() {
50
- return (control) => {
51
- if (!control.value) {
52
- return null;
53
- }
54
- if (control.value.length < 8) {
55
- return {
56
- passwordtooshort: true,
57
- };
58
- }
59
- if (!/.*[A-Z].*/.test(control.value)) {
60
- return {
61
- noupperinpassword: true,
62
- };
63
- }
64
- if (!/.*[a-z].*/.test(control.value)) {
65
- return {
66
- nolowerinpassword: true,
67
- };
68
- }
69
- if (!/.*[A-Z].*/.test(control.value)) {
70
- return {
71
- noupperinpassword: true,
72
- };
73
- }
74
- if (!/.*[-`~!@#$%^&*()_+=\[\]{};:'",.<>/?|\\].*/.test(control.value)) {
75
- return {
76
- nosymbolinpassword: true,
77
- };
78
- }
79
- return null;
80
- };
81
- }
82
- static areEqual(controlName, otherControlName) {
83
- return (control) => {
84
- const g = control;
85
- const a = g.controls[controlName];
86
- const b = g.controls[otherControlName];
87
- return a.value !== b.value
88
- ? {
89
- areequal: true,
90
- }
91
- : null;
92
- };
93
- }
94
- }
95
-
96
- class AuthJwtAccountService {
97
- constructor(_http, _error, _env) {
98
- this._http = _http;
99
- this._error = _error;
100
- this._env = _env;
101
- }
102
- /**
103
- * Checks if the specified email address is registered on the server.
104
- * @param email email address to test.
105
- * @returns result.
106
- */
107
- isEmailRegistered(email) {
108
- return this._http.get(this._env.get('apiUrl') +
109
- 'accounts/emailexists/' +
110
- encodeURIComponent(email));
111
- }
112
- /**
113
- * Checks if the specified user's given name is registered on the server.
114
- * This name is a nickname chosen by users during registration, and is the key
115
- * used for referencing users when talking to the server.
116
- * @param name name to test.
117
- * @returns result.
118
- */
119
- isNameRegistered(name) {
120
- return this._http.get(this._env.get('apiUrl') +
121
- 'accounts/nameexists/' +
122
- encodeURIComponent(name));
123
- }
124
- /**
125
- * Register the user with the specified registration data.
126
- * @param registration The registration data.
127
- * @param confirmed True to automatically confirm the user's email address
128
- * without sending the confirmation email message.
129
- */
130
- register(registration, confirmed = false) {
131
- return this._http.post(this._env.get('apiUrl') +
132
- 'accounts/register' +
133
- (confirmed ? '?confirmed=true' : ''), registration);
134
- }
135
- /**
136
- * Resend the confirmation email to the specified address.
137
- * @param email address.
138
- */
139
- resendConfirmEmail(email) {
140
- return this._http.get(this._env.get('apiUrl') +
141
- 'accounts/resendconfirm/' +
142
- encodeURIComponent(email)
143
- // options
144
- );
145
- }
146
- /**
147
- * Request a password reset for the specified email address.
148
- * @param email Email address.
149
- */
150
- requestPasswordReset(email) {
151
- return this._http.post(this._env.get('apiUrl') + 'accounts/resetpassword/request', { email });
152
- }
153
- getAllUsers() {
154
- return this._http
155
- .get(this._env.get('apiUrl') + 'users', {
156
- params: new HttpParams().set('pageNumber', '1'),
157
- })
158
- .pipe(retry(3), catchError(this._error.handleError));
159
- }
160
- getUsers(filter, pageNumber = 1, pageSize = 20) {
161
- let httpParams = new HttpParams();
162
- httpParams = httpParams.set('pageNumber', pageNumber.toString());
163
- httpParams = httpParams.set('pageSize', pageSize.toString());
164
- if (filter.name) {
165
- httpParams = httpParams.set('name', filter.name);
166
- }
167
- return this._http
168
- .get(this._env.get('apiUrl') + 'users', {
169
- params: httpParams,
170
- })
171
- .pipe(retry(3), catchError(this._error.handleError));
172
- }
173
- /**
174
- * Get the top N users matching the specified name filter.
175
- * @param nameFilter The user name filter.
176
- * @param limit The maximum number of users to get.
177
- */
178
- getTopUsers(nameFilter, limit = 10) {
179
- let httpParams = new HttpParams();
180
- httpParams = httpParams.set('pageNumber', '1');
181
- httpParams = httpParams.set('pageSize', limit.toString());
182
- if (nameFilter) {
183
- httpParams = httpParams.set('name', nameFilter);
184
- }
185
- const options = httpParams.keys().length > 0
186
- ? {
187
- params: httpParams,
188
- }
189
- : {};
190
- return this._http
191
- .get(this._env.get('apiUrl') + 'users', options)
192
- .pipe(retry(3), catchError(this._error.handleError));
193
- }
194
- /**
195
- * Get information about all the users listed in the specified names.
196
- * @param names User(s) names.
197
- */
198
- getUsersFromNames(names) {
199
- let httpParams = new HttpParams();
200
- if (names && names.length > 0) {
201
- httpParams = httpParams.set('names', names.join(','));
202
- }
203
- const options = httpParams.keys().length > 0
204
- ? {
205
- params: httpParams,
206
- }
207
- : {};
208
- return this._http
209
- .get(this._env.get('apiUrl') + 'users-from-names', options)
210
- .pipe(retry(3), catchError(this._error.handleError));
211
- }
212
- /**
213
- * Get data about the specified user.
214
- * @param name The user name.
215
- */
216
- getUser(name) {
217
- return this._http
218
- .get(this._env.get('apiUrl') + 'users/' + name)
219
- .pipe(retry(3), catchError(this._error.handleError));
220
- }
221
- /**
222
- * Update the editable data for the specified user.
223
- * @param user The user to update.
224
- */
225
- updateUser(user) {
226
- return this._http
227
- .put(this._env.get('apiUrl') +
228
- 'users' +
229
- (user.emailConfirmed ? '?confirmed=true' : ''), user)
230
- .pipe(catchError(this._error.handleError));
231
- }
232
- /**
233
- * Request a password reset email for the specified email address.
234
- * @param email The email address to receive the reset message.
235
- */
236
- resetPassword(email) {
237
- return this._http
238
- .post(this._env.get('apiUrl') + 'accounts/resetpassword/request', {
239
- email: email,
240
- })
241
- .pipe(catchError(this._error.handleError));
242
- }
243
- /**
244
- * Change the password.
245
- * @param change The password change data.
246
- */
247
- changePassword(change) {
248
- return this._http
249
- .post(this._env.get('apiUrl') + 'accounts/changepassword', change)
250
- .pipe(catchError(this._error.handleError));
251
- }
252
- /**
253
- * Delete the user with the specified username.
254
- * @param name The user name.
255
- */
256
- deleteUser(name) {
257
- return this._http
258
- .delete(this._env.get('apiUrl') + 'accounts/' + name)
259
- .pipe(catchError(this._error.handleError));
260
- }
261
- }
262
- AuthJwtAccountService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtAccountService, deps: [{ token: i1.HttpClient }, { token: i2.ErrorService }, { token: i2.EnvService }], target: i0.ɵɵFactoryTarget.Injectable });
263
- AuthJwtAccountService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtAccountService, providedIn: 'root' });
264
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtAccountService, decorators: [{
265
- type: Injectable,
266
- args: [{
267
- providedIn: 'root',
268
- }]
269
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i2.ErrorService }, { type: i2.EnvService }]; } });
270
-
271
- class PasswordStrengthBarComponent {
272
- constructor() {
273
- this._colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
274
- this.strengthChange = new EventEmitter();
275
- this.strengthChange = new EventEmitter();
276
- this.bars = [];
277
- }
278
- measureStrength(p) {
279
- let force = 0;
280
- const regex = /[$-/:-?{-~!"^_`\[\]]/g; // "
281
- const lowerLetters = /[a-z]+/.test(p);
282
- const upperLetters = /[A-Z]+/.test(p);
283
- const numbers = /[0-9]+/.test(p);
284
- const symbols = regex.test(p);
285
- const flags = [lowerLetters, upperLetters, numbers, symbols];
286
- let passedMatches = 0;
287
- for (const flag of flags) {
288
- passedMatches += flag === true ? 1 : 0;
289
- }
290
- force += 2 * p.length + (p.length >= 10 ? 1 : 0);
291
- force += passedMatches * 10;
292
- // penalty (short password)
293
- force = p.length <= 6 ? Math.min(force, 10) : force;
294
- // penalty (poor letiety of characters)
295
- force = passedMatches === 1 ? Math.min(force, 10) : force;
296
- force = passedMatches === 2 ? Math.min(force, 20) : force;
297
- force = passedMatches === 3 ? Math.min(force, 40) : force;
298
- return force;
299
- }
300
- getColor(s) {
301
- let idx = 0;
302
- if (s <= 10) {
303
- idx = 0;
304
- }
305
- else if (s <= 20) {
306
- idx = 1;
307
- }
308
- else if (s <= 30) {
309
- idx = 2;
310
- }
311
- else if (s <= 40) {
312
- idx = 3;
313
- }
314
- else {
315
- idx = 4;
316
- }
317
- return {
318
- idx: idx + 1,
319
- col: this._colors[idx],
320
- };
321
- }
322
- ngOnChanges(changes) {
323
- const password = changes['passwordToCheck'].currentValue;
324
- this.setBarColors(5, '#DDD');
325
- if (password) {
326
- const strength = this.measureStrength(password);
327
- const c = this.getColor(strength);
328
- this.setBarColors(c.idx, c.col);
329
- this.strengthChange.emit(strength);
330
- }
331
- }
332
- setBarColors(count, col) {
333
- for (let n = 0; n < count; n++) {
334
- this.bars[n] = col;
335
- }
336
- }
337
- }
338
- PasswordStrengthBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: PasswordStrengthBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
339
- PasswordStrengthBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", 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"] });
340
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: PasswordStrengthBarComponent, decorators: [{
341
- type: Component,
342
- 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"] }]
343
- }], ctorParameters: function () { return []; }, propDecorators: { passwordToCheck: [{
344
- type: Input
345
- }], strengthChange: [{
346
- type: Output
347
- }] } });
348
-
349
- class AuthJwtRegistrationComponent {
350
- constructor(formBuilder, _snackbar, _accountService) {
351
- this._snackbar = _snackbar;
352
- this._accountService = _accountService;
353
- this.registered = new EventEmitter();
354
- // form
355
- this.email = formBuilder.control('', {
356
- validators: [Validators.required, Validators.email],
357
- asyncValidators: this.getUniqueEmailValidator(this._accountService).bind(this),
358
- nonNullable: true,
359
- });
360
- this.name = formBuilder.control('', {
361
- validators: Validators.required,
362
- asyncValidators: this.getUniqueNameValidator(this._accountService).bind(this),
363
- nonNullable: true,
364
- });
365
- this.firstName = formBuilder.control('', {
366
- validators: [Validators.required, Validators.maxLength(50)],
367
- nonNullable: true,
368
- });
369
- this.lastName = formBuilder.control('', {
370
- validators: [Validators.required, Validators.maxLength(50)],
371
- nonNullable: true,
372
- });
373
- // http://stackoverflow.com/questions/35474991/angular-2-form-validating-for-repeat-password
374
- this.password = formBuilder.control('', {
375
- validators: [Validators.required, PasswordValidators.standard()],
376
- nonNullable: true,
377
- });
378
- this.confirmPassword = formBuilder.control('', {
379
- validators: Validators.required,
380
- nonNullable: true,
381
- });
382
- this.form = formBuilder.group({
383
- email: this.email,
384
- name: this.name,
385
- firstName: this.firstName,
386
- lastName: this.lastName,
387
- password: this.password,
388
- confirmPassword: this.confirmPassword,
389
- }, {
390
- validators: [
391
- PasswordValidators.areEqual('password', 'confirmPassword'),
392
- ],
393
- });
394
- }
395
- /**
396
- * Creates a unique name validator. There is no dependency injection at this level,
397
- * but we can use closures. As a matter of fact, we have access to the service instance
398
- * from the component where we register validators. So we will implement a function
399
- * that will accept the service as parameter, and create the actual validation function.
400
- * This function will have access to the service when called during the validation process.
401
- * See http://restlet.com/blog/2016/02/17/implementing-angular2-forms-beyond-basics-part-2/.
402
- */
403
- getUniqueNameValidator(service) {
404
- return (control) => {
405
- return new Promise((resolve, reject) => {
406
- // avoid checking if empty
407
- if (!control.value) {
408
- resolve(null);
409
- }
410
- else {
411
- service.isNameRegistered(control.value).subscribe({
412
- next: (data) => {
413
- if (!data.isExisting) {
414
- resolve(null);
415
- }
416
- else {
417
- resolve({ uniqueName: true });
418
- }
419
- },
420
- error: (error) => {
421
- console.error('Unique name validator error' +
422
- (error ? JSON.stringify(error) : ''));
423
- resolve({ uniqueName: true });
424
- },
425
- });
426
- }
427
- });
428
- };
429
- }
430
- getUniqueEmailValidator(service) {
431
- return (control) => {
432
- return new Promise((resolve, reject) => {
433
- // avoid checking if empty
434
- if (!control.value) {
435
- resolve(null);
436
- }
437
- else {
438
- service.isEmailRegistered(control.value).subscribe({
439
- next: (data) => {
440
- if (!data.isExisting) {
441
- resolve(null);
442
- }
443
- else {
444
- resolve({ uniqueEmail: true });
445
- }
446
- },
447
- error: (error) => {
448
- console.error('Unique email validator error' +
449
- (error ? JSON.stringify(error) : ''));
450
- resolve({ uniqueEmail: true });
451
- },
452
- });
453
- }
454
- });
455
- };
456
- }
457
- onSubmit() {
458
- if (!this.form.valid ||
459
- this.busy ||
460
- this.name.pending ||
461
- this.email.pending) {
462
- return;
463
- }
464
- const model = {
465
- email: this.email.value,
466
- name: this.name.value,
467
- firstName: this.firstName.value,
468
- lastName: this.lastName.value,
469
- password: this.password.value,
470
- };
471
- this.busy = true;
472
- this._accountService
473
- .register(model)
474
- .pipe(take(1))
475
- .subscribe({
476
- next: () => {
477
- this.busy = false;
478
- this._snackbar.open($localize `Registration succeeded`, 'OK');
479
- this.registered.emit();
480
- },
481
- error: (error) => {
482
- this.busy = false;
483
- console.error('Registration error' + (error ? JSON.stringify(error) : ''));
484
- this._snackbar.open($localize `Registration error`, 'OK');
485
- },
486
- });
487
- }
488
- }
489
- AuthJwtRegistrationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtRegistrationComponent, deps: [{ token: i1$1.FormBuilder }, { token: i2$1.MatSnackBar }, { token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Component });
490
- AuthJwtRegistrationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", type: AuthJwtRegistrationComponent, selector: "auth-jwt-registration", outputs: { registered: "registered" }, ngImport: i0, template: "<div>\r\n <form role=\"form\" [formGroup]=\"form\" (submit)=\"onSubmit()\">\r\n <fieldset>\r\n <legend i18n>registration</legend>\r\n <!-- email -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n>email</mat-label>\r\n <input\r\n matInput\r\n type=\"email\"\r\n id=\"email\"\r\n maxlength=\"256\"\r\n required\r\n autofocus\r\n spellcheck=\"false\"\r\n [formControl]=\"email\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(email).errors?.required && (email.dirty || email.touched)\r\n \"\r\n >email required</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"$any(email).errors?.email && (email.dirty || email.touched)\"\r\n >invalid email</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(email).errors?.uniqueEmail && (email.dirty || email.touched)\r\n \"\r\n >email already registered</mat-error\r\n >\r\n </mat-form-field>\r\n <mat-icon *ngIf=\"email.pending\">hourglass</mat-icon>\r\n </div>\r\n\r\n <!-- name -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n>username</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"name\"\r\n maxlength=\"50\"\r\n required\r\n pattern=\"^[a-zA-Z][a-zA-Z0-9]{2,49}$\"\r\n spellcheck=\"false\"\r\n [formControl]=\"name\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"$any(name).errors?.required && (name.dirty || name.touched)\"\r\n >username required</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"$any(name).errors?.pattern && (name.dirty || name.touched)\"\r\n >invalid username</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(name).errors?.uniqueName && (name.dirty || name.touched)\r\n \"\r\n >username already registered</mat-error\r\n >\r\n </mat-form-field>\r\n <mat-icon *ngIf=\"name.pending\">hourglass</mat-icon>\r\n </div>\r\n\r\n <!-- first name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>first name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"firstName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"firstName\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n firstName.hasError('required') &&\r\n (firstName.dirty || firstName.touched)\r\n \"\r\n class=\"text-danger small\"\r\n >\r\n first name required\r\n </mat-error>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- last name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>last name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"lastName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"lastName\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n lastName.hasError('required') &&\r\n (lastName.dirty || lastName.touched)\r\n \"\r\n class=\"text-danger small\"\r\n >\r\n last name required\r\n </mat-error>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- <div [formGroup]=\"passwords\"> -->\r\n <!-- password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>password</mat-label>\r\n <input\r\n matInput\r\n type=\"password\"\r\n name=\"password\"\r\n autocomplete=\"new-password\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"password\"\r\n />\r\n <auth-jwt-password-strength-bar [passwordToCheck]=\"password.value\">\r\n </auth-jwt-password-strength-bar>\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.required &&\r\n (password.dirty || password.touched)\r\n \"\r\n >password required</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.passwordtooshort &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 8 characters</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.noupperinpassword &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 1 uppercase letter</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.nolowerinpassword &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 1 lowercase letter</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.nosymbolinpassword &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 1 punctuation/symbol</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- confirm password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>confirm password</mat-label>\r\n <input\r\n matInput\r\n type=\"password\"\r\n name=\"confirmPassword\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"confirmPassword\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n <div\r\n i18n\r\n *ngIf=\"form.errors?.areequal && confirmPassword.touched\"\r\n style=\"color: red\"\r\n >\r\n password differs from confirmation password\r\n </div>\r\n\r\n <button i18n\r\n mat-raised-button\r\n type=\"submit\"\r\n color=\"primary\"\r\n [disabled]=\"\r\n form.invalid || form.pristine || busy || name.pending || email.pending\r\n \"\r\n >\r\n register\r\n </button>\r\n <mat-progress-spinner diameter=\"20\" *ngIf=\"busy\"></mat-progress-spinner>\r\n </fieldset>\r\n </form>\r\n\r\n <details>\r\n <summary i18n>Hints</summary>\r\n <p i18n>\r\n To register a new user, you must provide his email address, choose a\r\n password, and choose a username, which must be unique (you will be\r\n notified if another user has already taken that name). The username must\r\n include only letters/digits, start with a letter, and be no shorter than 3\r\n characters, nor longer than 50.\r\n </p>\r\n <p i18n>\r\n To promote a decent security level, the password must include at least 8\r\n characters, uppercase and lowercase letters, digits, and punctuation (like\r\n dashes, stops, parentheses, etc.).\r\n </p>\r\n <p i18n>\r\n Once registered, if messaging is enabled on the server side the user will\r\n receive an email message to the email address you specified; he will have\r\n to click on the provided link to complete the registration process.\r\n Otherwise, you should edit the newly created user and confirm the email\r\n registration.\r\n </p>\r\n </details>\r\n</div>\r\n", styles: ["mat-form-field{width:400px}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}details{margin:8px}\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.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.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.MatLabel, selector: "mat-label" }, { 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"] }] });
491
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtRegistrationComponent, decorators: [{
492
- type: Component,
493
- args: [{ selector: 'auth-jwt-registration', template: "<div>\r\n <form role=\"form\" [formGroup]=\"form\" (submit)=\"onSubmit()\">\r\n <fieldset>\r\n <legend i18n>registration</legend>\r\n <!-- email -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n>email</mat-label>\r\n <input\r\n matInput\r\n type=\"email\"\r\n id=\"email\"\r\n maxlength=\"256\"\r\n required\r\n autofocus\r\n spellcheck=\"false\"\r\n [formControl]=\"email\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(email).errors?.required && (email.dirty || email.touched)\r\n \"\r\n >email required</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"$any(email).errors?.email && (email.dirty || email.touched)\"\r\n >invalid email</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(email).errors?.uniqueEmail && (email.dirty || email.touched)\r\n \"\r\n >email already registered</mat-error\r\n >\r\n </mat-form-field>\r\n <mat-icon *ngIf=\"email.pending\">hourglass</mat-icon>\r\n </div>\r\n\r\n <!-- name -->\r\n <div class=\"form-row\">\r\n <mat-form-field>\r\n <mat-label i18n>username</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"name\"\r\n maxlength=\"50\"\r\n required\r\n pattern=\"^[a-zA-Z][a-zA-Z0-9]{2,49}$\"\r\n spellcheck=\"false\"\r\n [formControl]=\"name\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"$any(name).errors?.required && (name.dirty || name.touched)\"\r\n >username required</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"$any(name).errors?.pattern && (name.dirty || name.touched)\"\r\n >invalid username</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(name).errors?.uniqueName && (name.dirty || name.touched)\r\n \"\r\n >username already registered</mat-error\r\n >\r\n </mat-form-field>\r\n <mat-icon *ngIf=\"name.pending\">hourglass</mat-icon>\r\n </div>\r\n\r\n <!-- first name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>first name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"firstName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"firstName\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n firstName.hasError('required') &&\r\n (firstName.dirty || firstName.touched)\r\n \"\r\n class=\"text-danger small\"\r\n >\r\n first name required\r\n </mat-error>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- last name -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>last name</mat-label>\r\n <input\r\n matInput\r\n type=\"text\"\r\n id=\"lastName\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"lastName\"\r\n />\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n lastName.hasError('required') &&\r\n (lastName.dirty || lastName.touched)\r\n \"\r\n class=\"text-danger small\"\r\n >\r\n last name required\r\n </mat-error>\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- <div [formGroup]=\"passwords\"> -->\r\n <!-- password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>password</mat-label>\r\n <input\r\n matInput\r\n type=\"password\"\r\n name=\"password\"\r\n autocomplete=\"new-password\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"password\"\r\n />\r\n <auth-jwt-password-strength-bar [passwordToCheck]=\"password.value\">\r\n </auth-jwt-password-strength-bar>\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.required &&\r\n (password.dirty || password.touched)\r\n \"\r\n >password required</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.passwordtooshort &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 8 characters</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.noupperinpassword &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 1 uppercase letter</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.nolowerinpassword &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 1 lowercase letter</mat-error\r\n >\r\n <mat-error\r\n i18n\r\n *ngIf=\"\r\n $any(password).errors?.nosymbolinpassword &&\r\n (password.dirty || password.touched)\r\n \"\r\n >at least 1 punctuation/symbol</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n\r\n <!-- confirm password -->\r\n <div>\r\n <mat-form-field>\r\n <mat-label i18n>confirm password</mat-label>\r\n <input\r\n matInput\r\n type=\"password\"\r\n name=\"confirmPassword\"\r\n maxlength=\"50\"\r\n required\r\n spellcheck=\"false\"\r\n [formControl]=\"confirmPassword\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n <div\r\n i18n\r\n *ngIf=\"form.errors?.areequal && confirmPassword.touched\"\r\n style=\"color: red\"\r\n >\r\n password differs from confirmation password\r\n </div>\r\n\r\n <button i18n\r\n mat-raised-button\r\n type=\"submit\"\r\n color=\"primary\"\r\n [disabled]=\"\r\n form.invalid || form.pristine || busy || name.pending || email.pending\r\n \"\r\n >\r\n register\r\n </button>\r\n <mat-progress-spinner diameter=\"20\" *ngIf=\"busy\"></mat-progress-spinner>\r\n </fieldset>\r\n </form>\r\n\r\n <details>\r\n <summary i18n>Hints</summary>\r\n <p i18n>\r\n To register a new user, you must provide his email address, choose a\r\n password, and choose a username, which must be unique (you will be\r\n notified if another user has already taken that name). The username must\r\n include only letters/digits, start with a letter, and be no shorter than 3\r\n characters, nor longer than 50.\r\n </p>\r\n <p i18n>\r\n To promote a decent security level, the password must include at least 8\r\n characters, uppercase and lowercase letters, digits, and punctuation (like\r\n dashes, stops, parentheses, etc.).\r\n </p>\r\n <p i18n>\r\n Once registered, if messaging is enabled on the server side the user will\r\n receive an email message to the email address you specified; he will have\r\n to click on the provided link to complete the registration process.\r\n Otherwise, you should edit the newly created user and confirm the email\r\n registration.\r\n </p>\r\n </details>\r\n</div>\r\n", styles: ["mat-form-field{width:400px}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}details{margin:8px}\n"] }]
494
- }], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: i2$1.MatSnackBar }, { type: AuthJwtAccountService }]; }, propDecorators: { registered: [{
495
- type: Output
496
- }] } });
497
-
498
- const PAGE_SIZE = 20;
499
- class UserListRepository {
500
- constructor(_accService) {
501
- this._accService = _accService;
502
- // create store
503
- this._store = this.createStore();
504
- this._lastPageSize = PAGE_SIZE;
505
- this._loading$ = new BehaviorSubject(false);
506
- this._saving$ = new BehaviorSubject(false);
507
- this.loading$ = this._loading$.asObservable();
508
- this.saving$ = this._saving$.asObservable();
509
- // combine pagination parameters with page data for our consumers
510
- this.pagination$ = combineLatest([
511
- this._store.pipe(selectPaginationData()),
512
- this._store.pipe(selectCurrentPageEntities()),
513
- ]).pipe(map(([pagination, data]) => (Object.assign(Object.assign({}, pagination), { data }))), debounceTime(0));
514
- // the active user, if required
515
- this.activeUser$ = this._store.pipe(selectActiveEntity());
516
- // the filter, if required
517
- this.filter$ = this._store.pipe(select((state) => state.filter));
518
- this.filter$.subscribe((filter) => {
519
- // when filter changed, reset any existing page and move to page 1
520
- const paginationData = this._store.getValue().pagination;
521
- this._store.update(deleteAllPages());
522
- // load page 1
523
- this.loadPage(1, paginationData.perPage);
524
- });
525
- // the request status
526
- this.status$ = this._store.pipe(selectRequestStatus('user-list'));
527
- // load page 1 and subscribe to pagination
528
- this.loadPage(1, PAGE_SIZE);
529
- this.pagination$.subscribe(console.log);
530
- }
531
- createStore() {
532
- const store = createStore({ name: 'user-list' }, withProps({
533
- filter: {},
534
- }), withEntities({ idKey: 'userName' }), withActiveId(), withRequestsCache(), withRequestsStatus(), withPagination());
535
- return store;
536
- }
537
- adaptPage(page) {
538
- // adapt the server page DataPage<T> to Elf pagination
539
- return {
540
- currentPage: page.pageNumber,
541
- perPage: page.pageSize,
542
- lastPage: page.pageCount,
543
- total: page.total,
544
- data: page.items,
545
- };
546
- }
547
- addPage(response) {
548
- const { data } = response, paginationData = __rest(response, ["data"]);
549
- this._store.update(upsertEntities(data), updatePaginationData(paginationData), setPage(paginationData.currentPage, data.map((c) => c.userName)));
550
- }
551
- loadPage(pageNumber, pageSize) {
552
- if (!pageSize) {
553
- pageSize = PAGE_SIZE;
554
- }
555
- // if the page exists and page size is the same, just move to it
556
- if (this._store.query(hasPage(pageNumber)) &&
557
- pageSize === this._lastPageSize) {
558
- console.log('Page exists: ' + pageNumber);
559
- this._store.update(setCurrentPage(pageNumber));
560
- return;
561
- }
562
- // reset cached pages if page size changed
563
- if (this._lastPageSize !== pageSize) {
564
- this._store.update(deleteAllPages());
565
- this._lastPageSize = pageSize;
566
- }
567
- // load page from server
568
- this._store.update(updateRequestStatus('user-list', 'pending'));
569
- this._loading$.next(true);
570
- this._accService
571
- .getUsers(this._store.getValue().filter, pageNumber, pageSize)
572
- .pipe(take$1(1))
573
- .subscribe((page) => {
574
- this._loading$.next(false);
575
- this.addPage(Object.assign(Object.assign({}, this.adaptPage(page)), { data: page.items }));
576
- this._store.update(updateRequestStatus('user-list', 'success'));
577
- });
578
- }
579
- setFilter(filter) {
580
- this._store.update((state) => (Object.assign(Object.assign({}, state), { filter: filter })));
581
- }
582
- clearCache() {
583
- this._store.update(deleteAllEntities(), deleteAllPages());
584
- }
585
- setActive(name) {
586
- this._store.update(setActiveId(name));
587
- }
588
- updateActive(user) {
589
- const promise = new Promise((resolve, reject) => {
590
- this._saving$.next(true);
591
- this._accService.updateUser(user).subscribe({
592
- next: (_) => {
593
- this._saving$.next(false);
594
- this._store.update(upsertEntities(user));
595
- resolve(true);
596
- },
597
- error: (error) => {
598
- this._saving$.next(false);
599
- console.error(`Error updating user ${user.userName}: ` +
600
- JSON.stringify(error || {}));
601
- resolve(false);
602
- },
603
- });
604
- });
605
- return promise;
606
- }
607
- deleteUser(name) {
608
- const promise = new Promise((resolve, reject) => {
609
- this._saving$.next(true);
610
- this._accService.deleteUser(name).subscribe({
611
- next: (_) => {
612
- this._saving$.next(false);
613
- this.clearCache();
614
- this.loadPage(1);
615
- resolve(true);
616
- },
617
- error: (error) => {
618
- this._saving$.next(false);
619
- console.error(`Error deleting user ${name}: ` + JSON.stringify(error || {}));
620
- reject(error);
621
- },
622
- });
623
- });
624
- return promise;
625
- }
626
- }
627
- UserListRepository.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserListRepository, deps: [{ token: AuthJwtAccountService }], target: i0.ɵɵFactoryTarget.Injectable });
628
- UserListRepository.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserListRepository, providedIn: 'root' });
629
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserListRepository, decorators: [{
630
- type: Injectable,
631
- args: [{ providedIn: 'root' }]
632
- }], ctorParameters: function () { return [{ type: AuthJwtAccountService }]; } });
633
-
634
- class UserFilterComponent {
635
- constructor(formBuilder, _repository) {
636
- this._repository = _repository;
637
- this.filter$ = _repository.filter$;
638
- // form
639
- this.name = formBuilder.control(null);
640
- this.form = formBuilder.group({
641
- name: this.name,
642
- });
643
- }
644
- ngOnInit() {
645
- this.filter$.subscribe((f) => {
646
- this.updateForm(f);
647
- });
648
- }
649
- updateForm(filter) {
650
- this.name.setValue(filter.name || null);
651
- this.form.markAsPristine();
652
- }
653
- reset() {
654
- this.form.reset();
655
- this.apply();
656
- }
657
- getFilter() {
658
- var _a;
659
- return {
660
- name: (_a = this.name.value) === null || _a === void 0 ? void 0 : _a.trim(),
661
- };
662
- }
663
- apply() {
664
- if (this.form.invalid) {
665
- return;
666
- }
667
- const filter = this.getFilter();
668
- // update filter in state
669
- this._repository.setFilter(filter);
670
- }
671
- }
672
- UserFilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserFilterComponent, deps: [{ token: i1$1.FormBuilder }, { token: UserListRepository }], target: i0.ɵɵFactoryTarget.Component });
673
- UserFilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", 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 <mat-label i18n>name or ID</mat-label>\n <input matInput [formControl]=\"name\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n color=\"warn\"\n i18n-matTooltip\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 i18n-matTooltip\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.MatLabel, selector: "mat-label" }, { kind: "directive", type: i8.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i7$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
674
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserFilterComponent, decorators: [{
675
- type: Component,
676
- 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 <mat-label i18n>name or ID</mat-label>\n <input matInput [formControl]=\"name\" />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"reset()\"\n color=\"warn\"\n i18n-matTooltip\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 i18n-matTooltip\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"] }]
677
- }], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: UserListRepository }]; }, propDecorators: { disabled: [{
678
- type: Input
679
- }] } });
680
-
681
- // https://medium.com/@tarik.nzl/making-use-of-dialogs-in-material-2-mddialog-7533d27df41
682
- class ConfirmDialogComponent {
683
- constructor(dialogRef, data) {
684
- this.dialogRef = dialogRef;
685
- this.data = data;
686
- this.title = $localize `Confirm`;
687
- this.prompt = $localize `Confirm operation?`;
688
- this.ok = $localize `yes`;
689
- this.cancel = $localize `no`;
690
- }
691
- ngOnInit() { }
692
- }
693
- ConfirmDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: ConfirmDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
694
- ConfirmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", 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"] }] });
695
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
696
- type: Component,
697
- 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" }]
698
- }], ctorParameters: function () {
699
- return [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
700
- type: Optional
701
- }, {
702
- type: Inject,
703
- args: [MAT_DIALOG_DATA]
704
- }] }];
705
- } });
706
-
707
- // https://medium.com/@tarik.nzl/making-use-of-dialogs-in-material-2-mddialog-7533d27df41
708
- /**
709
- * This service acts as a wrapper for MatDialog to simplify the process of calling
710
- * the dialog and subscribing to it. What it will do is create an Instance of
711
- * MatDialog with our custom component (ConfirmDialogComponent). Then it will set
712
- * any public properties it needs to by setting the properties on the
713
- * componentInstance object. It will return the observable afterClosed()
714
- * to the caller so they can subscribe to it. This will emit an event whenever
715
- * the dialog is closed.
716
- */
717
- class DialogService {
718
- constructor(dialog) {
719
- this.dialog = dialog;
720
- }
721
- confirm(title, prompt, ok = $localize `yes`, cancel = $localize `no`) {
722
- let dialogRef;
723
- dialogRef = this.dialog.open(ConfirmDialogComponent);
724
- dialogRef.componentInstance.title = title;
725
- dialogRef.componentInstance.prompt = prompt;
726
- dialogRef.componentInstance.ok = ok;
727
- dialogRef.componentInstance.cancel = cancel;
728
- return dialogRef.afterClosed();
729
- }
730
- }
731
- DialogService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: DialogService, deps: [{ token: i1$2.MatDialog }], target: i0.ɵɵFactoryTarget.Injectable });
732
- DialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: DialogService, providedIn: 'root' });
733
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: DialogService, decorators: [{
734
- type: Injectable,
735
- args: [{
736
- providedIn: 'root'
737
- }]
738
- }], ctorParameters: function () { return [{ type: i1$2.MatDialog }]; } });
739
-
740
- class UserEditorComponent {
741
- constructor(formBuilder, _authService) {
742
- this._authService = _authService;
743
- // events
744
- this.userChange = new EventEmitter();
745
- this.editorClose = new EventEmitter();
746
- // form
747
- this.email = formBuilder.control(null, [
748
- Validators.required,
749
- Validators.email,
750
- ]);
751
- this.emailConfirmed = formBuilder.control(false);
752
- this.lockoutEnabled = formBuilder.control(false);
753
- this.firstName = formBuilder.control(null, [
754
- Validators.required,
755
- Validators.maxLength(50),
756
- ]);
757
- this.lastName = formBuilder.control(null, [
758
- Validators.required,
759
- Validators.maxLength(50),
760
- ]);
761
- this.roles = formBuilder.control(null, Validators.maxLength(200));
762
- this.form = formBuilder.group({
763
- email: this.email,
764
- emailConfirmed: this.emailConfirmed,
765
- lockoutEnabled: this.lockoutEnabled,
766
- firstName: this.firstName,
767
- lastName: this.lastName,
768
- roles: this.roles,
769
- });
770
- }
771
- set user(value) {
772
- this._user = value;
773
- this.updateForm(value);
774
- }
775
- get user() {
776
- return this._user;
777
- }
778
- ngOnInit() { }
779
- updateForm(user) {
780
- var _a;
781
- if (!user) {
782
- this.form.reset();
783
- }
784
- else {
785
- this.email.setValue(user.email);
786
- this.emailConfirmed.setValue(user.emailConfirmed);
787
- this.lockoutEnabled.setValue(user.lockoutEnabled);
788
- this.firstName.setValue(user.firstName);
789
- this.lastName.setValue(user.lastName);
790
- if (((_a = user.roles) === null || _a === void 0 ? void 0 : _a.length) > 0) {
791
- this.roles.setValue(user.roles.join(' '));
792
- }
793
- else {
794
- this.roles.setValue(null);
795
- }
796
- }
797
- }
798
- getUserFromForm() {
799
- var _a;
800
- return {
801
- userName: ((_a = this._user) === null || _a === void 0 ? void 0 : _a.userName) || '',
802
- email: this.email.value,
803
- emailConfirmed: this.emailConfirmed.value,
804
- lockoutEnabled: this.lockoutEnabled.value,
805
- firstName: this.firstName.value,
806
- lastName: this.lastName.value,
807
- roles: this.roles.value
808
- ? this.roles.value.split(' ').filter((s) => s)
809
- : [],
810
- };
811
- }
812
- endLockout() {
813
- if (this.unlocked) {
814
- return;
815
- }
816
- this._user.lockoutEnd = this._authService.getUTCDate();
817
- this.unlocked = true;
818
- }
819
- close() {
820
- this.editorClose.emit();
821
- }
822
- save() {
823
- if (this.form.invalid) {
824
- return;
825
- }
826
- this.userChange.emit(this.getUserFromForm());
827
- }
828
- }
829
- UserEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserEditorComponent, deps: [{ token: i1$1.UntypedFormBuilder }, { token: i2$2.AuthJwtService }], target: i0.ɵɵFactoryTarget.Component });
830
- UserEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", 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 i18n>email</mat-label>\n <input type=\"text\" matInput [formControl]=\"email\" />\n <mat-error\n i18n\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n i18n\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\" i18n\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formControl]=\"lockoutEnabled\" i18n\n >lockout enabled</mat-checkbox\n >\n <button\n mat-icon-button\n color=\"primary\"\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n i18n-matTooltip\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 i18n>first name</mat-label>\n <input type=\"text\" matInput [formControl]=\"firstName\" />\n <mat-error\n i18n\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n i18n\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 i18n>last name</mat-label>\n <input type=\"text\" matInput [formControl]=\"lastName\" />\n <mat-error\n i18n\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n i18n\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 i18n>roles</mat-label>\n <input type=\"text\" matInput [formControl]=\"roles\" />\n <mat-error\n i18n\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n <mat-hint i18n>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matTooltip\n matTooltip=\"Close\"\n (click)=\"close()\"\n >\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 i18n-matTooltip\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: i7$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
831
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserEditorComponent, decorators: [{
832
- type: Component,
833
- 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 i18n>email</mat-label>\n <input type=\"text\" matInput [formControl]=\"email\" />\n <mat-error\n i18n\n *ngIf=\"email.hasError('required') && (email.dirty || email.touched)\"\n >\n email address required\n </mat-error>\n <mat-error\n i18n\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\" i18n\n >email address confirmed</mat-checkbox\n >\n </div>\n\n <!-- lockoutEnabled -->\n <div class=\"form-row\">\n <mat-checkbox [formControl]=\"lockoutEnabled\" i18n\n >lockout enabled</mat-checkbox\n >\n <button\n mat-icon-button\n color=\"primary\"\n (click)=\"endLockout()\"\n [disabled]=\"unlocked\"\n i18n-matTooltip\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 i18n>first name</mat-label>\n <input type=\"text\" matInput [formControl]=\"firstName\" />\n <mat-error\n i18n\n *ngIf=\"\n firstName.hasError('required') &&\n (firstName.dirty || firstName.touched)\n \"\n >\n first name required\n </mat-error>\n <mat-error\n i18n\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 i18n>last name</mat-label>\n <input type=\"text\" matInput [formControl]=\"lastName\" />\n <mat-error\n i18n\n *ngIf=\"\n lastName.hasError('required') && (lastName.dirty || lastName.touched)\n \"\n >\n last name required\n </mat-error>\n <mat-error\n i18n\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 i18n>roles</mat-label>\n <input type=\"text\" matInput [formControl]=\"roles\" />\n <mat-error\n i18n\n *ngIf=\"roles.hasError('maxlength') && (roles.dirty || roles.touched)\"\n >\n too long\n </mat-error>\n <mat-hint i18n>roles (separated by space)</mat-hint>\n </mat-form-field>\n </div>\n\n <!-- buttons -->\n <br />\n <div>\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matTooltip\n matTooltip=\"Close\"\n (click)=\"close()\"\n >\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 i18n-matTooltip\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"] }]
834
- }], ctorParameters: function () { return [{ type: i1$1.UntypedFormBuilder }, { type: i2$2.AuthJwtService }]; }, propDecorators: { user: [{
835
- type: Input
836
- }], userChange: [{
837
- type: Output
838
- }], editorClose: [{
839
- type: Output
840
- }] } });
841
-
842
- class UserListComponent {
843
- constructor(_repository, _dialogService, _gravatarService) {
844
- this._repository = _repository;
845
- this._dialogService = _dialogService;
846
- this._gravatarService = _gravatarService;
847
- this.pagination$ = _repository.pagination$;
848
- this.active$ = _repository.activeUser$;
849
- this.loading$ = _repository.loading$;
850
- }
851
- pageChange(event) {
852
- this._repository.loadPage(event.pageIndex + 1, event.pageSize);
853
- }
854
- deleteUser(user) {
855
- this._dialogService
856
- .confirm($localize `Confirm`, $localize `Delete user ${user.userName}?`)
857
- .pipe(take(1))
858
- .subscribe((yes) => {
859
- if (!yes) {
860
- return;
861
- }
862
- this._repository.deleteUser(user.userName).finally(() => {
863
- this._repository.clearCache();
864
- this._repository.loadPage(1);
865
- });
866
- });
867
- }
868
- setActiveUser(user) {
869
- this._repository.setActive((user === null || user === void 0 ? void 0 : user.userName) || null);
870
- }
871
- resetActiveUser() {
872
- this._repository.setActive(null);
873
- }
874
- saveActiveUser(user) {
875
- this._repository.updateActive(user);
876
- this._repository.setActive(null);
877
- }
878
- onUserEditorClose() {
879
- this._repository.setActive(null);
880
- }
881
- getGravatarUrl(email, size = 80) {
882
- return this._gravatarService.buildGravatarUrl(email, size);
883
- }
884
- clearCache() {
885
- this._repository.clearCache();
886
- this._repository.loadPage(1);
887
- }
888
- }
889
- UserListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserListComponent, deps: [{ token: UserListRepository }, { token: DialogService }, { token: i2$2.GravatarService }], target: i0.ɵɵFactoryTarget.Component });
890
- UserListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", type: UserListComponent, selector: "auth-jwt-user-list", ngImport: i0, template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div id=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n <div id=\"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 i18n>name</th>\n <th i18n class=\"noif-lt-md\">first</th>\n <th i18n class=\"noif-lt-md\">last</th>\n <th i18n class=\"noif-lt-md\">email</th>\n <th i18n>roles</th>\n <th i18n 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 i18n-matTooltip\n matTooltip=\"Edit this user\"\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 i18n-matTooltip\n matTooltip=\"Delete this user\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n alt=\"avatar\"\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 id=\"paginator\" class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matmatTooltip\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 <mat-expansion-panel\n id=\"editor\"\n [expanded]=\"active$ | async\"\n [disabled]=\"!(active$ | async)\"\n >\n <div *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 </mat-expansion-panel>\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#filters{grid-area:filters}div#list{grid-area:list}div#paginator{grid-area:paginator;justify-content:end}div#editor{grid-area:editor}div#container{display:grid;grid-template-rows:auto 1fr auto auto;grid-template-columns:1fr;grid-template-areas:\"filters\" \"list\" \"paginator\" \"editor\";gap:8px}@media only screen and (max-width: 959px){.noif-lt-md{display:none}}@media only screen and (min-width: 1920px){div#container{grid-template-rows:auto 1fr auto;grid-template-columns:1fr auto;grid-template-areas:\"filters filters\" \"list editor\" \"paginator .\"}}\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$1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["disabled", "expanded", "hideToggle", "togglePosition"], outputs: ["opened", "closed", "expandedChange", "afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8$1.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: i9$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "directive", type: i7$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" }] });
891
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: UserListComponent, decorators: [{
892
- type: Component,
893
- args: [{ selector: 'auth-jwt-user-list', template: "<div id=\"container\">\n <div>\n <!-- filters -->\n <div id=\"filters\">\n <auth-jwt-user-filter></auth-jwt-user-filter>\n </div>\n\n <!-- list -->\n <div id=\"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 i18n>name</th>\n <th i18n class=\"noif-lt-md\">first</th>\n <th i18n class=\"noif-lt-md\">last</th>\n <th i18n class=\"noif-lt-md\">email</th>\n <th i18n>roles</th>\n <th i18n 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 i18n-matTooltip\n matTooltip=\"Edit this user\"\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 i18n-matTooltip\n matTooltip=\"Delete this user\"\n color=\"warn\"\n (click)=\"deleteUser(user)\"\n >\n <mat-icon>remove_circle</mat-icon>\n </button>\n </td>\n <td>\n <img\n alt=\"avatar\"\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 id=\"paginator\" class=\"form-row\">\n <button\n type=\"button\"\n mat-icon-button\n color=\"warn\"\n i18n-matmatTooltip\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 <mat-expansion-panel\n id=\"editor\"\n [expanded]=\"active$ | async\"\n [disabled]=\"!(active$ | async)\"\n >\n <div *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 </mat-expansion-panel>\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#filters{grid-area:filters}div#list{grid-area:list}div#paginator{grid-area:paginator;justify-content:end}div#editor{grid-area:editor}div#container{display:grid;grid-template-rows:auto 1fr auto auto;grid-template-columns:1fr;grid-template-areas:\"filters\" \"list\" \"paginator\" \"editor\";gap:8px}@media only screen and (max-width: 959px){.noif-lt-md{display:none}}@media only screen and (min-width: 1920px){div#container{grid-template-rows:auto 1fr auto;grid-template-columns:1fr auto;grid-template-areas:\"filters filters\" \"list editor\" \"paginator .\"}}\n"] }]
894
- }], ctorParameters: function () { return [{ type: UserListRepository }, { type: DialogService }, { type: i2$2.GravatarService }]; } });
895
-
896
- class AuthJwtAdminModule {
897
- }
898
- AuthJwtAdminModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtAdminModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
899
- AuthJwtAdminModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtAdminModule, declarations: [AuthJwtRegistrationComponent,
900
- PasswordStrengthBarComponent,
901
- UserFilterComponent,
902
- UserListComponent,
903
- ConfirmDialogComponent,
904
- UserEditorComponent], imports: [CommonModule,
905
- HttpClientModule,
906
- FormsModule,
907
- RouterModule,
908
- ReactiveFormsModule,
909
- // material
910
- MatButtonModule,
911
- MatCardModule,
912
- MatCheckboxModule,
913
- MatDialogModule,
914
- MatExpansionModule,
915
- MatIconModule,
916
- MatInputModule,
917
- MatPaginatorModule,
918
- MatProgressBarModule,
919
- MatProgressSpinnerModule,
920
- MatSnackBarModule,
921
- MatTooltipModule,
922
- AuthJwtLoginModule,
923
- NgToolsModule], exports: [AuthJwtRegistrationComponent,
924
- PasswordStrengthBarComponent,
925
- UserFilterComponent,
926
- UserListComponent] });
927
- AuthJwtAdminModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtAdminModule, imports: [CommonModule,
928
- HttpClientModule,
929
- FormsModule,
930
- RouterModule,
931
- ReactiveFormsModule,
932
- // material
933
- MatButtonModule,
934
- MatCardModule,
935
- MatCheckboxModule,
936
- MatDialogModule,
937
- MatExpansionModule,
938
- MatIconModule,
939
- MatInputModule,
940
- MatPaginatorModule,
941
- MatProgressBarModule,
942
- MatProgressSpinnerModule,
943
- MatSnackBarModule,
944
- MatTooltipModule,
945
- AuthJwtLoginModule,
946
- NgToolsModule] });
947
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: AuthJwtAdminModule, decorators: [{
948
- type: NgModule,
949
- args: [{
950
- declarations: [
951
- AuthJwtRegistrationComponent,
952
- PasswordStrengthBarComponent,
953
- UserFilterComponent,
954
- UserListComponent,
955
- ConfirmDialogComponent,
956
- UserEditorComponent,
957
- ],
958
- imports: [
959
- CommonModule,
960
- HttpClientModule,
961
- FormsModule,
962
- RouterModule,
963
- ReactiveFormsModule,
964
- // material
965
- MatButtonModule,
966
- MatCardModule,
967
- MatCheckboxModule,
968
- MatDialogModule,
969
- MatExpansionModule,
970
- MatIconModule,
971
- MatInputModule,
972
- MatPaginatorModule,
973
- MatProgressBarModule,
974
- MatProgressSpinnerModule,
975
- MatSnackBarModule,
976
- MatTooltipModule,
977
- AuthJwtLoginModule,
978
- NgToolsModule
979
- ],
980
- exports: [
981
- AuthJwtRegistrationComponent,
982
- PasswordStrengthBarComponent,
983
- UserFilterComponent,
984
- UserListComponent
985
- ],
986
- }]
987
- }] });
988
-
989
- /*
990
- * Public API Surface of auth-jwt-admin
991
- */
992
-
993
- /**
994
- * Generated bundle index. Do not edit.
995
- */
996
-
997
- export { AuthJwtAccountService, AuthJwtAdminModule, AuthJwtRegistrationComponent, PasswordStrengthBarComponent, PasswordValidators, UserFilterComponent, UserListComponent, UserListRepository };
998
- //# sourceMappingURL=myrmidon-auth-jwt-admin.mjs.map