From 8e897cf7b2682a58ed46ee9a8a008502e5d0dde3 Mon Sep 17 00:00:00 2001 From: Alex ORLUC <alex.orluc@maarch.org> Date: Fri, 6 Nov 2020 12:25:05 +0100 Subject: [PATCH] FEAT #15350 TIME 1:15 fix redirect indexing models modal (performance issues) --- ...ndexing-models-administration.component.ts | 59 ++--- .../redirect-indexing-model.component.html | 88 ++++--- .../redirect-indexing-model.component.ts | 214 +++++++++++------- 3 files changed, 198 insertions(+), 163 deletions(-) diff --git a/src/frontend/app/administration/indexingModel/indexing-models-administration.component.ts b/src/frontend/app/administration/indexingModel/indexing-models-administration.component.ts index f29489a8715..de62dd2ea54 100644 --- a/src/frontend/app/administration/indexingModel/indexing-models-administration.component.ts +++ b/src/frontend/app/administration/indexingModel/indexing-models-administration.component.ts @@ -11,7 +11,7 @@ import { ConfirmComponent } from '../../../plugins/modal/confirm.component'; import { MatDialogRef, MatDialog } from '@angular/material/dialog'; import { FunctionsService } from '@service/functions.service'; import { of } from 'rxjs'; -import {RedirectIndexingModelComponent} from './redirectIndexingModel/redirect-indexing-model.component'; +import { RedirectIndexingModelComponent } from './redirectIndexingModel/redirect-indexing-model.component'; import { AdministrationService } from '../administration.service'; @Component({ @@ -23,7 +23,7 @@ export class IndexingModelsAdministrationComponent implements OnInit { @ViewChild('adminMenuTemplate', { static: true }) adminMenuTemplate: TemplateRef<any>; - + search: string = null; indexingModels: any[] = []; @@ -56,7 +56,7 @@ export class IndexingModelsAdministrationComponent implements OnInit { this.loading = true; - this.http.get('../rest/indexingModels?showDisabled=true&admin=true').pipe( + this.http.get('../rest/indexingModels?showDisabled=true').pipe( map((data: any) => { return data.indexingModels.filter((info: any) => info.private === false); }), @@ -76,46 +76,23 @@ export class IndexingModelsAdministrationComponent implements OnInit { } delete(indexingModel: any) { + this.dialogRef = this.dialog.open(RedirectIndexingModelComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { indexingModel: indexingModel } }); - if (indexingModel.used.length === 0) { - this.dialogRef = this.dialog.open(ConfirmComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.translate.instant('lang.delete'), msg: this.translate.instant('lang.confirmAction') } }); - - this.dialogRef.afterClosed().pipe( - filter((data: string) => data === 'ok'), - exhaustMap(() => this.http.delete('../rest/indexingModels/' + indexingModel.id)), - tap(() => { - for (const i in this.indexingModels) { - if (this.indexingModels[i].id === indexingModel.id) { - this.indexingModels.splice(Number(i), 1); - } - } - this.adminService.setDataSource('admin_indexing_models', this.indexingModels, this.sort, this.paginator, this.filterColumns); - this.notify.success(this.translate.instant('lang.indexingModelDeleted')); - }), - catchError((err: any) => { - this.notify.handleSoftErrors(err); - return of(false); - }) - ).subscribe(); - } else { - this.dialogRef = this.dialog.open(RedirectIndexingModelComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.translate.instant('lang.delete'), msg: this.translate.instant('lang.confirmAction'), indexingModel: indexingModel } }); - - this.dialogRef.afterClosed().pipe( - filter((data: string) => data === 'ok'), - tap(() => { - for (const i in this.indexingModels) { - if (this.indexingModels[i].id === indexingModel.id) { - this.indexingModels.splice(Number(i), 1); - } + this.dialogRef.afterClosed().pipe( + filter((data: string) => data === 'ok'), + tap(() => { + for (const i in this.indexingModels) { + if (this.indexingModels[i].id === indexingModel.id) { + this.indexingModels.splice(Number(i), 1); } - this.adminService.setDataSource('admin_indexing_models', this.indexingModels, this.sort, this.paginator, this.filterColumns); - }), - catchError((err: any) => { - this.notify.handleSoftErrors(err); - return of(false); - }) - ).subscribe(); - } + } + this.adminService.setDataSource('admin_indexing_models', this.indexingModels, this.sort, this.paginator, this.filterColumns); + }), + catchError((err: any) => { + this.notify.handleSoftErrors(err); + return of(false); + }) + ).subscribe(); } disableIndexingModel(indexingModel: any) { diff --git a/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.html b/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.html index 2c99d357baf..2107f9b728a 100644 --- a/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.html +++ b/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.html @@ -1,40 +1,54 @@ <div class="mat-dialog-content-container"> - <h1 mat-dialog-title>{{'lang.indexingModelReassign' | translate}}</h1> - <div mat-dialog-content> - <div class="alert-message alert-message-info"> - {{'lang.indexingModelUsedBy' | translate}} - <ul> - <li *ngFor="let usage of mainIndexingModel.used"> - <b>{{usage.count}}</b> {{'lang.mailsWithStatus' | translate}} <b>{{usage.status}}</b> - </li> - </ul> - {{'lang.indexingModelReplaceToDelete' | translate}} - </div> - <div *ngIf="!loading"> - <mat-form-field style="padding: 10px; margin-top: 15px"> - <mat-select name="model" [(ngModel)]="modelIds" - [placeholder]="'lang.indexingModel' | translate" required (selectionChange)="changeModel($event)"> - <mat-option *ngFor="let model of indexingModels;let i=index" [value]="model.id" [disabled]="model.id === mainIndexingModel.id"> - {{model.label}} - </mat-option> - </mat-select> - </mat-form-field> - </div> - <div class="alert-message alert-message-danger" *ngIf="resetFields.length !== 0"> - {{'lang.indexingModelFieldsReset' | translate}} - <ul> - <li *ngFor="let field of resetFields"> - {{field.label}} - </li> - </ul> + <h1 mat-dialog-title>{{title | translate}}</h1> + <div mat-dialog-content> + <ng-container *ngIf="loading; else elseLoading"> + <mat-spinner style="margin:auto;"></mat-spinner> + </ng-container> + <ng-template #elseLoading> + <ng-container *ngIf="mainIndexingModel.used.length === 0; else elseTemplate"> + <div class="alert-message alert-message-info" style="margin: 20px 0;" role="alert" + [innerHTML]="'lang.confirmAction' | translate"> + </div> + </ng-container> + <ng-template #elseTemplate> + <div class="alert-message alert-message-info"> + {{'lang.indexingModelUsedBy' | translate}} + <ul> + <li *ngFor="let usage of mainIndexingModel.used"> + <b>{{usage.count}}</b> {{'lang.mailsWithStatus' | translate}} <b>{{usage.status}}</b> + </li> + </ul> + {{'lang.indexingModelReplaceToDelete' | translate}} + </div> + <div> + <mat-form-field style="padding: 10px; margin-top: 15px"> + <mat-select name="model" [(ngModel)]="modelIds" [placeholder]="'lang.indexingModel' | translate" + required (selectionChange)="changeModel($event)"> + <mat-option *ngFor="let model of indexingModels;let i=index" [value]="model.id" + [disabled]="model.id === mainIndexingModel.id"> + {{model.label}} + </mat-option> + </mat-select> + </mat-form-field> + </div> + <div class="alert-message alert-message-danger" *ngIf="resetFields.length !== 0"> + {{'lang.indexingModelFieldsReset' | translate}} + <ul> + <li *ngFor="let field of resetFields"> + {{field.label}} + </li> + </ul> - {{'lang.confirmAction' | translate}} - </div> - <span class="divider-modal"></span> - <div mat-dialog-actions> - <button class="actions" color="primary" mat-raised-button [disabled]="selectedModelId === undefined" - (click)="onSubmit()">{{'lang.validate' | translate}}</button> - <button class="actions" color="" mat-raised-button (click)="this.dialogRef.close('');">{{'lang.cancel' | translate}}</button> + {{'lang.confirmAction' | translate}} + </div> + </ng-template> + </ng-template> + <span class="divider-modal"></span> + <div mat-dialog-actions> + <button class="actions" color="primary" mat-raised-button [disabled]="!isValid()" + (click)="onSubmit()">{{'lang.validate' | translate}}</button> + <button class="actions" color="" mat-raised-button + (click)="this.dialogRef.close('');">{{'lang.cancel' | translate}}</button> + </div> </div> - </div> -</div> +</div> \ No newline at end of file diff --git a/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.ts b/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.ts index b2d4e8107c0..98a6cd8a974 100644 --- a/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.ts +++ b/src/frontend/app/administration/indexingModel/redirectIndexingModel/redirect-indexing-model.component.ts @@ -14,15 +14,16 @@ import { NotificationService } from '@service/notification/notification.service' }) export class RedirectIndexingModelComponent implements OnInit { - - + title: string = 'lang.delete'; indexingModels: any[] = []; modelIds: any[] = []; selectedModelId: any; selectedModelFields: any[]; - mainIndexingModel: any; + mainIndexingModel: any = { + used: [] + }; mainIndexingModelFields: any[]; resetFields: any[] = []; @@ -89,7 +90,7 @@ export class RedirectIndexingModelComponent implements OnInit { }, ]; - loading: boolean = false; + loading: boolean = true; constructor( public translate: TranslateService, @@ -99,98 +100,117 @@ export class RedirectIndexingModelComponent implements OnInit { private notify: NotificationService, private sortPipe: SortPipe, ) { - this.mainIndexingModel = data.indexingModel; + this.mainIndexingModel.id = data.indexingModel.id; } async ngOnInit() { - this.loadIndexingModels(); + await this.loadIndexingModelFields(); + + if (this.mainIndexingModel.used.length > 0) { + this.title = 'lang.indexingModelReassign'; + await this.loadIndexingModels(); + + await this.loadStatuses(); - this.loadStatuses(); + await this.loadCustomFields(); - this.loadCustomFields(); + this.formatFields(); + } - this.loadIndexingModelFields(); + this.loading = false; } loadIndexingModels() { - this.http.get('../rest/indexingModels').pipe( - map((data: any) => { - return data.indexingModels.filter((info: any) => info.private === false); - }), - tap((data: any) => { - this.indexingModels = data; + return new Promise((resolve) => { + this.http.get('../rest/indexingModels').pipe( + map((data: any) => { + return data.indexingModels.filter((info: any) => info.private === false); + }), + tap((data: any) => { + this.indexingModels = data; - this.sortPipe.transform(this.indexingModels, 'label'); + this.sortPipe.transform(this.indexingModels, 'label'); - this.modelIds = this.indexingModels.map(model => model.id); - }), - finalize(() => this.loading = false), - catchError((err: any) => { - this.notify.handleErrors(err); - return of(false); - }) - ).subscribe(); + this.modelIds = this.indexingModels.map(model => model.id); + }), + finalize(() => resolve(true)), + catchError((err: any) => { + this.notify.handleErrors(err); + return of(false); + }) + ).subscribe(); + }); } loadIndexingModelFields() { - this.http.get('../rest/indexingModels/' + this.mainIndexingModel.id).pipe( - tap((data: any) => { - this.mainIndexingModelFields = data.indexingModel.fields; - this.mainIndexingModelFields = this.mainIndexingModelFields.map(field => { - const availableField = this.availableFields.find(elem => elem.identifier === field.identifier); + return new Promise((resolve) => { + this.http.get('../rest/indexingModels/' + this.mainIndexingModel.id + '?used=true').pipe( + tap((data: any) => { + this.mainIndexingModel.used = data.indexingModel.used; - field.label = availableField === undefined ? this.translate.instant('lang.undefined') : availableField.label; - return field; - }); - }), - catchError((err: any) => { - this.notify.handleErrors(err); - return of(false); - }) - ).subscribe(); + this.mainIndexingModelFields = data.indexingModel.fields; + }), + tap(() => resolve(true)), + catchError((err: any) => { + this.notify.handleErrors(err); + return of(false); + }) + ).subscribe(); + }); + } + + formatFields() { + this.mainIndexingModelFields = this.mainIndexingModelFields.map(field => { + const availableField = this.availableFields.find(elem => elem.identifier === field.identifier); + field.label = availableField === undefined ? this.translate.instant('lang.undefined') : availableField.label; + return field; + }); } loadStatuses() { - this.http.get('../rest/statuses').pipe( - tap((data: any) => { - this.statuses = data.statuses; - - this.mainIndexingModel.used.forEach((element: any) => { - const elementStatus = this.statuses.find(status => status.id === element.status); - if (elementStatus !== undefined) { - element.status = elementStatus.label_status; - } - }); - }), - catchError((err: any) => { - this.notify.handleErrors(err); - return of(false); - }) - ).subscribe(); + return new Promise((resolve) => { + this.http.get('../rest/statuses').pipe( + tap((data: any) => { + this.statuses = data.statuses; + + this.mainIndexingModel.used.forEach((element: any) => { + const elementStatus = this.statuses.find(status => status.id === element.status); + if (elementStatus !== undefined) { + element.status = elementStatus.label_status; + } + }); + }), + finalize(() => resolve(true)), + catchError((err: any) => { + this.notify.handleErrors(err); + return of(false); + }) + ).subscribe(); + }); } loadCustomFields() { - this.http.get('../rest/customFields').pipe( - tap((data: any) => { - data.customFields = data.customFields.map((custom: any) => { - return { - identifier: 'indexingCustomField_' + custom.id, - label: custom.label - }; - }); - data.customFields.forEach((custom: any) => { - this.availableFields.push(custom); - }); - - this.sortPipe.transform(this.availableFields, 'label'); - - this.loadIndexingModelFields(); - }), - catchError((err: any) => { - this.notify.handleErrors(err); - return of(false); - }) - ).subscribe(); + return new Promise((resolve) => { + this.http.get('../rest/customFields').pipe( + tap((data: any) => { + data.customFields = data.customFields.map((custom: any) => { + return { + identifier: 'indexingCustomField_' + custom.id, + label: custom.label + }; + }); + data.customFields.forEach((custom: any) => { + this.availableFields.push(custom); + }); + this.sortPipe.transform(this.availableFields, 'label'); + }), + finalize(() => resolve(true)), + catchError((err: any) => { + this.notify.handleErrors(err); + return of(false); + }) + ).subscribe(); + }); } changeModel(event: any) { @@ -210,16 +230,40 @@ export class RedirectIndexingModelComponent implements OnInit { ).subscribe(); } + isValid() { + if (this.loading) { + return false; + } else if (this.mainIndexingModel.used.length === 0) { + return true; + } else { + return this.selectedModelId !== undefined; + } + } + onSubmit() { - this.http.request('DELETE', '../rest/indexingModels/' + this.mainIndexingModel.id, { body: { targetId: this.selectedModelId } }).pipe( - tap(() => { - this.notify.success(this.translate.instant('lang.indexingModelDeleted')); - this.dialogRef.close('ok'); - }), - catchError((err: any) => { - this.notify.handleSoftErrors(err); - return of(false); - }) - ).subscribe(); + if (this.mainIndexingModel.used.length === 0) { + this.http.delete('../rest/indexingModels/' + this.mainIndexingModel.id).pipe( + tap(() => { + this.notify.success(this.translate.instant('lang.indexingModelDeleted')); + this.dialogRef.close('ok'); + }), + catchError((err: any) => { + this.notify.handleSoftErrors(err); + return of(false); + }) + ).subscribe(); + } else { + this.http.request('DELETE', '../rest/indexingModels/' + this.mainIndexingModel.id, { body: { targetId: this.selectedModelId } }).pipe( + tap(() => { + this.notify.success(this.translate.instant('lang.indexingModelDeleted')); + this.dialogRef.close('ok'); + }), + catchError((err: any) => { + this.notify.handleSoftErrors(err); + return of(false); + }) + ).subscribe(); + } + } } -- GitLab