Merge branch 'VM/RED-6801'
This commit is contained in:
commit
98dd16ca0d
@ -1,19 +1,82 @@
|
||||
<div class="header-wrapper">
|
||||
<div class="header-left">
|
||||
<div class="heading">
|
||||
<div>{{ dossierDictionary?.label }}</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ 'edit-dossier-dialog.dictionary.entries' | translate : { length: (dossierDictionary?.entries || []).length } }}
|
||||
<div class="dictionary-content" *ngIf="dictionaries && selectedDictionary">
|
||||
<div class="dictionaries">
|
||||
<div
|
||||
class="dictionary"
|
||||
*ngFor="let dictionary of dictionaries"
|
||||
[class.active]="dictionary.label === selectedDictionary.label"
|
||||
(click)="selectDictionary(dictionary)"
|
||||
>
|
||||
<redaction-annotation-icon [color]="dictionary.hexColor" label="R" type="square"></redaction-annotation-icon>
|
||||
<div class="details">
|
||||
<span> {{ dictionary.label }} </span>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{
|
||||
dictionary.entries.length +
|
||||
dictionary.falsePositiveEntries.length +
|
||||
dictionary.falseRecommendationEntries.length
|
||||
}}
|
||||
entries
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="entries">
|
||||
<div class="header-wrapper">
|
||||
<div class="header-left">
|
||||
<div class="heading">
|
||||
<div class="flex-align-items-center">
|
||||
{{ selectedDictionary?.label }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
<ng-container *ngIf="activeEntryType === entryTypes.ENTRY">
|
||||
{{ 'edit-dossier-dialog.dictionary.entries' | translate : { length: entriesToDisplay.length } }}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="activeEntryType === entryTypes.FALSE_POSITIVE">
|
||||
{{
|
||||
'edit-dossier-dialog.dictionary.false-positive-entries'
|
||||
| translate : { length: entriesToDisplay.length }
|
||||
}}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="activeEntryType === entryTypes.FALSE_RECOMMENDATION">
|
||||
{{
|
||||
'edit-dossier-dialog.dictionary.false-recommendation-entries'
|
||||
| translate : { length: entriesToDisplay.length }
|
||||
}}
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-right flex">
|
||||
<iqser-icon-button
|
||||
[label]="'edit-dossier-dialog.dictionary.to-redact' | translate"
|
||||
[active]="activeEntryType === entryTypes.ENTRY"
|
||||
(click)="selectEntryType(entryTypes.ENTRY)"
|
||||
></iqser-icon-button>
|
||||
<iqser-icon-button
|
||||
[label]="'edit-dossier-dialog.dictionary.false-positives' | translate"
|
||||
[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]="activeEntryType === entryTypes.FALSE_RECOMMENDATION"
|
||||
(click)="selectEntryType(entryTypes.FALSE_RECOMMENDATION)"
|
||||
></iqser-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<redaction-dictionary-manager
|
||||
[canEdit]="canEdit"
|
||||
[initialEntries]="dossierDictionary?.entries || []"
|
||||
[withFloatingActions]="false"
|
||||
></redaction-dictionary-manager>
|
||||
<redaction-dictionary-manager
|
||||
[canEdit]="canEdit"
|
||||
[initialEntries]="entriesToDisplay || []"
|
||||
[withFloatingActions]="false"
|
||||
[selectedDictionaryType]="selectedDictionary.type"
|
||||
[activeEntryType]="activeEntryType"
|
||||
></redaction-dictionary-manager>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,29 +1,68 @@
|
||||
:host {
|
||||
flex: 1;
|
||||
:host ::ng-deep .content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.dictionary-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.dictionaries {
|
||||
border-right: 1px solid var(--iqser-separator);
|
||||
width: 30%;
|
||||
overflow-y: scroll;
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
.dictionary {
|
||||
height: 40px;
|
||||
padding: 15px;
|
||||
border: 1px solid var(--iqser-separator);
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
.iqser-input-group {
|
||||
margin-left: 24px;
|
||||
span {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--iqser-grey-8);
|
||||
box-shadow: 0 5px 4px -4px rgba(0, 0, 0, 0.2);
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
.entries {
|
||||
width: 100%;
|
||||
padding: 24px 32px;
|
||||
.header-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.display-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
.header-left {
|
||||
display: flex;
|
||||
|
||||
> div {
|
||||
font-weight: 600;
|
||||
.iqser-input-group {
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.display-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
> div {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
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';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { CircleButtonTypes, LoadingService } from '@iqser/common-ui';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { List } from '@iqser/common-ui/lib/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-edit-dossier-dictionary',
|
||||
@ -17,9 +18,13 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
||||
@Input() dossier: Dossier;
|
||||
|
||||
canEdit = false;
|
||||
dossierDictionary: Dictionary;
|
||||
dictionaries: Dictionary[];
|
||||
selectedDictionary: Dictionary;
|
||||
activeEntryType = DictionaryEntryTypes.ENTRY;
|
||||
entriesToDisplay: List = [];
|
||||
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly entryTypes = DictionaryEntryTypes;
|
||||
@ViewChild(DictionaryManagerComponent, { static: false }) private readonly _dictionaryManager: DictionaryManagerComponent;
|
||||
|
||||
constructor(
|
||||
@ -30,7 +35,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
||||
) {}
|
||||
|
||||
get changed(): boolean {
|
||||
return this._dictionaryManager.editor.hasChanges;
|
||||
return this._dictionaryManager?.editor.hasChanges;
|
||||
}
|
||||
|
||||
get disabled(): boolean {
|
||||
@ -38,7 +43,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
||||
}
|
||||
|
||||
get valid(): boolean {
|
||||
return this._dictionaryManager.editor.hasChanges;
|
||||
return this._dictionaryManager?.editor.hasChanges;
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -54,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();
|
||||
@ -70,8 +76,47 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
||||
this._dictionaryManager.revert();
|
||||
}
|
||||
|
||||
selectDictionary(dictionary: Dictionary, entryType: DictionaryEntryType = DictionaryEntryTypes.ENTRY) {
|
||||
this.selectedDictionary = dictionary;
|
||||
this.selectEntryType(entryType);
|
||||
}
|
||||
|
||||
selectEntryType(selectedEntryType: DictionaryEntryType) {
|
||||
this.activeEntryType = selectedEntryType;
|
||||
|
||||
switch (selectedEntryType) {
|
||||
case DictionaryEntryTypes.ENTRY: {
|
||||
this.entriesToDisplay = this.selectedDictionary.entries;
|
||||
break;
|
||||
}
|
||||
case DictionaryEntryTypes.FALSE_POSITIVE: {
|
||||
this.entriesToDisplay = this.selectedDictionary.falsePositiveEntries;
|
||||
break;
|
||||
}
|
||||
case DictionaryEntryTypes.FALSE_RECOMMENDATION: {
|
||||
this.entriesToDisplay = this.selectedDictionary.falseRecommendationEntries;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async #updateDossierDictionary() {
|
||||
const { dossierId, dossierTemplateId } = this.dossier;
|
||||
this.dossierDictionary = await this._dictionaryService.loadDossierDictionary(dossierTemplateId, dossierId);
|
||||
const dictionaryTypes = this._dictionaryService.getPossibleDictionaries(dossierTemplateId, false, true).map(d => d.type);
|
||||
this.dictionaries = await firstValueFrom(
|
||||
this._dictionaryService.loadDictionaryEntriesByType(dictionaryTypes, dossierTemplateId, dossierId),
|
||||
);
|
||||
//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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,14 +13,16 @@
|
||||
flex: 1;
|
||||
|
||||
.content {
|
||||
padding: 24px 32px;
|
||||
overflow: auto;
|
||||
@include common-mixins.scroll-bar;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
padding: 24px 32px;
|
||||
margin-right: 16px;
|
||||
|
||||
&.no-padding {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&.no-actions {
|
||||
|
||||
@ -83,7 +83,7 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A
|
||||
}
|
||||
|
||||
get noPaddingTab(): boolean {
|
||||
return ['dossierAttributes'].includes(this.activeNav);
|
||||
return ['dossierAttributes', 'dossierDictionary'].includes(this.activeNav);
|
||||
}
|
||||
|
||||
get showHeading(): boolean {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { firstValueFrom, forkJoin, Observable, throwError } from 'rxjs';
|
||||
import { firstValueFrom, forkJoin, Observable, of, throwError } from 'rxjs';
|
||||
import { EntitiesService, QueryParam, Toaster } from '@iqser/common-ui';
|
||||
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IDictionary, IUpdateDictionary, SuperTypes } from '@red/domain';
|
||||
import { catchError, map, switchMap, tap } from 'rxjs/operators';
|
||||
@ -261,6 +261,17 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
);
|
||||
}
|
||||
|
||||
loadDictionaryEntriesByType(types: string[], dossierTemplateId: string, dossierId: string): Observable<Dictionary[]> {
|
||||
const queryParams = [{ key: 'dossierId', value: dossierId }];
|
||||
const requests = [];
|
||||
for (const type of types) {
|
||||
const request = this.getAll(`${this._defaultModelPath}/merged/${type}/${dossierTemplateId}`, queryParams);
|
||||
requests.push(request);
|
||||
}
|
||||
|
||||
return forkJoin(requests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dictionary entries with entry type.
|
||||
*/
|
||||
@ -291,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));
|
||||
}
|
||||
|
||||
@ -1119,7 +1119,12 @@
|
||||
"change-successful": "Dossier wurde aktualisiert.",
|
||||
"delete-successful": "Dossier wurde gelöscht.",
|
||||
"dictionary": {
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}}"
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}}",
|
||||
"false-positive-entries": "",
|
||||
"false-positives": "",
|
||||
"false-recommendation-entries": "",
|
||||
"false-recommendations": "",
|
||||
"to-redact": ""
|
||||
},
|
||||
"general-info": {
|
||||
"form": {
|
||||
|
||||
@ -675,7 +675,7 @@
|
||||
},
|
||||
"revert-changes": "Revert",
|
||||
"save-changes": "Save Changes",
|
||||
"search": "Search...",
|
||||
"search": "Search entries ...",
|
||||
"select-dictionary": "Select a dictionary above to compare with the current one.",
|
||||
"success": {
|
||||
"generic": "Dictionary updated!"
|
||||
@ -1119,7 +1119,12 @@
|
||||
"change-successful": "Dossier {dossierName} was updated.",
|
||||
"delete-successful": "Dossier {dossierName} was deleted.",
|
||||
"dictionary": {
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}}"
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}} to redact",
|
||||
"false-positive-entries": "{length} false positive {length, plural, one{entry} other{entries}}",
|
||||
"false-positives": "False Positives",
|
||||
"false-recommendation-entries": "{length} false recommendation {length, plural, one{entry} other{entries}}",
|
||||
"false-recommendations": "False Recommendations",
|
||||
"to-redact": "To Redact"
|
||||
},
|
||||
"general-info": {
|
||||
"form": {
|
||||
|
||||
@ -1119,7 +1119,12 @@
|
||||
"change-successful": "Dossier wurde aktualisiert.",
|
||||
"delete-successful": "Dossier wurde gelöscht.",
|
||||
"dictionary": {
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}}"
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}}",
|
||||
"false-positive-entries": "",
|
||||
"false-positives": "",
|
||||
"false-recommendation-entries": "",
|
||||
"false-recommendations": "",
|
||||
"to-redact": ""
|
||||
},
|
||||
"general-info": {
|
||||
"form": {
|
||||
|
||||
@ -675,7 +675,7 @@
|
||||
},
|
||||
"revert-changes": "Revert",
|
||||
"save-changes": "Save Changes",
|
||||
"search": "Search...",
|
||||
"search": "Search entries ...",
|
||||
"select-dictionary": "Select a dictionary above to compare with the current one.",
|
||||
"success": {
|
||||
"generic": "Dictionary updated!"
|
||||
@ -1119,7 +1119,12 @@
|
||||
"change-successful": "Dossier {dossierName} was updated.",
|
||||
"delete-successful": "Dossier {dossierName} was deleted.",
|
||||
"dictionary": {
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}}"
|
||||
"entries": "{length} {length, plural, one{entry} other{entries}} to redact",
|
||||
"false-positive-entries": "{length} false positive {length, plural, one{entry} other{entries}}",
|
||||
"false-positives": "False Positives",
|
||||
"false-recommendation-entries": "{length} false recommendation {length, plural, one{entry} other{entries}}",
|
||||
"false-recommendations": "False Recommendations",
|
||||
"to-redact": "To Redact"
|
||||
},
|
||||
"general-info": {
|
||||
"form": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user