From 4fa6ae4c082f34ce4bce0f735315709554e42518 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 8 Apr 2022 00:32:03 +0300 Subject: [PATCH] RED-3747: add rectangles to multiple pages --- .../manual-annotation-dialog.component.html | 82 +++++++++++-------- .../manual-annotation-dialog.component.scss | 20 +++++ .../manual-annotation-dialog.component.ts | 44 +++++++++- .../file-preview-screen.component.ts | 14 ++-- apps/red-ui/src/assets/i18n/de.json | 4 + apps/red-ui/src/assets/i18n/en.json | 4 + 6 files changed, 123 insertions(+), 45 deletions(-) diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.html index e09aa6ea9..bb0fbcd81 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.html @@ -3,39 +3,35 @@
- -
- -
- {{ form.get('selectedText').value }} - -
- +
+ +
+ {{ form.get('selectedText').value }} +
- + +
- -
- -
-
+
+ +
-
+
@@ -53,7 +49,7 @@
-
+
-
+
-
+
-
+
-
+
+ +
+ + {{ 'manual-annotation.dialog.content.apply-on-multiple-pages' | translate }} + + +
+ + + {{ 'manual-annotation.dialog.content.apply-on-multiple-pages-hint' | translate }} +
+
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.scss b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.scss index 07b46869c..a0421d753 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.scss +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.scss @@ -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; +} diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts index 2acec7c55..b3db1abc3 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts @@ -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, - @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: '', }); } diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index 2a0c8f2cf..dfc0a80f6 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -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)))); }, ); diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index cf9aac978..3a691f506 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -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", diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 317e7b7d8..0ceb4c396 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -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",