DM-337 - Add/Remove annotations dialog in DocuMine

This commit is contained in:
Valentin Mihai 2023-07-24 00:46:54 +03:00
parent fab49ae183
commit 9806149dff
17 changed files with 150 additions and 220 deletions

View File

@ -8,18 +8,15 @@ import { ActiveDossiersService } from '@services/dossiers/active-dossiers.servic
import { DictionaryService } from '@services/entity-services/dictionary.service'; import { DictionaryService } from '@services/entity-services/dictionary.service';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { IqserDialogComponent } from '@common-ui/dialog/iqser-dialog-component.directive'; import { IqserDialogComponent } from '@iqser/common-ui';
import { RedactOrHintData, RedactOrHintResult } from '../../utils/dialog-types';
import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options'; import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options';
import { AddHintData, AddHintResult } from '../../utils/dialog-types';
@Component({ @Component({
templateUrl: './add-hint-dialog.component.html', templateUrl: './add-hint-dialog.component.html',
styleUrls: ['./add-hint-dialog.component.scss'], styleUrls: ['./add-hint-dialog.component.scss'],
}) })
export class AddHintDialogComponent export class AddHintDialogComponent extends IqserDialogComponent<AddHintDialogComponent, AddHintData, AddHintResult> implements OnInit {
extends IqserDialogComponent<AddHintDialogComponent, RedactOrHintData, RedactOrHintResult>
implements OnInit
{
readonly roles = Roles; readonly roles = Roles;
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly options: DetailsRadioOption<RedactOrHintOption>[]; readonly options: DetailsRadioOption<RedactOrHintOption>[];
@ -27,7 +24,6 @@ export class AddHintDialogComponent
dictionaries: Dictionary[] = []; dictionaries: Dictionary[] = [];
form!: UntypedFormGroup; form!: UntypedFormGroup;
#manualRedactionTypeExists = true;
#applyToAllDossiers: boolean; #applyToAllDossiers: boolean;
readonly #dossier: Dossier; readonly #dossier: Dossier;
@ -43,7 +39,6 @@ export class AddHintDialogComponent
super(); super();
this.#dossier = _activeDossiersService.find(this.data.dossierId); this.#dossier = _activeDossiersService.find(this.data.dossierId);
this.#applyToAllDossiers = this.data.applyToAllDossiers ?? true; this.#applyToAllDossiers = this.data.applyToAllDossiers ?? true;
this.#manualRedactionTypeExists = this._dictionaryService.hasManualType(this.#dossier.dossierTemplateId);
this.options = getRedactOrHintOptions(this.#dossier, this.#isRss, true, this.#applyToAllDossiers, this.data.isApprover); this.options = getRedactOrHintOptions(this.#dossier, this.#isRss, true, this.#applyToAllDossiers, this.data.isApprover);
this.form = this.#getForm(); this.form = this.#getForm();
@ -122,11 +117,8 @@ export class AddHintDialogComponent
#getForm(): UntypedFormGroup { #getForm(): UntypedFormGroup {
return this._formBuilder.group({ return this._formBuilder.group({
selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value, selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value,
reason: [null],
comment: [null], comment: [null],
dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], dictionary: [null],
classification: ['non-readable content'],
section: [null],
option: [this.options[0]], option: [this.options[0]],
}); });
} }
@ -134,7 +126,7 @@ export class AddHintDialogComponent
#enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) {
addRedactionRequest.reason = 'Dictionary Request'; addRedactionRequest.reason = 'Dictionary Request';
addRedactionRequest.type = this.form.get('dictionary').value; addRedactionRequest.type = this.form.get('dictionary').value;
addRedactionRequest.section = this.form.get('section').value; addRedactionRequest.section = null;
addRedactionRequest.value = this.form.get('selectedText').value; addRedactionRequest.value = this.form.get('selectedText').value;
const selectedType = this.dictionaries.find(d => d.type === addRedactionRequest.type); const selectedType = this.dictionaries.find(d => d.type === addRedactionRequest.type);
@ -154,10 +146,6 @@ export class AddHintDialogComponent
if (!this.#isRss) { if (!this.#isRss) {
this.options[1].extraOption.checked = this.#applyToAllDossiers; this.options[1].extraOption.checked = this.#applyToAllDossiers;
} }
if (this.dictionaryRequest) {
this.form.get('dictionary').setValue(null); this.form.get('dictionary').setValue(null);
return;
}
this.form.get('dictionary').setValue(this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null);
} }
} }

View File

