Revision of the dossier dictionary presentation

This commit is contained in:
Adina Țeudan 2024-09-23 13:18:05 +03:00
parent 63e53cb2ed
commit 5de6b359ee
8 changed files with 87 additions and 140 deletions

View File

@ -18,12 +18,15 @@
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:entries"></mat-icon>
{{
dictionary.entries.length +
dictionary.falsePositiveEntries.length +
dictionary.falseRecommendationEntries.length
}}
entries
<span
[translateParams]="{
count:
dictionary.entries.length +
dictionary.falsePositiveEntries.length +
dictionary.falseRecommendationEntries.length,
}"
translate="edit-dossier-dialog.dictionary.entries-count"
></span>
</div>
</div>
</div>
@ -36,12 +39,12 @@
<div class="flex-align-items-center">
{{ selectedDictionary?.label }}
<iqser-circle-button
*ngIf="selectedDictionary.dossierDictionaryOnly && selectedDictionary.hasDictionary"
(action)="openEditDictionaryModal()"
*ngIf="selectedDictionary.dossierDictionaryOnly && selectedDictionary.hasDictionary"
[size]="20"
[tooltip]="'edit-dossier-dialog.dictionary.edit-button-tooltip' | translate"
icon="iqser:edit"
class="p-left-8"
icon="iqser:edit"
></iqser-circle-button>
</div>
<div class="small-label stats-subtitle">
@ -68,23 +71,6 @@
</div>
</div>
</div>
<div *ngIf="!selectedDictionary.hint" [class.read-only]="!canEdit" class="header-right flex">
<iqser-icon-button
(click)="selectEntryType(entryTypes.ENTRY)"
[active]="activeEntryType === entryTypes.ENTRY"
[label]="'edit-dossier-dialog.dictionary.to-redact' | translate"
></iqser-icon-button>
<iqser-icon-button
(click)="selectEntryType(entryTypes.FALSE_POSITIVE)"
[active]="activeEntryType === entryTypes.FALSE_POSITIVE"
[label]="'edit-dossier-dialog.dictionary.false-positives' | translate"
></iqser-icon-button>
<iqser-icon-button
(click)="selectEntryType(entryTypes.FALSE_RECOMMENDATION)"
[active]="activeEntryType === entryTypes.FALSE_RECOMMENDATION"
[label]="'edit-dossier-dialog.dictionary.false-recommendations' | translate"
></iqser-icon-button>
</div>
</div>
<redaction-dictionary-manager
@ -97,6 +83,32 @@
[selectedDictionaryTypeLabel]="selectedDictionary.label"
[selectedDictionaryType]="selectedDictionary.type"
[withFloatingActions]="false"
></redaction-dictionary-manager>
>
<ng-container slot="typeSwitch">
<div *ngIf="!selectedDictionary.hint" [class.read-only]="!canEdit" class="header-right flex">
<iqser-icon-button
(click)="selectEntryType(entryTypes.ENTRY)"
[active]="activeEntryType === entryTypes.ENTRY"
[label]="'edit-dossier-dialog.dictionary.to-redact' | translate: { count: selectedDictionary.entries.length }"
></iqser-icon-button>
<iqser-icon-button
(click)="selectEntryType(entryTypes.FALSE_POSITIVE)"
[active]="activeEntryType === entryTypes.FALSE_POSITIVE"
[label]="
'edit-dossier-dialog.dictionary.false-positives'
| translate: { count: selectedDictionary.falsePositiveEntries.length }
"
></iqser-icon-button>
<iqser-icon-button
(click)="selectEntryType(entryTypes.FALSE_RECOMMENDATION)"
[active]="activeEntryType === entryTypes.FALSE_RECOMMENDATION"
[label]="
'edit-dossier-dialog.dictionary.false-recommendations'
| translate: { count: selectedDictionary.falseRecommendationEntries.length }
"
></iqser-icon-button>
</div>
</ng-container>
</redaction-dictionary-manager>
</div>
</div>

View File

