Pull request #234: RED-684

Merge in RED/ui from RED-684 to master

* commit '542f0a282d24bce28f1bcbf68609a35349da82ed':
  Reset password, refactored user listing dialogs
  Refactored admin dialog service
This commit is contained in:
Adina Teudan 2021-07-08 13:55:54 +02:00
commit a9a6026f37
30 changed files with 589 additions and 608 deletions

View File

@ -34,6 +34,8 @@ import { ActiveFieldsListingComponent } from './dialogs/file-attributes-csv-impo
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component'; import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor'; import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
import { ReportsScreenComponent } from './screens/reports/reports-screen.component'; import { ReportsScreenComponent } from './screens/reports/reports-screen.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 = [ const dialogs = [
AddEditDossierTemplateDialogComponent, AddEditDossierTemplateDialogComponent,
@ -44,8 +46,7 @@ const dialogs = [
SmtpAuthDialogComponent, SmtpAuthDialogComponent,
AddEditUserDialogComponent, AddEditUserDialogComponent,
ConfirmDeleteUsersDialogComponent, ConfirmDeleteUsersDialogComponent,
FileAttributesCsvImportDialogComponent, FileAttributesCsvImportDialogComponent
AdminSideNavComponent
]; ];
const screens = [ const screens = [
@ -60,7 +61,8 @@ const screens = [
LicenseInformationScreenComponent, LicenseInformationScreenComponent,
UserListingScreenComponent, UserListingScreenComponent,
WatermarkScreenComponent, WatermarkScreenComponent,
SmtpConfigScreenComponent SmtpConfigScreenComponent,
ReportsScreenComponent
]; ];
const components = [ const components = [
@ -70,13 +72,16 @@ const components = [
ComboSeriesVerticalComponent, ComboSeriesVerticalComponent,
UsersStatsComponent, UsersStatsComponent,
ActiveFieldsListingComponent, ActiveFieldsListingComponent,
AdminSideNavComponent,
ResetPasswordComponent,
UserDetailsComponent,
...dialogs, ...dialogs,
...screens ...screens
]; ];
@NgModule({ @NgModule({
declarations: [...components, ReportsScreenComponent], declarations: [...components],
providers: [AdminDialogService], providers: [AdminDialogService],
imports: [ imports: [
CommonModule, CommonModule,

View File

@ -3,6 +3,8 @@ import { PermissionsService } from '@services/permissions.service';
import { AppStateService } from '@state/app-state.service'; import { AppStateService } from '@state/app-state.service';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { DossierTemplateControllerService } from '@redaction/red-ui-http';
import { LoadingService } from '../../../../services/loading.service';
@Component({ @Component({
selector: 'redaction-dossier-template-actions', selector: 'redaction-dossier-template-actions',
@ -16,6 +18,8 @@ export class DossierTemplateActionsComponent {
constructor( constructor(
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
private readonly _dossierTemplateControllerService: DossierTemplateControllerService,
private readonly _loadingService: LoadingService,
private readonly _router: Router, private readonly _router: Router,
readonly permissionsService: PermissionsService readonly permissionsService: PermissionsService
) { ) {
@ -29,21 +33,22 @@ export class DossierTemplateActionsComponent {
} }
openEditDossierTemplateDialog($event: any) { openEditDossierTemplateDialog($event: any) {
$event.stopPropagation(); this._dialogService.openDialog(
this._dialogService.openAddEditDossierTemplateDialog( 'addEditDossierTemplate',
$event,
this.dossierTemplate, this.dossierTemplate,
async newDossierTemplate => { () => {
if (newDossierTemplate && this.loadDossierTemplatesData) { this.loadDossierTemplatesData?.emit();
this.loadDossierTemplatesData.emit();
}
} }
); );
} }
openDeleteDossierTemplateDialog($event?: MouseEvent) { openDeleteDossierTemplateDialog($event?: MouseEvent) {
$event?.stopPropagation(); this._dialogService.openDialog('confirm', $event, null, async () => {
this._loadingService.start();
this._dialogService.openDeleteDossierTemplateDialog(this.dossierTemplate, async () => { await this._dossierTemplateControllerService
.deleteDossierTemplates([this.dossierTemplateId])
.toPromise();
await this._appStateService.loadAllDossierTemplates(); await this._appStateService.loadAllDossierTemplates();
await this._appStateService.loadDictionaryData(); await this._appStateService.loadDictionaryData();
await this._router.navigate(['main', 'admin']); await this._router.navigate(['main', 'admin']);

View File

@ -90,7 +90,7 @@ export class AddEditDictionaryDialogComponent {
} }
observable.subscribe( observable.subscribe(
() => this._dialogRef.close(this.dictionary ? null : typeValue), () => this._dialogRef.close(true),
error => { error => {
if (error.status === 409) { if (error.status === 409) {
this._notifyError('add-edit-dictionary.error.dictionary-already-exists'); this._notifyError('add-edit-dictionary.error.dictionary-already-exists');

View File

@ -1,72 +1,17 @@
<section class="dialog"> <section class="dialog">
<div class="dialog-header heading-l"> <redaction-user-details
{{ (user ? 'add-edit-user.title.edit' : 'add-edit-user.title.new') | translate }} (closeDialog)="dialogRef.close($event)"
</div> (toggleResetPassword)="toggleResetPassword()"
*ngIf="!resettingPassword"
[user]="user"
></redaction-user-details>
<form (submit)="save()" [formGroup]="userForm"> <redaction-reset-password
<div class="dialog-content"> (close)="dialogRef.close($event)"
<div class="red-input-group required w-300"> (toggleResetPassword)="toggleResetPassword()"
<label translate="add-edit-user.form.first-name"></label> *ngIf="resettingPassword"
<input formControlName="firstName" name="firstName" type="text" /> [user]="user"
</div> ></redaction-reset-password>
<div class="red-input-group required w-300">
<label translate="add-edit-user.form.last-name"></label>
<input formControlName="lastName" name="lastName" type="text" />
</div>
<div class="red-input-group required w-300">
<label translate="add-edit-user.form.email"></label>
<input formControlName="email" name="email" type="email" />
</div>
<!-- <div class="red-input-group required w-300">-->
<!-- <label translate="add-edit-user.form.password"></label>-->
<!-- <input formControlName="password" name="password" type="password" />-->
<!-- </div>-->
<div class="red-input-group">
<label translate="add-edit-user.form.role"></label>
<div class="roles-wrapper">
<mat-checkbox
*ngFor="let role of ROLES"
[formControlName]="role"
color="primary"
>
{{ 'roles.' + role | translate }}
</mat-checkbox>
</div>
</div>
</div>
<div class="dialog-actions">
<button
[disabled]="userForm.invalid || !changed"
color="primary"
mat-flat-button
type="submit"
>
{{
(user ? 'add-edit-user.actions.save-changes' : 'add-edit-user.actions.save')
| translate
}}
</button>
<redaction-icon-button
(action)="delete()"
*ngIf="user"
icon="red:trash"
text="add-edit-user.actions.delete"
type="show-bg"
></redaction-icon-button>
<div
class="all-caps-label cancel"
mat-dialog-close
translate="add-edit-user.actions.cancel"
></div>
</div>
</form>
<redaction-circle-button <redaction-circle-button
class="dialog-close" class="dialog-close"

View File

@ -1,7 +0,0 @@
.roles-wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
grid-row-gap: 8px;
margin-top: 8px;
width: 300px;
}

View File

@ -1,8 +1,6 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { User } from '@redaction/red-ui-http'; import { User } from '@redaction/red-ui-http';
import { UserService } from '@services/user.service';
@Component({ @Component({
selector: 'redaction-add-edit-user-dialog', selector: 'redaction-add-edit-user-dialog',
@ -10,91 +8,14 @@ import { UserService } from '@services/user.service';
styleUrls: ['./add-edit-user-dialog.component.scss'] styleUrls: ['./add-edit-user-dialog.component.scss']
}) })
export class AddEditUserDialogComponent { export class AddEditUserDialogComponent {
userForm: FormGroup; resettingPassword = false;
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( constructor(
private readonly _formBuilder: FormBuilder,
private readonly _userService: UserService,
public dialogRef: MatDialogRef<AddEditUserDialogComponent>, public dialogRef: MatDialogRef<AddEditUserDialogComponent>,
@Inject(MAT_DIALOG_DATA) public user: User @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 { toggleResetPassword() {
if (!this.user) return true; this.resettingPassword = !this.resettingPassword;
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');
}
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();
}
});
}
} }
} }

View File

@ -0,0 +1,26 @@
<div
[translateParams]="{ userName: userName }"
[translate]="'reset-password-dialog.header'"
class="dialog-header heading-l"
></div>
<form (submit)="save()" [formGroup]="passwordForm">
<div class="dialog-content">
<div class="red-input-group required w-300">
<label translate="reset-password-dialog.form.password"></label>
<input formControlName="temporaryPassword" name="temporaryPassword" type="password" />
</div>
</div>
<div class="dialog-actions">
<button [disabled]="passwordForm.invalid" color="primary" mat-flat-button type="submit">
{{ 'reset-password-dialog.actions.save' | translate }}
</button>
<div
(click)="toggleResetPassword.emit()"
class="all-caps-label cancel"
translate="reset-password-dialog.actions.cancel"
></div>
</div>
</form>

View File

@ -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();
}
}

View File

@ -0,0 +1,66 @@
<div class="dialog-header heading-l">
{{ (user ? 'add-edit-user.title.edit' : 'add-edit-user.title.new') | translate }}
</div>
<form (submit)="save()" [formGroup]="userForm">
<div class="dialog-content">
<div class="red-input-group required w-300">
<label translate="add-edit-user.form.first-name"></label>
<input formControlName="firstName" name="firstName" type="text" />
</div>
<div class="red-input-group required w-300">
<label translate="add-edit-user.form.last-name"></label>
<input formControlName="lastName" name="lastName" type="text" />
</div>
<div class="red-input-group required w-300">
<label translate="add-edit-user.form.email"></label>
<input formControlName="email" name="email" type="email" />
</div>
<div class="red-input-group">
<label translate="add-edit-user.form.role"></label>
<div class="roles-wrapper">
<mat-checkbox *ngFor="let role of ROLES" [formControlName]="role" color="primary">
{{ 'roles.' + role | translate }}
</mat-checkbox>
</div>
</div>
<div
(click)="toggleResetPassword.emit()"
*ngIf="!!user"
class="mt-24 fit-content link-action"
translate="add-edit-user.form.reset-password"
></div>
</div>
<div class="dialog-actions">
<button
[disabled]="userForm.invalid || !changed"
color="primary"
mat-flat-button
type="submit"
>
{{
(user ? 'add-edit-user.actions.save-changes' : 'add-edit-user.actions.save')
| translate
}}
</button>
<redaction-icon-button
(action)="delete()"
*ngIf="user"
icon="red:trash"
text="add-edit-user.actions.delete"
type="show-bg"
></redaction-icon-button>
<div
class="all-caps-label cancel"
mat-dialog-close
translate="add-edit-user.actions.cancel"
></div>
</div>
</form>

View File

@ -0,0 +1,7 @@
.roles-wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
grid-row-gap: 8px;
margin-top: 8px;
width: 300px;
}

View File

@ -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<any>();
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();
}
});
}
}
}

View File

@ -1,5 +1,4 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { FileAttributeConfig } from '@redaction/red-ui-http'; import { FileAttributeConfig } from '@redaction/red-ui-http';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
@ -17,7 +16,6 @@ export class ConfirmDeleteFileAttributeDialogComponent {
showToast = false; showToast = false;
constructor( constructor(
private readonly _appStateService: AppStateService,
public dialogRef: MatDialogRef<ConfirmDeleteFileAttributeDialogComponent>, public dialogRef: MatDialogRef<ConfirmDeleteFileAttributeDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: FileAttributeConfig @Inject(MAT_DIALOG_DATA) public data: FileAttributeConfig
) { ) {

View File

@ -1,7 +1,8 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; 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 { AppStateService } from '@state/app-state.service';
import { LoadingService } from '../../../../services/loading.service';
@Component({ @Component({
selector: 'redaction-confirm-delete-users-dialog', selector: 'redaction-confirm-delete-users-dialog',
@ -17,9 +18,11 @@ export class ConfirmDeleteUsersDialogComponent {
dossiersCount: number; dossiersCount: number;
constructor( constructor(
@Inject(MAT_DIALOG_DATA) public users: User[],
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
public dialogRef: MatDialogRef<ConfirmDeleteUsersDialogComponent> private readonly _loadingService: LoadingService,
private readonly _userControllerService: UserControllerService,
public dialogRef: MatDialogRef<ConfirmDeleteUsersDialogComponent>,
@Inject(MAT_DIALOG_DATA) public users: User[]
) { ) {
this.dossiersCount = this._appStateService.allDossiers.filter(dw => { this.dossiersCount = this._appStateService.allDossiers.filter(dw => {
for (const user of this.users) { for (const user of this.users) {
@ -41,6 +44,10 @@ export class ConfirmDeleteUsersDialogComponent {
async deleteUser() { async deleteUser() {
if (this.valid) { if (this.valid) {
this._loadingService.start();
await this._userControllerService
.deleteUsers(this.users.map(u => u.userId))
.toPromise();
this.dialogRef.close(true); this.dialogRef.close(true);
} else { } else {
this.showToast = true; this.showToast = true;

View File

@ -87,7 +87,3 @@
</div> </div>
</div> </div>
</section> </section>
<redaction-full-page-loading-indicator
[displayed]="!viewReady"
></redaction-full-page-loading-indicator>

View File

@ -1,21 +1,24 @@
import { Component, Injector } from '@angular/core'; import { Component, Injector, OnInit } from '@angular/core';
import { AppStateService } from '@state/app-state.service'; import { AppStateService } from '@state/app-state.service';
import { Colors, DictionaryControllerService } from '@redaction/red-ui-http'; import { Colors, DictionaryControllerService } from '@redaction/red-ui-http';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { BaseListingComponent } from '@shared/base/base-listing.component'; import { BaseListingComponent } from '@shared/base/base-listing.component';
import { LoadingService } from '../../../../services/loading.service';
@Component({ @Component({
selector: 'redaction-default-colors-screen', selector: 'redaction-default-colors-screen',
templateUrl: './default-colors-screen.component.html', templateUrl: './default-colors-screen.component.html',
styleUrls: ['./default-colors-screen.component.scss'] styleUrls: ['./default-colors-screen.component.scss']
}) })
export class DefaultColorsScreenComponent extends BaseListingComponent<{ export class DefaultColorsScreenComponent
key: string; extends BaseListingComponent<{
value: string; key: string;
}> { value: string;
viewReady = false; }>
implements OnInit
{
protected readonly _sortKey = 'default-colors'; protected readonly _sortKey = 'default-colors';
private _colorsObj: Colors; private _colorsObj: Colors;
@ -24,35 +27,43 @@ export class DefaultColorsScreenComponent extends BaseListingComponent<{
private readonly _activatedRoute: ActivatedRoute, private readonly _activatedRoute: ActivatedRoute,
private readonly _dictionaryControllerService: DictionaryControllerService, private readonly _dictionaryControllerService: DictionaryControllerService,
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _loadingService: LoadingService,
readonly permissionsService: PermissionsService, readonly permissionsService: PermissionsService,
protected readonly _injector: Injector protected readonly _injector: Injector
) { ) {
super(_injector); super(_injector);
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId); _appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
this._loadColors(); }
async ngOnInit() {
await this._loadColors();
} }
openEditColorDialog($event: any, color: { key: string; value: string }) { openEditColorDialog($event: any, color: { key: string; value: string }) {
$event.stopPropagation(); this._dialogService.openDialog(
this._dialogService.openEditColorsDialog( 'editColor',
this._colorsObj, $event,
color.key, {
this._appStateService.activeDossierTemplateId, colors: this._colorsObj,
async () => this._loadColors() colorKey: color.key,
dossierTemplateId: this._appStateService.activeDossierTemplateId
},
async () => {
await this._loadColors();
}
); );
} }
private _loadColors() { private async _loadColors() {
this._dictionaryControllerService this._loadingService.start();
const data = await this._dictionaryControllerService
.getColors(this._appStateService.activeDossierTemplateId) .getColors(this._appStateService.activeDossierTemplateId)
.toPromise() .toPromise();
.then(data => { this._colorsObj = data;
this._colorsObj = data; this.allEntities = Object.keys(data).map(key => ({
this.allEntities = Object.keys(data).map(key => ({ key,
key, value: data[key]
value: data[key] }));
})); this._loadingService.stop();
this.viewReady = true;
});
} }
} }

View File

@ -59,12 +59,28 @@ export class DictionaryListingScreenComponent
} }
openDeleteDictionariesDialog($event?: MouseEvent, types = this.selectedEntitiesIds) { openDeleteDictionariesDialog($event?: MouseEvent, types = this.selectedEntitiesIds) {
$event?.stopPropagation(); this._dialogService.openDialog('confirm', $event, null, async () => {
this._dialogService.openDeleteDictionariesDialog( this._loadingService.start();
types, await this._dictionaryControllerService
this._appStateService.activeDossierTemplateId, .deleteTypes(types, this._appStateService.activeDossierTemplateId)
.toPromise();
this.selectedEntitiesIds = [];
await this._appStateService.loadDictionaryData();
this._loadDictionaryData(false);
this._calculateData();
this._loadingService.stop();
});
}
openAddEditDictionaryDialog($event?: MouseEvent, dictionary?: TypeValueWrapper) {
this._dialogService.openDialog(
'addEditDictionary',
$event,
{
dictionary,
dossierTemplateId: this._appStateService.activeDossierTemplateId
},
async () => { async () => {
this.selectedEntitiesIds = [];
this._loadingService.start(); this._loadingService.start();
await this._appStateService.loadDictionaryData(); await this._appStateService.loadDictionaryData();
this._loadDictionaryData(false); this._loadDictionaryData(false);
@ -74,23 +90,6 @@ export class DictionaryListingScreenComponent
); );
} }
openAddEditDictionaryDialog($event?: MouseEvent, dict?: TypeValueWrapper) {
$event?.stopPropagation();
this._dialogService.openAddEditDictionaryDialog(
dict,
this._appStateService.activeDossierTemplateId,
async newDictionary => {
if (newDictionary) {
this._loadingService.start();
await this._appStateService.loadDictionaryData();
this._loadDictionaryData(false);
this._calculateData();
this._loadingService.stop();
}
}
);
}
private _loadDictionaryData(loadEntries = true): void { private _loadDictionaryData(loadEntries = true): void {
const appStateDictionaryData = const appStateDictionaryData =
this._appStateService.dictionaryData[this._appStateService.activeDossierTemplateId]; this._appStateService.dictionaryData[this._appStateService.activeDossierTemplateId];

View File

@ -10,6 +10,7 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component'; import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionarySaveService } from '@shared/services/dictionary-save.service'; import { DictionarySaveService } from '@shared/services/dictionary-save.service';
import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper'; import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper';
import { LoadingService } from '../../../../services/loading.service';
@Component({ @Component({
selector: 'redaction-dictionary-overview-screen', selector: 'redaction-dictionary-overview-screen',
@ -32,7 +33,8 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _router: Router, private readonly _router: Router,
private readonly _activatedRoute: ActivatedRoute, private readonly _activatedRoute: ActivatedRoute,
private readonly _appStateService: AppStateService private readonly _appStateService: AppStateService,
private readonly _loadingService: LoadingService
) { ) {
super(_translateService); super(_translateService);
this._appStateService.activateDictionary( this._appStateService.activateDictionary(
@ -54,12 +56,17 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple
} }
openEditDictionaryDialog($event: any) { openEditDictionaryDialog($event: any) {
$event.stopPropagation(); this._dialogService.openDialog(
this._dialogService.openAddEditDictionaryDialog( 'addEditDictionary',
this.dictionary, $event,
this.dictionary.dossierTemplateId, {
dictionary: this.dictionary,
dossierTemplateId: this.dictionary.dossierTemplateId
},
async () => { async () => {
this._loadingService.start();
await this._appStateService.loadDictionaryData(); await this._appStateService.loadDictionaryData();
this._loadingService.stop();
} }
); );
} }
@ -67,20 +74,19 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple
openDeleteDictionaryDialog($event?: MouseEvent) { openDeleteDictionaryDialog($event?: MouseEvent) {
$event?.stopPropagation(); $event?.stopPropagation();
this._dialogService.openDeleteDictionariesDialog( this._dialogService.openDialog('confirm', $event, null, async () => {
[this.dictionary.type], await this._dictionaryControllerService
this.dictionary.dossierTemplateId, .deleteTypes([this.dictionary.type], this.dictionary.dossierTemplateId)
async () => { .toPromise();
await this._appStateService.loadDictionaryData(); await this._appStateService.loadDictionaryData();
await this._router.navigate([ await this._router.navigate([
'/main', '/main',
'admin', 'admin',
'dossier-templates', 'dossier-templates',
this._appStateService.activeDossierTemplateId, this._appStateService.activeDossierTemplateId,
'dictionaries' 'dictionaries'
]); ]);
} });
);
} }
download(): void { download(): void {

View File

@ -34,7 +34,7 @@
}} }}
</span> </span>
<ng-container *ngIf="areSomeEntitiesSelected && !loading"> <ng-container *ngIf="areSomeEntitiesSelected">
<redaction-circle-button <redaction-circle-button
(action)="openDeleteTemplatesDialog($event)" (action)="openDeleteTemplatesDialog($event)"
*ngIf="permissionsService.isAdmin()" *ngIf="permissionsService.isAdmin()"
@ -44,8 +44,6 @@
></redaction-circle-button> ></redaction-circle-button>
</ng-container> </ng-container>
<mat-spinner *ngIf="loading" diameter="15"></mat-spinner>
<div class="actions flex-1"> <div class="actions flex-1">
<redaction-input-with-action <redaction-input-with-action
[form]="searchForm" [form]="searchForm"

View File

@ -5,6 +5,8 @@ import { UserPreferenceService } from '@services/user-preference.service';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { BaseListingComponent } from '@shared/base/base-listing.component'; import { BaseListingComponent } from '@shared/base/base-listing.component';
import { DossierTemplateModelWrapper } from '../../../../models/file/dossier-template-model.wrapper'; import { DossierTemplateModelWrapper } from '../../../../models/file/dossier-template-model.wrapper';
import { LoadingService } from '../../../../services/loading.service';
import { DossierTemplateControllerService } from '@redaction/red-ui-http';
@Component({ @Component({
selector: 'redaction-dossier-templates-listing-screen', selector: 'redaction-dossier-templates-listing-screen',
@ -15,7 +17,6 @@ export class DossierTemplatesListingScreenComponent
extends BaseListingComponent<DossierTemplateModelWrapper> extends BaseListingComponent<DossierTemplateModelWrapper>
implements OnInit implements OnInit
{ {
loading = false;
protected readonly _searchKey = 'name'; protected readonly _searchKey = 'name';
protected readonly _selectionKey = 'dossierTemplateId'; protected readonly _selectionKey = 'dossierTemplateId';
protected readonly _sortKey = 'dossier-templates-listing'; protected readonly _sortKey = 'dossier-templates-listing';
@ -23,9 +24,11 @@ export class DossierTemplatesListingScreenComponent
constructor( constructor(
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
private readonly _loadingService: LoadingService,
private readonly _dossierTemplateControllerService: DossierTemplateControllerService,
protected readonly _injector: Injector,
readonly permissionsService: PermissionsService, readonly permissionsService: PermissionsService,
readonly userPreferenceService: UserPreferenceService, readonly userPreferenceService: UserPreferenceService
protected readonly _injector: Injector
) { ) {
super(_injector); super(_injector);
} }
@ -35,34 +38,38 @@ export class DossierTemplatesListingScreenComponent
} }
openDeleteTemplatesDialog($event?: MouseEvent) { openDeleteTemplatesDialog($event?: MouseEvent) {
$event?.stopPropagation(); return this._dialogService.openDialog('confirm', $event, null, async () => {
this._loadingService.start();
this._dialogService.openBulkDeleteDossierTemplatesDialog( await this._dossierTemplateControllerService
this.selectedEntitiesIds, .deleteDossierTemplates(this.selectedEntitiesIds)
async () => { .toPromise();
this.selectedEntitiesIds = []; this.selectedEntitiesIds = [];
this.loading = true; await this._appStateService.loadAllDossierTemplates();
await this._appStateService.loadAllDossierTemplates(); await this._appStateService.loadDictionaryData();
await this._appStateService.loadDictionaryData(); this.loadDossierTemplatesData();
this.loadDossierTemplatesData(); });
this.loading = false;
}
);
} }
loadDossierTemplatesData() { loadDossierTemplatesData() {
this._loadingService.start();
this._appStateService.reset(); this._appStateService.reset();
this.allEntities = this._appStateService.dossierTemplates; this.allEntities = this._appStateService.dossierTemplates;
this._executeSearchImmediately(); this._executeSearchImmediately();
this._loadDossierTemplateStats(); this._loadDossierTemplateStats();
this._loadingService.stop();
} }
openAddDossierTemplateDialog() { openAddDossierTemplateDialog() {
this._dialogService.openAddEditDossierTemplateDialog(null, async newDossierTemplate => { this._dialogService.openDialog(
if (newDossierTemplate) { 'addEditDossierTemplate',
this.loadDossierTemplatesData(); null,
null,
async newDossierTemplate => {
if (newDossierTemplate) {
this.loadDossierTemplatesData();
}
} }
}); );
} }
private _loadDossierTemplateStats() { private _loadDossierTemplateStats() {

View File

@ -43,8 +43,6 @@
> >
</redaction-circle-button> </redaction-circle-button>
<mat-spinner *ngIf="loading" diameter="15"></mat-spinner>
<div class="attributes-actions-container"> <div class="attributes-actions-container">
<redaction-input-with-action <redaction-input-with-action
[form]="searchForm" [form]="searchForm"
@ -204,7 +202,3 @@
<div class="right-container"></div> <div class="right-container"></div>
</div> </div>
</section> </section>
<redaction-full-page-loading-indicator
[displayed]="!viewReady"
></redaction-full-page-loading-indicator>

View File

@ -9,6 +9,7 @@ import { AppStateService } from '@state/app-state.service';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { BaseListingComponent } from '@shared/base/base-listing.component'; import { BaseListingComponent } from '@shared/base/base-listing.component';
import { LoadingService } from '../../../../services/loading.service';
@Component({ @Component({
selector: 'redaction-file-attributes-listing-screen', selector: 'redaction-file-attributes-listing-screen',
@ -19,8 +20,6 @@ export class FileAttributesListingScreenComponent
extends BaseListingComponent<FileAttributeConfig> extends BaseListingComponent<FileAttributeConfig>
implements OnInit implements OnInit
{ {
viewReady = false;
loading = false;
protected readonly _searchKey = 'label'; protected readonly _searchKey = 'label';
protected readonly _selectionKey = 'id'; protected readonly _selectionKey = 'id';
protected readonly _sortKey = 'file-attributes-listing'; protected readonly _sortKey = 'file-attributes-listing';
@ -34,6 +33,7 @@ export class FileAttributesListingScreenComponent
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
private readonly _activatedRoute: ActivatedRoute, private readonly _activatedRoute: ActivatedRoute,
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _loadingService: LoadingService,
protected readonly _injector: Injector protected readonly _injector: Injector
) { ) {
super(_injector); super(_injector);
@ -47,12 +47,12 @@ export class FileAttributesListingScreenComponent
} }
openAddEditAttributeDialog($event: MouseEvent, fileAttribute?: FileAttributeConfig) { openAddEditAttributeDialog($event: MouseEvent, fileAttribute?: FileAttributeConfig) {
$event.stopPropagation(); this._dialogService.openDialog(
this._dialogService.openAddEditFileAttributeDialog( 'addEditFileAttribute',
fileAttribute, $event,
this._appStateService.activeDossierTemplateId, { fileAttribute, dossierTemplateId: this._appStateService.activeDossierTemplateId },
async (newValue: FileAttributeConfig) => { async newValue => {
this.loading = true; this._loadingService.start();
await this._fileAttributesService await this._fileAttributesService
.setFileAttributesConfiguration( .setFileAttributesConfiguration(
newValue, newValue,
@ -65,40 +65,39 @@ export class FileAttributesListingScreenComponent
} }
openConfirmDeleteAttributeDialog($event: MouseEvent, fileAttribute?: FileAttributeConfig) { openConfirmDeleteAttributeDialog($event: MouseEvent, fileAttribute?: FileAttributeConfig) {
$event.stopPropagation(); this._dialogService.openDialog('deleteFileAttribute', $event, fileAttribute, async () => {
this._dialogService.openConfirmDeleteFileAttributeDialog( this._loadingService.start();
fileAttribute, if (fileAttribute) {
this._appStateService.activeDossierTemplateId, await this._fileAttributesService
async () => { .deleteFileAttribute(
this.loading = true; this._appStateService.activeDossierTemplateId,
if (fileAttribute) { fileAttribute.id
await this._fileAttributesService )
.deleteFileAttribute( .toPromise();
this._appStateService.activeDossierTemplateId, } else {
fileAttribute.id await this._fileAttributesService
) .deleteFileAttributes(
.toPromise(); this.selectedEntitiesIds,
} else { this._appStateService.activeDossierTemplateId
await this._fileAttributesService )
.deleteFileAttributes( .toPromise();
this.selectedEntitiesIds,
this._appStateService.activeDossierTemplateId
)
.toPromise();
}
await this._loadData();
} }
); await this._loadData();
});
} }
importCSV(files: FileList | File[]) { importCSV(files: FileList | File[]) {
const csvFile = files[0]; const csv = files[0];
this._fileInput.nativeElement.value = null; this._fileInput.nativeElement.value = null;
this._dialogService.openImportFileAttributeCSVDialog( this._dialogService.openDialog(
csvFile, 'importFileAttributes',
this._appStateService.activeDossierTemplateId, null,
this._existingConfiguration, {
csv,
dossierTemplateId: this._appStateService.activeDossierTemplateId,
existingConfiguration: this._existingConfiguration
},
async () => { async () => {
await this._loadData(); await this._loadData();
} }
@ -107,6 +106,7 @@ export class FileAttributesListingScreenComponent
private async _loadData() { private async _loadData() {
try { try {
this._loadingService.start();
const response = await this._fileAttributesService const response = await this._fileAttributesService
.getFileAttributesConfiguration(this._appStateService.activeDossierTemplateId) .getFileAttributesConfiguration(this._appStateService.activeDossierTemplateId)
.toPromise(); .toPromise();
@ -115,8 +115,7 @@ export class FileAttributesListingScreenComponent
} catch (e) { } catch (e) {
} finally { } finally {
this._executeSearchImmediately(); this._executeSearchImmediately();
this.viewReady = true; this._loadingService.stop();
this.loading = false;
} }
} }
} }

View File

@ -79,8 +79,4 @@
</div> </div>
</section> </section>
<redaction-full-page-loading-indicator
[displayed]="!viewReady"
></redaction-full-page-loading-indicator>
<input #fileInput (change)="uploadFile($event)" hidden type="file" /> <input #fileInput (change)="uploadFile($event)" hidden type="file" />

View File

@ -4,6 +4,7 @@ import { AppStateService } from '../../../../state/app-state.service';
import { ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http'; import { ReportTemplate, ReportTemplateControllerService } from '@redaction/red-ui-http';
import { download } from '../../../../utils/file-download-utils'; import { download } from '../../../../utils/file-download-utils';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { LoadingService } from '../../../../services/loading.service';
@Component({ @Component({
selector: 'redaction-reports-screen', selector: 'redaction-reports-screen',
@ -11,7 +12,6 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
styleUrls: ['./reports-screen.component.scss'] styleUrls: ['./reports-screen.component.scss']
}) })
export class ReportsScreenComponent implements OnInit { export class ReportsScreenComponent implements OnInit {
viewReady = false;
placeholders: string[] = [ placeholders: string[] = [
'report', 'report',
'predefined placeholder 1', 'predefined placeholder 1',
@ -26,7 +26,8 @@ export class ReportsScreenComponent implements OnInit {
private readonly _activatedRoute: ActivatedRoute, private readonly _activatedRoute: ActivatedRoute,
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
private readonly _reportTemplateService: ReportTemplateControllerService, private readonly _reportTemplateService: ReportTemplateControllerService,
private readonly _dialogService: AdminDialogService private readonly _dialogService: AdminDialogService,
private readonly _loadingService: LoadingService
) { ) {
this._appStateService.activateDossierTemplate( this._appStateService.activateDossierTemplate(
_activatedRoute.snapshot.params.dossierTemplateId _activatedRoute.snapshot.params.dossierTemplateId
@ -39,11 +40,11 @@ export class ReportsScreenComponent implements OnInit {
async ngOnInit() { async ngOnInit() {
await this._loadReportTemplates(); await this._loadReportTemplates();
this.viewReady = true; this._loadingService.stop();
} }
async uploadFile($event) { async uploadFile($event) {
this.viewReady = false; this._loadingService.start();
const file = $event.target.files[0]; const file = $event.target.files[0];
await this._reportTemplateService await this._reportTemplateService
@ -52,7 +53,6 @@ export class ReportsScreenComponent implements OnInit {
this._fileInput.nativeElement.value = null; this._fileInput.nativeElement.value = null;
await this._loadReportTemplates(); await this._loadReportTemplates();
this.viewReady = true;
} }
async download(template: ReportTemplate) { async download(template: ReportTemplate) {
@ -63,18 +63,20 @@ export class ReportsScreenComponent implements OnInit {
} }
deleteTemplate(template: ReportTemplate) { deleteTemplate(template: ReportTemplate) {
this._dialogService.openDeleteReportTemplateDialog( this._dialogService.openDialog('confirm', null, null, async () => {
template.templateId, this._loadingService.start();
template.dossierTemplateId, await this._reportTemplateService
async () => { .deleteTemplate(template.dossierTemplateId, template.templateId)
await this._loadReportTemplates(); .toPromise();
} await this._loadReportTemplates();
); });
} }
private async _loadReportTemplates() { private async _loadReportTemplates() {
this._loadingService.start();
this.availableTemplates = await this._reportTemplateService this.availableTemplates = await this._reportTemplateService
.getAvailableReportTemplates(this._appStateService.activeDossierTemplateId) .getAvailableReportTemplates(this._appStateService.activeDossierTemplateId)
.toPromise(); .toPromise();
this._loadingService.stop();
} }
} }

View File

@ -4,8 +4,8 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { import {
GeneralConfigurationModel, GeneralConfigurationModel,
SmtpConfigurationControllerService,
GeneralSettingsControllerService, GeneralSettingsControllerService,
SmtpConfigurationControllerService,
SMTPConfigurationModel SMTPConfigurationModel
} from '@redaction/red-ui-http'; } from '@redaction/red-ui-http';
import { NotificationService, NotificationType } from '@services/notification.service'; import { NotificationService, NotificationType } from '@services/notification.service';
@ -103,13 +103,19 @@ export class SmtpConfigScreenComponent implements OnInit {
} }
openAuthConfigDialog(skipDisableOnCancel?: boolean) { openAuthConfigDialog(skipDisableOnCancel?: boolean) {
this._dialogService.openSMTPAuthConfigDialog(this.configForm.getRawValue(), authConfig => { this._dialogService.openDialog(
if (authConfig) { 'smtpAuthConfig',
this.configForm.patchValue(authConfig); null,
} else if (!skipDisableOnCancel) { this.configForm.getRawValue(),
this.configForm.patchValue({ auth: false }, { emitEvent: false }); authConfig => {
} if (authConfig) {
}); this.configForm.patchValue(authConfig);
} else if (!skipDisableOnCancel) {
this.configForm.patchValue({ auth: false }, { emitEvent: false });
}
},
false
);
} }
async testConnection() { async testConnection() {

View File

@ -131,7 +131,7 @@
type="dark-bg" type="dark-bg"
></redaction-circle-button> ></redaction-circle-button>
<redaction-circle-button <redaction-circle-button
(action)="openDeleteUserDialog([user], $event)" (action)="openDeleteUsersDialog([user], $event)"
[disabled]="user.userId === userService.userId" [disabled]="user.userId === userService.userId"
icon="red:trash" icon="red:trash"
tooltip="user-listing.action.delete" tooltip="user-listing.action.delete"

View File

@ -25,7 +25,7 @@ export class UserListingScreenComponent extends BaseListingComponent<User> imple
readonly permissionsService: PermissionsService, readonly permissionsService: PermissionsService,
readonly userService: UserService, readonly userService: UserService,
private readonly _translateService: TranslateService, private readonly _translateService: TranslateService,
private readonly _adminDialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _userControllerService: UserControllerService, private readonly _userControllerService: UserControllerService,
private readonly _translateChartService: TranslateChartService, private readonly _translateChartService: TranslateChartService,
private readonly _loadingService: LoadingService, private readonly _loadingService: LoadingService,
@ -43,31 +43,13 @@ export class UserListingScreenComponent extends BaseListingComponent<User> imple
} }
openAddEditUserDialog($event: MouseEvent, user?: User) { openAddEditUserDialog($event: MouseEvent, user?: User) {
$event.stopPropagation(); this._dialogService.openDialog('addEditUser', $event, user, async () => {
this._adminDialogService.openAddEditUserDialog(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();
}
await this._loadData(); await this._loadData();
}); });
} }
openDeleteUserDialog(users: User[], $event?: MouseEvent) { openDeleteUsersDialog(users: User[], $event?: MouseEvent) {
$event?.stopPropagation(); this._dialogService.openDialog('deleteUsers', $event, users, async () => {
this._adminDialogService.openConfirmDeleteUsersDialog(users, async () => {
this._loadingService.start();
await this._userControllerService.deleteUsers(users.map(u => u.userId)).toPromise();
await this._loadData(); await this._loadData();
}); });
} }
@ -92,7 +74,7 @@ export class UserListingScreenComponent extends BaseListingComponent<User> imple
} }
async bulkDelete() { 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) { trackById(index: number, user: User) {

View File

@ -1,17 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import {
Colors,
DictionaryControllerService,
DossierTemplateControllerService,
DossierTemplateModel,
FileAttributeConfig,
FileAttributesConfig,
ReportTemplateControllerService,
SMTPConfigurationModel,
TypeValue,
User
} from '@redaction/red-ui-http';
import { AddEditFileAttributeDialogComponent } from '../dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component'; import { AddEditFileAttributeDialogComponent } from '../dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
import { AddEditDictionaryDialogComponent } from '../dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component'; import { AddEditDictionaryDialogComponent } from '../dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component';
import { AddEditDossierTemplateDialogComponent } from '../dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component'; import { AddEditDossierTemplateDialogComponent } from '../dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component';
@ -22,7 +10,19 @@ import { SmtpAuthDialogComponent } from '../dialogs/smtp-auth-dialog/smtp-auth-d
import { AddEditUserDialogComponent } from '../dialogs/add-edit-user-dialog/add-edit-user-dialog.component'; 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 { 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 { FileAttributesCsvImportDialogComponent } from '../dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component';
import { TypeValueWrapper } from '../../../models/file/type-value.wrapper'; import { ComponentType } from '@angular/cdk/portal';
type DialogType =
| 'confirm'
| 'addEditDictionary'
| 'editColor'
| 'addEditFileAttribute'
| 'deleteFileAttribute'
| 'importFileAttributes'
| 'addEditUser'
| 'deleteUsers'
| 'smtpAuthConfig'
| 'addEditDossierTemplate';
const largeDialogConfig = { const largeDialogConfig = {
width: '90vw', width: '90vw',
@ -39,244 +39,74 @@ const dialogConfig = {
@Injectable() @Injectable()
export class AdminDialogService { export class AdminDialogService {
constructor( private readonly _config: {
private readonly _dialog: MatDialog, [key in DialogType]: {
private readonly _dossierTemplateControllerService: DossierTemplateControllerService, component: ComponentType<any>;
private readonly _reportTemplateService: ReportTemplateControllerService, dialogConfig?: object;
private readonly _dictionaryControllerService: DictionaryControllerService };
) {} } = {
confirm: {
component: ConfirmationDialogComponent
},
addEditDictionary: {
component: AddEditDictionaryDialogComponent,
dialogConfig: { autoFocus: true }
},
editColor: {
component: EditColorDialogComponent,
dialogConfig: { autoFocus: true }
},
addEditFileAttribute: {
component: AddEditFileAttributeDialogComponent,
dialogConfig: { autoFocus: true }
},
deleteFileAttribute: {
component: ConfirmDeleteFileAttributeDialogComponent
},
importFileAttributes: {
component: FileAttributesCsvImportDialogComponent,
dialogConfig: largeDialogConfig
},
deleteUsers: {
component: ConfirmDeleteUsersDialogComponent,
dialogConfig: { autoFocus: true }
},
addEditUser: {
component: AddEditUserDialogComponent,
dialogConfig: { autoFocus: true }
},
smtpAuthConfig: {
component: SmtpAuthDialogComponent,
dialogConfig: { autoFocus: true }
},
addEditDossierTemplate: {
component: AddEditDossierTemplateDialogComponent,
dialogConfig: { width: '900px', autoFocus: true }
}
};
openDeleteDictionariesDialog( constructor(private readonly _dialog: MatDialog) {}
dictionaryTypes: string[],
dossierTemplateId: string, openDialog(
cb?: () => void type: DialogType,
): MatDialogRef<ConfirmationDialogComponent> { $event: MouseEvent,
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig); data: any,
cb?: Function,
checkForResult = true
): MatDialogRef<any> {
const config = this._config[type];
$event?.stopPropagation();
const ref = this._dialog.open(config.component, {
...dialogConfig,
...(config.dialogConfig || {}),
data
});
ref.afterClosed().subscribe(async result => { ref.afterClosed().subscribe(async result => {
if (result) { if ((result || !checkForResult) && cb) {
await this._dictionaryControllerService await cb(result);
.deleteTypes(dictionaryTypes, dossierTemplateId)
.toPromise();
if (cb) cb();
} }
}); });
return ref; return ref;
} }
openDeleteReportTemplateDialog(
templateId: string,
dossierTemplateId: string,
cb?: Function
): MatDialogRef<ConfirmationDialogComponent> {
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig);
ref.afterClosed().subscribe(async result => {
if (result) {
await this._reportTemplateService
.deleteTemplate(dossierTemplateId, templateId)
.toPromise();
if (cb) cb();
}
});
return ref;
}
openDeleteDossierTemplateDialog(
dossierTemplate: DossierTemplateModel,
cb?: () => void
): MatDialogRef<ConfirmationDialogComponent> {
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig);
ref.afterClosed().subscribe(async result => {
if (result) {
if (cb) await cb();
}
});
return ref;
}
openBulkDeleteDossierTemplatesDialog(
dossierTemplateIds: string[],
cb?: Function
): MatDialogRef<ConfirmationDialogComponent> {
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig);
ref.afterClosed().subscribe(async result => {
if (result) {
if (cb) await cb();
}
});
return ref;
}
openAddEditDictionaryDialog(
dictionary: TypeValueWrapper,
dossierTemplateId: string,
cb?: (newDictionary: TypeValue | null) => void
): MatDialogRef<AddEditDictionaryDialogComponent> {
const ref = this._dialog.open(AddEditDictionaryDialogComponent, {
...dialogConfig,
data: { dictionary, dossierTemplateId },
autoFocus: true
});
ref.afterClosed().subscribe((newDictionary: TypeValue) => {
if (newDictionary && cb) cb(newDictionary);
else if (cb) cb(null);
});
return ref;
}
openEditColorsDialog(
colors: Colors,
colorKey: string,
dossierTemplateId: string,
cb?: (result: boolean) => void
): MatDialogRef<EditColorDialogComponent> {
const ref = this._dialog.open(EditColorDialogComponent, {
...dialogConfig,
data: { colors, colorKey, dossierTemplateId },
autoFocus: true
});
ref.afterClosed().subscribe((result: boolean) => {
if (result && cb) {
cb(result);
}
});
return ref;
}
openAddEditDossierTemplateDialog(
dossierTemplate: DossierTemplateModel,
cb?: Function
): MatDialogRef<AddEditDossierTemplateDialogComponent> {
const ref = this._dialog.open(AddEditDossierTemplateDialogComponent, {
...dialogConfig,
width: '900px',
data: dossierTemplate,
autoFocus: true
});
ref.afterClosed().subscribe(result => {
if (result && cb) {
cb(result);
}
});
return ref;
}
openImportFileAttributeCSVDialog(
csv: File,
dossierTemplateId: string,
existingConfiguration: FileAttributesConfig,
cb?: Function
): MatDialogRef<FileAttributesCsvImportDialogComponent> {
const ref = this._dialog.open(FileAttributesCsvImportDialogComponent, {
...largeDialogConfig,
data: { csv, dossierTemplateId, existingConfiguration }
});
ref.afterClosed().subscribe(result => {
if (result && cb) {
cb(result);
}
});
return ref;
}
openAddEditFileAttributeDialog(
fileAttribute: FileAttributeConfig,
dossierTemplateId: string,
cb?: Function
): MatDialogRef<AddEditFileAttributeDialogComponent> {
const ref = this._dialog.open(AddEditFileAttributeDialogComponent, {
...dialogConfig,
data: { fileAttribute, dossierTemplateId },
autoFocus: true
});
ref.afterClosed().subscribe(result => {
if (result && cb) {
cb(result);
}
});
return ref;
}
openConfirmDeleteFileAttributeDialog(
fileAttribute: FileAttributeConfig,
dossierTemplateId: string,
cb?: Function
): MatDialogRef<ConfirmDeleteFileAttributeDialogComponent> {
const ref = this._dialog.open(ConfirmDeleteFileAttributeDialogComponent, {
...dialogConfig,
data: fileAttribute,
autoFocus: true
});
ref.afterClosed().subscribe(result => {
if (result && cb) {
cb(result);
}
});
return ref;
}
openSMTPAuthConfigDialog(
smtpConfig: SMTPConfigurationModel,
cb?: Function
): MatDialogRef<SmtpAuthDialogComponent> {
const ref = this._dialog.open(SmtpAuthDialogComponent, {
...dialogConfig,
data: smtpConfig,
autoFocus: true
});
ref.afterClosed().subscribe(result => {
if (cb) {
cb(result);
}
});
return ref;
}
openAddEditUserDialog(user?: User, cb?: Function): MatDialogRef<AddEditUserDialogComponent> {
const ref = this._dialog.open(AddEditUserDialogComponent, {
...dialogConfig,
data: user,
autoFocus: true
});
ref.afterClosed().subscribe(result => {
if (result && cb) {
cb(result);
}
});
return ref;
}
openConfirmDeleteUsersDialog(
users: User[],
cb?: Function
): MatDialogRef<ConfirmDeleteUsersDialogComponent> {
const ref = this._dialog.open(ConfirmDeleteUsersDialogComponent, {
...dialogConfig,
data: users,
autoFocus: true
});
ref.afterClosed().subscribe(result => {
if (result && cb) {
cb(result);
}
});
return ref;
}
} }

View File

@ -97,7 +97,8 @@
"email": "Email", "email": "Email",
"first-name": "First Name", "first-name": "First Name",
"last-name": "Last Name", "last-name": "Last Name",
"role": "Role" "role": "Role",
"reset-password": "Reset Password"
}, },
"title": { "title": {
"edit": "Edit User", "edit": "Edit User",
@ -338,6 +339,16 @@
"formula": "Formula" "formula": "Formula"
} }
}, },
"reset-password-dialog": {
"header": "Set Temporary Password for {{userName}}",
"form": {
"password": "Temporary password"
},
"actions": {
"save": "Save",
"cancel": "Cancel"
}
},
"comment": "Comment", "comment": "Comment",
"comments": { "comments": {
"add-comment": "Enter comment", "add-comment": "Enter comment",

View File

@ -364,3 +364,7 @@ section.settings {
.d-flex { .d-flex {
display: flex; display: flex;
} }
.cdk-overlay-container {
z-index: 800;
}