@ -0,0 +1,8 @@
label {
font-weight: bold;
padding-bottom: 8px;
}
iqser-details-radio {
padding-top: 20px;
}

View File

@ -1,46 +1,29 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui'; import { IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui';
import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry, SuperTypes } from '@red/domain'; import { Dictionary, Dossier, IAddRedactionRequest, SuperTypes } from '@red/domain';
import { FormBuilder, UntypedFormGroup } from '@angular/forms'; import { FormBuilder, UntypedFormGroup } from '@angular/forms';
import { Roles } from '@users/roles'; import { Roles } from '@users/roles';
import { JustificationsService } from '@services/entity-services/justifications.service';
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 { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
import { IqserDialogComponent } from '@iqser/common-ui'; import { IqserDialogComponent } from '@iqser/common-ui';
import { AddAnnotationData, AddAnnotationResult } from '../../../utils/dialog-types';
export interface AddAnnotationData {
manualRedactionEntryWrapper: ManualRedactionEntryWrapper;
dossierId: string;
file: File;
}
interface DialogResult {
redaction: IManualRedactionEntry;
dictionary: Dictionary;
applyToAllDossiers: boolean | null;
}
@Component({ @Component({
templateUrl: './add-annotation-dialog.component.html', templateUrl: './add-annotation-dialog.component.html',
styleUrls: ['./add-annotation-dialog.component.scss'], styleUrls: ['./add-annotation-dialog.component.scss'],
}) })
export class AddAnnotationDialogComponent export class AddAnnotationDialogComponent
extends IqserDialogComponent<AddAnnotationDialogComponent, AddAnnotationData, DialogResult> extends IqserDialogComponent<AddAnnotationDialogComponent, AddAnnotationData, AddAnnotationResult>
implements OnInit implements OnInit
{ {
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
dictionaries: Dictionary[] = []; dictionaries: Dictionary[] = [];
form!: UntypedFormGroup; form!: UntypedFormGroup;
#manualRedactionTypeExists = true;
readonly #dossier: Dossier; readonly #dossier: Dossier;
readonly #isRss = this._iqserPermissionsService.has(Roles.getRss); readonly #isRss = this._iqserPermissionsService.has(Roles.getRss);
readonly hint: boolean;
constructor( constructor(
private readonly _justificationsService: JustificationsService,
private readonly _activeDossiersService: ActiveDossiersService, private readonly _activeDossiersService: ActiveDossiersService,
private readonly _dictionaryService: DictionaryService, private readonly _dictionaryService: DictionaryService,
private readonly _iqserPermissionsService: IqserPermissionsService, private readonly _iqserPermissionsService: IqserPermissionsService,
@ -48,8 +31,6 @@ export class AddAnnotationDialogComponent
) { ) {
super(); super();
this.#dossier = _activeDossiersService.find(this.data.dossierId); this.#dossier = _activeDossiersService.find(this.data.dossierId);
this.#manualRedactionTypeExists = this._dictionaryService.hasManualType(this.#dossier.dossierTemplateId);
this.form = this.#getForm(); this.form = this.#getForm();
} }
@ -67,7 +48,6 @@ export class AddAnnotationDialogComponent
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
this.dictionaries = this._dictionaryService.getRedactionTypes(this.#dossier.dossierTemplateId); this.dictionaries = this._dictionaryService.getRedactionTypes(this.#dossier.dossierTemplateId);
this.#formatSelectedTextValue();
} }
save(): void { save(): void {
@ -82,23 +62,11 @@ export class AddAnnotationDialogComponent
#getForm(): UntypedFormGroup { #getForm(): UntypedFormGroup {
return this._formBuilder.group({ return this._formBuilder.group({
selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value, selectedText: this.data?.manualRedactionEntryWrapper?.manualRedactionEntry?.value,
reason: [null],
comment: [null], comment: [null],
dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], dictionary: [null],
classification: ['non-readable content'],
section: [null],
}); });
} }
#formatSelectedTextValue(): void {
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',
);
}
#enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) {
addRedactionRequest.type = this.form.get('dictionary').value; addRedactionRequest.type = this.form.get('dictionary').value;
@ -110,7 +78,7 @@ export class AddAnnotationDialogComponent
} }
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 = null;
addRedactionRequest.value = this.form.get('selectedText').value; addRedactionRequest.value = this.form.get('selectedText').value;
} }
} }

View File

