diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/false-positive-dialog/false-positive-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/false-positive-dialog/false-positive-dialog.component.html
new file mode 100644
index 000000000..4655e7d22
--- /dev/null
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/false-positive-dialog/false-positive-dialog.component.html
@@ -0,0 +1,31 @@
+
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/false-positive-dialog/false-positive-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/false-positive-dialog/false-positive-dialog.component.ts
new file mode 100644
index 000000000..d25da3c8e
--- /dev/null
+++ b/apps/red-ui/src/app/modules/file-preview/dialogs/false-positive-dialog/false-positive-dialog.component.ts
@@ -0,0 +1,30 @@
+import { Component, Inject, OnInit } from '@angular/core';
+import { BaseDialogComponent } from '@iqser/common-ui';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+
+export interface FalsePositiveDialogInput {
+ text: string;
+ context: string;
+}
+
+@Component({
+ templateUrl: './false-positive-dialog.component.html',
+})
+export class FalsePositiveDialogComponent extends BaseDialogComponent implements OnInit {
+ constructor(
+ protected readonly _dialogRef: MatDialogRef,
+ @Inject(MAT_DIALOG_DATA) readonly data: FalsePositiveDialogInput[],
+ ) {
+ super(_dialogRef);
+ }
+
+ ngOnInit() {
+ const controlsConfig = { comment: [null] };
+ this.form = this._formBuilder.group(controlsConfig);
+ this.initialFormValue = this.form.getRawValue();
+ }
+
+ save(): void {
+ this._dialogRef.close(this.form.getRawValue());
+ }
+}
diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts
index 91386b77f..922f8700c 100644
--- a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts
+++ b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts
@@ -64,6 +64,7 @@ import { SuggestionsService } from './services/suggestions.service';
import { PagesComponent } from './components/pages/pages.component';
import { SharedModule } from '@shared/shared.module';
import { SharedDossiersModule } from '../shared-dossiers/shared-dossiers.module';
+import { FalsePositiveDialogComponent } from './dialogs/false-positive-dialog/false-positive-dialog.component';
const routes: IqserRoutes = [
{
@@ -87,6 +88,7 @@ const dialogs = [
DocumentInfoDialogComponent,
ImportRedactionsDialogComponent,
RssDialogComponent,
+ FalsePositiveDialogComponent,
];
const components = [
diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts
index 1d4c5b12a..fcefcf3ce 100644
--- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts
+++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { ManualRedactionService } from './manual-redaction.service';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
-import { Observable } from 'rxjs';
+import { firstValueFrom, Observable } from 'rxjs';
import { getFirstRelevantTextPart } from '../../../utils';
import { Core } from '@pdftron/webviewer';
import {
@@ -50,7 +50,7 @@ export class AnnotationActionsService {
const { dossierId, fileId } = this._state;
const ids = annotations.map(a => a.id);
const request = this._manualRedactionService.approve(ids, dossierId, fileId);
- this.#processObsAndEmit(request);
+ this.#processObsAndEmit(request).then();
}
removeHighlights(highlights: AnnotationWrapper[]): void {
@@ -72,7 +72,7 @@ export class AnnotationActionsService {
fileId,
annotations[0].isModifyDictionary,
),
- );
+ ).then();
}
forceAnnotation(annotations: AnnotationWrapper[], hint: boolean = false) {
@@ -86,7 +86,7 @@ export class AnnotationActionsService {
fileId,
annotations[0].isIgnoredHint,
),
- );
+ ).then();
});
}
@@ -104,7 +104,7 @@ export class AnnotationActionsService {
value: data.value,
}));
- this.#processObsAndEmit(this._manualRedactionService.changeLegalBasis(body, dossierId, fileId));
+ this.#processObsAndEmit(this._manualRedactionService.changeLegalBasis(body, dossierId, fileId)).then();
},
);
}
@@ -125,7 +125,7 @@ export class AnnotationActionsService {
}));
this.#processObsAndEmit(
this._manualRedactionService.removeOrSuggestRemove(body, dossierId, fileId, removeFromDictionary, annotations[0].isHint),
- );
+ ).then();
});
}
@@ -138,7 +138,7 @@ export class AnnotationActionsService {
type,
comment,
}));
- this.#processObsAndEmit(this._manualRedactionService.recategorizeImage(body, dossierId, fileId));
+ this.#processObsAndEmit(this._manualRedactionService.recategorizeImage(body, dossierId, fileId)).then();
});
}
@@ -152,10 +152,10 @@ export class AnnotationActionsService {
fileId,
modifyDictionary,
),
- );
+ ).then();
}
- convertRecommendationToAnnotation(recommendations: AnnotationWrapper[]) {
+ async convertRecommendationToAnnotation(recommendations: AnnotationWrapper[]) {
const { dossierId, fileId } = this._state;
const dialogRef = this._dialog.open(
AcceptRecommendationDialogComponent,
@@ -163,7 +163,7 @@ export class AnnotationActionsService {
);
// TODO: remove observables
const dialogClosed = dialogRef.afterClosed().pipe(filter(value => !!value && !!value.annotations));
- dialogClosed.subscribe(({ annotations, comment: commentText }) => {
+ await firstValueFrom(dialogClosed).then(({ annotations, comment: commentText }) => {
if (isJustOne(annotations) && this._annotationManager.resizingAnnotationId === annotations[0].id) {
this.cancelResize(annotations[0]).then();
}
@@ -231,20 +231,24 @@ export class AnnotationActionsService {
}
markAsFalsePositive(annotations: AnnotationWrapper[]) {
- const requests: List = annotations.map(annotation => ({
- sourceId: annotation.id,
- value: this._getFalsePositiveText(annotation),
- type: annotation.type,
- positions: annotation.positions,
- addToDictionary: true,
- reason: 'False Positive',
- dictionaryEntryType: annotation.isRecommendation
- ? DictionaryEntryTypes.FALSE_RECOMMENDATION
- : DictionaryEntryTypes.FALSE_POSITIVE,
- }));
- const { dossierId, fileId } = this._state;
+ const data = annotations.map(annotation => ({ text: annotation.value, context: this._getFalsePositiveText(annotation) }));
+ this._dialogService.openDialog('falsePositive', data, (result: { comment: string }) => {
+ const requests: List = annotations.map(annotation => ({
+ sourceId: annotation.id,
+ value: this._getFalsePositiveText(annotation),
+ type: annotation.type,
+ positions: annotation.positions,
+ addToDictionary: true,
+ reason: 'False Positive',
+ dictionaryEntryType: annotation.isRecommendation
+ ? DictionaryEntryTypes.FALSE_RECOMMENDATION
+ : DictionaryEntryTypes.FALSE_POSITIVE,
+ comment: result.comment ? { text: result.comment } : null,
+ }));
+ const { dossierId, fileId } = this._state;
- this.#processObsAndEmit(this._manualRedactionService.addAnnotation(requests, dossierId, fileId));
+ this.#processObsAndEmit(this._manualRedactionService.addAnnotation(requests, dossierId, fileId)).then();
+ });
}
#generateRectangle(annotationWrapper: AnnotationWrapper) {
@@ -279,12 +283,15 @@ export class AnnotationActionsService {
};
}
- #processObsAndEmit(obs: Observable) {
+ async #processObsAndEmit(obs: Observable) {
// TODO: remove observables and use promises instead
- obs.subscribe({
- next: () => this._fileDataService.annotationsChanged(),
- error: () => this._fileDataService.annotationsChanged(),
- });
+ await firstValueFrom(obs)
+ .then(() => this._fileDataService.annotationsChanged())
+ .catch(() => this._fileDataService.annotationsChanged());
+ // obs.subscribe({
+ // next: () => this._fileDataService.annotationsChanged(),
+ // error: () => this._fileDataService.annotationsChanged(),
+ // });
}
private _getFalsePositiveText(annotation: AnnotationWrapper) {
diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts
index 49a7df222..e8abdb76b 100644
--- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts
+++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-dialog.service.ts
@@ -10,6 +10,7 @@ import { ConfirmationDialogComponent, DialogConfig, DialogService } from '@iqser
import { ResizeAnnotationDialogComponent } from '../dialogs/resize-annotation-dialog/resize-annotation-dialog.component';
import { HighlightActionDialogComponent } from '../dialogs/highlight-action-dialog/highlight-action-dialog.component';
import { RssDialogComponent } from '../dialogs/rss-dialog/rss-dialog.component';
+import { FalsePositiveDialogComponent } from '../dialogs/false-positive-dialog/false-positive-dialog.component';
type DialogType =
| 'confirm'
@@ -21,7 +22,8 @@ type DialogType =
| 'resizeAnnotation'
| 'forceAnnotation'
| 'manualAnnotation'
- | 'highlightAction';
+ | 'highlightAction'
+ | 'falsePositive';
@Injectable()
export class FilePreviewDialogService extends DialogService {
@@ -60,6 +62,9 @@ export class FilePreviewDialogService extends DialogService {
component: RssDialogComponent,
dialogConfig: { width: '90vw' },
},
+ falsePositive: {
+ component: FalsePositiveDialogComponent,
+ },
};
constructor(protected readonly _dialog: MatDialog) {
diff --git a/apps/red-ui/src/assets/i18n/redact/de.json b/apps/red-ui/src/assets/i18n/redact/de.json
index f282d792a..f3bb93680 100644
--- a/apps/red-ui/src/assets/i18n/redact/de.json
+++ b/apps/red-ui/src/assets/i18n/redact/de.json
@@ -1994,6 +1994,17 @@
"annotations": "",
"title": ""
},
+ "false-positive-dialog": {
+ "actions": {
+ "cancel": "",
+ "save": ""
+ },
+ "content": {
+ "comment": "",
+ "body-text": ""
+ },
+ "header": ""
+ },
"rules-screen": {
"error": {
"generic": "Es ist ein Fehler aufgetreten ... Die Regeln konnten nicht aktualisiert werden!"
diff --git a/apps/red-ui/src/assets/i18n/redact/en.json b/apps/red-ui/src/assets/i18n/redact/en.json
index 39db74751..8ca3dd376 100644
--- a/apps/red-ui/src/assets/i18n/redact/en.json
+++ b/apps/red-ui/src/assets/i18n/redact/en.json
@@ -1994,6 +1994,17 @@
"annotations": "",
"title": "Structured Component Management"
},
+ "false-positive-dialog": {
+ "actions": {
+ "cancel": "Cancel",
+ "save": "Yes, proceed"
+ },
+ "content": {
+ "comment": "Comment",
+ "body-text": "''{value}'' is a false positive in this context: {context}"
+ },
+ "header": "False Positive"
+ },
"rules-screen": {
"error": {
"generic": "Something went wrong... Rules update failed!"