@ -1,29 +1,7 @@
<div class="content-container">
<div class="actions-bar">
<div class="flex-align-items-center mr-32">
<div class="iqser-input-group w-250">
<input
#inputElement
(keyup)="searchChanged(searchText)"
[(ngModel)]="searchText"
[class.with-matches]="searchText.length > 0"
[placeholder]="'dictionary-overview.search' | translate"
type="text"
/>
<div class="input-icons">
<div *ngIf="searchText.length === 0" class="no-input">
<mat-icon svgIcon="iqser:search"></mat-icon>
</div>
<div *ngIf="searchText.length > 0" class="with-input">
{{ currentMatch + '/' + findMatches.length }}
<mat-icon (click)="previousSearchMatch()" class="pointer" svgIcon="red:arrow-up"></mat-icon>
<mat-icon (click)="nextSearchMatch()" class="pointer" svgIcon="iqser:arrow-down"></mat-icon>
<mat-icon (click)="revert(); inputElement.focus()" class="pointer" svgIcon="iqser:close"></mat-icon>
</div>
</div>
</div>
<ng-content select="[slot=typeSwitch]"></ng-content>
<iqser-circle-button
(action)="download()"
@ -33,6 +11,13 @@
class="ml-8"
icon="iqser:download"
></iqser-circle-button>
<iqser-circle-button
(action)="editor.openFindPanel()"
[matTooltip]="'dictionary-overview.search' | translate"
class="ml-8"
icon="iqser:search"
></iqser-circle-button>
</div>
<div class="compare">

View File

