RED-7340 - converted ManualAnnotationDialog into RectangleAnnotationDialog
This commit is contained in:
parent
40d9eb15cf
commit
7a1e968a52
@ -11,12 +11,7 @@ import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select
|
|||||||
import { NgForOf, NgIf } from '@angular/common';
|
import { NgForOf, NgIf } from '@angular/common';
|
||||||
import { MatTooltip } from '@angular/material/tooltip';
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { LegalBasisOption } from '../../utils/dialog-types';
|
||||||
export interface LegalBasisOption {
|
|
||||||
label?: string;
|
|
||||||
legalBasis?: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './change-legal-basis-dialog.component.html',
|
templateUrl: './change-legal-basis-dialog.component.html',
|
||||||
|
|||||||
@ -26,8 +26,7 @@ import {
|
|||||||
ValueColumn,
|
ValueColumn,
|
||||||
} from '../../components/selected-annotations-table/selected-annotations-table.component';
|
} from '../../components/selected-annotations-table/selected-annotations-table.component';
|
||||||
import { getEditRedactionOptions } from '../../utils/dialog-options';
|
import { getEditRedactionOptions } from '../../utils/dialog-options';
|
||||||
import { EditRedactionData, EditRedactionOption, EditRedactResult } from '../../utils/dialog-types';
|
import { EditRedactionData, EditRedactionOption, EditRedactResult, LegalBasisOption } from '../../utils/dialog-types';
|
||||||
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
|
||||||
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
|
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
|
||||||
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
|
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
|
||||||
|
|
||||||
|
|||||||
@ -26,17 +26,11 @@ import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select
|
|||||||
import { MatTooltip } from '@angular/material/tooltip';
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
|
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
|
||||||
import { ForceAnnotationOption, RedactOrHintOption } from '../../utils/dialog-types';
|
import { ForceAnnotationOption, LegalBasisOption } from '../../utils/dialog-types';
|
||||||
import { getForceAnnotationOptions, getRedactOrHintOptions } from '../../utils/dialog-options';
|
import { getForceAnnotationOptions } from '../../utils/dialog-options';
|
||||||
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
|
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
|
||||||
import { SystemDefaults } from '../../../account/utils/dialog-defaults';
|
import { SystemDefaults } from '../../../account/utils/dialog-defaults';
|
||||||
|
|
||||||
export interface LegalBasisOption {
|
|
||||||
label?: string;
|
|
||||||
legalBasis?: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DOCUMINE_LEGAL_BASIS = 'n-a.';
|
const DOCUMINE_LEGAL_BASIS = 'n-a.';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@ -3,35 +3,11 @@
|
|||||||
<div [translate]="title" class="dialog-header heading-l"></div>
|
<div [translate]="title" class="dialog-header heading-l"></div>
|
||||||
|
|
||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
<iqser-details-radio [options]="options" (extraOptionChanged)="extraOptionChanged($event)" formControlName="option">
|
<iqser-details-radio
|
||||||
</iqser-details-radio>
|
[options]="options"
|
||||||
|
(extraOptionChanged)="extraOptionChanged($event)"
|
||||||
<div *ngIf="!isRectangle" class="iqser-input-group w-450">
|
formControlName="option"
|
||||||
<label [translate]="'manual-annotation.dialog.content.text'"></label>
|
></iqser-details-radio>
|
||||||
<div *ngIf="!isEditingSelectedText" class="flex-align-items-center">
|
|
||||||
{{ form.get('selectedText').value }}
|
|
||||||
<iqser-circle-button
|
|
||||||
(action)="isEditingSelectedText = true"
|
|
||||||
*ngIf="isDictionaryRequest"
|
|
||||||
[tooltip]="'manual-annotation.dialog.content.edit-selected-text' | translate"
|
|
||||||
icon="iqser:edit"
|
|
||||||
tooltipPosition="below"
|
|
||||||
></iqser-circle-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<textarea
|
|
||||||
*ngIf="isEditingSelectedText"
|
|
||||||
formControlName="selectedText"
|
|
||||||
iqserHasScrollbar
|
|
||||||
name="comment"
|
|
||||||
rows="4"
|
|
||||||
type="text"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="isRectangle" class="iqser-input-group">
|
|
||||||
<label [translate]="'manual-annotation.dialog.content.rectangle'"></label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
*ngIf="!isFalsePositiveRequest && (isDictionaryRequest || !manualRedactionTypeExists)"
|
*ngIf="!isFalsePositiveRequest && (isDictionaryRequest || !manualRedactionTypeExists)"
|
||||||
@ -80,12 +56,12 @@
|
|||||||
<input [value]="form.get('reason').value?.legalBasis" disabled type="text" />
|
<input [value]="form.get('reason').value?.legalBasis" disabled type="text" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="isRectangle" class="iqser-input-group w-450">
|
<div class="iqser-input-group w-450">
|
||||||
<label [translate]="'manual-annotation.dialog.content.section'"></label>
|
<label [translate]="'manual-annotation.dialog.content.section'"></label>
|
||||||
<input formControlName="section" name="section" type="text" />
|
<input formControlName="section" name="section" type="text" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="isRectangle" class="iqser-input-group w-450">
|
<div class="iqser-input-group w-450">
|
||||||
<label [translate]="'manual-annotation.dialog.content.classification'"></label>
|
<label [translate]="'manual-annotation.dialog.content.classification'"></label>
|
||||||
<input formControlName="classification" name="classification" type="text" />
|
<input formControlName="classification" name="classification" type="text" />
|
||||||
</div>
|
</div>
|
||||||
@ -2,6 +2,11 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
height: 650px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.apply-on-multiple-pages {
|
.apply-on-multiple-pages {
|
||||||
min-height: 55px;
|
min-height: 55px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -1,24 +1,23 @@
|
|||||||
import { Component, Inject, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormBuilder, ReactiveFormsModule, UntypedFormGroup, Validators } from '@angular/forms';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
import {
|
import {
|
||||||
BaseDialogComponent,
|
|
||||||
CircleButtonComponent,
|
CircleButtonComponent,
|
||||||
HasScrollbarDirective,
|
HasScrollbarDirective,
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
IqserDenyDirective,
|
IqserDenyDirective,
|
||||||
|
IqserDialogComponent,
|
||||||
IqserPermissionsService,
|
IqserPermissionsService,
|
||||||
|
Toaster,
|
||||||
} from '@iqser/common-ui';
|
} from '@iqser/common-ui';
|
||||||
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
||||||
import { Dictionary, Dossier, File, IAddRedactionRequest, SuperTypes } from '@red/domain';
|
import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry, SuperTypes } from '@red/domain';
|
||||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||||
import { JustificationsService } from '@services/entity-services/justifications.service';
|
import { JustificationsService } from '@services/entity-services/justifications.service';
|
||||||
import { Roles } from '@users/roles';
|
import { Roles } from '@users/roles';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { ManualRedactionService } from '../../services/manual-redaction.service';
|
import { ManualRedactionService } from '../../services/manual-redaction.service';
|
||||||
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
|
|
||||||
import { NgForOf, NgIf } from '@angular/common';
|
import { NgForOf, NgIf } from '@angular/common';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { MatFormField } from '@angular/material/form-field';
|
import { MatFormField } from '@angular/material/form-field';
|
||||||
@ -26,23 +25,28 @@ import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select
|
|||||||
import { MatTooltip } from '@angular/material/tooltip';
|
import { MatTooltip } from '@angular/material/tooltip';
|
||||||
import { MatCheckbox } from '@angular/material/checkbox';
|
import { MatCheckbox } from '@angular/material/checkbox';
|
||||||
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
|
import { DetailsRadioOption } from '@common-ui/inputs/details-radio/details-radio-option';
|
||||||
import { RectangleRedactOption, RectangleRedactOptions, RedactOrHintOption } from '../../utils/dialog-types';
|
import { LegalBasisOption, RectangleRedactOption, RectangleRedactOptions } from '../../utils/dialog-types';
|
||||||
import { getRectangleRedactOptions } from '../../utils/dialog-options';
|
import { getRectangleRedactOptions } from '../../utils/dialog-options';
|
||||||
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
|
import { DetailsRadioComponent } from '@common-ui/inputs/details-radio/details-radio.component';
|
||||||
import { SystemDefaults } from '../../../account/utils/dialog-defaults';
|
import { SystemDefaults } from '../../../account/utils/dialog-defaults';
|
||||||
import { validatePageRange } from '../../utils/form-validators';
|
import { validatePageRange } from '../../utils/form-validators';
|
||||||
|
import { getMultiplePagesRectangle } from '../../utils/enhance-manual-redaction-request.utils';
|
||||||
|
|
||||||
export interface LegalBasisOption {
|
interface RectangleDialogData {
|
||||||
label?: string;
|
dossierId: string;
|
||||||
legalBasis?: string;
|
manualRedactionEntryWrapper: ManualRedactionEntryWrapper;
|
||||||
description?: string;
|
file: File;
|
||||||
|
}
|
||||||
|
export interface RectangleDialogResult {
|
||||||
|
annotation: IManualRedactionEntry;
|
||||||
|
dictionary: Dictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NON_READABLE_CONTENT = 'non-readable content';
|
export const NON_READABLE_CONTENT = 'non-readable content';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './manual-annotation-dialog.component.html',
|
templateUrl: './rectangle-annotation-dialog.component.html',
|
||||||
styleUrls: ['./manual-annotation-dialog.component.scss'],
|
styleUrls: ['./rectangle-annotation-dialog.component.scss'],
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
@ -63,29 +67,30 @@ export const NON_READABLE_CONTENT = 'non-readable content';
|
|||||||
],
|
],
|
||||||
providers: [ManualRedactionService],
|
providers: [ManualRedactionService],
|
||||||
})
|
})
|
||||||
export class ManualAnnotationDialogComponent extends BaseDialogComponent implements OnInit {
|
export class RectangleAnnotationDialog
|
||||||
|
extends IqserDialogComponent<RectangleAnnotationDialog, RectangleDialogData, RectangleDialogResult>
|
||||||
|
implements OnInit
|
||||||
|
{
|
||||||
readonly #dossier: Dossier;
|
readonly #dossier: Dossier;
|
||||||
protected readonly roles = Roles;
|
protected readonly roles = Roles;
|
||||||
protected readonly options: DetailsRadioOption<RectangleRedactOption>[];
|
protected readonly options: DetailsRadioOption<RectangleRedactOption>[];
|
||||||
protected isDictionaryRequest: boolean;
|
protected isDictionaryRequest: boolean;
|
||||||
protected isFalsePositiveRequest: boolean;
|
protected isFalsePositiveRequest: boolean;
|
||||||
protected isEditingSelectedText = false;
|
|
||||||
protected applyOnMultiplePages = false;
|
|
||||||
protected manualRedactionTypeExists = true;
|
protected manualRedactionTypeExists = true;
|
||||||
protected possibleDictionaries: Dictionary[] = [];
|
protected possibleDictionaries: Dictionary[] = [];
|
||||||
protected legalOptions: LegalBasisOption[] = [];
|
protected legalOptions: LegalBasisOption[] = [];
|
||||||
|
readonly form: UntypedFormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly iqserPermissionsService: IqserPermissionsService,
|
private readonly iqserPermissionsService: IqserPermissionsService,
|
||||||
private readonly _justificationsService: JustificationsService,
|
private readonly _justificationsService: JustificationsService,
|
||||||
private readonly _manualRedactionService: ManualRedactionService,
|
private readonly _manualRedactionService: ManualRedactionService,
|
||||||
activeDossiersService: ActiveDossiersService,
|
private readonly activeDossiersService: ActiveDossiersService,
|
||||||
private readonly _dictionaryService: DictionaryService,
|
private readonly _dictionaryService: DictionaryService,
|
||||||
protected readonly _dialogRef: MatDialogRef<ManualAnnotationDialogComponent>,
|
private readonly _formBuilder: FormBuilder,
|
||||||
private readonly _annotationManager: REDAnnotationManager,
|
private readonly _toaster: Toaster,
|
||||||
@Inject(MAT_DIALOG_DATA) readonly data: { manualRedactionEntryWrapper: ManualRedactionEntryWrapper; dossierId: string; file: File },
|
|
||||||
) {
|
) {
|
||||||
super(_dialogRef);
|
super();
|
||||||
this.#dossier = activeDossiersService.find(this.data.dossierId);
|
this.#dossier = activeDossiersService.find(this.data.dossierId);
|
||||||
|
|
||||||
this.isFalsePositiveRequest = this.data.manualRedactionEntryWrapper.type === 'FALSE_POSITIVE';
|
this.isFalsePositiveRequest = this.data.manualRedactionEntryWrapper.type === 'FALSE_POSITIVE';
|
||||||
@ -111,10 +116,6 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
|||||||
return this._manualRedactionService.getTitle(this.data.manualRedactionEntryWrapper.type);
|
return this._manualRedactionService.getTitle(this.data.manualRedactionEntryWrapper.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isRectangle() {
|
|
||||||
return !!this.data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle;
|
|
||||||
}
|
|
||||||
|
|
||||||
get displayedDictionaryLabel() {
|
get displayedDictionaryLabel() {
|
||||||
const dictType = this.form.get('dictionary').value;
|
const dictType = this.form.get('dictionary').value;
|
||||||
if (dictType) {
|
if (dictType) {
|
||||||
@ -124,7 +125,7 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
get disabled() {
|
get disabled() {
|
||||||
return this.form.invalid || (this.applyOnMultiplePages && !this.form.get('multiplePages')?.value);
|
return this.form.invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@ -142,21 +143,17 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
|||||||
this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));
|
this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
|
|
||||||
this.#selectReason();
|
this.#selectReason();
|
||||||
|
|
||||||
if (!this.isRectangle) {
|
|
||||||
this.#formatSelectedTextValue();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry);
|
this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry);
|
||||||
try {
|
try {
|
||||||
const annotations =
|
const annotation =
|
||||||
this.isRectangle && !!this.form.get('multiplePages').value
|
this.form.get('option').value.value === RectangleRedactOptions.MULTIPLE_PAGES
|
||||||
? this.#getRectangles()
|
? getMultiplePagesRectangle(this.#multiplePagesRectangleData).manualRedactionEntry
|
||||||
: [this.data.manualRedactionEntryWrapper];
|
: this.data.manualRedactionEntryWrapper;
|
||||||
this._dialogRef.close({
|
super.close({
|
||||||
annotations,
|
annotation,
|
||||||
dictionary: this.possibleDictionaries.find(d => d.type === this.form.get('dictionary').value),
|
dictionary: this.possibleDictionaries.find(d => d.type === this.form.get('dictionary').value),
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -164,47 +161,12 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
get #multiplePagesRectangleData() {
|
||||||
super.close();
|
return {
|
||||||
if (this.isRectangle) {
|
manualRedactionEntryWrapper: this.data.manualRedactionEntryWrapper,
|
||||||
this._annotationManager.delete(this._annotationManager.selected[0].Id);
|
pages: this.form.get('option').value.additionalInput.value,
|
||||||
}
|
file: this.data.file,
|
||||||
}
|
};
|
||||||
|
|
||||||
#getRectangles() {
|
|
||||||
const quads = this.data.manualRedactionEntryWrapper.manualRedactionEntry.positions.find(a => !!a);
|
|
||||||
const value: string = this.form.get('multiplePages').value.replace(/[^0-9-,]/g, '');
|
|
||||||
const entry = { ...this.data.manualRedactionEntryWrapper.manualRedactionEntry };
|
|
||||||
const wrapper = { ...this.data.manualRedactionEntryWrapper };
|
|
||||||
const wrappers: ManualRedactionEntryWrapper[] = [wrapper];
|
|
||||||
|
|
||||||
value.split(',').forEach(range => {
|
|
||||||
const splitted = range.split('-');
|
|
||||||
const startPage = parseInt(splitted[0], 10);
|
|
||||||
const endPage = splitted.length > 1 ? parseInt(splitted[1], 10) : startPage;
|
|
||||||
if (!startPage || !endPage || startPage > this.data.file.numberOfPages || endPage > this.data.file.numberOfPages) {
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let page = startPage; page <= endPage; page++) {
|
|
||||||
if (page === wrapper.manualRedactionEntry.positions[0].page) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const manualRedactionEntry = { ...entry, positions: [{ ...quads, page }] };
|
|
||||||
wrappers.push({ ...wrapper, manualRedactionEntry });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return wrappers;
|
|
||||||
}
|
|
||||||
|
|
||||||
#formatSelectedTextValue() {
|
|
||||||
this.data.manualRedactionEntryWrapper.manualRedactionEntry.value =
|
|
||||||
this.data.manualRedactionEntryWrapper.manualRedactionEntry.value.replace(
|
|
||||||
// eslint-disable-next-line no-control-regex,max-len
|
|
||||||
/([^\s\d-]{2,})[-\u00AD]\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]/gi,
|
|
||||||
'$1',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#getForm() {
|
#getForm() {
|
||||||
@ -217,7 +179,6 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
|||||||
: [this.manualRedactionTypeExists ? SuperTypes.ManualRedaction : null, Validators.required],
|
: [this.manualRedactionTypeExists ? SuperTypes.ManualRedaction : null, Validators.required],
|
||||||
comment: [null],
|
comment: [null],
|
||||||
classification: [NON_READABLE_CONTENT],
|
classification: [NON_READABLE_CONTENT],
|
||||||
multiplePages: '',
|
|
||||||
option: [this.#getOption(SystemDefaults.RECTANGLE_REDACT_DEFAULT), validatePageRange()],
|
option: [this.#getOption(SystemDefaults.RECTANGLE_REDACT_DEFAULT), validatePageRange()],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -243,9 +204,7 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
|||||||
const commentValue = this.form.get('comment').value;
|
const commentValue = this.form.get('comment').value;
|
||||||
addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
|
addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
|
||||||
addRedactionRequest.section = this.form.get('section').value;
|
addRedactionRequest.section = this.form.get('section').value;
|
||||||
addRedactionRequest.value = addRedactionRequest.rectangle
|
addRedactionRequest.value = this.form.get('classification').value;
|
||||||
? this.form.get('classification').value
|
|
||||||
: this.form.get('selectedText').value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#getOption(option: RectangleRedactOption): DetailsRadioOption<RectangleRedactOption> {
|
#getOption(option: RectangleRedactOption): DetailsRadioOption<RectangleRedactOption> {
|
||||||
@ -23,13 +23,13 @@ import {
|
|||||||
} from '../../components/selected-annotations-table/selected-annotations-table.component';
|
} from '../../components/selected-annotations-table/selected-annotations-table.component';
|
||||||
import { getRedactOrHintOptions } from '../../utils/dialog-options';
|
import { getRedactOrHintOptions } from '../../utils/dialog-options';
|
||||||
import {
|
import {
|
||||||
|
LegalBasisOption,
|
||||||
RedactOrHintOption,
|
RedactOrHintOption,
|
||||||
RedactOrHintOptions,
|
RedactOrHintOptions,
|
||||||
RedactRecommendationData,
|
RedactRecommendationData,
|
||||||
RedactRecommendationResult,
|
RedactRecommendationResult,
|
||||||
ResizeOptions,
|
ResizeOptions,
|
||||||
} from '../../utils/dialog-types';
|
} from '../../utils/dialog-types';
|
||||||
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './redact-recommendation-dialog.component.html',
|
templateUrl: './redact-recommendation-dialog.component.html',
|
||||||
|
|||||||
@ -21,8 +21,14 @@ import { firstValueFrom, Observable } from 'rxjs';
|
|||||||
import { map, tap } from 'rxjs/operators';
|
import { map, tap } from 'rxjs/operators';
|
||||||
import { SystemDefaultOption, SystemDefaults } from '../../../account/utils/dialog-defaults';
|
import { SystemDefaultOption, SystemDefaults } from '../../../account/utils/dialog-defaults';
|
||||||
import { getRedactOrHintOptions } from '../../utils/dialog-options';
|
import { getRedactOrHintOptions } from '../../utils/dialog-options';
|
||||||
import { RedactOrHintOption, RedactOrHintOptions, RedactTextData, RedactTextResult, ResizeOptions } from '../../utils/dialog-types';
|
import {
|
||||||
import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
|
LegalBasisOption,
|
||||||
|
RedactOrHintOption,
|
||||||
|
RedactOrHintOptions,
|
||||||
|
RedactTextData,
|
||||||
|
RedactTextResult,
|
||||||
|
ResizeOptions,
|
||||||
|
} from '../../utils/dialog-types';
|
||||||
import { enhanceManualRedactionRequest, EnhanceRequestData } from '../../utils/enhance-manual-redaction-request.utils';
|
import { enhanceManualRedactionRequest, EnhanceRequestData } from '../../utils/enhance-manual-redaction-request.utils';
|
||||||
|
|
||||||
const MAXIMUM_TEXT_AREA_WIDTH = 421;
|
const MAXIMUM_TEXT_AREA_WIDTH = 421;
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { copyLocalStorageFiltersValues, FilterService, NestedFilter, processFilt
|
|||||||
import { AutoUnsubscribe, Bind, bool, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils';
|
import { AutoUnsubscribe, Bind, bool, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils';
|
||||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||||
import { ManualRedactionEntryTypes, ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
import { ManualRedactionEntryTypes, ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
||||||
import { Dictionary, File, ViewModes } from '@red/domain';
|
import { File, ViewModes } from '@red/domain';
|
||||||
import { ConfigService } from '@services/config.service';
|
import { ConfigService } from '@services/config.service';
|
||||||
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
|
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
|
||||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||||
@ -71,6 +71,7 @@ import { TypeFilterComponent } from '@shared/components/type-filter/type-filter.
|
|||||||
import { FileHeaderComponent } from './components/file-header/file-header.component';
|
import { FileHeaderComponent } from './components/file-header/file-header.component';
|
||||||
import { StructuredComponentManagementComponent } from './components/structured-component-management/structured-component-management.component';
|
import { StructuredComponentManagementComponent } from './components/structured-component-management/structured-component-management.component';
|
||||||
import { DocumentInfoService } from './services/document-info.service';
|
import { DocumentInfoService } from './services/document-info.service';
|
||||||
|
import { RectangleAnnotationDialog } from './dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './file-preview-screen.component.html',
|
templateUrl: './file-preview-screen.component.html',
|
||||||
@ -363,29 +364,27 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
this._viewerHeaderService.resetLayers();
|
this._viewerHeaderService.resetLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
openManualAnnotationDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) {
|
async openRectangleAnnotationDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) {
|
||||||
const file = this.state.file();
|
const file = this.state.file();
|
||||||
|
|
||||||
this._dialogService.openDialog(
|
const data = { manualRedactionEntryWrapper, file, dossierId: this.dossierId };
|
||||||
'manualAnnotation',
|
const result = await this._iqserDialog.openDefault(RectangleAnnotationDialog, { data }).result();
|
||||||
{ manualRedactionEntryWrapper, dossierId: this.dossierId, file },
|
|
||||||
(result: { annotations: ManualRedactionEntryWrapper[]; dictionary?: Dictionary }) => {
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const selectedAnnotations = this._annotationManager.selected;
|
const selectedAnnotations = this._annotationManager.selected;
|
||||||
if (selectedAnnotations.length > 0) {
|
if (selectedAnnotations.length > 0) {
|
||||||
this._annotationManager.delete([selectedAnnotations[0].Id]);
|
this._annotationManager.delete([selectedAnnotations[0].Id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const add$ = this._manualRedactionService.addAnnotation(
|
const add$ = this._manualRedactionService.addAnnotation([result.annotation], this.dossierId, this.fileId, {
|
||||||
result.annotations.map(w => w.manualRedactionEntry).filter(e => e.positions[0].page <= file.numberOfPages),
|
dictionaryLabel: result.dictionary?.label,
|
||||||
this.dossierId,
|
});
|
||||||
this.fileId,
|
|
||||||
{ dictionaryLabel: result.dictionary?.label },
|
|
||||||
);
|
|
||||||
|
|
||||||
const addAndReload$ = add$.pipe(switchMap(() => this._filesService.reload(this.dossierId, file)));
|
const addAndReload$ = add$.pipe(switchMap(() => this._filesService.reload(this.dossierId, file)));
|
||||||
return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined))));
|
return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined))));
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async viewerReady(pageNumber?: string) {
|
async viewerReady(pageNumber?: string) {
|
||||||
@ -622,7 +621,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
.subscribe();
|
.subscribe();
|
||||||
|
|
||||||
this.addActiveScreenSubscription = this.pdfProxyService.manualAnnotationRequested$.subscribe($event => {
|
this.addActiveScreenSubscription = this.pdfProxyService.manualAnnotationRequested$.subscribe($event => {
|
||||||
this.openManualAnnotationDialog($event);
|
this.openRectangleAnnotationDialog($event).then();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addActiveScreenSubscription = this.pdfProxyService.redactTextRequested$.subscribe($event => {
|
this.addActiveScreenSubscription = this.pdfProxyService.redactTextRequested$.subscribe($event => {
|
||||||
|
|||||||
@ -48,7 +48,7 @@ import { FilePreviewDialogService } from './file-preview-dialog.service';
|
|||||||
import { FilePreviewStateService } from './file-preview-state.service';
|
import { FilePreviewStateService } from './file-preview-state.service';
|
||||||
import { ManualRedactionService } from './manual-redaction.service';
|
import { ManualRedactionService } from './manual-redaction.service';
|
||||||
import { SkippedService } from './skipped.service';
|
import { SkippedService } from './skipped.service';
|
||||||
import { NON_READABLE_CONTENT } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
import { NON_READABLE_CONTENT } from '../dialogs/rectangle-annotation-dialog/rectangle-annotation-dialog.component';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AnnotationActionsService {
|
export class AnnotationActionsService {
|
||||||
|
|||||||
@ -5,9 +5,8 @@ import { ChangeLegalBasisDialogComponent } from '../dialogs/change-legal-basis-d
|
|||||||
import { DocumentInfoDialogComponent } from '../dialogs/document-info-dialog/document-info-dialog.component';
|
import { DocumentInfoDialogComponent } from '../dialogs/document-info-dialog/document-info-dialog.component';
|
||||||
import { ForceAnnotationDialogComponent } from '../dialogs/force-redaction-dialog/force-annotation-dialog.component';
|
import { ForceAnnotationDialogComponent } from '../dialogs/force-redaction-dialog/force-annotation-dialog.component';
|
||||||
import { HighlightActionDialogComponent } from '../dialogs/highlight-action-dialog/highlight-action-dialog.component';
|
import { HighlightActionDialogComponent } from '../dialogs/highlight-action-dialog/highlight-action-dialog.component';
|
||||||
import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
|
||||||
|
|
||||||
type DialogType = 'confirm' | 'documentInfo' | 'changeLegalBasis' | 'forceAnnotation' | 'manualAnnotation' | 'highlightAction';
|
type DialogType = 'confirm' | 'documentInfo' | 'changeLegalBasis' | 'forceAnnotation' | 'highlightAction';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FilePreviewDialogService extends DialogService<DialogType> {
|
export class FilePreviewDialogService extends DialogService<DialogType> {
|
||||||
@ -26,10 +25,6 @@ export class FilePreviewDialogService extends DialogService<DialogType> {
|
|||||||
forceAnnotation: {
|
forceAnnotation: {
|
||||||
component: ForceAnnotationDialogComponent,
|
component: ForceAnnotationDialogComponent,
|
||||||
},
|
},
|
||||||
manualAnnotation: {
|
|
||||||
component: ManualAnnotationDialogComponent,
|
|
||||||
dialogConfig: { autoFocus: true },
|
|
||||||
},
|
|
||||||
highlightAction: {
|
highlightAction: {
|
||||||
component: HighlightActionDialogComponent,
|
component: HighlightActionDialogComponent,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -139,7 +139,9 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add(body: List<IAddRedactionRequest>, dossierId: string, fileId: string, bulkLocal = false) {
|
add(body: List<IAddRedactionRequest>, dossierId: string, fileId: string, bulkLocal = false) {
|
||||||
|
bulkLocal = bulkLocal || !!body[0].pageNumbers.length;
|
||||||
const bulkPath = bulkLocal ? this.#bulkLocal : this.#bulkRedaction;
|
const bulkPath = bulkLocal ? this.#bulkLocal : this.#bulkRedaction;
|
||||||
|
|
||||||
return this._post(bulkLocal ? body[0] : body, `${bulkPath}/add/${dossierId}/${fileId}`).pipe(this.#log('Add', body));
|
return this._post(bulkLocal ? body[0] : body, `${bulkPath}/add/${dossierId}/${fileId}`).pipe(this.#log('Add', body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -148,7 +148,7 @@ export const getResizeRedactionOptions = (
|
|||||||
tooltip: !dictBasedType ? translations.inDossier.tooltip : null,
|
tooltip: !dictBasedType ? translations.inDossier.tooltip : null,
|
||||||
icon: FOLDER_ICON,
|
icon: FOLDER_ICON,
|
||||||
value: ResizeOptions.IN_DOSSIER,
|
value: ResizeOptions.IN_DOSSIER,
|
||||||
extraOption: {
|
additionalCheck: {
|
||||||
label: translations.inDossier.extraOptionLabel,
|
label: translations.inDossier.extraOptionLabel,
|
||||||
checked: applyToAllDossiers,
|
checked: applyToAllDossiers,
|
||||||
hidden: !isApprover,
|
hidden: !isApprover,
|
||||||
|
|||||||
@ -47,6 +47,12 @@ export const RemoveAnnotationOptions = RemoveRedactionOptions;
|
|||||||
export type RemoveRedactionOption = keyof typeof RemoveRedactionOptions;
|
export type RemoveRedactionOption = keyof typeof RemoveRedactionOptions;
|
||||||
export type RemoveAnnotationOption = RemoveRedactionOption;
|
export type RemoveAnnotationOption = RemoveRedactionOption;
|
||||||
|
|
||||||
|
export interface LegalBasisOption {
|
||||||
|
label?: string;
|
||||||
|
legalBasis?: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RedactTextData {
|
export interface RedactTextData {
|
||||||
manualRedactionEntryWrapper: ManualRedactionEntryWrapper;
|
manualRedactionEntryWrapper: ManualRedactionEntryWrapper;
|
||||||
dossierId: string;
|
dossierId: string;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Dictionary, IAddRedactionRequest, SuperType } from '@red/domain';
|
import { Dictionary, File, IAddRedactionRequest, SuperType } from '@red/domain';
|
||||||
import { LegalBasisOption } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
||||||
|
import { LegalBasisOption } from './dialog-types';
|
||||||
|
|
||||||
export interface EnhanceRequestData {
|
export interface EnhanceRequestData {
|
||||||
readonly type: SuperType | null;
|
readonly type: SuperType | null;
|
||||||
@ -12,6 +13,12 @@ export interface EnhanceRequestData {
|
|||||||
readonly applyToAllDossiers: boolean;
|
readonly applyToAllDossiers: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MultiplePagesRectangleData {
|
||||||
|
manualRedactionEntryWrapper: ManualRedactionEntryWrapper;
|
||||||
|
pages: string;
|
||||||
|
file: File;
|
||||||
|
}
|
||||||
|
|
||||||
export const enhanceManualRedactionRequest = (addRedactionRequest: IAddRedactionRequest, data: EnhanceRequestData) => {
|
export const enhanceManualRedactionRequest = (addRedactionRequest: IAddRedactionRequest, data: EnhanceRequestData) => {
|
||||||
addRedactionRequest.type = data.type;
|
addRedactionRequest.type = data.type;
|
||||||
addRedactionRequest.section = null;
|
addRedactionRequest.section = null;
|
||||||
@ -38,3 +45,31 @@ export const enhanceManualRedactionRequest = (addRedactionRequest: IAddRedaction
|
|||||||
addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
|
addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
|
||||||
addRedactionRequest.addToAllDossiers = data.isApprover && data.dictionaryRequest && data.applyToAllDossiers;
|
addRedactionRequest.addToAllDossiers = data.isApprover && data.dictionaryRequest && data.applyToAllDossiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getMultiplePagesRectangle = (data: MultiplePagesRectangleData) => {
|
||||||
|
const value: string = data.pages.replace(/[^0-9-,]/g, '');
|
||||||
|
const entry = { ...data.manualRedactionEntryWrapper.manualRedactionEntry, pageNumbers: [] };
|
||||||
|
const wrapper = {
|
||||||
|
...data.manualRedactionEntryWrapper,
|
||||||
|
manualRedactionEntry: entry,
|
||||||
|
};
|
||||||
|
|
||||||
|
value.split(',').forEach(range => {
|
||||||
|
const splitted = range.split('-');
|
||||||
|
const startPage = parseInt(splitted[0], 10);
|
||||||
|
const endPage = splitted.length > 1 ? parseInt(splitted[1], 10) : startPage;
|
||||||
|
if (!startPage || !endPage || startPage > data.file.numberOfPages || endPage > data.file.numberOfPages) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let page = startPage; page <= endPage; page++) {
|
||||||
|
if (page === wrapper.manualRedactionEntry.positions[0].page) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper.manualRedactionEntry.pageNumbers.push(page);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
};
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"ADMIN_CONTACT_NAME": null,
|
"ADMIN_CONTACT_NAME": null,
|
||||||
"ADMIN_CONTACT_URL": null,
|
"ADMIN_CONTACT_URL": null,
|
||||||
"API_URL": "https://dan1.iqser.cloud",
|
"API_URL": "https://dan2.iqser.cloud",
|
||||||
"APP_NAME": "RedactManager",
|
"APP_NAME": "RedactManager",
|
||||||
"IS_DOCUMINE": false,
|
"IS_DOCUMINE": false,
|
||||||
"RULE_EDITOR_DEV_ONLY": false,
|
"RULE_EDITOR_DEV_ONLY": false,
|
||||||
@ -13,7 +13,7 @@
|
|||||||
"MAX_RETRIES_ON_SERVER_ERROR": 3,
|
"MAX_RETRIES_ON_SERVER_ERROR": 3,
|
||||||
"OAUTH_CLIENT_ID": "redaction",
|
"OAUTH_CLIENT_ID": "redaction",
|
||||||
"OAUTH_IDP_HINT": null,
|
"OAUTH_IDP_HINT": null,
|
||||||
"OAUTH_URL": "https://dan1.iqser.cloud/auth",
|
"OAUTH_URL": "https://dan2.iqser.cloud/auth",
|
||||||
"RECENT_PERIOD_IN_HOURS": 24,
|
"RECENT_PERIOD_IN_HOURS": 24,
|
||||||
"SELECTION_MODE": "structural",
|
"SELECTION_MODE": "structural",
|
||||||
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
|
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit 34387d49d29ba6449c1311cc1c5434b540398660
|
Subproject commit 3c89b8f7e71eb9253aa40f40c1598eac2c400c71
|
||||||
@ -14,4 +14,6 @@ export interface IAddRedactionRequest {
|
|||||||
section?: string;
|
section?: string;
|
||||||
rectangle?: boolean;
|
rectangle?: boolean;
|
||||||
addToAllDossiers?: boolean;
|
addToAllDossiers?: boolean;
|
||||||
|
pageNumbers?: [];
|
||||||
|
caseSensitive?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user