diff --git a/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts index 98035a664..5ed382572 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/entities/screens/dictionary/dictionary-screen.component.ts @@ -47,16 +47,14 @@ export class DictionaryScreenComponent implements OnInit { this._loadingService.start(); try { - await lastValueFrom( - this._dictionaryService.saveEntries( - entries, - this.initialEntries$.value, - this.#dossierTemplateId, - this.entityType, - null, - true, - DICTIONARY_TO_ENTRY_TYPE_MAP[this.type], - ), + await this._dictionaryService.saveEntries( + entries, + this.initialEntries$.value, + this.#dossierTemplateId, + this.entityType, + null, + true, + DICTIONARY_TO_ENTRY_TYPE_MAP[this.type], ); await this._loadEntries(); } catch (e) { diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts index af47cfbd7..30d1e781f 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component.ts @@ -50,15 +50,13 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa async save(): EditDossierSaveResult { try { - await firstValueFrom( - this._dictionaryService.saveEntries( - this._dictionaryManager.editor.currentEntries, - this._dictionaryManager.initialEntries, - this.dossier.dossierTemplateId, - this.dossierDictionary.type, - this.dossier.id, - false, - ), + await this._dictionaryService.saveEntries( + this._dictionaryManager.editor.currentEntries, + this._dictionaryManager.initialEntries, + this.dossier.dossierTemplateId, + this.dossierDictionary.type, + this.dossier.id, + false, ); await this.#updateDossierDictionary(); diff --git a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html index f35b02351..33b8651e9 100644 --- a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html +++ b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.html @@ -97,6 +97,7 @@ [label]="'dictionary-overview.save-changes' | translate" [type]="iconButtonTypes.primary" icon="iqser:check" + [disabled]="!!(_loadingService.isLoading$ | async)" >
diff --git a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts index 7f97a508e..90e22c1a4 100644 --- a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts @@ -57,7 +57,7 @@ export class DictionaryManagerComponent implements OnChanges { constructor( private readonly _dictionaryService: DictionaryService, private readonly _dictionariesMapService: DictionariesMapService, - private readonly _loadingService: LoadingService, + protected readonly _loadingService: LoadingService, private readonly _changeRef: ChangeDetectorRef, readonly activeDossiersService: ActiveDossiersService, readonly dossierTemplatesService: DossierTemplatesService, diff --git a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.html b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.html index 0a113be28..441062e92 100644 --- a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.html +++ b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.html @@ -1,6 +1,6 @@ + + diff --git a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts index b59f54434..2b34ec87f 100644 --- a/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/editor/editor.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; -import { Debounce, List, LoadingService, OnChange } from '@iqser/common-ui'; +import { List, LoadingService, OnChange } from '@iqser/common-ui'; import { EditorThemeService } from '@services/editor-theme.service'; import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions; import ICodeEditor = monaco.editor.ICodeEditor; @@ -7,6 +7,8 @@ import IDiffEditor = monaco.editor.IDiffEditor; import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration; import ILineChange = monaco.editor.ILineChange; import IEditorMouseEvent = monaco.editor.IEditorMouseEvent; +import { BehaviorSubject } from 'rxjs'; +import { debounceTime, filter, tap } from 'rxjs/operators'; const MIN_WORD_LENGTH = 2; const lineChangeToDecoration = ({ originalEndLineNumber, originalStartLineNumber }: ILineChange) => @@ -41,6 +43,17 @@ export class EditorComponent implements OnInit, OnChanges { value: string; private _diffEditor: IDiffEditor; private _decorations: string[] = []; + private readonly _codeEditorTextChanged$ = new BehaviorSubject(''); + protected readonly _codeEditorTextChangedHandler$ = this._codeEditorTextChanged$.asObservable().pipe( + filter(Boolean), + debounceTime(0), // prevent race condition with onPaste event + tap(newText => { + const newDecorations = this.#getDecorations(newText); + this._decorations = this.codeEditor.deltaDecorations(this._decorations, newDecorations); + this.diffValue = this.value; + this._loadingService.stop(); + }), + ); constructor(private readonly _loadingService: LoadingService, private readonly _editorThemeService: EditorThemeService) {} @@ -56,12 +69,12 @@ export class EditorComponent implements OnInit, OnChanges { return this.currentEntries.length; } - @Debounce() - codeEditorTextChanged() { - const newDecorations = this.#getDecorations(); - this._decorations = this.codeEditor.deltaDecorations(this._decorations, newDecorations); - this.diffValue = this.value; - this._loadingService.stop(); + onPaste() { + this._loadingService.start(); + } + + codeEditorTextChanged(event) { + this._codeEditorTextChanged$.next(event); } ngOnChanges(changes: SimpleChanges) { @@ -105,12 +118,8 @@ export class EditorComponent implements OnInit, OnChanges { this._diffEditor?.getModifiedEditor().setValue(this.diffValue); } - onPaste() { - this._loadingService.start(); - } - - #getDecorations() { - const currentEntries = this.currentEntries; + #getDecorations(newText: string) { + const currentEntries = newText.split('/n'); const newDecorations: IModelDeltaDecoration[] = []; for (let index = 0; index < currentEntries.length; ++index) { diff --git a/apps/red-ui/src/app/services/entity-services/dictionary.service.ts b/apps/red-ui/src/app/services/entity-services/dictionary.service.ts index 158a4b176..ea65f2479 100644 --- a/apps/red-ui/src/app/services/entity-services/dictionary.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dictionary.service.ts @@ -86,7 +86,7 @@ export class DictionaryService extends EntitiesService ); } - saveEntries( + async saveEntries( entries: List, initialEntries: List, dossierTemplateId: string, @@ -94,42 +94,50 @@ export class DictionaryService extends EntitiesService dossierId: string, showToast = true, dictionaryEntryType = DictionaryEntryTypes.ENTRY, - ): Observable { - const entriesToAdd = entries.map(e => e.trim()).filter(e => !!e); - const deletedEntries = initialEntries.filter(e => !entries.includes(e)); - console.log({ entriesToAdd, deletedEntries }); + ): Promise { + const entriesToAdd: Array = []; + const deletedEntries: Array = []; + for (let i = 0; i < entries.length; i++) { + if (!entries.at(i).trim()) { + continue; + } + entriesToAdd.push(entries.at(i)); + } + for (let i = 0; i < initialEntries.length; i++) { + if (entries.includes(initialEntries.at(i))) { + continue; + } + 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 obs: Observable[] = []; + const promises: Promise[] = []; if (deletedEntries.length) { - obs.push(this._deleteEntries(deletedEntries, dossierTemplateId, type, dictionaryEntryType, dossierId)); + promises.push(firstValueFrom(this._deleteEntries(deletedEntries, dossierTemplateId, type, dictionaryEntryType, dossierId))); } if (entriesToAdd.filter(e => !initialEntries.includes(e)).length) { - obs.push(this._addEntries(entriesToAdd, dossierTemplateId, type, dictionaryEntryType, dossierId)); + 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; } - return zip(obs).pipe( - switchMap(dictionary => this._dossierTemplateStatsService.getFor([dossierTemplateId]).pipe(map(() => dictionary))), - tap({ - next: () => { - if (showToast) { - this._toaster.success(_('dictionary-overview.success.generic')); - } - }, - error: (error: unknown) => { - if ((error as HttpErrorResponse).status === 400) { - this._toaster.error(_('dictionary-overview.error.400')); - } else { - this._toaster.error(_('dictionary-overview.error.generic')); - } - }, - }), - ); } this._toaster.error(_('dictionary-overview.error.entries-too-short')); - return throwError(() => 'Entries too short'); + throw new Error('Entries too short'); } hasManualType(dossierTemplateId: string): boolean {