@ -8,9 +8,7 @@ import { DossierTemplatesService } from '@services/dossier-templates/dossier-tem
import { EditorComponent } from '@shared/components/editor/editor.component';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
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 { List } from '@iqser/common-ui/lib/utils';
import { firstValueFrom } from 'rxjs';
import { MatIcon } from '@angular/material/icon';
import { NgForOf, NgIf } from '@angular/common';
@ -23,7 +21,6 @@ import { MatOption, MatSelect } from '@angular/material/select';
import { MatDivider } from '@angular/material/divider';
const COMPARE_ENTRIES_ERROR = 'compare-entries-error';
const SMOOTH_SCROLL = 0;
const HELP_MODE_KEYS = {
dictionary: 'dictionary_entity',
'false-positive': 'false_recommendations_entity',
@ -53,8 +50,6 @@ const HELP_MODE_KEYS = {
],
})
export class DictionaryManagerComponent implements OnChanges, OnInit {
private _searchDecorations: string[] = [];
readonly #currentTab = window.location.href.split('/').pop();
@Input() type: DictionaryType = 'dictionary';
@Input() entityType?: string;
@Input() currentDossierId: string;
@ -73,11 +68,8 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
readonly iconButtonTypes = IconButtonTypes;
dossiers: Dossier[];
dossierTemplates: DossierTemplate[] = this.dossierTemplatesService.all;
currentMatch = 0;
findMatches: FindMatch[] = [];
diffEditorText = '';
showDiffEditor = false;
searchText = '';
selectDossier = { dossierName: _('dictionary-overview.compare.select-dossier') } as Dossier;
selectDictionary = {
label: _('dictionary-overview.compare.select-dictionary'),
@ -85,10 +77,11 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
selectDossierTemplate = { name: _('dictionary-overview.compare.select-dossier-template') } as DossierTemplate;
compare = false;
dictionaries: List<Dictionary> = this.#dictionaries;
protected initialDossierTemplateId: string;
readonly #currentTab = window.location.href.split('/').pop();
#dossierTemplate = this.dossierTemplatesService.all[0];
#dossier = this.selectDossier;
#dictionary = this.selectDictionary;
protected initialDossierTemplateId: string;
constructor(
private readonly _dictionaryService: DictionaryService,
@ -99,11 +92,6 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
readonly dossierTemplatesService: DossierTemplatesService,
) {}
ngOnInit() {
this.initialDossierTemplateId = this.currentDossierTemplateId;
this.#updateDropdownsOptions();
}
get selectedDossierTemplate() {
return this.#dossierTemplate;
}
@ -150,6 +138,7 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
if (dictionary.type) {
this.selectedDictionaryType = dictionary.type;
this.#dictionary = dictionary;
console.log(dictionary);
this.#onDossierChanged(this.#dossier.dossierTemplateId).then(entries => this.#updateDiffEditorText(entries));
}
}
@ -185,6 +174,11 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
);
}
ngOnInit() {
this.initialDossierTemplateId = this.currentDossierTemplateId;
this.#updateDropdownsOptions();
}
download(): void {
const content = this.editor.currentEntries.join('\n');
const blob = new Blob([content], {
@ -195,35 +189,6 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
revert() {
this.editor?.revert();
this.searchText = '';
this.searchChanged('');
}
@Debounce()
searchChanged(text: string) {
this.findMatches = this.#getMatches(text.toLowerCase());
this.#applySearchDecorations();
this.currentMatch = 0;
this.nextSearchMatch();
}
nextSearchMatch(): void {
if (this.findMatches.length <= 0) {
return;
}
this.currentMatch = this.currentMatch < this.findMatches.length ? this.currentMatch + 1 : 1;
this.#scrollToCurrentMatch();
}
previousSearchMatch(): void {
if (this.findMatches.length <= 0) {
return;
}
this.currentMatch = this.currentMatch > 1 ? this.currentMatch - 1 : this.findMatches.length;
this.#scrollToCurrentMatch();
}
toggleCompareMode() {
@ -246,30 +211,6 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
}
}
#applySearchDecorations() {
this._searchDecorations = this.editor.codeEditor?.deltaDecorations(this._searchDecorations, []) || [];
const decorations = this.findMatches.map(match => this.#getSearchDecoration(match));
this._searchDecorations = this.editor.codeEditor?.deltaDecorations(this._searchDecorations, decorations) || [];
}
#getMatches(text: string): FindMatch[] {
const model = this.editor.codeEditor?.getModel();
return model?.findMatches(text, false, false, false, null, false) || [];
}
#getSearchDecoration(match: FindMatch): IModelDeltaDecoration {
return { range: match.range, options: { inlineClassName: 'search-marker' } };
}
#scrollToCurrentMatch(): void {
const range = this.findMatches[this.currentMatch - 1].range;
this.editor.codeEditor.setSelection(range);
this.editor.codeEditor.revealLineInCenter(range.startLineNumber, SMOOTH_SCROLL);
}
async #onDossierChanged(dossierTemplateId: string, dossierId?: string) {
let dictionary: IDictionary;
if (dossierId === 'template') {

View File

@ -5,15 +5,15 @@ import { Subject } from 'rxjs';
import { debounceTime, filter, tap } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { List, OnChange } from '@iqser/common-ui/lib/utils';
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
import ICodeEditor = monaco.editor.ICodeEditor;
import IDiffEditor = monaco.editor.IDiffEditor;
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
import ILineChange = monaco.editor.ILineChange;
import IEditorMouseEvent = monaco.editor.IEditorMouseEvent;
import { MonacoEditorModule, MonacoStandaloneCodeEditor, MonacoStandaloneDiffEditor } from '@materia-ui/ngx-monaco-editor';
import { FormsModule } from '@angular/forms';
import { NgIf } from '@angular/common';
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
import IDiffEditor = monaco.editor.IDiffEditor;
import ICodeEditor = monaco.editor.ICodeEditor;
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
import ILineChange = monaco.editor.ILineChange;
import IEditorMouseEvent = monaco.editor.IEditorMouseEvent;
const MIN_WORD_LENGTH = 2;
const lineChangeToDecoration = ({ originalEndLineNumber, originalStartLineNumber }: ILineChange) =>
@ -35,10 +35,6 @@ const notZero = (lineChange: ILineChange) => lineChange.originalEndLineNumber !=
imports: [MonacoEditorModule, FormsModule, NgIf],
})
export class EditorComponent implements OnInit, OnChanges {
#initialEntriesSet = new Set<string>();
private _diffEditor: IDiffEditor;
private _decorations: string[] = [];
protected readonly _editorTextChanged$ = new Subject<string>();
@Input() showDiffEditor = false;
@Input() diffEditorText: string;
@Input() @OnChange<List, EditorComponent>('revert') initialEntries: List;
@ -51,6 +47,10 @@ export class EditorComponent implements OnInit, OnChanges {
editorOptions: IStandaloneEditorConstructionOptions = {};
codeEditor: ICodeEditor;
value: string;
protected readonly _editorTextChanged$ = new Subject<string>();
#initialEntriesSet = new Set<string>();
private _diffEditor: IDiffEditor;
private _decorations: string[] = [];
constructor(
private readonly _loadingService: LoadingService,
@ -84,6 +84,11 @@ export class EditorComponent implements OnInit, OnChanges {
return this.currentEntries.length;
}
async openFindPanel(): Promise<void> {
const editor = this.showDiffEditor ? this._diffEditor.getOriginalEditor() : this.codeEditor;
await editor.getAction('actions.find').run();
}
onPaste(event: ClipboardEvent) {
if ((event.target as HTMLTextAreaElement).ariaRoleDescription === 'editor') {
this._loadingService.start();

View File

@ -1234,11 +1234,12 @@
"title": "{label} bearbeiten"
},
"entries": "{length} {length, plural, one{Eintrag} other{Einträge}}",
"entries-count": "",
"false-positive-entries": "{length} {length, plural, one{Falsch-Positiver} other{Falsch-Positive}}",
"false-positives": "Falsch-Positive",
"false-positives": "Falsch-Positive ({count})",
"false-recommendation-entries": "{length} {length, plural, one{falsche Empfehlung} other{falsche Empfehlungen}}",
"false-recommendations": "Falsche Empfehlungen",
"to-redact": "Schwärzungen"
"false-recommendations": "Falsche Empfehlungen ({count})",
"to-redact": "Schwärzungen ({count})"
},
"general-info": {
"form": {

View File

@ -1234,11 +1234,12 @@
"title": "Edit {label}"
},
"entries": "{length} {length, plural, one{entry} other{entries}} to redact",
"entries-count": "{count} {count, plural, one{entry} other{entries}}",
"false-positive-entries": "{length} false positive {length, plural, one{entry} other{entries}}",
"false-positives": "False positives",
"false-positives": "False positives ({count})",
"false-recommendation-entries": "{length} false recommendation {length, plural, one{entry} other{entries}}",
"false-recommendations": "False recommendations",
"to-redact": "To redact"
"false-recommendations": "False recommendations ({count})",
"to-redact": "Entries ({count})"
},
"general-info": {
"form": {
@ -1264,7 +1265,7 @@
"choose-download": "Select the documents for your download:",
"dictionary": "Dictionaries",
"dossier-attributes": "Dossier attributes",
"dossier-dictionary": "Dictionaries",
"dossier-dictionary": "Dossier entries",
"dossier-info": "Dossier info",
"download-package": "Download package",
"general-info": "General information",

View File

@ -1234,11 +1234,12 @@
"title": ""
},
"entries": "{length} {length, plural, one{entry} other{entries}} to {hint, select, true{annotate} other{redact}}",
"entries-count": "",
"false-positive-entries": "{length} false positive {length, plural, one{entry} other{entries}}",
"false-positives": "False positives",
"false-positives": "False positives ({count})",
"false-recommendation-entries": "{length} false recommendation {length, plural, one{entry} other{entries}}",
"false-recommendations": "False recommendations",
"to-redact": "To redact"
"false-recommendations": "False recommendations ({count})",
"to-redact": "To redact ({count})"
},
"general-info": {
"form": {

View File

@ -1234,11 +1234,12 @@
"title": ""
},
"entries": "{length} {length, plural, one{entry} other{entries}} to {hint, select, true{annotate} other{redact}}",
"entries-count": "{count} {count, plural, one{entry} other{entries}}",
"false-positive-entries": "{length} false positive {length, plural, one{entry} other{entries}}",
"false-positives": "False positives",
"false-positives": "False positives ({count})",
"false-recommendation-entries": "{length} false recommendation {length, plural, one{entry} other{entries}}",
"false-recommendations": "False recommendations",
"to-redact": "To redact"
"false-recommendations": "False recommendations ({count})",
"to-redact": "To redact ({count})"
},
"general-info": {
"form": {