RED-6786: faster dictionary saving

This commit is contained in:
Dan Percic 2023-05-26 01:20:33 +03:00
parent ec91aa27e7
commit b5b5d5095c
2 changed files with 52 additions and 41 deletions

View File

@ -3,10 +3,11 @@ import { ActivatedRoute } from '@angular/router';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { getCurrentUser, getParam, IqserPermissionsService, List, LoadingService } from '@iqser/common-ui';
import { BehaviorSubject, firstValueFrom, lastValueFrom } from 'rxjs';
import { BehaviorSubject, firstValueFrom } from 'rxjs';
import { DICTIONARY_TO_ENTRY_TYPE_MAP, DICTIONARY_TYPE_KEY_MAP, DictionaryType, DOSSIER_TEMPLATE_ID, ENTITY_TYPE, User } from '@red/domain';
import { PermissionsService } from '@services/permissions.service';
import { ROLES } from '@users/roles';
import { NGXLogger } from 'ngx-logger';
@Component({
templateUrl: './dictionary-screen.component.html',
@ -30,6 +31,7 @@ export class DictionaryScreenComponent implements OnInit {
readonly iqserPermissionsService: IqserPermissionsService,
private readonly _loadingService: LoadingService,
private readonly _dictionaryService: DictionaryService,
private readonly _logger: NGXLogger,
) {
this.type = route.snapshot.routeConfig.path as DictionaryType;
}
@ -43,6 +45,7 @@ export class DictionaryScreenComponent implements OnInit {
}
async save() {
this._logger.info('[EDITOR] Saving...');
const entries = this._dictionaryManager.editor?.currentEntries;
this._loadingService.start();

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { firstValueFrom, forkJoin, Observable, throwError, zip } from 'rxjs';
import { firstValueFrom, forkJoin, Observable, throwError } from 'rxjs';
import { EntitiesService, List, QueryParam, Toaster } from '@iqser/common-ui';
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IDictionary, IUpdateDictionary, SuperTypes } from '@red/domain';
import { catchError, map, switchMap, tap } from 'rxjs/operators';
@ -94,50 +94,58 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
dossierId: string,
showToast = true,
dictionaryEntryType = DictionaryEntryTypes.ENTRY,
): Promise<unknown> {
) {
const entriesToAdd: Array<string> = [];
const deletedEntries: Array<string> = [];
const initialEntriesSet = new Set(initialEntries);
let hasInvalidRows = false;
let hasNewEntries = false;
for (let i = 0; i < entries.length; i++) {
if (!entries.at(i).trim()) {
const entry = entries.at(i);
if (!entry.trim()) {
continue;
}
entriesToAdd.push(entries.at(i));
}
for (let i = 0; i < initialEntries.length; i++) {
if (entries.includes(initialEntries.at(i))) {
continue;
if (entry.length < MIN_WORD_LENGTH) {
hasInvalidRows = true;
}
deletedEntries.push(initialEntries.at(i));
}
// remove empty lines
const invalidRowsExist = entriesToAdd.filter(e => e.length < MIN_WORD_LENGTH);
if (invalidRowsExist.length === 0) {
// can add at least 1 - block UI
const promises: Promise<IDictionary>[] = [];
if (deletedEntries.length) {
promises.push(firstValueFrom(this._deleteEntries(deletedEntries, dossierTemplateId, type, dictionaryEntryType, dossierId)));
if (!hasNewEntries && !initialEntriesSet.has(entry)) {
hasNewEntries = true;
}
if (entriesToAdd.filter(e => !initialEntries.includes(e)).length) {
promises.push(firstValueFrom(this._addEntries(entriesToAdd, dossierTemplateId, type, dictionaryEntryType, dossierId)));
}
try {
await Promise.all(promises);
if (showToast) {
this._toaster.success(_('dictionary-overview.success.generic'));
}
return;
} catch (error) {
if ((error as HttpErrorResponse).status === 400) {
this._toaster.error(_('dictionary-overview.error.400'));
} else {
this._toaster.error(_('dictionary-overview.error.generic'));
}
return;
}
}
this._toaster.error(_('dictionary-overview.error.entries-too-short'));
throw new Error('Entries too short');
entriesToAdd.push(entry);
}
if (hasInvalidRows) {
this._toaster.error(_('dictionary-overview.error.entries-too-short'));
throw new Error('Entries too short');
}
const deletedEntries: Array<string> = [];
const entriesSet = new Set(entries);
for (let i = 0; i < initialEntries.length; i++) {
const entry = initialEntries.at(i);
if (entriesSet.has(entry)) {
continue;
}
deletedEntries.push(entry);
}
try {
if (deletedEntries.length) {
await this._deleteEntries(deletedEntries, dossierTemplateId, type, dictionaryEntryType, dossierId);
}
if (hasNewEntries) {
await this._addEntries(entriesToAdd, dossierTemplateId, type, dictionaryEntryType, dossierId);
}
if (showToast) {
this._toaster.success(_('dictionary-overview.success.generic'));
}
} catch (error) {
if ((error as HttpErrorResponse).status === 400) {
this._toaster.error(_('dictionary-overview.error.400'));
} else {
this._toaster.error(_('dictionary-overview.error.generic'));
}
}
}
hasManualType(dossierTemplateId: string): boolean {
@ -240,7 +248,7 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
{ key: 'removeCurrent', value: true },
];
const url = `${this._defaultModelPath}/${type}/${dossierTemplateId}`;
return this._post(entries, url, queryParams);
return firstValueFrom(this._post(entries, url, queryParams));
}
/**
@ -258,7 +266,7 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
? [{ key: 'dossierId', value: dossierId }]
: [{ key: 'dictionaryEntryType', value: dictionaryEntryType }];
const url = `${this._defaultModelPath}/delete/${type}/${dossierTemplateId}`;
return this._post(entries, url, queryParams);
return firstValueFrom(this._post(entries, url, queryParams));
}
#addUpdateDictionaryErrorToast(error: HttpErrorResponse | unknown): Observable<never> {