diff --git a/apps/red-ui/src/app/modules/admin/admin.module.ts b/apps/red-ui/src/app/modules/admin/admin.module.ts index 7151ac307..5e628823c 100644 --- a/apps/red-ui/src/app/modules/admin/admin.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin.module.ts @@ -34,7 +34,8 @@ import { ActiveFieldsListingComponent } from './dialogs/file-attributes-csv-impo import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component'; import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor'; import { ReportsScreenComponent } from './screens/reports/reports-screen.component'; -import { ResetPasswordDialogComponent } from './dialogs/reset-password-dialog/reset-password-dialog.component'; +import { ResetPasswordComponent } from './dialogs/add-edit-user-dialog/reset-password/reset-password.component'; +import { UserDetailsComponent } from './dialogs/add-edit-user-dialog/user-details/user-details.component'; const dialogs = [ AddEditDossierTemplateDialogComponent, @@ -45,8 +46,7 @@ const dialogs = [ SmtpAuthDialogComponent, AddEditUserDialogComponent, ConfirmDeleteUsersDialogComponent, - FileAttributesCsvImportDialogComponent, - ResetPasswordDialogComponent + FileAttributesCsvImportDialogComponent ]; const screens = [ @@ -73,6 +73,8 @@ const components = [ UsersStatsComponent, ActiveFieldsListingComponent, AdminSideNavComponent, + ResetPasswordComponent, + UserDetailsComponent, ...dialogs, ...screens diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.html index e7dbc94a4..17b725f7a 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.html +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/add-edit-user-dialog.component.html @@ -1,79 +1,17 @@
-
- {{ (user ? 'add-edit-user.title.edit' : 'add-edit-user.title.new') | translate }} -
+ -
-
-
- - -
- -
- - -
- -
- - -
- - - - - - -
- -
- - {{ 'roles.' + role | translate }} - -
-
- - -
- -
- - - - -
-
-
+ , @Inject(MAT_DIALOG_DATA) public user: User - ) { - const rolesControls = this.ROLES.reduce( - (prev, role) => ({ - ...prev, - [role]: [ - { - value: this.user && this.user.roles.indexOf(role) !== -1, - disabled: - this.user && - Object.keys(this._ROLE_REQUIREMENTS).reduce( - (value, key) => - value || - (role === this._ROLE_REQUIREMENTS[key] && - this.user.roles.indexOf(key) !== -1), - false - ) - } - ] - }), - {} - ); - this.userForm = this._formBuilder.group({ - firstName: [this.user?.firstName, Validators.required], - lastName: [this.user?.lastName, Validators.required], - email: [ - { value: this.user?.email, disabled: !!user }, - [Validators.required, Validators.email] - ], - // password: [this.user?.password, Validators.required], - ...rolesControls - }); - this._setRolesRequirements(); - } + ) {} - get changed(): boolean { - if (!this.user) return true; - - for (const key of Object.keys(this.userForm.getRawValue())) { - if (this.user[key] !== this.userForm.get(key).value) { - return true; - } - } - - return false; - } - - get activeRoles(): string[] { - return this.ROLES.reduce((acc, role) => { - if (this.userForm.get(role).value) { - acc.push(role); - } - return acc; - }, []); - } - - async save() { - this.dialogRef.close({ - action: this.user ? 'UPDATE' : 'CREATE', - user: { ...this.userForm.getRawValue(), roles: this.activeRoles } - }); - } - - async delete() { - this.dialogRef.close('DELETE'); - } - - resetPassword() { - // this._dialogService.openre; - this._dialogService.openDialog('resetPassword', null, { user: this.user }, (res: any) => { - console.log(res); - }); - } - - private _setRolesRequirements() { - for (const key of Object.keys(this._ROLE_REQUIREMENTS)) { - this.userForm.controls[key].valueChanges.subscribe(checked => { - if (checked) { - this.userForm.patchValue({ [this._ROLE_REQUIREMENTS[key]]: true }); - this.userForm.controls[this._ROLE_REQUIREMENTS[key]].disable(); - } else { - this.userForm.controls[this._ROLE_REQUIREMENTS[key]].enable(); - } - }); - } + toggleResetPassword() { + this.resettingPassword = !this.resettingPassword; } } diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.html new file mode 100644 index 000000000..fee0ff69f --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.html @@ -0,0 +1,26 @@ +
+ +
+
+
+ + +
+
+ +
+ + +
+
+
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.scss rename to apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.scss diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts new file mode 100644 index 000000000..5d01c27a4 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts @@ -0,0 +1,46 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { User, UserControllerService } from '@redaction/red-ui-http'; +import { UserService } from '../../../../../services/user.service'; +import { LoadingService } from '../../../../../services/loading.service'; + +@Component({ + selector: 'redaction-reset-password', + templateUrl: './reset-password.component.html', + styleUrls: ['./reset-password.component.scss'] +}) +export class ResetPasswordComponent { + passwordForm: FormGroup; + @Input() user: User; + @Output() toggleResetPassword = new EventEmitter(); + + constructor( + private readonly _formBuilder: FormBuilder, + private readonly _userControllerService: UserControllerService, + private readonly _userService: UserService, + private readonly _loadingService: LoadingService + ) { + this.passwordForm = this._formBuilder.group({ + temporaryPassword: [null, Validators.required] + }); + } + + get userName() { + return this._userService.getNameForId(this.user.userId); + } + + async save() { + this._loadingService.start(); + await this._userControllerService + .resetPassword( + { + password: this.passwordForm.get('temporaryPassword').value, + temporary: true + }, + this.user.userId + ) + .toPromise(); + this._loadingService.stop(); + this.toggleResetPassword.emit(); + } +} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.html new file mode 100644 index 000000000..3e8f0a829 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.html @@ -0,0 +1,66 @@ +
+ {{ (user ? 'add-edit-user.title.edit' : 'add-edit-user.title.new') | translate }} +
+ +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + {{ 'roles.' + role | translate }} + +
+
+ + +
+ +
+ + + + +
+
+
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.scss new file mode 100644 index 000000000..65fd1e545 --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.scss @@ -0,0 +1,7 @@ +.roles-wrapper { + display: grid; + grid-template-columns: 1fr 1fr; + grid-row-gap: 8px; + margin-top: 8px; + width: 300px; +} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts new file mode 100644 index 000000000..9e480468d --- /dev/null +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts @@ -0,0 +1,121 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { User, UserControllerService } from '@redaction/red-ui-http'; +import { AdminDialogService } from '../../../services/admin-dialog.service'; +import { LoadingService } from '../../../../../services/loading.service'; + +@Component({ + selector: 'redaction-user-details', + templateUrl: './user-details.component.html', + styleUrls: ['./user-details.component.scss'] +}) +export class UserDetailsComponent implements OnInit { + @Input() user: User; + @Output() toggleResetPassword = new EventEmitter(); + @Output() closeDialog = new EventEmitter(); + userForm: FormGroup; + readonly ROLES = ['RED_USER', 'RED_MANAGER', 'RED_USER_ADMIN', 'RED_ADMIN']; + private readonly _ROLE_REQUIREMENTS = { RED_MANAGER: 'RED_USER', RED_ADMIN: 'RED_USER_ADMIN' }; + + constructor( + private readonly _formBuilder: FormBuilder, + private readonly _dialogService: AdminDialogService, + private readonly _loadingService: LoadingService, + private readonly _userControllerService: UserControllerService + ) {} + + get changed(): boolean { + if (!this.user) return true; + + if (this.user.roles.length !== this.activeRoles.length) { + return true; + } + + for (const key of Object.keys(this.userForm.getRawValue())) { + const keyValue = this.userForm.get(key).value; + if (key.startsWith('RED_')) { + if (this.user.roles.includes(key) !== keyValue) { + return true; + } + } else if (this.user[key] !== keyValue) { + return true; + } + } + + return false; + } + + get activeRoles(): string[] { + return this.ROLES.reduce((acc, role) => { + if (this.userForm.get(role).value) { + acc.push(role); + } + return acc; + }, []); + } + + ngOnInit() { + const rolesControls = this.ROLES.reduce( + (prev, role) => ({ + ...prev, + [role]: [ + { + value: this.user && this.user.roles.indexOf(role) !== -1, + disabled: + this.user && + Object.keys(this._ROLE_REQUIREMENTS).reduce( + (value, key) => + value || + (role === this._ROLE_REQUIREMENTS[key] && + this.user.roles.indexOf(key) !== -1), + false + ) + } + ] + }), + {} + ); + this.userForm = this._formBuilder.group({ + firstName: [this.user?.firstName, Validators.required], + lastName: [this.user?.lastName, Validators.required], + email: [ + { value: this.user?.email, disabled: !!this.user }, + [Validators.required, Validators.email] + ], + ...rolesControls + }); + this._setRolesRequirements(); + } + + async save() { + this._loadingService.start(); + const userData = { ...this.userForm.getRawValue(), roles: this.activeRoles }; + + if (!this.user) { + await this._userControllerService.createUser(userData).toPromise(); + } else { + await this._userControllerService.updateProfile(userData, this.user.userId).toPromise(); + } + + this.closeDialog.emit(true); + } + + async delete() { + this._dialogService.openDialog('deleteUsers', null, [this.user], async () => { + this.closeDialog.emit(true); + }); + } + + private _setRolesRequirements() { + for (const key of Object.keys(this._ROLE_REQUIREMENTS)) { + this.userForm.controls[key].valueChanges.subscribe(checked => { + if (checked) { + this.userForm.patchValue({ [this._ROLE_REQUIREMENTS[key]]: true }); + this.userForm.controls[this._ROLE_REQUIREMENTS[key]].disable(); + } else { + this.userForm.controls[this._ROLE_REQUIREMENTS[key]].enable(); + } + }); + } + } +} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts index c02558f73..f2ce9fe8d 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts @@ -1,7 +1,8 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { User } from '@redaction/red-ui-http'; +import { User, UserControllerService } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; +import { LoadingService } from '../../../../services/loading.service'; @Component({ selector: 'redaction-confirm-delete-users-dialog', @@ -17,9 +18,11 @@ export class ConfirmDeleteUsersDialogComponent { dossiersCount: number; constructor( - @Inject(MAT_DIALOG_DATA) public users: User[], private readonly _appStateService: AppStateService, - public dialogRef: MatDialogRef + private readonly _loadingService: LoadingService, + private readonly _userControllerService: UserControllerService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public users: User[] ) { this.dossiersCount = this._appStateService.allDossiers.filter(dw => { for (const user of this.users) { @@ -41,6 +44,10 @@ export class ConfirmDeleteUsersDialogComponent { async deleteUser() { if (this.valid) { + this._loadingService.start(); + await this._userControllerService + .deleteUsers(this.users.map(u => u.userId)) + .toPromise(); this.dialogRef.close(true); } else { this.showToast = true; diff --git a/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.html deleted file mode 100644 index 05a0c1e57..000000000 --- a/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.html +++ /dev/null @@ -1 +0,0 @@ -

reset-password-dialog works!

diff --git a/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.spec.ts b/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.spec.ts deleted file mode 100644 index 00f5eaa74..000000000 --- a/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ResetPasswordDialogComponent } from './reset-password-dialog.component'; - -describe('ResetPasswordDialogComponent', () => { - let component: ResetPasswordDialogComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ResetPasswordDialogComponent] - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ResetPasswordDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.ts deleted file mode 100644 index b2451638a..000000000 --- a/apps/red-ui/src/app/modules/admin/dialogs/reset-password-dialog/reset-password-dialog.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'redaction-reset-password-dialog', - templateUrl: './reset-password-dialog.component.html', - styleUrls: ['./reset-password-dialog.component.scss'] -}) -export class ResetPasswordDialogComponent implements OnInit { - constructor() {} - - ngOnInit(): void { - console.log('do sth'); - } -} diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html index 4f54334e5..d70a11116 100644 --- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html @@ -131,7 +131,7 @@ type="dark-bg" >
imple } openAddEditUserDialog($event: MouseEvent, user?: User) { - this._dialogService.openDialog('addEditUser', $event, user, async result => { - if (result === 'DELETE') { - return this.openDeleteUserDialog([user]); - } - - this._loadingService.start(); - - if (result.action === 'CREATE') { - await this._userControllerService.createUser(result.user).toPromise(); - } else if (result.action === 'UPDATE') { - await this._userControllerService - .updateProfile(result.user, user.userId) - .toPromise(); - } - + this._dialogService.openDialog('addEditUser', $event, user, async () => { await this._loadData(); }); } - openDeleteUserDialog(users: User[], $event?: MouseEvent) { + openDeleteUsersDialog(users: User[], $event?: MouseEvent) { this._dialogService.openDialog('deleteUsers', $event, users, async () => { - this._loadingService.start(); - await this._userControllerService.deleteUsers(users.map(u => u.userId)).toPromise(); await this._loadData(); }); } @@ -90,7 +74,7 @@ export class UserListingScreenComponent extends BaseListingComponent imple } async bulkDelete() { - this.openDeleteUserDialog(this.allEntities.filter(u => this.isSelected(u))); + this.openDeleteUsersDialog(this.allEntities.filter(u => this.isSelected(u))); } trackById(index: number, user: User) { diff --git a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts index 465c15ceb..49d3c25f9 100644 --- a/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts +++ b/apps/red-ui/src/app/modules/admin/services/admin-dialog.service.ts @@ -10,12 +10,10 @@ import { SmtpAuthDialogComponent } from '../dialogs/smtp-auth-dialog/smtp-auth-d import { AddEditUserDialogComponent } from '../dialogs/add-edit-user-dialog/add-edit-user-dialog.component'; import { ConfirmDeleteUsersDialogComponent } from '../dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component'; import { FileAttributesCsvImportDialogComponent } from '../dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component'; -import { ResetPasswordDialogComponent } from '../dialogs/reset-password-dialog/reset-password-dialog.component'; import { ComponentType } from '@angular/cdk/portal'; type DialogType = | 'confirm' - | 'resetPassword' | 'addEditDictionary' | 'editColor' | 'addEditFileAttribute' @@ -50,10 +48,6 @@ export class AdminDialogService { confirm: { component: ConfirmationDialogComponent }, - resetPassword: { - component: ResetPasswordDialogComponent, - dialogConfig: { autoFocus: true } - }, addEditDictionary: { component: AddEditDictionaryDialogComponent, dialogConfig: { autoFocus: true } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index f8490173d..a14f2f188 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -339,6 +339,16 @@ "formula": "Formula" } }, + "reset-password-dialog": { + "header": "Set Temporary Password for {{userName}}", + "form": { + "password": "Temporary password" + }, + "actions": { + "save": "Save", + "cancel": "Cancel" + } + }, "comment": "Comment", "comments": { "add-comment": "Enter comment", diff --git a/apps/red-ui/src/assets/styles/red-page-layout.scss b/apps/red-ui/src/assets/styles/red-page-layout.scss index aee7c369e..436dc08f1 100644 --- a/apps/red-ui/src/assets/styles/red-page-layout.scss +++ b/apps/red-ui/src/assets/styles/red-page-layout.scss @@ -364,3 +364,7 @@ section.settings { .d-flex { display: flex; } + +.cdk-overlay-container { + z-index: 800; +}