RED-3747: add rectangles to multiple pages
This commit is contained in:
parent
7d4424cf24
commit
4fa6ae4c08
@ -3,39 +3,35 @@
|
||||
<div [translate]="title" class="dialog-header heading-l"></div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<ng-container *ngIf="!data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle">
|
||||
<div class="iqser-input-group w-400">
|
||||
<label translate="manual-annotation.dialog.content.text"></label>
|
||||
<div class="flex-align-items-center" *ngIf="!isEditingSelectedText">
|
||||
{{ form.get('selectedText').value }}
|
||||
<iqser-circle-button
|
||||
*ngIf="isDictionaryRequest"
|
||||
(action)="isEditingSelectedText = true"
|
||||
[tooltip]="'manual-annotation.dialog.content.edit-selected-text' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:edit"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
<textarea
|
||||
*ngIf="isEditingSelectedText"
|
||||
formControlName="selectedText"
|
||||
iqserHasScrollbar
|
||||
name="comment"
|
||||
rows="4"
|
||||
type="text"
|
||||
>
|
||||
</textarea>
|
||||
<div *ngIf="!isRectangle" class="iqser-input-group w-450">
|
||||
<label translate="manual-annotation.dialog.content.text"></label>
|
||||
<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"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:edit"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<textarea
|
||||
*ngIf="isEditingSelectedText"
|
||||
formControlName="selectedText"
|
||||
iqserHasScrollbar
|
||||
name="comment"
|
||||
rows="4"
|
||||
type="text"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle">
|
||||
<div class="iqser-input-group">
|
||||
<label translate="manual-annotation.dialog.content.rectangle"></label>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div *ngIf="isRectangle" class="iqser-input-group">
|
||||
<label translate="manual-annotation.dialog.content.rectangle"></label>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isFalsePositiveRequest && isDictionaryRequest" class="iqser-input-group required w-400">
|
||||
<div *ngIf="!isFalsePositiveRequest && isDictionaryRequest" class="iqser-input-group required w-450">
|
||||
<label translate="manual-annotation.dialog.content.dictionary"></label>
|
||||
|
||||
<mat-select formControlName="dictionary">
|
||||
@ -53,7 +49,7 @@
|
||||
</mat-select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isDictionaryRequest" class="iqser-input-group required w-400">
|
||||
<div *ngIf="!isDictionaryRequest" class="iqser-input-group required w-450">
|
||||
<label translate="manual-annotation.dialog.content.reason"></label>
|
||||
<mat-select
|
||||
[placeholder]="'manual-annotation.dialog.content.reason-placeholder' | translate"
|
||||
@ -71,25 +67,41 @@
|
||||
</mat-select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isDictionaryRequest" class="iqser-input-group w-400">
|
||||
<div *ngIf="!isDictionaryRequest" class="iqser-input-group w-450">
|
||||
<label translate="manual-annotation.dialog.content.legalBasis"></label>
|
||||
<input [value]="form.get('reason').value?.legalBasis" disabled type="text" />
|
||||
</div>
|
||||
|
||||
<div *ngIf="data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle" class="iqser-input-group w-400">
|
||||
<div *ngIf="isRectangle" class="iqser-input-group w-450">
|
||||
<label translate="manual-annotation.dialog.content.section"></label>
|
||||
<input formControlName="section" name="section" type="text" />
|
||||
</div>
|
||||
|
||||
<div *ngIf="data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle" class="iqser-input-group w-400">
|
||||
<div *ngIf="isRectangle" class="iqser-input-group w-450">
|
||||
<label translate="manual-annotation.dialog.content.classification"></label>
|
||||
<input formControlName="classification" name="classification" type="text" />
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-300">
|
||||
<div class="iqser-input-group w-450">
|
||||
<label translate="manual-annotation.dialog.content.comment"></label>
|
||||
<textarea formControlName="comment" iqserHasScrollbar name="comment" rows="4" type="text"></textarea>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isRectangle" class="apply-on-multiple-pages iqser-input-group w-450">
|
||||
<mat-checkbox #checkbox class="mb-15" color="primary">
|
||||
{{ 'manual-annotation.dialog.content.apply-on-multiple-pages' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<div *ngIf="checkbox.checked">
|
||||
<input
|
||||
[placeholder]="'manual-annotation.dialog.content.apply-on-multiple-pages-placeholder' | translate"
|
||||
class="full-width"
|
||||
formControlName="multiplePages"
|
||||
/>
|
||||
|
||||
<span class="hint">{{ 'manual-annotation.dialog.content.apply-on-multiple-pages-hint' | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
|
||||
@ -1,3 +1,23 @@
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.apply-on-multiple-pages {
|
||||
min-height: 55px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
&.iqser-input-group input {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
mat-checkbox {
|
||||
width: fit-content;
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.mb-15 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@ import { JustificationsService } from '@services/entity-services/justifications.
|
||||
import { Dictionary, Dossier, IAddRedactionRequest } from '@red/domain';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { BaseDialogComponent, CircleButtonTypes } from '@iqser/common-ui';
|
||||
import { BaseDialogComponent, CircleButtonTypes, Toaster } from '@iqser/common-ui';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { ManualRedactionService } from '../../services/manual-redaction.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
|
||||
export interface LegalBasisOption {
|
||||
label?: string;
|
||||
@ -38,8 +39,9 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _toaster: Toaster,
|
||||
protected readonly _dialogRef: MatDialogRef<ManualAnnotationDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: { manualRedactionEntryWrapper: ManualRedactionEntryWrapper; dossierId: string },
|
||||
@Inject(MAT_DIALOG_DATA) readonly data: { manualRedactionEntryWrapper: ManualRedactionEntryWrapper; dossierId: string },
|
||||
) {
|
||||
super(_injector, _dialogRef);
|
||||
this._dossier = this._activeDossiersService.find(this.data.dossierId);
|
||||
@ -55,6 +57,10 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
||||
return this._manualRedactionService.getTitle(this.data.manualRedactionEntryWrapper.type, this._dossier);
|
||||
}
|
||||
|
||||
get isRectangle() {
|
||||
return !!this.data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle;
|
||||
}
|
||||
|
||||
get displayedDictionaryLabel() {
|
||||
const dictType = this.form.get('dictionary').value;
|
||||
if (dictType) {
|
||||
@ -81,14 +87,43 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
||||
}));
|
||||
|
||||
this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));
|
||||
if (!this.data.manualRedactionEntryWrapper.manualRedactionEntry.rectangle) {
|
||||
if (!this.isRectangle) {
|
||||
this._formatSelectedTextValue();
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
this._enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry);
|
||||
this._dialogRef.close(this.data.manualRedactionEntryWrapper);
|
||||
try {
|
||||
const annotations = this.isRectangle ? this.#getRectangles() : [this.data.manualRedactionEntryWrapper];
|
||||
this._dialogRef.close(annotations);
|
||||
} catch (e) {
|
||||
this._toaster.error(_('manual-annotation.dialog.error'));
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
for (let page = startPage; page <= endPage; page++) {
|
||||
const manualRedactionEntry = { ...entry, positions: [{ ...quads, page }] };
|
||||
wrappers.push({ ...wrapper, manualRedactionEntry });
|
||||
}
|
||||
});
|
||||
|
||||
return wrappers;
|
||||
}
|
||||
|
||||
private _formatSelectedTextValue() {
|
||||
@ -110,6 +145,7 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme
|
||||
: ['manual', Validators.required],
|
||||
comment: [null],
|
||||
classification: ['non-readable content'],
|
||||
multiplePages: '',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ import { FileWorkloadComponent } from './components/file-workload/file-workload.
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { FilesService } from '@services/entity-services/files.service';
|
||||
import { FileManagementService } from '@services/entity-services/file-management.service';
|
||||
import { catchError, debounceTime, map, startWith, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { catchError, debounceTime, map, startWith, switchMap, tap } from 'rxjs/operators';
|
||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||
import { WatermarkService } from '@shared/services/watermark.service';
|
||||
import { ExcludedPagesService } from './services/excluded-pages.service';
|
||||
@ -266,12 +266,14 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
'manualAnnotation',
|
||||
null,
|
||||
{ manualRedactionEntryWrapper, dossierId: this.dossierId },
|
||||
({ manualRedactionEntry }: ManualRedactionEntryWrapper) => {
|
||||
const add$ = this._manualRedactionService.addAnnotation([manualRedactionEntry], this.dossierId, this.fileId);
|
||||
const addAndReload$ = add$.pipe(
|
||||
withLatestFrom(this.state.file$),
|
||||
switchMap(([, file]) => this._filesService.reload(this.dossierId, file)),
|
||||
async (wrappers: ManualRedactionEntryWrapper[]) => {
|
||||
const file = await this.state.file;
|
||||
const add$ = this._manualRedactionService.addAnnotation(
|
||||
wrappers.map(w => w.manualRedactionEntry).filter(e => e.positions[0].page <= file.numberOfPages),
|
||||
this.dossierId,
|
||||
this.fileId,
|
||||
);
|
||||
const addAndReload$ = add$.pipe(switchMap(() => this._filesService.reload(this.dossierId, file)));
|
||||
return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined))));
|
||||
},
|
||||
);
|
||||
|
||||
@ -1516,6 +1516,9 @@
|
||||
"save": "Speichern"
|
||||
},
|
||||
"content": {
|
||||
"apply-on-multiple-pages": "",
|
||||
"apply-on-multiple-pages-hint": "",
|
||||
"apply-on-multiple-pages-placeholder": "",
|
||||
"classification": "Wert / Klassifizierung",
|
||||
"comment": "Kommentar",
|
||||
"dictionary": "Wörterbuch",
|
||||
@ -1527,6 +1530,7 @@
|
||||
"section": "Absatz / Ort",
|
||||
"text": "Ausgewählter Text:"
|
||||
},
|
||||
"error": "",
|
||||
"header": {
|
||||
"dictionary": "Zum Wörterbuch hinzufügen",
|
||||
"false-positive": "Als Falsch-Positiv definieren",
|
||||
|
||||
@ -1516,6 +1516,9 @@
|
||||
"save": "Save"
|
||||
},
|
||||
"content": {
|
||||
"apply-on-multiple-pages": "Apply on multiple pages",
|
||||
"apply-on-multiple-pages-hint": "Minus(-) for range and comma(,) for enumeration.",
|
||||
"apply-on-multiple-pages-placeholder": "e.g. 1-20,22,32",
|
||||
"classification": "Value / Classification",
|
||||
"comment": "Comment",
|
||||
"dictionary": "Dictionary",
|
||||
@ -1527,6 +1530,7 @@
|
||||
"section": "Paragraph / Location",
|
||||
"text": "Selected text:"
|
||||
},
|
||||
"error": "Error! Invalid page selection",
|
||||
"header": {
|
||||
"dictionary": "Add to dictionary",
|
||||
"false-positive": "Set false positive",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user