RED-6801 - Effective dossier dictionary in Dossier Settings

This commit is contained in:
Valentin Mihai 2023-07-19 22:40:35 +03:00
parent a23a3691cf
commit 6531ec1fd3
4 changed files with 74 additions and 161 deletions

View File

@ -3,7 +3,7 @@
<div
class="dictionary"
*ngFor="let dictionary of dictionaries"
[class.active]="dictionary.id === selectedDictionary.id"
[class.active]="dictionary.label === selectedDictionary.label"
(click)="selectDictionary(dictionary)"
>
<redaction-annotation-icon [color]="dictionary.hexColor" label="R" type="square"></redaction-annotation-icon>
@ -33,16 +33,16 @@
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:entries"></mat-icon>
<ng-container *ngIf="activeDictionaryTab === dictionaryTab.TO_REDACT">
<ng-container *ngIf="activeEntryType === entryTypes.ENTRY">
{{ 'edit-dossier-dialog.dictionary.entries' | translate : { length: entriesToDisplay.length } }}
</ng-container>
<ng-container *ngIf="activeDictionaryTab === dictionaryTab.FALSE_POSITIVES">
<ng-container *ngIf="activeEntryType === entryTypes.FALSE_POSITIVE">
{{
'edit-dossier-dialog.dictionary.false-positive-entries'
| translate : { length: entriesToDisplay.length }
}}
</ng-container>
<ng-container *ngIf="activeDictionaryTab === dictionaryTab.FALSE_RECOMMENDATIONS">
<ng-container *ngIf="activeEntryType === entryTypes.FALSE_RECOMMENDATION">
{{
'edit-dossier-dialog.dictionary.false-recommendation-entries'
| translate : { length: entriesToDisplay.length }
@ -55,18 +55,18 @@
<div class="header-right flex">
<iqser-icon-button
[label]="'edit-dossier-dialog.dictionary.to-redact' | translate"
[active]="activeDictionaryTab === dictionaryTab.TO_REDACT"
(click)="selectDictionaryTab(dictionaryTab.TO_REDACT)"
[active]="activeEntryType === entryTypes.ENTRY"
(click)="selectEntryType(entryTypes.ENTRY)"
></iqser-icon-button>
<iqser-icon-button
[label]="'edit-dossier-dialog.dictionary.false-positives' | translate"
[active]="activeDictionaryTab === dictionaryTab.FALSE_POSITIVES"
(click)="selectDictionaryTab(dictionaryTab.FALSE_POSITIVES)"
[active]="activeEntryType === entryTypes.FALSE_POSITIVE"
(click)="selectEntryType(entryTypes.FALSE_POSITIVE)"
></iqser-icon-button>
<iqser-icon-button
[label]="'edit-dossier-dialog.dictionary.false-recommendations' | translate"
[active]="activeDictionaryTab === dictionaryTab.FALSE_RECOMMENDATIONS"
(click)="selectDictionaryTab(dictionaryTab.FALSE_RECOMMENDATIONS)"
[active]="activeEntryType === entryTypes.FALSE_RECOMMENDATION"
(click)="selectEntryType(entryTypes.FALSE_RECOMMENDATION)"
></iqser-icon-button>
</div>
</div>
@ -75,6 +75,8 @@
[canEdit]="canEdit"
[initialEntries]="entriesToDisplay || []"
[withFloatingActions]="false"
[selectedDictionaryType]="selectedDictionary.type"
[activeEntryType]="activeEntryType"
></redaction-dictionary-manager>
</div>
</div>

View File

@ -1,5 +1,5 @@
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { Dictionary, Dossier } from '@red/domain';
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, Dossier } from '@red/domain';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { PermissionsService } from '@services/permissions.service';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
@ -9,12 +9,6 @@ import { DossiersDialogService } from '../../../services/dossiers-dialog.service
import { firstValueFrom } from 'rxjs';
import { List } from '@iqser/common-ui/lib/utils';
enum DictionaryTab {
TO_REDACT,
FALSE_POSITIVES,
FALSE_RECOMMENDATIONS,
}
@Component({
selector: 'redaction-edit-dossier-dictionary',
templateUrl: './edit-dossier-dictionary.component.html',
@ -24,14 +18,13 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
@Input() dossier: Dossier;
canEdit = false;
dossierDictionary: Dictionary;
dictionaries: Dictionary[];
selectedDictionary: Dictionary;
activeDictionaryTab = DictionaryTab.FALSE_RECOMMENDATIONS;
activeEntryType = DictionaryEntryTypes.ENTRY;
entriesToDisplay: List = [];
readonly circleButtonTypes = CircleButtonTypes;
readonly dictionaryTab = DictionaryTab;
readonly entryTypes = DictionaryEntryTypes;
@ViewChild(DictionaryManagerComponent, { static: false }) private readonly _dictionaryManager: DictionaryManagerComponent;
constructor(
@ -66,9 +59,10 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
this._dictionaryManager.editor.currentEntries,
this._dictionaryManager.initialEntries,
this.dossier.dossierTemplateId,
this.dossierDictionary.type,
this.selectedDictionary.type,
this.dossier.id,
false,
this.activeEntryType,
);
await this.#updateDossierDictionary();
@ -82,24 +76,24 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
this._dictionaryManager.revert();
}
selectDictionary(dictionary: Dictionary) {
selectDictionary(dictionary: Dictionary, entryType: DictionaryEntryType = DictionaryEntryTypes.ENTRY) {
this.selectedDictionary = dictionary;
this.selectDictionaryTab(DictionaryTab.TO_REDACT);
this.selectEntryType(entryType);
}
selectDictionaryTab(selectedDictionaryTab: DictionaryTab) {
this.activeDictionaryTab = selectedDictionaryTab;
selectEntryType(selectedEntryType: DictionaryEntryType) {
this.activeEntryType = selectedEntryType;
switch (selectedDictionaryTab) {
case DictionaryTab.TO_REDACT: {
switch (selectedEntryType) {
case DictionaryEntryTypes.ENTRY: {
this.entriesToDisplay = this.selectedDictionary.entries;
break;
}
case DictionaryTab.FALSE_POSITIVES: {
case DictionaryEntryTypes.FALSE_POSITIVE: {
this.entriesToDisplay = this.selectedDictionary.falsePositiveEntries;
break;
}
case DictionaryTab.FALSE_RECOMMENDATIONS: {
case DictionaryEntryTypes.FALSE_RECOMMENDATION: {
this.entriesToDisplay = this.selectedDictionary.falseRecommendationEntries;
break;
}
@ -112,6 +106,17 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
this.dictionaries = await firstValueFrom(
this._dictionaryService.loadDictionaryEntriesByType(dictionaryTypes, dossierTemplateId, dossierId),
);
this.selectDictionary(this.dictionaries[0]);
//TODO remove this when backend will send also the type
this.#setType(dictionaryTypes);
this.selectDictionary(this.dictionaries[0], this.activeEntryType);
}
//TODO remove this when backend will send also the type
#setType(dictionaryTypes: string[]) {
for (let i = 0; i < this.dictionaries.length; i++) {
const { ...dictionaryWithType } = this.dictionaries[i];
dictionaryWithType.type = dictionaryTypes[i];
this.dictionaries[i] = dictionaryWithType as Dictionary;
}
}
}

View File

@ -1,6 +1,14 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
import { IconButtonTypes, LoadingService } from '@iqser/common-ui';
import { Dictionary, DICTIONARY_TYPE_KEY_MAP, DictionaryType, Dossier, DossierTemplate } from '@red/domain';
import {
Dictionary,
DICTIONARY_TYPE_KEY_MAP,
DictionaryEntryType,
DictionaryEntryTypes,
DictionaryType,
Dossier,
DossierTemplate,
} 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';
@ -11,6 +19,7 @@ import { saveAs } from 'file-saver';
import { Debounce, List } from '@iqser/common-ui/lib/utils';
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
import FindMatch = monaco.editor.FindMatch;
import { firstValueFrom } from 'rxjs';
const SMOOTH_SCROLL = 0;
const HELP_MODE_KEYS = {
@ -35,6 +44,8 @@ export class DictionaryManagerComponent implements OnChanges {
@Input() canEdit = false;
@Input() canDownload = false;
@Input() isLeavingPage = false;
@Input() selectedDictionaryType = 'dossier_redaction';
@Input() activeEntryType: DictionaryEntryType = DictionaryEntryTypes.ENTRY;
@Output() readonly saveDictionary = new EventEmitter<string[]>();
@ViewChild(EditorComponent) readonly editor: EditorComponent;
readonly iconButtonTypes = IconButtonTypes;
@ -197,6 +208,12 @@ export class DictionaryManagerComponent implements OnChanges {
if (!changes.isLeavingPage) {
this.revert();
}
if (changes.activeEntryType && this._dossier?.dossierTemplateId && this.dossier?.dossierId) {
this.#onDossierChanged(this._dossier.dossierTemplateId, this._dossier.dossierId).then(entries => {
this.diffEditorText = entries;
this.showDiffEditor = true;
});
}
}
private _applySearchDecorations() {
@ -223,9 +240,19 @@ export class DictionaryManagerComponent implements OnChanges {
this.editor.codeEditor.revealLineInCenter(range.startLineNumber, SMOOTH_SCROLL);
}
async #onDossierChanged(dossierTemplateId: string, dossierId?: string, type = 'dossier_redaction') {
const dictionary = await this._dictionaryService.getForType(dossierTemplateId, type, dossierId);
return this.#toString([...dictionary.entries]);
async #onDossierChanged(dossierTemplateId: string, dossierId?: string) {
const dictionary = (
await firstValueFrom(
this._dictionaryService.loadDictionaryEntriesByType([this.selectedDictionaryType], dossierTemplateId, dossierId),
)
)[0];
const activeEntries =
this.activeEntryType === DictionaryEntryTypes.ENTRY
? [...dictionary.entries]
: this.activeEntryType === DictionaryEntryTypes.FALSE_POSITIVE
? [...dictionary.falsePositiveEntries]
: [...dictionary.falseRecommendationEntries];
return this.#toString(activeEntries);
}
#toString(entries: string[]): string {

View File

@ -14,127 +14,6 @@ import { List } from '@iqser/common-ui/lib/utils';
const MIN_WORD_LENGTH = 2;
const IMAGE_TYPES = ['image', 'formula', 'ocr'];
const DICTIONARIES = [
{
addToDictionaryAction: true,
caseInsensitive: true,
description: 'All site names and addresses, ading the…). Except addresses in published literature and the applicant address.',
dossierTemplateId: '56e8b136-e87e-45fc-851b-434704add3c4',
entries: ['test', 'test entry', 'entry 10'],
falsePositiveEntries: ['test false positive entry'],
falseRecommendationEntries: [
'false recommendation entry',
'test',
'test',
'test',
'false recommendation entry',
'test',
'test',
'test',
'false recommendation entry',
'test',
'test',
'test',
'false recommendation entry',
'test',
'test',
'test',
'false recommendation entry',
'test',
'test',
'test',
'false recommendation entry',
'test',
'test',
'test',
'false recommendation entry',
'test',
'test',
'test',
'false recommendation entry',
'test',
'test',
'test',
],
hexColor: '#9398a0',
recommendationHexColor: '#8df06c',
skippedHexColor: '#c498fa',
hint: false,
label: 'CBI Address',
rank: 140,
recommendation: false,
type: 'CBI_address',
hasDictionary: true,
systemManaged: false,
dossierDictionaryOnly: false,
id: '1',
},
{
virtual: false,
addToDictionaryAction: true,
caseInsensitive: false,
description: 'All authors named in the study documentation. Except names in published literature.',
dossierTemplateId: '56e8b136-e87e-45fc-851b-434704add3c4',
entries: [],
falsePositiveEntries: [],
falseRecommendationEntries: [],
hexColor: '#9398a0',
recommendationHexColor: '#8df06c',
skippedHexColor: '#c498fa',
hint: false,
label: 'CBI Author',
rank: 130,
recommendation: false,
type: 'CBI_author',
hasDictionary: true,
systemManaged: false,
dossierDictionaryOnly: false,
id: '2',
},
{
addToDictionaryAction: true,
caseInsensitive: true,
description: 'Entries in this dictionary will only be redacted in this dossier.',
dossierTemplateId: '56e8b136-e87e-45fc-851b-434704add3c4',
entries: [],
falsePositiveEntries: [],
falseRecommendationEntries: [],
hexColor: '#9398a0',
recommendationHexColor: '#8df06c',
skippedHexColor: '#c498fa',
hint: false,
label: 'Dossier Redaction',
rank: 1500,
recommendation: false,
type: 'dossier_redaction',
hasDictionary: true,
systemManaged: true,
dossierDictionaryOnly: true,
id: '3',
},
{
addToDictionaryAction: true,
caseInsensitive: false,
description: 'Not authors but listed in the document: Names, signatures, telephone, email etc.; e.g. Reg Manager, QA Manager',
dossierTemplateId: '56e8b136-e87e-45fc-851b-434704add3c4',
entries: [],
falsePositiveEntries: [],
falseRecommendationEntries: [],
hexColor: '#9398a0',
recommendationHexColor: '#8df06c',
skippedHexColor: '#c498fa',
hint: false,
label: 'Personal Data',
rank: 150,
recommendation: false,
type: 'PII',
hasDictionary: true,
systemManaged: false,
dossierDictionaryOnly: false,
id: '4',
},
];
@Injectable({
providedIn: 'root',
})
@ -386,12 +265,11 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
const queryParams = [{ key: 'dossierId', value: dossierId }];
const requests = [];
for (const type of types) {
const request = this.getAll(`/${this._defaultModelPath}/${type}/${dossierTemplateId}`, queryParams);
const request = this.getAll(`${this._defaultModelPath}/merged/${type}/${dossierTemplateId}`, queryParams);
requests.push(request);
}
// return forkJoin(requests);
return of(DICTIONARIES as any[]);
return forkJoin(requests);
}
/**
@ -424,9 +302,10 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
dictionaryEntryType: DictionaryEntryType,
dossierId: string,
) {
const queryParams = dossierId
? [{ key: 'dossierId', value: dossierId }]
: [{ key: 'dictionaryEntryType', value: dictionaryEntryType }];
const queryParams = [
{ key: 'dossierId', value: dossierId },
{ key: 'dictionaryEntryType', value: dictionaryEntryType },
];
const url = `${this._defaultModelPath}/delete/${type}/${dossierTemplateId}`;
return firstValueFrom(this._post(entries, url, queryParams));
}