@ -1,35 +1,10 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui'; import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui';
import { FormBuilder, UntypedFormGroup } from '@angular/forms'; import { FormBuilder, UntypedFormGroup } from '@angular/forms';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { Dossier } from '@red/domain';
import { IqserDialogComponent } from '@iqser/common-ui'; import { IqserDialogComponent } from '@iqser/common-ui';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { RemoveAnnotationOption, RemoveAnnotationOptions } from './remove-annotation-options'; import { RemoveAnnotationData, RemoveAnnotationResult } from '../../../utils/dialog-types';
import { removeAnnotationTranslations } from '@translations/remove-annotation-translations'; import { getRemoveRedactionOptions, RemoveAnnotationOption, RemoveAnnotationOptions } from '../../../utils/dialog-options';
const PIN_ICON = 'red:push-pin';
const FOLDER_ICON = 'red:folder';
const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict';
export interface RemoveAnnotationPermissions {
canRemoveOnlyHere: boolean;
canRemoveFromDictionary: boolean;
canMarkAsFalsePositive: boolean;
}
export interface RemoveAnnotationData {
annotation: AnnotationWrapper;
dossier: Dossier;
falsePositiveContext: string;
permissions: RemoveAnnotationPermissions;
applyToAllDossiers: boolean;
}
export interface RemoveAnnotationResult {
comment: string;
option: DetailsRadioOption<RemoveAnnotationOption>;
}
@Component({ @Component({
templateUrl: './remove-annotation-dialog.component.html', templateUrl: './remove-annotation-dialog.component.html',
@ -45,20 +20,19 @@ export class RemoveAnnotationDialogComponent extends IqserDialogComponent<
form!: UntypedFormGroup; form!: UntypedFormGroup;
readonly #annotation: AnnotationWrapper;
readonly #permissions: RemoveAnnotationPermissions;
readonly #translations = removeAnnotationTranslations;
constructor(private readonly _formBuilder: FormBuilder, private readonly _permissionsService: PermissionsService) { constructor(private readonly _formBuilder: FormBuilder, private readonly _permissionsService: PermissionsService) {
super(); super();
this.#annotation = this.data.annotation; this.options = getRemoveRedactionOptions(this.data, true);
this.#permissions = this.data.permissions;
this.options = this.#options();
this.form = this.#getForm(); this.form = this.#getForm();
} }
get #applyToAllDossiers(): boolean {
const selectedOption = this.form.get('option').value.value;
return selectedOption === RemoveAnnotationOptions.IN_DOSSIER || selectedOption === RemoveAnnotationOptions.FALSE_POSITIVE;
}
save(): void { save(): void {
this.dialogRef.close(this.form.getRawValue()); this.dialogRef.close({ ...this.form.getRawValue(), applyToAllDossiers: this.#applyToAllDossiers });
} }
#getForm(): UntypedFormGroup { #getForm(): UntypedFormGroup {
@ -67,33 +41,4 @@ export class RemoveAnnotationDialogComponent extends IqserDialogComponent<
option: [this.options[0]], option: [this.options[0]],
}); });
} }
#options() {
const options: DetailsRadioOption<RemoveAnnotationOption>[] = [];
if (this.#permissions.canRemoveOnlyHere) {
options.push({
label: this.#translations.ONLY_HERE.label,
description: this.#translations.ONLY_HERE.description,
icon: PIN_ICON,
value: RemoveAnnotationOptions.ONLY_HERE,
});
}
if (this.#permissions.canRemoveFromDictionary) {
options.push({
label: this.#translations.IN_DOSSIER.label,
description: this.#translations.IN_DOSSIER.description,
icon: FOLDER_ICON,
value: RemoveAnnotationOptions.IN_DOSSIER,
});
}
if (this.#permissions.canMarkAsFalsePositive) {
options.push({
label: this.#translations.FALSE_POSITIVE.label,
description: this.#translations.FALSE_POSITIVE.description,
icon: REMOVE_FROM_DICT_ICON,
value: RemoveAnnotationOptions.FALSE_POSITIVE,
});
}
return options;
}
} }

View File

@ -1,7 +0,0 @@
export const RemoveAnnotationOptions = {
ONLY_HERE: 'ONLY_HERE',
IN_DOSSIER: 'IN_DOSSIER',
FALSE_POSITIVE: 'FALSE_POSITIVE',
} as const;
export type RemoveAnnotationOption = keyof typeof RemoveAnnotationOptions;

View File

