Merge branch 'master' into VM/RED-8748
This commit is contained in:
commit
cae3f2dec3
@ -6,15 +6,21 @@
|
|||||||
<ngx-monaco-editor (init)="onCodeEditorInit($event)" [(ngModel)]="codeEditorText" [options]="editorOptions"></ngx-monaco-editor>
|
<ngx-monaco-editor (init)="onCodeEditorInit($event)" [(ngModel)]="codeEditorText" [options]="editorOptions"></ngx-monaco-editor>
|
||||||
|
|
||||||
<div *ngIf="changed && permissionsService.canEditRules() && !isLeaving" class="changes-box">
|
<div *ngIf="changed && permissionsService.canEditRules() && !isLeaving" class="changes-box">
|
||||||
<div (click)="goToErrors()" *ngIf="numberOfErrors()" class="errors">
|
<div (click)="goToErrors()" *ngIf="numberOfErrors() || numberOfWarnings()" class="errors">
|
||||||
<span>
|
<span>
|
||||||
<mat-icon [svgIcon]="'iqser:alert-circle'" class="icon"></mat-icon>
|
<mat-icon *ngIf="numberOfErrors()" [svgIcon]="'iqser:alert-circle'" class="icon"></mat-icon>
|
||||||
<div class="found-errors">
|
<div class="found-errors">
|
||||||
<span [translateParams]="{ errors: numberOfErrors() }" [translate]="translations[this.type]['errors-found']"></span>
|
<span
|
||||||
|
*ngIf="numberOfErrors()"
|
||||||
|
[translateParams]="{ errors: numberOfErrors() }"
|
||||||
|
[translate]="translations[this.type]['errors-found']"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
[translateParams]="{ warnings: numberOfWarnings() }"
|
[translateParams]="{ warnings: numberOfWarnings() }"
|
||||||
[translate]="translations[this.type]['warnings-found']"
|
[translate]="translations[this.type]['warnings-found']"
|
||||||
class="warning"
|
class="warning"
|
||||||
|
[class.only-warning]="!numberOfErrors()"
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -63,6 +63,10 @@ ngx-monaco-editor {
|
|||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
color: var(--iqser-warn);
|
color: var(--iqser-warn);
|
||||||
|
|
||||||
|
&.only-warning {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -144,7 +144,7 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
|
|||||||
}),
|
}),
|
||||||
).then(
|
).then(
|
||||||
async (response: UploadResponse) => {
|
async (response: UploadResponse) => {
|
||||||
const errors = this.#mapErrors(response);
|
const errors = this.#mapErrors(response, dryRun);
|
||||||
this.#drawErrorMarkers(errors);
|
this.#drawErrorMarkers(errors);
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
await this.#initialize();
|
await this.#initialize();
|
||||||
@ -154,10 +154,13 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
|
|||||||
error => {
|
error => {
|
||||||
let errors: SyntaxError[];
|
let errors: SyntaxError[];
|
||||||
if (error.error?.syntaxErrorMessages) {
|
if (error.error?.syntaxErrorMessages) {
|
||||||
errors = this.#mapErrors(error.error);
|
errors = this.#mapErrors(error.error, dryRun);
|
||||||
} else {
|
} else {
|
||||||
const syntaxError: SyntaxError = { message: error.error.message, line: 1, column: 0 };
|
const syntaxError: SyntaxError = { message: error.error.message, line: 1, column: 0 };
|
||||||
errors = this.#mapErrors({ blacklistErrorMessages: [], syntaxErrorMessages: [syntaxError], deprecatedWarnings: [] });
|
errors = this.#mapErrors(
|
||||||
|
{ blacklistErrorMessages: [], syntaxErrorMessages: [syntaxError], deprecatedWarnings: [] },
|
||||||
|
dryRun,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
this.#drawErrorMarkers(errors);
|
this.#drawErrorMarkers(errors);
|
||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
@ -176,12 +179,12 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
|
|||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#mapErrors(response: UploadResponse) {
|
#mapErrors(response: UploadResponse, dryRun = false) {
|
||||||
return [
|
const warnings = response.deprecatedWarnings.map(w => ({ ...w, warning: true }));
|
||||||
...response.blacklistErrorMessages,
|
if (dryRun) {
|
||||||
...response.syntaxErrorMessages,
|
return warnings;
|
||||||
...response.deprecatedWarnings.map(w => ({ ...w, warning: true })),
|
}
|
||||||
];
|
return [...response.blacklistErrorMessages, ...response.syntaxErrorMessages, ...warnings];
|
||||||
}
|
}
|
||||||
|
|
||||||
#getValue(): string {
|
#getValue(): string {
|
||||||
@ -238,6 +241,7 @@ export class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
|
|||||||
#drawErrorMarkers(errors: SyntaxError[] | undefined) {
|
#drawErrorMarkers(errors: SyntaxError[] | undefined) {
|
||||||
const model = this.#codeEditor?.getModel();
|
const model = this.#codeEditor?.getModel();
|
||||||
if (!model || !errors?.length) {
|
if (!model || !errors?.length) {
|
||||||
|
this.#removeErrorMarkers();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const markers = [];
|
const markers = [];
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th *ngFor="let column of columns" [ngClass]="{ hide: !column.show }">
|
<th *ngFor="let column of columns" [ngClass]="{ hide: !column.show, 'w-50': staticColumns }">
|
||||||
<label>{{ column.label }}</label>
|
<label>{{ column.label }}</label>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody [ngStyle]="{ height: redactedTextsAreaHeight + 'px' }">
|
<tbody [ngStyle]="{ height: redactedTextsAreaHeight + 'px' }">
|
||||||
<tr *ngFor="let row of data">
|
<tr *ngFor="let row of data">
|
||||||
<td *ngFor="let cell of row" [ngClass]="{ hide: !cell.show, bold: cell.bold }">
|
<td *ngFor="let cell of row" [ngClass]="{ hide: !cell.show, bold: cell.bold, 'w-50': staticColumns }">
|
||||||
{{ cell.label }}
|
{{ cell.label }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -27,8 +27,10 @@ table {
|
|||||||
|
|
||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
|
&:not(.w-50) {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
max-width: 0;
|
max-width: 0;
|
||||||
width: 25%;
|
|
||||||
text-align: start;
|
text-align: start;
|
||||||
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -58,6 +60,15 @@ tbody tr:nth-child(odd) {
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-50 {
|
||||||
|
max-width: 0;
|
||||||
|
min-width: 50%;
|
||||||
|
|
||||||
|
&.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.bold {
|
.bold {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ const MAX_ITEMS_DISPLAY = 10;
|
|||||||
export class SelectedAnnotationsTableComponent {
|
export class SelectedAnnotationsTableComponent {
|
||||||
@Input({ required: true }) columns: ValueColumn[];
|
@Input({ required: true }) columns: ValueColumn[];
|
||||||
@Input({ required: true }) data: ValueColumn[][];
|
@Input({ required: true }) data: ValueColumn[][];
|
||||||
|
@Input() staticColumns = false;
|
||||||
|
|
||||||
get redactedTextsAreaHeight() {
|
get redactedTextsAreaHeight() {
|
||||||
return this.data.length <= MAX_ITEMS_DISPLAY ? TABLE_ROW_SIZE * this.data.length : TABLE_ROW_SIZE * MAX_ITEMS_DISPLAY;
|
return this.data.length <= MAX_ITEMS_DISPLAY ? TABLE_ROW_SIZE * this.data.length : TABLE_ROW_SIZE * MAX_ITEMS_DISPLAY;
|
||||||
|
|||||||
@ -8,7 +8,11 @@
|
|||||||
|
|
||||||
<div class="dialog-content redaction" [class.fixed-height]="isRedacted && isImage">
|
<div class="dialog-content redaction" [class.fixed-height]="isRedacted && isImage">
|
||||||
<div class="iqser-input-group" *ngIf="!isImage && redactedTexts.length && !allRectangles">
|
<div class="iqser-input-group" *ngIf="!isImage && redactedTexts.length && !allRectangles">
|
||||||
<redaction-selected-annotations-list [values]="redactedTexts"></redaction-selected-annotations-list>
|
<redaction-selected-annotations-table
|
||||||
|
[columns]="tableColumns"
|
||||||
|
[data]="tableData"
|
||||||
|
[staticColumns]="true"
|
||||||
|
></redaction-selected-annotations-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="!isManualRedaction" class="iqser-input-group w-450" [class.required]="!form.controls.type.disabled">
|
<div *ngIf="!isManualRedaction" class="iqser-input-group w-450" [class.required]="!form.controls.type.disabled">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
@use 'common-mixins';
|
|
||||||
|
|
||||||
.dialog-content {
|
.dialog-content {
|
||||||
|
padding-top: 8px;
|
||||||
|
|
||||||
&.fixed-height {
|
&.fixed-height {
|
||||||
height: 386px;
|
height: 386px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { EditRedactionData, EditRedactResult } from '../../utils/dialog-types';
|
|||||||
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
||||||
import { Roles } from '@users/roles';
|
import { Roles } from '@users/roles';
|
||||||
import { DialogHelpModeKeys } from '../../utils/constants';
|
import { DialogHelpModeKeys } from '../../utils/constants';
|
||||||
|
import { ValueColumn } from '../../components/selected-annotations-table/selected-annotations-table.component';
|
||||||
|
|
||||||
interface TypeSelectOptions {
|
interface TypeSelectOptions {
|
||||||
type: string;
|
type: string;
|
||||||
@ -38,6 +39,20 @@ export class EditRedactionDialogComponent
|
|||||||
readonly isRedacted = this.annotations.every(annotation => annotation.isRedacted);
|
readonly isRedacted = this.annotations.every(annotation => annotation.isRedacted);
|
||||||
readonly isImported: boolean = this.annotations.every(annotation => annotation.imported);
|
readonly isImported: boolean = this.annotations.every(annotation => annotation.imported);
|
||||||
readonly allRectangles = this.annotations.reduce((acc, a) => acc && a.AREA, true);
|
readonly allRectangles = this.annotations.reduce((acc, a) => acc && a.AREA, true);
|
||||||
|
readonly tableColumns = [
|
||||||
|
{
|
||||||
|
label: 'Value',
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Type',
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
readonly tableData: ValueColumn[][] = this.data.annotations.map(redaction => [
|
||||||
|
{ label: redaction.value, show: true, bold: true },
|
||||||
|
{ label: redaction.typeLabel, show: true },
|
||||||
|
]);
|
||||||
protected readonly roles = Roles;
|
protected readonly roles = Roles;
|
||||||
|
|
||||||
options: DetailsRadioOption<RedactOrHintOption>[] | undefined;
|
options: DetailsRadioOption<RedactOrHintOption>[] | undefined;
|
||||||
@ -112,6 +127,10 @@ export class EditRedactionDialogComponent
|
|||||||
return DialogHelpModeKeys.REDACTION_EDIT;
|
return DialogHelpModeKeys.REDACTION_EDIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get sameType() {
|
||||||
|
return this.annotations.every(annotation => annotation.type === this.annotations[0].type);
|
||||||
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.#setTypes();
|
this.#setTypes();
|
||||||
const data = await firstValueFrom(this._justificationsService.loadAll(this.#dossier.dossierTemplateId));
|
const data = await firstValueFrom(this._justificationsService.loadAll(this.#dossier.dossierTemplateId));
|
||||||
@ -163,10 +182,11 @@ export class EditRedactionDialogComponent
|
|||||||
|
|
||||||
#setTypes() {
|
#setTypes() {
|
||||||
this.dictionaries = this._dictionaryService.getEditableRedactionTypes(
|
this.dictionaries = this._dictionaryService.getEditableRedactionTypes(
|
||||||
this.#dossier.dossierTemplateId,
|
this.#dossier.dossierId,
|
||||||
this.isImage,
|
this.isImage,
|
||||||
this.isHint,
|
this.isHint,
|
||||||
this.annotations.every(annotation => annotation.isOCR),
|
this.annotations.every(annotation => annotation.isOCR),
|
||||||
|
this.sameType ? this.annotations[0].type : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.typeSelectOptions = this.dictionaries.map(dictionary => ({
|
this.typeSelectOptions = this.dictionaries.map(dictionary => ({
|
||||||
@ -198,13 +218,12 @@ export class EditRedactionDialogComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
#getForm() {
|
#getForm() {
|
||||||
const sameType = this.annotations.every(annotation => annotation.type === this.annotations[0].type);
|
|
||||||
const sameSection = this.annotations.every(annotation => annotation.section === this.annotations[0].section);
|
const sameSection = this.annotations.every(annotation => annotation.section === this.annotations[0].section);
|
||||||
return new FormGroup({
|
return new FormGroup({
|
||||||
reason: new FormControl<LegalBasisOption>({ value: null, disabled: this.someSkipped }),
|
reason: new FormControl<LegalBasisOption>({ value: null, disabled: this.someSkipped }),
|
||||||
comment: new FormControl<string>(null),
|
comment: new FormControl<string>(null),
|
||||||
type: new FormControl<string>({
|
type: new FormControl<string>({
|
||||||
value: sameType ? this.annotations[0].type : null,
|
value: this.sameType ? this.annotations[0].type : null,
|
||||||
disabled: this.isImported,
|
disabled: this.isImported,
|
||||||
}),
|
}),
|
||||||
section: new FormControl<string>({ value: sameSection ? this.annotations[0].section : null, disabled: this.isImported }),
|
section: new FormControl<string>({ value: sameSection ? this.annotations[0].section : null, disabled: this.isImported }),
|
||||||
|
|||||||
@ -4,7 +4,11 @@
|
|||||||
<div *ngIf="isHintDialog" class="dialog-header heading-l" [translate]="'manual-annotation.dialog.header.force-hint'"></div>
|
<div *ngIf="isHintDialog" class="dialog-header heading-l" [translate]="'manual-annotation.dialog.header.force-hint'"></div>
|
||||||
|
|
||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
<redaction-selected-annotations-table [columns]="tableColumns" [data]="tableData"></redaction-selected-annotations-table>
|
<redaction-selected-annotations-table
|
||||||
|
[columns]="tableColumns"
|
||||||
|
[data]="tableData"
|
||||||
|
[staticColumns]="true"
|
||||||
|
></redaction-selected-annotations-table>
|
||||||
<div *ngIf="!isHintDialog && !isDocumine" class="iqser-input-group required w-400">
|
<div *ngIf="!isHintDialog && !isDocumine" class="iqser-input-group required w-400">
|
||||||
<label [translate]="'manual-annotation.dialog.content.reason'"></label>
|
<label [translate]="'manual-annotation.dialog.content.reason'"></label>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
|
|||||||
@ -4,7 +4,11 @@
|
|||||||
|
|
||||||
<div class="dialog-content redaction">
|
<div class="dialog-content redaction">
|
||||||
<div class="iqser-input-group">
|
<div class="iqser-input-group">
|
||||||
<redaction-selected-annotations-list [values]="selectedValues"></redaction-selected-annotations-list>
|
<redaction-selected-annotations-table
|
||||||
|
[columns]="tableColumns"
|
||||||
|
[data]="tableData"
|
||||||
|
[staticColumns]="true"
|
||||||
|
></redaction-selected-annotations-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<iqser-details-radio
|
<iqser-details-radio
|
||||||
@ -17,7 +21,7 @@
|
|||||||
<label [translate]="'redact-text.dialog.content.type'"></label>
|
<label [translate]="'redact-text.dialog.content.type'"></label>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select [placeholder]="'redact-text.dialog.content.type-placeholder' | translate" formControlName="dictionary">
|
<mat-select [placeholder]="'redact-text.dialog.content.unchanged' | translate" formControlName="dictionary">
|
||||||
<mat-select-trigger>{{ displayedDictionaryLabel }}</mat-select-trigger>
|
<mat-select-trigger>{{ displayedDictionaryLabel }}</mat-select-trigger>
|
||||||
<mat-option
|
<mat-option
|
||||||
(click)="typeChanged()"
|
(click)="typeChanged()"
|
||||||
@ -46,7 +50,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dialog-actions">
|
<div class="dialog-actions">
|
||||||
<iqser-icon-button [label]="'redact-text.dialog.actions.save' | translate" [submit]="true" [type]="iconButtonTypes.primary">
|
<iqser-icon-button
|
||||||
|
[disabled]="disabled"
|
||||||
|
[label]="'redact-text.dialog.actions.save' | translate"
|
||||||
|
[submit]="true"
|
||||||
|
[type]="iconButtonTypes.primary"
|
||||||
|
>
|
||||||
</iqser-icon-button>
|
</iqser-icon-button>
|
||||||
|
|
||||||
<div [translate]="'redact-text.dialog.actions.cancel'" class="all-caps-label cancel" mat-dialog-close></div>
|
<div [translate]="'redact-text.dialog.actions.cancel'" class="all-caps-label cancel" mat-dialog-close></div>
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
.redaction {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
@ -12,9 +12,11 @@ import { tap } from 'rxjs/operators';
|
|||||||
import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options';
|
import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options';
|
||||||
import { RedactRecommendationData, RedactRecommendationResult } from '../../utils/dialog-types';
|
import { RedactRecommendationData, RedactRecommendationResult } from '../../utils/dialog-types';
|
||||||
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
||||||
|
import { ValueColumn } from '../../components/selected-annotations-table/selected-annotations-table.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './redact-recommendation-dialog.component.html',
|
templateUrl: './redact-recommendation-dialog.component.html',
|
||||||
|
styleUrl: './redact-recommendation-dialog.component.scss',
|
||||||
})
|
})
|
||||||
export class RedactRecommendationDialogComponent
|
export class RedactRecommendationDialogComponent
|
||||||
extends IqserDialogComponent<RedactRecommendationDialogComponent, RedactRecommendationData, RedactRecommendationResult>
|
extends IqserDialogComponent<RedactRecommendationDialogComponent, RedactRecommendationData, RedactRecommendationResult>
|
||||||
@ -30,7 +32,6 @@ export class RedactRecommendationDialogComponent
|
|||||||
dictionaryRequest = false;
|
dictionaryRequest = false;
|
||||||
legalOptions: LegalBasisOption[] = [];
|
legalOptions: LegalBasisOption[] = [];
|
||||||
dictionaries: Dictionary[] = [];
|
dictionaries: Dictionary[] = [];
|
||||||
readonly selectedValues = this.data.annotations.map(annotation => annotation.value);
|
|
||||||
readonly form = inject(FormBuilder).group({
|
readonly form = inject(FormBuilder).group({
|
||||||
selectedText: this.isMulti ? null : this.firstEntry.value,
|
selectedText: this.isMulti ? null : this.firstEntry.value,
|
||||||
comment: [null],
|
comment: [null],
|
||||||
@ -39,6 +40,21 @@ export class RedactRecommendationDialogComponent
|
|||||||
reason: [null],
|
reason: [null],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
readonly tableColumns = [
|
||||||
|
{
|
||||||
|
label: 'Value',
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Type',
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
readonly tableData: ValueColumn[][] = this.data.annotations.map(redaction => [
|
||||||
|
{ label: redaction.value, show: true, bold: true },
|
||||||
|
{ label: redaction.typeLabel, show: true },
|
||||||
|
]);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _justificationsService: JustificationsService,
|
private readonly _justificationsService: JustificationsService,
|
||||||
private readonly _dictionaryService: DictionaryService,
|
private readonly _dictionaryService: DictionaryService,
|
||||||
@ -69,7 +85,7 @@ export class RedactRecommendationDialogComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
get disabled() {
|
get disabled() {
|
||||||
return this.dictionaryRequest && !this.form.controls.dictionary.value;
|
return !this.form.controls.dictionary.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
@ -144,9 +160,10 @@ export class RedactRecommendationDialogComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
#resetValues() {
|
#resetValues() {
|
||||||
|
const sameType = this.data.annotations.every(annotation => annotation.type === this.firstEntry.type);
|
||||||
this.#applyToAllDossiers = this.data.applyToAllDossiers ?? true;
|
this.#applyToAllDossiers = this.data.applyToAllDossiers ?? true;
|
||||||
if (this.dictionaryRequest) {
|
if (this.dictionaryRequest) {
|
||||||
this.form.controls.dictionary.setValue(this.firstEntry.type);
|
this.form.controls.dictionary.setValue(sameType ? this.firstEntry.type : null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.form.controls.dictionary.setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null);
|
this.form.controls.dictionary.setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null);
|
||||||
|
|||||||
@ -3,48 +3,56 @@
|
|||||||
<div [translate]="'redact-text.dialog.title'" class="dialog-header heading-l"></div>
|
<div [translate]="'redact-text.dialog.title'" class="dialog-header heading-l"></div>
|
||||||
|
|
||||||
<div class="dialog-content redaction">
|
<div class="dialog-content redaction">
|
||||||
<div class="iqser-input-group w-450 selected-text-group">
|
<div class="iqser-input-group w-full selected-text-group">
|
||||||
<div
|
<div
|
||||||
[class.fixed-height-36]="dictionaryRequest"
|
[class.fixed-height-36]="dictionaryRequest"
|
||||||
[ngClass]="isEditingSelectedText ? 'flex relative' : 'flex-align-items-center'"
|
[ngClass]="isEditingSelectedText ? 'flex relative' : 'flex-align-items-center'"
|
||||||
>
|
>
|
||||||
<ul>
|
<div class="table">
|
||||||
<li>
|
<label>Value</label>
|
||||||
<span *ngIf="!isEditingSelectedText" [innerHTML]="form.controls.selectedText.value"></span>
|
<div class="row">
|
||||||
</li>
|
<span
|
||||||
</ul>
|
*ngIf="!isEditingSelectedText"
|
||||||
|
[innerHTML]="form.controls.selectedText.value"
|
||||||
|
[ngStyle]="{
|
||||||
|
'min-width': textWidth > maximumSelectedTextWidth ? '95%' : 'unset',
|
||||||
|
'max-width': textWidth > maximumSelectedTextWidth ? 0 : 'unset'
|
||||||
|
}"
|
||||||
|
></span>
|
||||||
|
<textarea
|
||||||
|
*ngIf="isEditingSelectedText"
|
||||||
|
[rows]="selectedTextRows"
|
||||||
|
[ngStyle]="{ width: maximumTextAreaWidth + 'px' }"
|
||||||
|
formControlName="selectedText"
|
||||||
|
iqserHasScrollbar
|
||||||
|
name="comment"
|
||||||
|
type="text"
|
||||||
|
></textarea>
|
||||||
|
|
||||||
<textarea
|
<iqser-circle-button
|
||||||
*ngIf="isEditingSelectedText"
|
(action)="toggleEditingSelectedText()"
|
||||||
[rows]="selectedTextRows"
|
*ngIf="dictionaryRequest"
|
||||||
class="w-full"
|
[showDot]="initialText !== form.get('selectedText').value && !isEditingSelectedText"
|
||||||
formControlName="selectedText"
|
[tooltip]="'redact-text.dialog.content.edit-text' | translate"
|
||||||
iqserHasScrollbar
|
[type]="isEditingSelectedText ? 'dark' : 'default'"
|
||||||
name="comment"
|
[size]="18"
|
||||||
type="text"
|
[iconSize]="13"
|
||||||
></textarea>
|
icon="iqser:edit"
|
||||||
|
tooltipPosition="below"
|
||||||
|
></iqser-circle-button>
|
||||||
|
|
||||||
<iqser-circle-button
|
<iqser-circle-button
|
||||||
(action)="toggleEditingSelectedText()"
|
(action)="undoTextChange()"
|
||||||
*ngIf="dictionaryRequest"
|
*ngIf="isEditingSelectedText"
|
||||||
[class.absolute]="isEditingSelectedText"
|
[showDot]="initialText !== form.get('selectedText').value"
|
||||||
[showDot]="initialText !== form.get('selectedText').value && !isEditingSelectedText"
|
[tooltip]="'redact-text.dialog.content.revert-text' | translate"
|
||||||
[tooltip]="'redact-text.dialog.content.edit-text' | translate"
|
[size]="18"
|
||||||
[type]="isEditingSelectedText ? 'dark' : 'default'"
|
[iconSize]="13"
|
||||||
class="edit-button"
|
icon="red:undo"
|
||||||
icon="iqser:edit"
|
tooltipPosition="below"
|
||||||
tooltipPosition="below"
|
></iqser-circle-button>
|
||||||
></iqser-circle-button>
|
</div>
|
||||||
|
</div>
|
||||||
<iqser-circle-button
|
|
||||||
(action)="undoTextChange()"
|
|
||||||
*ngIf="isEditingSelectedText"
|
|
||||||
[showDot]="initialText !== form.get('selectedText').value"
|
|
||||||
[tooltip]="'redact-text.dialog.content.revert-text' | translate"
|
|
||||||
class="absolute undo-button"
|
|
||||||
icon="red:undo"
|
|
||||||
tooltipPosition="below"
|
|
||||||
></iqser-circle-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -13,29 +13,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-button {
|
iqser-circle-button {
|
||||||
top: 0;
|
padding-left: 8px;
|
||||||
right: calc((0.5rem + 34px) * -1);
|
|
||||||
position: sticky;
|
|
||||||
}
|
|
||||||
|
|
||||||
.undo-button {
|
|
||||||
top: 0;
|
|
||||||
right: calc((0.5rem + 34px) * -2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-full {
|
.w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.absolute {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relative {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-height-36 {
|
.fixed-height-36 {
|
||||||
min-height: 36px;
|
min-height: 36px;
|
||||||
}
|
}
|
||||||
@ -43,3 +28,30 @@
|
|||||||
textarea {
|
textarea {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: calc(100% - 26px);
|
||||||
|
padding: 0 13px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
opacity: 0.7;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--iqser-alt-background);
|
||||||
|
min-width: 100%;
|
||||||
|
|
||||||
|
span {
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
list-style-position: inside;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from
|
|||||||
import { RedactTextData, RedactTextResult } from '../../utils/dialog-types';
|
import { RedactTextData, RedactTextResult } from '../../utils/dialog-types';
|
||||||
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
||||||
|
|
||||||
const MAXIMUM_SELECTED_TEXT_WIDTH = 421;
|
const MAXIMUM_TEXT_AREA_WIDTH = 421;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './redact-text-dialog.component.html',
|
templateUrl: './redact-text-dialog.component.html',
|
||||||
@ -39,6 +39,10 @@ export class RedactTextDialogComponent
|
|||||||
readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId);
|
readonly #dossier = inject(ActiveDossiersService).find(this.data.dossierId);
|
||||||
readonly #manualRedactionTypeExists = inject(DictionaryService).hasManualType(this.#dossier.dossierTemplateId);
|
readonly #manualRedactionTypeExists = inject(DictionaryService).hasManualType(this.#dossier.dossierTemplateId);
|
||||||
#applyToAllDossiers = this.data.applyToAllDossiers ?? true;
|
#applyToAllDossiers = this.data.applyToAllDossiers ?? true;
|
||||||
|
readonly maximumTextAreaWidth = MAXIMUM_TEXT_AREA_WIDTH;
|
||||||
|
readonly maximumSelectedTextWidth = 567;
|
||||||
|
|
||||||
|
textWidth: number;
|
||||||
|
|
||||||
get defaultOption() {
|
get defaultOption() {
|
||||||
const inDossierOption = this.options.find(option => option.value === RedactOrHintOptions.IN_DOSSIER);
|
const inDossierOption = this.options.find(option => option.value === RedactOrHintOptions.IN_DOSSIER);
|
||||||
@ -60,7 +64,7 @@ export class RedactTextDialogComponent
|
|||||||
this.options = getRedactOrHintOptions(this.#dossier, this.#applyToAllDossiers, this.data.isApprover, this.data.isPageExcluded);
|
this.options = getRedactOrHintOptions(this.#dossier, this.#applyToAllDossiers, this.data.isApprover, this.data.isPageExcluded);
|
||||||
this.form = this.#getForm();
|
this.form = this.#getForm();
|
||||||
this.#setupValidators(this.dictionaryRequest ? RedactOrHintOptions.IN_DOSSIER : RedactOrHintOptions.ONLY_HERE);
|
this.#setupValidators(this.dictionaryRequest ? RedactOrHintOptions.IN_DOSSIER : RedactOrHintOptions.ONLY_HERE);
|
||||||
|
this.textWidth = calcTextWidthInPixels(this.form.controls.selectedText.value);
|
||||||
this.form.controls.option.valueChanges
|
this.form.controls.option.valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((option: DetailsRadioOption<RedactOrHintOption>) => {
|
tap((option: DetailsRadioOption<RedactOrHintOption>) => {
|
||||||
@ -136,7 +140,7 @@ export class RedactTextDialogComponent
|
|||||||
this.isEditingSelectedText = !this.isEditingSelectedText;
|
this.isEditingSelectedText = !this.isEditingSelectedText;
|
||||||
if (this.isEditingSelectedText) {
|
if (this.isEditingSelectedText) {
|
||||||
const width = calcTextWidthInPixels(this.form.controls.selectedText.value);
|
const width = calcTextWidthInPixels(this.form.controls.selectedText.value);
|
||||||
this.selectedTextRows = Math.ceil(width / MAXIMUM_SELECTED_TEXT_WIDTH);
|
this.selectedTextRows = Math.ceil(width / MAXIMUM_TEXT_AREA_WIDTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,4 +217,6 @@ export class RedactTextDialogComponent
|
|||||||
}
|
}
|
||||||
this.form.controls.dictionary.setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null);
|
this.form.controls.dictionary.setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected readonly window = window;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
<redaction-selected-annotations-table
|
<redaction-selected-annotations-table
|
||||||
[columns]="tableColumns()"
|
[columns]="tableColumns()"
|
||||||
[data]="tableData()"
|
[data]="tableData()"
|
||||||
|
[staticColumns]="!hasFalsePositiveOption"
|
||||||
></redaction-selected-annotations-table>
|
></redaction-selected-annotations-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,10 @@ export class RemoveRedactionDialogComponent extends IqserDialogComponent<
|
|||||||
return DialogHelpModeKeys.REDACTION_REMOVE;
|
return DialogHelpModeKeys.REDACTION_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasFalsePositiveOption() {
|
||||||
|
return !!this.options.find(option => option.value === RemoveRedactionOptions.FALSE_POSITIVE);
|
||||||
|
}
|
||||||
|
|
||||||
get defaultOption() {
|
get defaultOption() {
|
||||||
const removeHereOption = this.options.find(option => option.value === RemoveRedactionOptions.ONLY_HERE);
|
const removeHereOption = this.options.find(option => option.value === RemoveRedactionOptions.ONLY_HERE);
|
||||||
if (!!removeHereOption && !removeHereOption.disabled) return removeHereOption;
|
if (!!removeHereOption && !removeHereOption.disabled) return removeHereOption;
|
||||||
|
|||||||
@ -56,7 +56,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
|||||||
value: annotation.value,
|
value: annotation.value,
|
||||||
reason: annotation.legalBasis ?? 'Dictionary Request',
|
reason: annotation.legalBasis ?? 'Dictionary Request',
|
||||||
positions: annotation.positions,
|
positions: annotation.positions,
|
||||||
type: redaction.type,
|
type: redaction.type ?? annotation.type,
|
||||||
comment: redaction.comment,
|
comment: redaction.comment,
|
||||||
}));
|
}));
|
||||||
return this.addAnnotation(recommendations, dossierId, fileId);
|
return this.addAnnotation(recommendations, dossierId, fileId);
|
||||||
|
|||||||
@ -162,15 +162,24 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
|||||||
.sort((a, b) => a.label.localeCompare(b.label));
|
.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
}
|
}
|
||||||
|
|
||||||
getEditableRedactionTypes(dossierTemplateId: string, isImage: boolean, isHint: boolean, isOCR: boolean): Dictionary[] {
|
getEditableRedactionTypes(
|
||||||
return this._dictionariesMapService
|
dossierId: string,
|
||||||
.get(dossierTemplateId)
|
isImage: boolean,
|
||||||
|
isHint: boolean,
|
||||||
|
isOCR: boolean,
|
||||||
|
currentlySelectedType: string,
|
||||||
|
): Dictionary[] {
|
||||||
|
return this.#extractDossierLevelTypes(dossierId)
|
||||||
.filter(
|
.filter(
|
||||||
d =>
|
d =>
|
||||||
d.model['typeId'] &&
|
d.model['typeId'] &&
|
||||||
(isImage
|
(isImage
|
||||||
? (isOCR ? [...IMAGE_CATEGORIES, 'ocr'] : IMAGE_CATEGORIES).includes(d.type)
|
? (isOCR ? [...IMAGE_CATEGORIES, 'ocr'] : IMAGE_CATEGORIES).includes(d.type)
|
||||||
: (isHint ? d.hint : !d.hint) && !d.virtual && !d.systemManaged && ![...IMAGE_CATEGORIES, 'ocr'].includes(d.type)),
|
: (isHint ? d.hint : !d.hint) &&
|
||||||
|
(d.addToDictionaryAction || currentlySelectedType === d.type) &&
|
||||||
|
!d.virtual &&
|
||||||
|
!d.systemManaged &&
|
||||||
|
![...IMAGE_CATEGORIES, 'ocr'].includes(d.type)),
|
||||||
)
|
)
|
||||||
.sort((a, b) => a.label.localeCompare(b.label));
|
.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,10 +115,7 @@ export class TrashService extends EntitiesService<TrashItem, TrashItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _hardDeleteFiles(dossierId: string, fileIds: List) {
|
private _hardDeleteFiles(dossierId: string, fileIds: List) {
|
||||||
const queryParams = fileIds.map<QueryParam>(id => ({ key: 'fileIds', value: id }));
|
return super._post(fileIds, `delete/hard-delete/${dossierId}`).pipe(switchMap(() => this._dossierStatsService.getFor([dossierId])));
|
||||||
return super
|
|
||||||
.delete({}, `delete/hard-delete/${dossierId}`, queryParams)
|
|
||||||
.pipe(switchMap(() => this._dossierStatsService.getFor([dossierId])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _restoreFiles(dossierId: string, fileIds: List) {
|
private _restoreFiles(dossierId: string, fileIds: List) {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export class FileManagementService extends GenericService<unknown> {
|
|||||||
|
|
||||||
delete(files: List<File>, dossierId: string) {
|
delete(files: List<File>, dossierId: string) {
|
||||||
const fileIds = files.map(f => f.id);
|
const fileIds = files.map(f => f.id);
|
||||||
return super._post(fileIds, `delete/hard-delete/${dossierId}`).pipe(switchMap(() => this.#filesService.loadAll(dossierId)));
|
return super._post(fileIds, `delete/${dossierId}`).pipe(switchMap(() => this.#filesService.loadAll(dossierId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
rotatePage(body: IPageRotationRequest, dossierId: string, fileId: string) {
|
rotatePage(body: IPageRotationRequest, dossierId: string, fileId: string) {
|
||||||
|
|||||||
@ -367,7 +367,6 @@
|
|||||||
"annotation": {
|
"annotation": {
|
||||||
"pending": "(Pending analysis)"
|
"pending": "(Pending analysis)"
|
||||||
},
|
},
|
||||||
"annotations": "",
|
|
||||||
"archived-dossiers-listing": {
|
"archived-dossiers-listing": {
|
||||||
"no-data": {
|
"no-data": {
|
||||||
"title": "No archived dossiers."
|
"title": "No archived dossiers."
|
||||||
@ -1998,7 +1997,8 @@
|
|||||||
"reason-placeholder": "Select a reason...",
|
"reason-placeholder": "Select a reason...",
|
||||||
"revert-text": "Revert to selected text",
|
"revert-text": "Revert to selected text",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"type-placeholder": "Select type..."
|
"type-placeholder": "Select type...",
|
||||||
|
"unchanged": ""
|
||||||
},
|
},
|
||||||
"title": "Redact text"
|
"title": "Redact text"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1998,7 +1998,8 @@
|
|||||||
"reason-placeholder": "Select a reason...",
|
"reason-placeholder": "Select a reason...",
|
||||||
"revert-text": "Revert to selected text",
|
"revert-text": "Revert to selected text",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"type-placeholder": "Select type..."
|
"type-placeholder": "Select type...",
|
||||||
|
"unchanged": "Unchanged"
|
||||||
},
|
},
|
||||||
"title": "Redact text"
|
"title": "Redact text"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -367,7 +367,6 @@
|
|||||||
"annotation": {
|
"annotation": {
|
||||||
"pending": "(Pending analysis)"
|
"pending": "(Pending analysis)"
|
||||||
},
|
},
|
||||||
"annotations": "",
|
|
||||||
"archived-dossiers-listing": {
|
"archived-dossiers-listing": {
|
||||||
"no-data": {
|
"no-data": {
|
||||||
"title": "No archived dossiers."
|
"title": "No archived dossiers."
|
||||||
@ -1998,7 +1997,8 @@
|
|||||||
"reason-placeholder": "Select a reasons...",
|
"reason-placeholder": "Select a reasons...",
|
||||||
"revert-text": "",
|
"revert-text": "",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"type-placeholder": "Select type..."
|
"type-placeholder": "Select type...",
|
||||||
|
"unchanged": ""
|
||||||
},
|
},
|
||||||
"title": "Redact text"
|
"title": "Redact text"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1998,7 +1998,8 @@
|
|||||||
"reason-placeholder": "Select a reasons...",
|
"reason-placeholder": "Select a reasons...",
|
||||||
"revert-text": "",
|
"revert-text": "",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"type-placeholder": "Select type..."
|
"type-placeholder": "Select type...",
|
||||||
|
"unchanged": ""
|
||||||
},
|
},
|
||||||
"title": "Redact text"
|
"title": "Redact text"
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user