RED-8045 - Dossier template selection/filter at dossier dictionary comparison

This commit is contained in:
Valentin Mihai 2024-01-05 18:58:18 +02:00
parent 645285bfe6
commit 4953ed2e68
5 changed files with 118 additions and 158 deletions

View File

@ -4,8 +4,9 @@
[canDownload]="permissionsService.canDownloadEntityDictionary()"
[canEdit]="currentUser.isAdmin && (iqserPermissionsService.has$(roles.dictionaryEntries.write) | async)"
[entityType]="entityType"
[filterByDossierTemplate]="true"
[initialEntries]="initialEntries$ | async"
[isLeavingPage]="isLeavingPage"
[currentDossierTemplateId]="dossierTemplateId"
[selectedDictionaryType]="entityType"
[type]="type"
></redaction-dictionary-manager>

View File

@ -20,10 +20,10 @@ export class DictionaryScreenComponent implements OnInit {
readonly currentUser = getCurrentUser<User>();
readonly roles = Roles;
readonly initialEntries$ = new BehaviorSubject<List>([]);
isLeavingPage = false;
readonly type: DictionaryType;
readonly entityType = getParam(ENTITY_TYPE);
readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
isLeavingPage = false;
dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
@ViewChild('dictionaryManager', { static: false })
private readonly _dictionaryManager: DictionaryManagerComponent;
@ -55,7 +55,7 @@ export class DictionaryScreenComponent implements OnInit {
await this._dictionaryService.saveEntries(
entries,
this.initialEntries$.value,
this.#dossierTemplateId,
this.dossierTemplateId,
this.entityType,
null,
true,
@ -70,7 +70,7 @@ export class DictionaryScreenComponent implements OnInit {
async #loadEntries() {
this._loadingService.start();
try {
const data = await this._dictionaryService.getForType(this.#dossierTemplateId, this.entityType);
const data = await this._dictionaryService.getForType(this.dossierTemplateId, this.entityType);
const entries: List = data[DICTIONARY_TYPE_KEY_MAP[this.type]];
this.initialEntries$.next(entries);
} catch (e) {

View File

@ -41,55 +41,45 @@
</mat-checkbox>
</div>
<ng-container *ngIf="filterByDossierTemplate">
<div *ngIf="dossierTemplatesService.all$ | async as templates" class="iqser-input-group w-200 mt-0 mr-8">
<ng-container>
<div *ngIf="dossierTemplates" class="iqser-input-group w-200 mt-0 mr-8">
<mat-form-field>
<mat-select [(ngModel)]="dossierTemplate" [disabled]="!compare">
<mat-option [value]="selectDossierTemplate">{{ selectDossierTemplate.name | translate }}</mat-option>
<mat-option *ngFor="let dossierTemplate of templates" [value]="dossierTemplate">
{{ dossierTemplate.name }}
</mat-option>
<mat-select
[(ngModel)]="selectedDossierTemplate"
[disabled]="!compare"
[placeholder]="compare ? selectedDossierTemplate.name : (selectDossierTemplate.name | translate)"
>
<ng-container *ngFor="let dossierTemplate of dossierTemplates">
<mat-option [value]="dossierTemplate" *ngIf="dossierTemplate?.id !== selectedDossierTemplate.id">
{{ dossierTemplate.name }}
</mat-option>
</ng-container>
</mat-select>
</mat-form-field>
</div>
<div class="iqser-input-group w-200 mt-0">
<mat-form-field>
<mat-select [(ngModel)]="compareDictionary" [disabled]="!compare || dossierTemplateIsNotSelected">
<mat-option [value]="selectDictionary">{{ selectDictionary.label | translate }}</mat-option>
<mat-option *ngFor="let dictionary of dictionaries" [value]="dictionary">
{{ dictionary.label }}
</mat-option>
<mat-select
[(ngModel)]="selectedDossier"
[disabled]="!compare"
[placeholder]="selectedDossier.dossierId ? selectedDossier.dossierName : (selectDictionary.label | translate)"
>
<ng-container *ngFor="let dossier of dossiers; let index = index">
<mat-option
*ngIf="dossier.dossierId !== selectedDossier.dossierId && dossier.dossierId !== currentDossierId"
[value]="dossier"
>
{{ dossier.dossierName }}
</mat-option>
<mat-divider
*ngIf="index === dossiers.length - 2 && !selectedDossier.dossierId?.includes('template')"
></mat-divider>
</ng-container>
</mat-select>
</mat-form-field>
</div>
</ng-container>
<div
*ngIf="!filterByDossierTemplate && !!dossiers.length"
class="iqser-input-group w-200 mt-0"
[class.not-clickable]="dossiers.length === 2 && !!selectedDossier.id"
>
<mat-form-field>
<mat-select
[(ngModel)]="selectedDossier"
[disabled]="!compare"
[placeholder]="selectedDossier.dossierId ? selectedDossier.dossierName : (selectDictionary.label | translate)"
>
<ng-container *ngFor="let dossier of dossiers; let index = index">
<mat-option
*ngIf="dossier.dossierId !== selectedDossier.dossierId && dossier.dossierId !== currentDossierId"
[value]="dossier"
>
{{ dossier.dossierName }}
</mat-option>
<mat-divider
*ngIf="index === dossiers.length - 2 && !selectedDossier.dossierId?.includes('template')"
></mat-divider>
</ng-container>
</mat-select>
</mat-form-field>
</div>
</div>
</div>

View File

@ -1,15 +1,6 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import {
Dictionary,
DICTIONARY_TYPE_KEY_MAP,
DictionaryEntryType,
DictionaryEntryTypes,
DictionaryType,
Dossier,
DossierTemplate,
IDictionary,
} from '@red/domain';
import { IconButtonTypes, LoadingService } from '@iqser/common-ui';
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, DictionaryType, Dossier, DossierTemplate, IDictionary } from '@red/domain';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
@ -22,6 +13,7 @@ import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
import FindMatch = monaco.editor.FindMatch;
import { firstValueFrom } from 'rxjs';
const COMPARE_ENTRIES_ERROR = 'compare-entries-error';
const SMOOTH_SCROLL = 0;
const HELP_MODE_KEYS = {
dictionary: 'dictionary_entity',
@ -40,9 +32,8 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
@Input() type: DictionaryType = 'dictionary';
@Input() entityType?: string;
@Input() currentDossierId: string;
@Input() currentDossierTemplateId: string;
@Input() currentDossierTemplateId!: string;
@Input() withFloatingActions = true;
@Input() filterByDossierTemplate = false;
@Input() initialEntries: List;
@Input() canEdit = false;
@Input() canDownload = false;
@ -54,7 +45,8 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
@Output() readonly saveDictionary = new EventEmitter<string[]>();
@ViewChild(EditorComponent) readonly editor: EditorComponent;
readonly iconButtonTypes = IconButtonTypes;
readonly dossiers: Dossier[];
dossiers: Dossier[];
dossierTemplates: DossierTemplate[];
currentMatch = 0;
findMatches: FindMatch[] = [];
diffEditorText = '';
@ -64,110 +56,64 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
selectDictionary = {
label: _('dictionary-overview.compare.select-dictionary'),
} as Dictionary;
#compareDictionary = this.selectDictionary;
selectDossierTemplate = { name: _('dictionary-overview.compare.select-dossier-template') } as DossierTemplate;
compare = false;
dictionaries: List<Dictionary> = this.#dictionaries;
#dossierTemplate = this.dossierTemplatesService.all[0];
#dossier = this.selectDossier;
#initialDossierTemplateId: string;
constructor(
private readonly _dictionaryService: DictionaryService,
private readonly _dictionariesMapService: DictionariesMapService,
protected readonly _loadingService: LoadingService,
private readonly _changeRef: ChangeDetectorRef,
private readonly _activeDossiersService: ActiveDossiersService,
private readonly _toaster: Toaster,
readonly dossierTemplatesService: DossierTemplatesService,
) {
this.dossiers = _activeDossiersService.all;
}
) {}
ngOnInit() {
const templateDictionary = {
id: 'template',
dossierId: 'template',
dossierName: 'Template Dictionary',
dossierTemplateId: this.currentDossierTemplateId,
} as Dossier;
this.dossiers.push(templateDictionary);
this.#initialDossierTemplateId = this.currentDossierTemplateId;
this.#updateDropdownsOptions();
}
private _dossierTemplate = this.selectDossierTemplate;
get dossierTemplate() {
return this._dossierTemplate;
get selectedDossierTemplate() {
return this.#dossierTemplate;
}
set dossierTemplate(value: DossierTemplate) {
this._dossierTemplate = value;
set selectedDossierTemplate(value: DossierTemplate) {
if (!value) {
value = this.dossierTemplates.find(t => t.id === this.#initialDossierTemplateId);
}
this.#dossierTemplate = value;
this.currentDossierTemplateId = value.dossierTemplateId;
this.#dossier = this.selectDossier;
this.dictionaries = this.#dictionaries;
this.#compareDictionary = this.selectDictionary;
this.showDiffEditor = false;
}
this.#disableDiffEditor();
private _dossier = this.selectDossier;
this.#updateDropdownsOptions(false);
}
get selectedDossier() {
return this._dossier;
return this.#dossier;
}
set selectedDossier(dossier: Dossier) {
this._dossier = dossier;
this.#dossier = dossier;
if (dossier.dossierName === this.selectDossier.dossierName) {
this.showDiffEditor = false;
this.diffEditorText = '';
this.#disableDiffEditor();
return;
}
this.#onDossierChanged(dossier.dossierTemplateId, dossier.id).then(entries => {
this.diffEditorText = entries;
this.showDiffEditor = true;
if (!entries.startsWith(COMPARE_ENTRIES_ERROR)) {
this.diffEditorText = entries;
this.showDiffEditor = true;
}
});
}
get compareDictionary() {
return this.#compareDictionary;
}
set compareDictionary(dictionary: Dictionary) {
this._loadingService.start();
this.#compareDictionary = dictionary;
if (dictionary.label === this.selectDictionary.label) {
this.showDiffEditor = false;
this.diffEditorText = '';
return;
}
const entries: List =
this.#compareDictionary.getEntries(this.type) ??
this._dictionariesMapService.get(this.#compareDictionary.dossierTemplateId, this.#compareDictionary.type).getEntries(this.type);
if (entries.length) {
this.diffEditorText = entries.join('\n');
this.showDiffEditor = true;
return;
}
this._dictionaryService
.getForType(this.#compareDictionary.dossierTemplateId, this.#compareDictionary.type)
.then(values => {
this.#compareDictionary.setEntries([...values[DICTIONARY_TYPE_KEY_MAP[this.type]]] ?? [], this.type);
this.diffEditorText = [...(this.#compareDictionary.getEntries(this.type) as string[])].join('\n');
this.showDiffEditor = true;
this._changeRef.markForCheck();
this._loadingService.stop();
})
.catch(() => this.#compareDictionary.setEntries([], this.type));
}
get dossierTemplateIsNotSelected() {
return this.filterByDossierTemplate && this._dossierTemplate.name === this.selectDossierTemplate.name;
}
get optionNotSelected() {
if (this.filterByDossierTemplate) {
return this.selectDictionary.label === this.#compareDictionary.label;
}
return this.selectedDossier.dossierName === this.selectDossier.dossierName;
}
@ -176,10 +122,16 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
}
get #dictionaries(): Dictionary[] {
if (!this._dossierTemplate || this._dossierTemplate.name === this.selectDossierTemplate.name) {
if (!this.#dossierTemplate || this.#dossierTemplate.name === this.selectDossierTemplate.name) {
return;
}
return this._dictionariesMapService.get(this.dossierTemplate?.dossierTemplateId).filter(dict => !dict.virtual);
return this._dictionariesMapService.get(this.selectedDossierTemplate?.dossierTemplateId).filter(dict => !dict.virtual);
}
get #templatesWithCurrentEntityType() {
return this.dossierTemplatesService.all.filter(t =>
this._dictionaryService.hasType(t.dossierTemplateId, this.selectedDictionaryType),
);
}
download(): void {
@ -198,8 +150,8 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
@Debounce()
searchChanged(text: string) {
this.findMatches = this._getMatches(text.toLowerCase());
this._applySearchDecorations();
this.findMatches = this.#getMatches(text.toLowerCase());
this.#applySearchDecorations();
this.currentMatch = 0;
this.nextSearchMatch();
@ -211,7 +163,7 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
}
this.currentMatch = this.currentMatch < this.findMatches.length ? this.currentMatch + 1 : 1;
this._scrollToCurrentMatch();
this.#scrollToCurrentMatch();
}
previousSearchMatch(): void {
@ -220,7 +172,7 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
}
this.currentMatch = this.currentMatch > 1 ? this.currentMatch - 1 : this.findMatches.length;
this._scrollToCurrentMatch();
this.#scrollToCurrentMatch();
}
toggleCompareMode() {
@ -231,39 +183,39 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
}
ngOnChanges(changes: SimpleChanges): void {
if (
(changes.selectedDictionaryType || changes.activeEntryType) &&
this._dossier?.dossierTemplateId &&
this.selectedDossier?.dossierId
) {
this.#onDossierChanged(this._dossier.dossierTemplateId, this._dossier.dossierId).then(entries => {
this.diffEditorText = entries;
this.showDiffEditor = true;
if (changes.activeEntryType && this.#dossier?.dossierTemplateId && this.selectedDossier?.dossierId) {
this.#onDossierChanged(this.#dossier.dossierTemplateId, this.#dossier.dossierId).then(entries => {
if (!entries.startsWith(COMPARE_ENTRIES_ERROR)) {
this.diffEditorText = entries;
this.showDiffEditor = true;
}
});
}
if (changes.selectedDictionaryType) {
this.searchText = '';
this.#disableDiffEditor();
this.#updateDropdownsOptions();
}
}
private _applySearchDecorations() {
#applySearchDecorations() {
this._searchDecorations = this.editor.codeEditor?.deltaDecorations(this._searchDecorations, []) || [];
const decorations = this.findMatches.map(match => this._getSearchDecoration(match));
const decorations = this.findMatches.map(match => this.#getSearchDecoration(match));
this._searchDecorations = this.editor.codeEditor?.deltaDecorations(this._searchDecorations, decorations) || [];
}
private _getMatches(text: string): FindMatch[] {
#getMatches(text: string): FindMatch[] {
const model = this.editor.codeEditor?.getModel();
return model?.findMatches(text, false, false, false, null, false) || [];
}
private _getSearchDecoration(match: FindMatch): IModelDeltaDecoration {
#getSearchDecoration(match: FindMatch): IModelDeltaDecoration {
return { range: match.range, options: { inlineClassName: 'search-marker' } };
}
private _scrollToCurrentMatch(): void {
#scrollToCurrentMatch(): void {
const range = this.findMatches[this.currentMatch - 1].range;
this.editor.codeEditor.setSelection(range);
@ -279,14 +231,7 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
await firstValueFrom(
this._dictionaryService.loadDictionaryEntriesByType([this.selectedDictionaryType], dossierTemplateId, dossierId),
).catch(() => {
const selectedDossierTemplate = this.dossierTemplatesService.find(dossierTemplateId);
this._toaster.error(_('dictionary-overview.compare-error'), {
params: {
type: this.selectedDictionaryTypeLabel,
template: selectedDossierTemplate.name,
},
});
return [{ entries: [], type: '' }];
return [{ entries: [COMPARE_ENTRIES_ERROR], type: '' }];
})
)[0];
}
@ -294,8 +239,28 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
this.activeEntryType === DictionaryEntryTypes.ENTRY || this.hint
? [...dictionary.entries]
: this.activeEntryType === DictionaryEntryTypes.FALSE_POSITIVE
? [...dictionary.falsePositiveEntries]
: [...dictionary.falseRecommendationEntries];
? [...dictionary.falsePositiveEntries]
: [...dictionary.falseRecommendationEntries];
return activeEntries.join('\n');
}
#updateDropdownsOptions(updateSelectedDossierTemplate = true) {
if (updateSelectedDossierTemplate) {
this.dossierTemplates = this.#templatesWithCurrentEntityType;
this.selectedDossierTemplate = this.dossierTemplates.find(t => t.id === this.currentDossierTemplateId);
}
this.dossiers = this._activeDossiersService.all.filter(d => d.dossierTemplateId === this.currentDossierTemplateId);
const templateDictionary = {
id: 'template',
dossierId: 'template',
dossierName: 'Template Dictionary',
dossierTemplateId: this.currentDossierTemplateId,
} as Dossier;
this.dossiers.push(templateDictionary);
}
#disableDiffEditor() {
this.showDiffEditor = false;
this.diffEditorText = '';
}
}

View File

@ -133,6 +133,10 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
return !!this._dictionariesMapService.get(dossierTemplateId).find(e => e.type === SuperTypes.ManualRedaction && !e.virtual);
}
hasType(dossierTemplateId: string, type: string): boolean {
return !!this._dictionariesMapService.get(dossierTemplateId).find(e => e.type === type && !e.virtual);
}
getRedactTextDictionaries(dossierTemplateId: string, dossierDictionaryOnly: boolean): Dictionary[] {
return this._dictionariesMapService
.get(dossierTemplateId)