@ -10,16 +10,16 @@ import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-d
import { DictionaryService } from '@services/entity-services/dictionary.service'; import { DictionaryService } from '@services/entity-services/dictionary.service';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { IqserDialogComponent } from '@common-ui/dialog/iqser-dialog-component.directive'; import { IqserDialogComponent } from '@iqser/common-ui';
import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options'; import { getRedactOrHintOptions, RedactOrHintOption, RedactOrHintOptions } from '../../utils/dialog-options';
import { RedactOrHintData, RedactOrHintResult } from '../../utils/dialog-types'; import { RedactTextData, RedactTextResult } from '../../utils/dialog-types';
@Component({ @Component({
templateUrl: './redact-text-dialog.component.html', templateUrl: './redact-text-dialog.component.html',
styleUrls: ['./redact-text-dialog.component.scss'], styleUrls: ['./redact-text-dialog.component.scss'],
}) })
export class RedactTextDialogComponent export class RedactTextDialogComponent
extends IqserDialogComponent<RedactTextDialogComponent, RedactOrHintData, RedactOrHintResult> extends IqserDialogComponent<RedactTextDialogComponent, RedactTextData, RedactTextResult>
implements OnInit implements OnInit
{ {
readonly roles = Roles; readonly roles = Roles;
@ -137,7 +137,6 @@ export class RedactTextDialogComponent
reason: [null], reason: [null],
comment: [null], comment: [null],
dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null], dictionary: [this.#manualRedactionTypeExists ? SuperTypes.ManualRedaction : null],
section: [null],
option: [this.options[0]], option: [this.options[0]],
}); });
} }
@ -150,7 +149,7 @@ export class RedactTextDialogComponent
#enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) { #enhanceManualRedaction(addRedactionRequest: IAddRedactionRequest) {
addRedactionRequest.type = this.form.get('dictionary').value; addRedactionRequest.type = this.form.get('dictionary').value;
addRedactionRequest.section = this.form.get('section').value; addRedactionRequest.section = null;
addRedactionRequest.value = this.form.get('selectedText').value; addRedactionRequest.value = this.form.get('selectedText').value;
const legalOption: LegalBasisOption = this.form.get('reason').value; const legalOption: LegalBasisOption = this.form.get('reason').value;

View File

@ -1,7 +1,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui'; import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui';
import { FormBuilder, UntypedFormGroup } from '@angular/forms'; import { FormBuilder, UntypedFormGroup } from '@angular/forms';
import { IqserDialogComponent } from '@common-ui/dialog/iqser-dialog-component.directive'; import { IqserDialogComponent } from '@iqser/common-ui';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

View File

