RED-6506: Added confirmation dialog for false positive action.
This commit is contained in:
parent
a5b7b76d46
commit
cd2f51c30e
@ -0,0 +1,31 @@
|
|||||||
|
<section class="dialog">
|
||||||
|
<form (submit)="save()" [formGroup]="form">
|
||||||
|
<div class="dialog-header heading-l" translate="false-positive-dialog.header"></div>
|
||||||
|
|
||||||
|
<div class="dialog-content">
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
*ngFor="let value of data"
|
||||||
|
[innerHTML]="'false-positive-dialog.content.body-text' | translate : { value: value.text, context: value.context }"
|
||||||
|
></li>
|
||||||
|
</ul>
|
||||||
|
<div class="iqser-input-group w-300">
|
||||||
|
<label translate="false-positive-dialog.content.comment"></label>
|
||||||
|
<textarea formControlName="comment" iqserHasScrollbar name="comment" rows="4" type="text"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-actions">
|
||||||
|
<iqser-icon-button
|
||||||
|
[disabled]="!form.valid"
|
||||||
|
[label]="'false-positive-dialog.actions.save' | translate"
|
||||||
|
[submit]="true"
|
||||||
|
[type]="iconButtonTypes.primary"
|
||||||
|
></iqser-icon-button>
|
||||||
|
|
||||||
|
<div class="all-caps-label cancel" mat-dialog-close translate="false-positive-dialog.actions.cancel"></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||||
|
</section>
|
||||||
@ -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<FalsePositiveDialogComponent>,
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -64,6 +64,7 @@ import { SuggestionsService } from './services/suggestions.service';
|
|||||||
import { PagesComponent } from './components/pages/pages.component';
|
import { PagesComponent } from './components/pages/pages.component';
|
||||||
import { SharedModule } from '@shared/shared.module';
|
import { SharedModule } from '@shared/shared.module';
|
||||||
import { SharedDossiersModule } from '../shared-dossiers/shared-dossiers.module';
|
import { SharedDossiersModule } from '../shared-dossiers/shared-dossiers.module';
|
||||||
|
import { FalsePositiveDialogComponent } from './dialogs/false-positive-dialog/false-positive-dialog.component';
|
||||||
|
|
||||||
const routes: IqserRoutes = [
|
const routes: IqserRoutes = [
|
||||||
{
|
{
|
||||||
@ -87,6 +88,7 @@ const dialogs = [
|
|||||||
DocumentInfoDialogComponent,
|
DocumentInfoDialogComponent,
|
||||||
ImportRedactionsDialogComponent,
|
ImportRedactionsDialogComponent,
|
||||||
RssDialogComponent,
|
RssDialogComponent,
|
||||||
|
FalsePositiveDialogComponent,
|
||||||
];
|
];
|
||||||
|
|
||||||
const components = [
|
const components = [
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ManualRedactionService } from './manual-redaction.service';
|
import { ManualRedactionService } from './manual-redaction.service';
|
||||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||||
import { Observable } from 'rxjs';
|
import { firstValueFrom, Observable } from 'rxjs';
|
||||||
import { getFirstRelevantTextPart } from '../../../utils';
|
import { getFirstRelevantTextPart } from '../../../utils';
|
||||||
import { Core } from '@pdftron/webviewer';
|
import { Core } from '@pdftron/webviewer';
|
||||||
import {
|
import {
|
||||||
@ -50,7 +50,7 @@ export class AnnotationActionsService {
|
|||||||
const { dossierId, fileId } = this._state;
|
const { dossierId, fileId } = this._state;
|
||||||
const ids = annotations.map(a => a.id);
|
const ids = annotations.map(a => a.id);
|
||||||
const request = this._manualRedactionService.approve(ids, dossierId, fileId);
|
const request = this._manualRedactionService.approve(ids, dossierId, fileId);
|
||||||
this.#processObsAndEmit(request);
|
this.#processObsAndEmit(request).then();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeHighlights(highlights: AnnotationWrapper[]): void {
|
removeHighlights(highlights: AnnotationWrapper[]): void {
|
||||||
@ -72,7 +72,7 @@ export class AnnotationActionsService {
|
|||||||
fileId,
|
fileId,
|
||||||
annotations[0].isModifyDictionary,
|
annotations[0].isModifyDictionary,
|
||||||
),
|
),
|
||||||
);
|
).then();
|
||||||
}
|
}
|
||||||
|
|
||||||
forceAnnotation(annotations: AnnotationWrapper[], hint: boolean = false) {
|
forceAnnotation(annotations: AnnotationWrapper[], hint: boolean = false) {
|
||||||
@ -86,7 +86,7 @@ export class AnnotationActionsService {
|
|||||||
fileId,
|
fileId,
|
||||||
annotations[0].isIgnoredHint,
|
annotations[0].isIgnoredHint,
|
||||||
),
|
),
|
||||||
);
|
).then();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ export class AnnotationActionsService {
|
|||||||
value: data.value,
|
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.#processObsAndEmit(
|
||||||
this._manualRedactionService.removeOrSuggestRemove(body, dossierId, fileId, removeFromDictionary, annotations[0].isHint),
|
this._manualRedactionService.removeOrSuggestRemove(body, dossierId, fileId, removeFromDictionary, annotations[0].isHint),
|
||||||
);
|
).then();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ export class AnnotationActionsService {
|
|||||||
type,
|
type,
|
||||||
comment,
|
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,
|
fileId,
|
||||||
modifyDictionary,
|
modifyDictionary,
|
||||||
),
|
),
|
||||||
);
|
).then();
|
||||||
}
|
}
|
||||||
|
|
||||||
convertRecommendationToAnnotation(recommendations: AnnotationWrapper[]) {
|
async convertRecommendationToAnnotation(recommendations: AnnotationWrapper[]) {
|
||||||
const { dossierId, fileId } = this._state;
|
const { dossierId, fileId } = this._state;
|
||||||
const dialogRef = this._dialog.open<AcceptRecommendationDialogComponent, AcceptRecommendationData, AcceptRecommendationReturnType>(
|
const dialogRef = this._dialog.open<AcceptRecommendationDialogComponent, AcceptRecommendationData, AcceptRecommendationReturnType>(
|
||||||
AcceptRecommendationDialogComponent,
|
AcceptRecommendationDialogComponent,
|
||||||
@ -163,7 +163,7 @@ export class AnnotationActionsService {
|
|||||||
);
|
);
|
||||||
// TODO: remove observables
|
// TODO: remove observables
|
||||||
const dialogClosed = dialogRef.afterClosed().pipe(filter(value => !!value && !!value.annotations));
|
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) {
|
if (isJustOne(annotations) && this._annotationManager.resizingAnnotationId === annotations[0].id) {
|
||||||
this.cancelResize(annotations[0]).then();
|
this.cancelResize(annotations[0]).then();
|
||||||
}
|
}
|
||||||
@ -231,20 +231,24 @@ export class AnnotationActionsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
markAsFalsePositive(annotations: AnnotationWrapper[]) {
|
markAsFalsePositive(annotations: AnnotationWrapper[]) {
|
||||||
const requests: List<IAddRedactionRequest> = annotations.map(annotation => ({
|
const data = annotations.map(annotation => ({ text: annotation.value, context: this._getFalsePositiveText(annotation) }));
|
||||||
sourceId: annotation.id,
|
this._dialogService.openDialog('falsePositive', data, (result: { comment: string }) => {
|
||||||
value: this._getFalsePositiveText(annotation),
|
const requests: List<IAddRedactionRequest> = annotations.map(annotation => ({
|
||||||
type: annotation.type,
|
sourceId: annotation.id,
|
||||||
positions: annotation.positions,
|
value: this._getFalsePositiveText(annotation),
|
||||||
addToDictionary: true,
|
type: annotation.type,
|
||||||
reason: 'False Positive',
|
positions: annotation.positions,
|
||||||
dictionaryEntryType: annotation.isRecommendation
|
addToDictionary: true,
|
||||||
? DictionaryEntryTypes.FALSE_RECOMMENDATION
|
reason: 'False Positive',
|
||||||
: DictionaryEntryTypes.FALSE_POSITIVE,
|
dictionaryEntryType: annotation.isRecommendation
|
||||||
}));
|
? DictionaryEntryTypes.FALSE_RECOMMENDATION
|
||||||
const { dossierId, fileId } = this._state;
|
: 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) {
|
#generateRectangle(annotationWrapper: AnnotationWrapper) {
|
||||||
@ -279,12 +283,15 @@ export class AnnotationActionsService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#processObsAndEmit(obs: Observable<unknown>) {
|
async #processObsAndEmit(obs: Observable<unknown>) {
|
||||||
// TODO: remove observables and use promises instead
|
// TODO: remove observables and use promises instead
|
||||||
obs.subscribe({
|
await firstValueFrom(obs)
|
||||||
next: () => this._fileDataService.annotationsChanged(),
|
.then(() => this._fileDataService.annotationsChanged())
|
||||||
error: () => this._fileDataService.annotationsChanged(),
|
.catch(() => this._fileDataService.annotationsChanged());
|
||||||
});
|
// obs.subscribe({
|
||||||
|
// next: () => this._fileDataService.annotationsChanged(),
|
||||||
|
// error: () => this._fileDataService.annotationsChanged(),
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getFalsePositiveText(annotation: AnnotationWrapper) {
|
private _getFalsePositiveText(annotation: AnnotationWrapper) {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { ConfirmationDialogComponent, DialogConfig, DialogService } from '@iqser
|
|||||||
import { ResizeAnnotationDialogComponent } from '../dialogs/resize-annotation-dialog/resize-annotation-dialog.component';
|
import { ResizeAnnotationDialogComponent } from '../dialogs/resize-annotation-dialog/resize-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 { RssDialogComponent } from '../dialogs/rss-dialog/rss-dialog.component';
|
import { RssDialogComponent } from '../dialogs/rss-dialog/rss-dialog.component';
|
||||||
|
import { FalsePositiveDialogComponent } from '../dialogs/false-positive-dialog/false-positive-dialog.component';
|
||||||
|
|
||||||
type DialogType =
|
type DialogType =
|
||||||
| 'confirm'
|
| 'confirm'
|
||||||
@ -21,7 +22,8 @@ type DialogType =
|
|||||||
| 'resizeAnnotation'
|
| 'resizeAnnotation'
|
||||||
| 'forceAnnotation'
|
| 'forceAnnotation'
|
||||||
| 'manualAnnotation'
|
| 'manualAnnotation'
|
||||||
| 'highlightAction';
|
| 'highlightAction'
|
||||||
|
| 'falsePositive';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FilePreviewDialogService extends DialogService<DialogType> {
|
export class FilePreviewDialogService extends DialogService<DialogType> {
|
||||||
@ -60,6 +62,9 @@ export class FilePreviewDialogService extends DialogService<DialogType> {
|
|||||||
component: RssDialogComponent,
|
component: RssDialogComponent,
|
||||||
dialogConfig: { width: '90vw' },
|
dialogConfig: { width: '90vw' },
|
||||||
},
|
},
|
||||||
|
falsePositive: {
|
||||||
|
component: FalsePositiveDialogComponent,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(protected readonly _dialog: MatDialog) {
|
constructor(protected readonly _dialog: MatDialog) {
|
||||||
|
|||||||
@ -1994,6 +1994,17 @@
|
|||||||
"annotations": "",
|
"annotations": "",
|
||||||
"title": ""
|
"title": ""
|
||||||
},
|
},
|
||||||
|
"false-positive-dialog": {
|
||||||
|
"actions": {
|
||||||
|
"cancel": "",
|
||||||
|
"save": ""
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"comment": "",
|
||||||
|
"body-text": ""
|
||||||
|
},
|
||||||
|
"header": ""
|
||||||
|
},
|
||||||
"rules-screen": {
|
"rules-screen": {
|
||||||
"error": {
|
"error": {
|
||||||
"generic": "Es ist ein Fehler aufgetreten ... Die Regeln konnten nicht aktualisiert werden!"
|
"generic": "Es ist ein Fehler aufgetreten ... Die Regeln konnten nicht aktualisiert werden!"
|
||||||
|
|||||||
@ -1994,6 +1994,17 @@
|
|||||||
"annotations": "",
|
"annotations": "",
|
||||||
"title": "Structured Component Management"
|
"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": {
|
"rules-screen": {
|
||||||
"error": {
|
"error": {
|
||||||
"generic": "Something went wrong... Rules update failed!"
|
"generic": "Something went wrong... Rules update failed!"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user