@ -73,7 +73,8 @@ import { copyLocalStorageFiltersValues, FilterService, NestedFilter, processFilt
import { AutoUnsubscribe, Bind, bool, Debounce, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils'; import { AutoUnsubscribe, Bind, bool, Debounce, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils';
import { TenantsService } from '@iqser/common-ui/lib/tenants'; import { TenantsService } from '@iqser/common-ui/lib/tenants';
import { AddHintDialogComponent } from './dialogs/add-hint-dialog/add-hint-dialog.component'; import { AddHintDialogComponent } from './dialogs/add-hint-dialog/add-hint-dialog.component';
import { RedactOrHintData } from './utils/dialog-types'; import { AddAnnotationDialogComponent } from './dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component';
import { RedactTextData } from './utils/dialog-types';
const textActions = [TextPopups.REDACT_TEXT, TextPopups.ADD_HINT, TextPopups.ADD_FALSE_POSITIVE]; const textActions = [TextPopups.REDACT_TEXT, TextPopups.ADD_HINT, TextPopups.ADD_FALSE_POSITIVE];
@ -368,16 +369,13 @@ export class FilePreviewScreenComponent
); );
} }
async openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { async #openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) {
const file = this.state.file(); const file = this.state.file();
const hint = manualRedactionEntryWrapper.type === ManualRedactionEntryTypes.HINT; const hint = manualRedactionEntryWrapper.type === ManualRedactionEntryTypes.HINT;
const data = this.#getRedactTextDialogData(manualRedactionEntryWrapper, file); const data = this.#getRedactTextDialogData(manualRedactionEntryWrapper, file);
const ref = hint const result = await this.#getRedactTextDialog(hint, data).result();
? this._iqserDialog.openDefault(AddHintDialogComponent, { data: data as RedactOrHintData })
: this._iqserDialog.openDefault(RedactTextDialogComponent, { data: data as RedactOrHintData });
const result = await ref.result();
if (!result) { if (!result) {
return; return;
} }
@ -652,7 +650,7 @@ export class FilePreviewScreenComponent
}); });
this.addActiveScreenSubscription = this.pdfProxyService.redactTextRequested$.subscribe($event => { this.addActiveScreenSubscription = this.pdfProxyService.redactTextRequested$.subscribe($event => {
this.openRedactTextDialog($event).then(); this.#openRedactTextDialog($event).then();
}); });
this.addActiveScreenSubscription = this.pdfProxyService.pageChanged$.subscribe(page => this.addActiveScreenSubscription = this.pdfProxyService.pageChanged$.subscribe(page =>
@ -850,7 +848,17 @@ export class FilePreviewScreenComponent
} }
} }
#getRedactTextDialogData(manualRedactionEntryWrapper: ManualRedactionEntryWrapper, file: File) { #getRedactTextDialog(hint: boolean, data: RedactTextData) {
if (this.#isDocumine) {
return this._iqserDialog.openDefault(AddAnnotationDialogComponent, { data });
}
if (hint) {
return this._iqserDialog.openDefault(AddHintDialogComponent, { data });
}
return this._iqserDialog.openDefault(RedactTextDialogComponent, { data });
}
#getRedactTextDialogData(manualRedactionEntryWrapper: ManualRedactionEntryWrapper, file: File): RedactTextData {
const dossierTemplate = this._dossierTemplatesService.find(this.state.dossierTemplateId); const dossierTemplate = this._dossierTemplatesService.find(this.state.dossierTemplateId);
const data = { const data = {

View File

@ -19,7 +19,7 @@ import {
AcceptRecommendationDialogComponent, AcceptRecommendationDialogComponent,
AcceptRecommendationReturnType, AcceptRecommendationReturnType,
} from '../dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component'; } from '../dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component';
import { defaultDialogConfig } from '@iqser/common-ui'; import { defaultDialogConfig, getConfig } from '@iqser/common-ui';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { FilePreviewStateService } from './file-preview-state.service'; import { FilePreviewStateService } from './file-preview-state.service';
@ -34,11 +34,19 @@ import { IqserDialog } from '@common-ui/dialog/iqser-dialog.service';
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
import { isJustOne, List } from '@iqser/common-ui/lib/utils'; import { isJustOne, List } from '@iqser/common-ui/lib/utils';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { RemoveRedactionPermissions, RemoveRedactionResult } from '../utils/dialog-types'; import {
RedactTextData,
RemoveAnnotationResult,
RemoveRedactionData,
RemoveRedactionPermissions,
RemoveRedactionResult,
} from '../utils/dialog-types';
import { RemoveRedactionOptions } from '../utils/dialog-options'; import { RemoveRedactionOptions } from '../utils/dialog-options';
import { RemoveAnnotationDialogComponent } from '../dialogs/docu-mine/remove-annotation-dialog/remove-annotation-dialog.component';
@Injectable() @Injectable()
export class AnnotationActionsService { export class AnnotationActionsService {
readonly #isDocumine;
constructor( constructor(
private readonly _manualRedactionService: ManualRedactionService, private readonly _manualRedactionService: ManualRedactionService,
private readonly _dialogService: FilePreviewDialogService, private readonly _dialogService: FilePreviewDialogService,
@ -53,13 +61,8 @@ export class AnnotationActionsService {
private readonly _skippedService: SkippedService, private readonly _skippedService: SkippedService,
private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dossierTemplatesService: DossierTemplatesService,
private readonly _permissionsService: PermissionsService, private readonly _permissionsService: PermissionsService,
) {} ) {
this.#isDocumine = getConfig().IS_DOCUMINE;
acceptSuggestion(annotations: AnnotationWrapper[]) {
const { dossierId, fileId } = this._state;
const ids = annotations.map(a => a.id);
const request = this._manualRedactionService.approve(ids, dossierId, fileId);
this.#processObsAndEmit(request).then();
} }
removeHighlights(highlights: AnnotationWrapper[]): void { removeHighlights(highlights: AnnotationWrapper[]): void {
@ -127,18 +130,16 @@ export class AnnotationActionsService {
const dossierTemplate = this._dossierTemplatesService.find(this._state.dossierTemplateId); const dossierTemplate = this._dossierTemplatesService.find(this._state.dossierTemplateId);
const isApprover = this._permissionsService.isApprover(this._state.dossier()); const isApprover = this._permissionsService.isApprover(this._state.dossier());
const result: RemoveRedactionResult = await this._iqserDialog const data = {
.openDefault(RemoveRedactionDialogComponent, {
data: {
redaction, redaction,
dossier: this._state.dossier(), dossier: this._state.dossier(),
falsePositiveContext: this._getFalsePositiveText(redaction), falsePositiveContext: this._getFalsePositiveText(redaction),
permissions: removePermissions, permissions: removePermissions,
applyToAllDossiers: isApprover ? dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault : false, applyToAllDossiers: isApprover ? dossierTemplate.applyDictionaryUpdatesToAllDossiersByDefault : false,
isApprover, isApprover,
}, };
})
.result(); const result = await this.#getRemoveRedactionDialog(data).result();
if (result) { if (result) {
if (result.option.value === RemoveRedactionOptions.FALSE_POSITIVE) { if (result.option.value === RemoveRedactionOptions.FALSE_POSITIVE) {
@ -382,7 +383,7 @@ export class AnnotationActionsService {
type: redaction.type, type: redaction.type,
positions: redaction.positions, positions: redaction.positions,
addToDictionary: true, addToDictionary: true,
addToAllDossiers: !!dialogResult.option.extraOption?.checked, addToAllDossiers: !!dialogResult.option.extraOption?.checked || !!dialogResult.applyToAllDossiers,
reason: 'False Positive', reason: 'False Positive',
dictionaryEntryType: redaction.isRecommendation dictionaryEntryType: redaction.isRecommendation
? DictionaryEntryTypes.FALSE_RECOMMENDATION ? DictionaryEntryTypes.FALSE_RECOMMENDATION
@ -400,11 +401,18 @@ export class AnnotationActionsService {
annotationId: redaction.id, annotationId: redaction.id,
comment: dialogResult.comment, comment: dialogResult.comment,
removeFromDictionary, removeFromDictionary,
removeFromAllDossiers: !!dialogResult.option.extraOption?.checked, removeFromAllDossiers: !!dialogResult.option.extraOption?.checked || !!dialogResult.applyToAllDossiers,
}; };
const { dossierId, fileId } = this._state; const { dossierId, fileId } = this._state;
this.#processObsAndEmit( this.#processObsAndEmit(
this._manualRedactionService.removeRedaction([body], dossierId, fileId, removeFromDictionary, redaction.isHint), this._manualRedactionService.removeRedaction([body], dossierId, fileId, removeFromDictionary, redaction.isHint),
).then(); ).then();
} }
#getRemoveRedactionDialog(data: RemoveRedactionData) {
if (this.#isDocumine) {
return this._iqserDialog.openDefault(RemoveAnnotationDialogComponent, { data });
}
return this._iqserDialog.openDefault(RemoveRedactionDialogComponent, { data });
}
} }

View File

@ -4,6 +4,7 @@ import { redactTextTranslations } from '@translations/redact-text-translations';
import { Dossier } from '@red/domain'; import { Dossier } from '@red/domain';
import { removeRedactionTranslations } from '@translations/remove-redaction-translations'; import { removeRedactionTranslations } from '@translations/remove-redaction-translations';
import { RemoveRedactionData } from './dialog-types'; import { RemoveRedactionData } from './dialog-types';
import { removeAnnotationTranslations } from '@translations/remove-annotation-translations';
const PIN_ICON = 'red:push-pin'; const PIN_ICON = 'red:push-pin';
const FOLDER_ICON = 'red:folder'; const FOLDER_ICON = 'red:folder';
@ -21,8 +22,10 @@ export const RemoveRedactionOptions = {
IN_DOSSIER: 'IN_DOSSIER', IN_DOSSIER: 'IN_DOSSIER',
FALSE_POSITIVE: 'FALSE_POSITIVE', FALSE_POSITIVE: 'FALSE_POSITIVE',
} as const; } as const;
export const RemoveAnnotationOptions = RemoveRedactionOptions;
export type RemoveRedactionOption = keyof typeof RemoveRedactionOptions; export type RemoveRedactionOption = keyof typeof RemoveRedactionOptions;
export type RemoveAnnotationOption = RemoveRedactionOption;
export const getRedactOrHintOptions = ( export const getRedactOrHintOptions = (
dossier: Dossier, dossier: Dossier,
@ -57,8 +60,11 @@ export const getRedactOrHintOptions = (
return options; return options;
}; };
export const getRemoveRedactionOptions = (data: RemoveRedactionData): DetailsRadioOption<RemoveRedactionOption>[] => { export const getRemoveRedactionOptions = (
const translations = removeRedactionTranslations; data: RemoveRedactionData,
isDocumine: boolean = false,
): DetailsRadioOption<RemoveRedactionOption>[] => {
const translations = isDocumine ? removeAnnotationTranslations : removeRedactionTranslations;
const { permissions, redaction, applyToAllDossiers, isApprover, falsePositiveContext } = data; const { permissions, redaction, applyToAllDossiers, isApprover, falsePositiveContext } = data;
const options: DetailsRadioOption<RemoveRedactionOption>[] = []; const options: DetailsRadioOption<RemoveRedactionOption>[] = [];
@ -78,11 +84,13 @@ export const getRemoveRedactionOptions = (data: RemoveRedactionData): DetailsRad
descriptionParams: { type: redaction.hint ? 'hint' : 'redact', value: redaction.value }, descriptionParams: { type: redaction.hint ? 'hint' : 'redact', value: redaction.value },
icon: FOLDER_ICON, icon: FOLDER_ICON,
value: RemoveRedactionOptions.IN_DOSSIER, value: RemoveRedactionOptions.IN_DOSSIER,
extraOption: { extraOption: !isDocumine
? {
label: translations.IN_DOSSIER.extraOptionLabel, label: translations.IN_DOSSIER.extraOptionLabel,
checked: applyToAllDossiers ?? true, checked: applyToAllDossiers ?? true,
hidden: !isApprover, hidden: !isApprover,
}, }
: null,
}); });
} }
if (permissions.canMarkAsFalsePositive) { if (permissions.canMarkAsFalsePositive) {
@ -92,11 +100,13 @@ export const getRemoveRedactionOptions = (data: RemoveRedactionData): DetailsRad
descriptionParams: { value: redaction.value, type: redaction.type, context: falsePositiveContext }, descriptionParams: { value: redaction.value, type: redaction.type, context: falsePositiveContext },
icon: REMOVE_FROM_DICT_ICON, icon: REMOVE_FROM_DICT_ICON,
value: RemoveRedactionOptions.FALSE_POSITIVE, value: RemoveRedactionOptions.FALSE_POSITIVE,
extraOption: { extraOption: !isDocumine
? {
label: translations.FALSE_POSITIVE.extraOptionLabel, label: translations.FALSE_POSITIVE.extraOptionLabel,
checked: applyToAllDossiers ?? true, checked: applyToAllDossiers ?? true,
hidden: !isApprover, hidden: !isApprover,
}, }
: null,
}); });
} }
return options; return options;

View File

@ -4,19 +4,27 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { DetailsRadioOption } from '@iqser/common-ui'; import { DetailsRadioOption } from '@iqser/common-ui';
import { RemoveRedactionOption } from './dialog-options'; import { RemoveRedactionOption } from './dialog-options';
export interface RedactOrHintData { export interface AddAnnotationData {
manualRedactionEntryWrapper: ManualRedactionEntryWrapper; manualRedactionEntryWrapper: ManualRedactionEntryWrapper;
dossierId: string; dossierId: string;
file: File; file: File;
applyToAllDossiers: boolean;
isApprover: boolean;
} }
export interface RedactOrHintResult { export interface RedactTextData extends AddAnnotationData {
applyToAllDossiers?: boolean;
isApprover?: boolean;
}
export type AddHintData = RedactTextData;
export interface RedactTextResult {
redaction: IManualRedactionEntry; redaction: IManualRedactionEntry;
dictionary: Dictionary; dictionary: Dictionary;
} }
export type AddHintResult = RedactTextResult;
export type AddAnnotationResult = RedactTextResult;
export interface RemoveRedactionPermissions { export interface RemoveRedactionPermissions {
canRemoveOnlyHere: boolean; canRemoveOnlyHere: boolean;
canRemoveFromDictionary: boolean; canRemoveFromDictionary: boolean;
@ -32,8 +40,12 @@ export interface RemoveRedactionData {
isApprover: boolean; isApprover: boolean;
} }
export type RemoveAnnotationData = RemoveRedactionData;
export interface RemoveRedactionResult { export interface RemoveRedactionResult {
comment: string; comment: string;
option: DetailsRadioOption<RemoveRedactionOption>; option: DetailsRadioOption<RemoveRedactionOption>;
applyToAllDossiers: boolean | null; applyToAllDossiers?: boolean;
} }
export type RemoveAnnotationResult = RemoveRedactionResult;

View File

@ -1,7 +1,7 @@
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { RedactOrHintOption } from '@translations/redact-text-translations'; import { DialogOption } from '@translations/redact-text-translations';
export const addHintTranslations: Record<'onlyHere' | 'inDossier', RedactOrHintOption> = { export const addHintTranslations: Record<'onlyHere' | 'inDossier', DialogOption> = {
onlyHere: { onlyHere: {
label: _('add-hint.dialog.content.options.only-here.label'), label: _('add-hint.dialog.content.options.only-here.label'),
description: _('add-hint.dialog.content.options.only-here.description'), description: _('add-hint.dialog.content.options.only-here.description'),

View File

@ -1,12 +1,12 @@
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
export interface RedactOrHintOption { export interface DialogOption {
label: string; label: string;
description: string; description: string;
extraOptionLabel?: string; extraOptionLabel?: string;
} }
export const redactTextTranslations: Record<'onlyHere' | 'inDossier', RedactOrHintOption> = { export const redactTextTranslations: Record<'onlyHere' | 'inDossier', DialogOption> = {
onlyHere: { onlyHere: {
label: _('redact-text.dialog.content.options.only-here.label'), label: _('redact-text.dialog.content.options.only-here.label'),
description: _('redact-text.dialog.content.options.only-here.description'), description: _('redact-text.dialog.content.options.only-here.description'),

View File

@ -1,12 +1,8 @@
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { RemoveAnnotationOption } from '../modules/file-preview/dialogs/docu-mine/remove-annotation-dialog/remove-annotation-options'; import { RemoveAnnotationOption } from '../modules/file-preview/utils/dialog-options';
import { DialogOption } from '@translations/redact-text-translations';
interface Option { export const removeAnnotationTranslations: { [key in RemoveAnnotationOption]: DialogOption } = {
label: string;
description: string;
}
export const removeAnnotationTranslations: { [key in RemoveAnnotationOption]: Option } = {
ONLY_HERE: { ONLY_HERE: {
label: _('remove-annotation.dialog.content.options.only-here.label'), label: _('remove-annotation.dialog.content.options.only-here.label'),
description: _('remove-annotation.dialog.content.options.only-here.description'), description: _('remove-annotation.dialog.content.options.only-here.description'),

View File

@ -1,13 +1,8 @@
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { RemoveRedactionOption } from '../modules/file-preview/utils/dialog-options'; import { RemoveRedactionOption } from '../modules/file-preview/utils/dialog-options';
import { DialogOption } from '@translations/redact-text-translations';
interface Option { export const removeRedactionTranslations: { [key in RemoveRedactionOption]: DialogOption } = {
label: string;
description: string;
extraOptionLabel?: string;
}
export const removeRedactionTranslations: { [key in RemoveRedactionOption]: Option } = {
ONLY_HERE: { ONLY_HERE: {
label: _('remove-redaction.dialog.content.options.only-here.label'), label: _('remove-redaction.dialog.content.options.only-here.label'),
description: _('remove-redaction.dialog.content.options.only-here.description'), description: _('remove-redaction.dialog.content.options.only-here.description'),

View File

@ -1983,28 +1983,28 @@
"remove-annotation": { "remove-annotation": {
"dialog": { "dialog": {
"actions": { "actions": {
"cancel": "", "cancel": "Cancel",
"save": "" "save": "Save"
}, },
"content": { "content": {
"comment": "", "comment": "Comment",
"comment-placeholder": "", "comment-placeholder": "Add remarks or mentions ...",
"options": { "options": {
"false-positive": { "false-positive": {
"description": "", "description": "\"{value}\" is not a {type} in this context: \"{context}\".",
"label": "" "label": "False positive"
}, },
"in-dossier": { "in-dossier": {
"description": "", "description": "Do not annotate \"{value}\" in any document of the current dossier.",
"label": "" "label": "Remove from dossier"
}, },
"only-here": { "only-here": {
"description": "", "description": "Do not annotate \"{value}\" at this position in the current document.",
"label": "" "label": "Remove here"
} }
} }
}, },
"title": "" "title": "Remove annotation"
} }
}, },
"remove-redaction": { "remove-redaction": {

View File

@ -1983,28 +1983,28 @@
"remove-annotation": { "remove-annotation": {
"dialog": { "dialog": {
"actions": { "actions": {
"cancel": "", "cancel": "Cancel",
"save": "" "save": "Save"
}, },
"content": { "content": {
"comment": "", "comment": "Comment",
"comment-placeholder": "", "comment-placeholder": "Add remarks or mentions ...",
"options": { "options": {
"false-positive": { "false-positive": {
"description": "", "description": "\"{value}\" is not a {type} in this context: \"{context}\".",
"label": "" "label": "False positive"
}, },
"in-dossier": { "in-dossier": {
"description": "", "description": "Do not annotate \"{value}\" in any document of the current dossier.",
"label": "" "label": "Remove from dossier"
}, },
"only-here": { "only-here": {
"description": "", "description": "Do not annotate \"{value}\" at this position in the current document.",
"label": "" "label": "Remove here"
} }
} }
}, },
"title": "" "title": "Remove annotation"
} }
}, },
"remove-redaction": { "remove-redaction": {