RED-6774 - checked file permissions for each dialog operation

This commit is contained in:
Valentin Mihai 2023-06-20 18:02:20 +03:00
parent 3e9ae643e1
commit bf4b8cba33
13 changed files with 220 additions and 165 deletions

View File

@ -10,6 +10,7 @@ export class AnnotationPermissions {
canMarkAsFalsePositive = true; canMarkAsFalsePositive = true;
canRemoveOrSuggestToRemoveOnlyHere = true; canRemoveOrSuggestToRemoveOnlyHere = true;
canRemoveOrSuggestToRemoveFromDictionary = true; canRemoveOrSuggestToRemoveFromDictionary = true;
canRemoveOrSuggestToRemoveRedaction = true;
canAcceptSuggestion = true; canAcceptSuggestion = true;
canRejectSuggestion = true; canRejectSuggestion = true;
canForceRedaction = true; canForceRedaction = true;
@ -63,6 +64,12 @@ export class AnnotationPermissions {
!annotation.pending && !annotation.pending &&
!annotation.hasBeenResized; !annotation.hasBeenResized;
permissions.canRemoveOrSuggestToRemoveRedaction =
annotations.length === 1 &&
(permissions.canRemoveOrSuggestToRemoveOnlyHere ||
permissions.canRemoveOrSuggestToRemoveFromDictionary ||
permissions.canMarkAsFalsePositive);
permissions.canChangeLegalBasis = canAddOrRequestRedaction && annotation.isRedacted && !annotation.pending; permissions.canChangeLegalBasis = canAddOrRequestRedaction && annotation.isRedacted && !annotation.pending;
permissions.canRecategorizeImage = permissions.canRecategorizeImage =

View File

@ -150,36 +150,36 @@
icon="red:visibility" icon="red:visibility"
></iqser-circle-button> ></iqser-circle-button>
<iqser-circle-button <!-- <iqser-circle-button-->
(action)="removeOrSuggestRemoveAnnotation(true)" <!-- (action)="removeOrSuggestRemoveAnnotation(true)"-->
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveFromDictionary" <!-- *ngIf="annotationPermissions.canRemoveOrSuggestToRemoveFromDictionary"-->
[tooltipPosition]="tooltipPosition" <!-- [tooltipPosition]="tooltipPosition"-->
[tooltip]="'annotation-actions.remove-annotation.remove-from-dict' | translate" <!-- [tooltip]="'annotation-actions.remove-annotation.remove-from-dict' | translate"-->
[type]="buttonType" <!-- [type]="buttonType"-->
icon="red:remove-from-dict" <!-- icon="red:remove-from-dict"-->
></iqser-circle-button> <!-- ></iqser-circle-button>-->
<iqser-circle-button <!-- <iqser-circle-button-->
(action)="markAsFalsePositive()" <!-- (action)="markAsFalsePositive()"-->
*ngIf="annotationPermissions.canMarkAsFalsePositive" <!-- *ngIf="annotationPermissions.canMarkAsFalsePositive"-->
[tooltipPosition]="tooltipPosition" <!-- [tooltipPosition]="tooltipPosition"-->
[tooltip]="'annotation-actions.remove-annotation.false-positive' | translate" <!-- [tooltip]="'annotation-actions.remove-annotation.false-positive' | translate"-->
[type]="buttonType" <!-- [type]="buttonType"-->
icon="red:thumb-down" <!-- icon="red:thumb-down"-->
></iqser-circle-button> <!-- ></iqser-circle-button>-->
<iqser-circle-button <!-- <iqser-circle-button-->
(action)="removeOrSuggestRemoveAnnotation(false)" <!-- (action)="removeOrSuggestRemoveAnnotation(false)"-->
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere" <!-- *ngIf="annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere"-->
[tooltipPosition]="tooltipPosition" <!-- [tooltipPosition]="tooltipPosition"-->
[tooltip]="'annotation-actions.remove-annotation.only-here' | translate" <!-- [tooltip]="'annotation-actions.remove-annotation.only-here' | translate"-->
[type]="buttonType" <!-- [type]="buttonType"-->
icon="iqser:trash" <!-- icon="iqser:trash"-->
></iqser-circle-button> <!-- ></iqser-circle-button>-->
<iqser-circle-button <iqser-circle-button
(action)="removeOrSuggestRemoveRedaction()" (action)="removeOrSuggestRemoveRedaction()"
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere && annotations.length === 1" *ngIf="annotationPermissions.canRemoveOrSuggestToRemoveRedaction"
[tooltipPosition]="tooltipPosition" [tooltipPosition]="tooltipPosition"
[tooltip]="'annotation-actions.remove-annotation.remove-redaction' | translate" [tooltip]="'annotation-actions.remove-annotation.remove-redaction' | translate"
[type]="buttonType" [type]="buttonType"

View File

@ -10,6 +10,7 @@ import { HelpModeService, IqserPermissionsService } from '@iqser/common-ui';
import { ViewModeService } from '../../services/view-mode.service'; import { ViewModeService } from '../../services/view-mode.service';
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service'; import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
import { Roles } from '@users/roles'; import { Roles } from '@users/roles';
import { RemoveRedactionPermissions } from '../../dialogs/remove-redaction-dialog/remove-redaction-dialog.component';
export const AnnotationButtonTypes = { export const AnnotationButtonTypes = {
dark: 'dark', dark: 'dark',
@ -79,7 +80,7 @@ export class AnnotationActionsComponent implements OnChanges {
} }
removeOrSuggestRemoveRedaction() { removeOrSuggestRemoveRedaction() {
this.annotationActionsService.removeOrSuggestRemoveRedaction(this.annotations[0]); this.annotationActionsService.removeOrSuggestRemoveRedaction(this.annotations[0], this.annotationPermissions);
} }
markAsFalsePositive() { markAsFalsePositive() {

View File

@ -1,15 +1,14 @@
import { Component, Inject, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { BaseDialogComponent, DetailsRadioOption, IqserPermissionsService } from '@iqser/common-ui'; import { DetailsRadioOption, IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Dictionary, Dossier, File, IAddRedactionRequest, IManualRedactionEntry, SuperTypes } from '@red/domain';
import { Dictionary, Dossier, File, IAddRedactionRequest, SuperTypes } from '@red/domain'; import { FormBuilder, UntypedFormGroup } from '@angular/forms';
import { UntypedFormGroup, Validators } from '@angular/forms';
import { Roles } from '@users/roles'; import { Roles } from '@users/roles';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { JustificationsService } from '@services/entity-services/justifications.service'; 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 { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component'; import { LegalBasisOption } from '../manual-redaction-dialog/manual-annotation-dialog.component';
import { DictionaryService } from '@services/entity-services/dictionary.service'; import { DictionaryService } from '@services/entity-services/dictionary.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { import {
ManualRedactionEntryType, ManualRedactionEntryType,
ManualRedactionEntryTypes, ManualRedactionEntryTypes,
@ -18,21 +17,39 @@ import {
import { redactTextTranslations } from '@translations/redact-text-translations'; import { redactTextTranslations } from '@translations/redact-text-translations';
import { RedactTextOption, RedactTextOptions } from './redact-text-options'; import { RedactTextOption, RedactTextOptions } from './redact-text-options';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { IqserDialogComponent } from '../../../../../../../../libs/common-ui/src/lib/dialog/iqser-dialog-component.directive';
const PIN_ICON = 'red:push-pin'; const PIN_ICON = 'red:push-pin';
const FOLDER_ICON = 'red:folder'; const FOLDER_ICON = 'red:folder';
interface RedactTextData {
manualRedactionEntryWrapper: ManualRedactionEntryWrapper;
dossierId: string;
file: File;
}
interface DialogResult {
redaction: IManualRedactionEntry;
dictionary: Dictionary;
}
@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 extends BaseDialogComponent implements OnInit { export class RedactTextDialogComponent
extends IqserDialogComponent<RedactTextDialogComponent, RedactTextData, DialogResult>
implements OnInit
{
readonly roles = Roles; readonly roles = Roles;
readonly iconButtonTypes = IconButtonTypes;
readonly options: DetailsRadioOption<RedactTextOption>[]; readonly options: DetailsRadioOption<RedactTextOption>[];
readonly type: ManualRedactionEntryType; readonly type: ManualRedactionEntryType;
dictionaryRequest = false; dictionaryRequest = false;
legalOptions: LegalBasisOption[] = []; legalOptions: LegalBasisOption[] = [];
dictionaries: Dictionary[] = []; dictionaries: Dictionary[] = [];
form!: UntypedFormGroup;
#manualRedactionTypeExists = true; #manualRedactionTypeExists = true;
@ -41,15 +58,13 @@ export class RedactTextDialogComponent extends BaseDialogComponent implements On
readonly #hint: boolean; readonly #hint: boolean;
constructor( constructor(
private _justificationsService: JustificationsService, private readonly _justificationsService: JustificationsService,
private _activeDossiersService: ActiveDossiersService, private readonly _activeDossiersService: ActiveDossiersService,
private _dictionaryService: DictionaryService, private readonly _dictionaryService: DictionaryService,
private _iqserPermissionsService: IqserPermissionsService, private readonly _iqserPermissionsService: IqserPermissionsService,
protected readonly _dialogRef: MatDialogRef<RedactTextDialogComponent>, private readonly _formBuilder: FormBuilder,
@Inject(MAT_DIALOG_DATA) readonly data: { manualRedactionEntryWrapper: ManualRedactionEntryWrapper; dossierId: string; file: File },
) { ) {
super(_dialogRef); super();
this.#dossier = _activeDossiersService.find(this.data.dossierId); this.#dossier = _activeDossiersService.find(this.data.dossierId);
this.type = this.data.manualRedactionEntryWrapper.type; this.type = this.data.manualRedactionEntryWrapper.type;
this.#hint = this.type === ManualRedactionEntryTypes.HINT; this.#hint = this.type === ManualRedactionEntryTypes.HINT;
@ -57,7 +72,18 @@ export class RedactTextDialogComponent extends BaseDialogComponent implements On
this.options = this.#options(); this.options = this.#options();
this.form = this.#getForm(); this.form = this.#getForm();
this.initialFormValue = this.form.getRawValue();
this.form
.get('option')
.valueChanges.pipe(
tap((option: DetailsRadioOption<RedactTextOption>) => {
this.dictionaryRequest = option.value === RedactTextOptions.IN_DOSSIER;
console.log('this.dictionaryRequest: ', this.dictionaryRequest);
this.#resetValues();
}),
takeUntilDestroyed(),
)
.subscribe();
} }
get displayedDictionaryLabel() { get displayedDictionaryLabel() {
@ -88,24 +114,12 @@ export class RedactTextDialogComponent extends BaseDialogComponent implements On
this.#selectReason(); this.#selectReason();
this.#formatSelectedTextValue(); this.#formatSelectedTextValue();
this._subscriptions.add(
this.form
.get('option')
.valueChanges.pipe(
tap((option: DetailsRadioOption<RedactTextOption>) => {
this.dictionaryRequest = option.value === RedactTextOptions.IN_DOSSIER;
this.#resetValues();
}),
)
.subscribe(),
);
} }
save(): void { save(): void {
this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry); this.#enhanceManualRedaction(this.data.manualRedactionEntryWrapper.manualRedactionEntry);
const redaction = this.data.manualRedactionEntryWrapper.manualRedactionEntry; const redaction = this.data.manualRedactionEntryWrapper.manualRedactionEntry;
this._dialogRef.close({ this.dialogRef.close({
redaction, redaction,
dictionary: this.dictionaries.find(d => d.type === this.form.get('dictionary').value), dictionary: this.dictionaries.find(d => d.type === this.form.get('dictionary').value),
}); });
@ -166,14 +180,16 @@ export class RedactTextDialogComponent extends BaseDialogComponent implements On
} }
#options() { #options() {
return [ const options: DetailsRadioOption<RedactTextOption>[] = [
{ {
label: this.#translations[this.type].onlyHere.label, label: this.#translations[this.type].onlyHere.label,
description: this.#translations[this.type].onlyHere.description, description: this.#translations[this.type].onlyHere.description,
icon: PIN_ICON, icon: PIN_ICON,
value: RedactTextOptions.ONLY_HERE, value: RedactTextOptions.ONLY_HERE,
}, },
{ ];
if (!this._iqserPermissionsService.has(Roles.getRss)) {
options.push({
label: this.#translations[this.type].inDossier.label, label: this.#translations[this.type].inDossier.label,
description: this.#translations[this.type].inDossier.description, description: this.#translations[this.type].inDossier.description,
descriptionParams: { dossierName: this.#dossier.dossierName }, descriptionParams: { dossierName: this.#dossier.dossierName },
@ -183,8 +199,9 @@ export class RedactTextDialogComponent extends BaseDialogComponent implements On
// label: this.#translations[this.type].inDossier.extraOptionLabel, // label: this.#translations[this.type].inDossier.extraOptionLabel,
// checked: true, // checked: true,
// }, // },
}, });
]; }
return options;
} }
#resetValues() { #resetValues() {

View File

@ -1,20 +1,28 @@
import { Component, Inject } from '@angular/core'; import { Component } from '@angular/core';
import { BaseDialogComponent, DetailsRadioOption } from '@iqser/common-ui'; import { DetailsRadioOption, IconButtonTypes } from '@iqser/common-ui';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { RemoveRedactionOption, RemoveRedactionOptions } from './remove-redaction-options'; import { RemoveRedactionOption, RemoveRedactionOptions } from './remove-redaction-options';
import { UntypedFormGroup } from '@angular/forms'; import { FormBuilder, UntypedFormGroup } from '@angular/forms';
import { removeRedactionTranslations } from '@translations/remove-redaction-translations'; import { removeRedactionTranslations } from '@translations/remove-redaction-translations';
import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { Dossier } from '@red/domain'; import { Dossier } from '@red/domain';
import { IqserDialogComponent } from '../../../../../../../../libs/common-ui/src/lib/dialog/iqser-dialog-component.directive';
import { PermissionsService } from '@services/permissions.service';
const PIN_ICON = 'red:push-pin'; const PIN_ICON = 'red:push-pin';
const FOLDER_ICON = 'red:folder'; const FOLDER_ICON = 'red:folder';
const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict'; const REMOVE_FROM_DICT_ICON = 'red:remove-from-dict';
export interface RemoveRedactionPermissions {
canRemoveOrSuggestToRemoveOnlyHere: boolean;
canRemoveOrSuggestToRemoveFromDictionary: boolean;
canMarkAsFalsePositive: boolean;
}
export interface RemoveRedactionData { export interface RemoveRedactionData {
redaction: AnnotationWrapper; redaction: AnnotationWrapper;
dossier: Dossier; dossier: Dossier;
falsePositiveContext: string; falsePositiveContext: string;
permissions: RemoveRedactionPermissions;
} }
export interface RemoveRedactionResult { export interface RemoveRedactionResult {
@ -26,25 +34,30 @@ export interface RemoveRedactionResult {
templateUrl: './remove-redaction-dialog.html', templateUrl: './remove-redaction-dialog.html',
styleUrls: ['./remove-redaction-dialog.component.scss'], styleUrls: ['./remove-redaction-dialog.component.scss'],
}) })
export class RemoveRedactionDialogComponent extends BaseDialogComponent { export class RemoveRedactionDialogComponent extends IqserDialogComponent<
RemoveRedactionDialogComponent,
RemoveRedactionData,
RemoveRedactionResult
> {
readonly iconButtonTypes = IconButtonTypes;
readonly options: DetailsRadioOption<RemoveRedactionOption>[]; readonly options: DetailsRadioOption<RemoveRedactionOption>[];
readonly #redaction: AnnotationWrapper;
form!: UntypedFormGroup;
readonly #redaction: AnnotationWrapper;
readonly #permissions: RemoveRedactionPermissions;
readonly #translations = removeRedactionTranslations; readonly #translations = removeRedactionTranslations;
constructor( constructor(private readonly _formBuilder: FormBuilder, private readonly _permissionsService: PermissionsService) {
protected readonly _dialogRef: MatDialogRef<RemoveRedactionDialogComponent, RemoveRedactionResult>, super();
@Inject(MAT_DIALOG_DATA) readonly data: RemoveRedactionData, this.#redaction = this.data.redaction;
) { this.#permissions = this.data.permissions;
super(_dialogRef);
this.#redaction = data.redaction;
this.options = this.#options(); this.options = this.#options();
this.form = this.#getForm(); this.form = this.#getForm();
this.initialFormValue = this.form.getRawValue();
} }
save(): void { save(): void {
this._dialogRef.close(this.form.getRawValue()); this.dialogRef.close(this.form.getRawValue());
} }
#getForm(): UntypedFormGroup { #getForm(): UntypedFormGroup {
@ -55,28 +68,34 @@ export class RemoveRedactionDialogComponent extends BaseDialogComponent {
} }
#options() { #options() {
return [ const options: DetailsRadioOption<RemoveRedactionOption>[] = [];
{ if (this.#permissions.canRemoveOrSuggestToRemoveOnlyHere) {
options.push({
label: this.#translations.ONLY_HERE.label, label: this.#translations.ONLY_HERE.label,
description: this.#translations.ONLY_HERE.description, description: this.#translations.ONLY_HERE.description,
descriptionParams: { value: this.#redaction.value }, descriptionParams: { value: this.#redaction.value },
icon: PIN_ICON, icon: PIN_ICON,
value: RemoveRedactionOptions.ONLY_HERE, value: RemoveRedactionOptions.ONLY_HERE,
}, });
{ }
if (this.#permissions.canRemoveOrSuggestToRemoveFromDictionary) {
options.push({
label: this.#translations.IN_DOSSIER.label, label: this.#translations.IN_DOSSIER.label,
description: this.#translations.IN_DOSSIER.description, description: this.#translations.IN_DOSSIER.description,
descriptionParams: { value: this.#redaction.value }, descriptionParams: { value: this.#redaction.value },
icon: FOLDER_ICON, icon: FOLDER_ICON,
value: RemoveRedactionOptions.IN_DOSSIER, value: RemoveRedactionOptions.IN_DOSSIER,
}, });
{ }
if (this.#permissions.canMarkAsFalsePositive) {
options.push({
label: this.#translations.FALSE_POSITIVE.label, label: this.#translations.FALSE_POSITIVE.label,
description: this.#translations.FALSE_POSITIVE.description, description: this.#translations.FALSE_POSITIVE.description,
descriptionParams: { value: this.#redaction.value, type: this.#redaction.type }, descriptionParams: { value: this.#redaction.value, type: this.#redaction.type, context: this.data.falsePositiveContext },
icon: REMOVE_FROM_DICT_ICON, icon: REMOVE_FROM_DICT_ICON,
value: RemoveRedactionOptions.FALSE_POSITIVE, value: RemoveRedactionOptions.FALSE_POSITIVE,
}, });
]; }
return options;
} }
} }

View File

@ -74,6 +74,9 @@ import { ConfigService } from '@services/config.service';
import { ReadableRedactionsService } from '../pdf-viewer/services/readable-redactions.service'; import { ReadableRedactionsService } from '../pdf-viewer/services/readable-redactions.service';
import { Roles } from '@users/roles'; import { Roles } from '@users/roles';
import { SuggestionsService } from './services/suggestions.service'; import { SuggestionsService } from './services/suggestions.service';
import { IqserDialog } from '../../../../../../libs/common-ui/src/lib/dialog/iqser-dialog.service';
import { RedactTextDialogComponent } from './dialogs/redact-text-dialog/redact-text-dialog.component';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
const textActions = [TextPopups.ADD_DICTIONARY, TextPopups.ADD_FALSE_POSITIVE]; const textActions = [TextPopups.ADD_DICTIONARY, TextPopups.ADD_FALSE_POSITIVE];
@ -124,6 +127,7 @@ export class FilePreviewScreenComponent
private readonly _changeRef: ChangeDetectorRef, private readonly _changeRef: ChangeDetectorRef,
private readonly _tenantsService: TenantsService, private readonly _tenantsService: TenantsService,
private readonly _dialogService: FilePreviewDialogService, private readonly _dialogService: FilePreviewDialogService,
private readonly _iqserDialog: IqserDialog,
private readonly _pageRotationService: PageRotationService, private readonly _pageRotationService: PageRotationService,
private readonly _viewerHeaderService: ViewerHeaderService, private readonly _viewerHeaderService: ViewerHeaderService,
private readonly _annotationDrawService: AnnotationDrawService, private readonly _annotationDrawService: AnnotationDrawService,
@ -366,26 +370,25 @@ export class FilePreviewScreenComponent
); );
} }
openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) { async openRedactTextDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) {
return this._ngZone.run(() => { const file = this.state.file();
const file = this.state.file(); const result = await this._iqserDialog
.openDefault(RedactTextDialogComponent, {
data: { manualRedactionEntryWrapper, dossierId: this.dossierId, file },
})
.result();
this._dialogService.openDialog( if (result) {
'redactText', const add$ = this._manualRedactionService.addAnnotation(
{ manualRedactionEntryWrapper, dossierId: this.dossierId, file }, [result.redaction],
(result: { redaction: IManualRedactionEntry; dictionary?: Dictionary }) => { this.dossierId,
const add$ = this._manualRedactionService.addAnnotation( this.fileId,
[result.redaction], result.dictionary?.label,
this.dossierId,
this.fileId,
result.dictionary?.label,
);
const addAndReload$ = add$.pipe(switchMap(() => this._filesService.reload(this.dossierId, file)));
return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined))));
},
); );
});
const addAndReload$ = add$.pipe(switchMap(() => this._filesService.reload(this.dossierId, file)));
return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined))));
}
} }
toggleFullScreen() { toggleFullScreen() {

View File

@ -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 { firstValueFrom, Observable } from 'rxjs'; import { firstValueFrom, Observable, of } from 'rxjs';
import { getFirstRelevantTextPart } from '../../../utils'; import { getFirstRelevantTextPart } from '../../../utils';
import { Core } from '@pdftron/webviewer'; import { Core } from '@pdftron/webviewer';
import { import {
@ -30,8 +30,13 @@ import { PdfViewer } from '../../pdf-viewer/services/pdf-viewer.service';
import { REDAnnotationManager } from '../../pdf-viewer/services/annotation-manager.service'; import { REDAnnotationManager } from '../../pdf-viewer/services/annotation-manager.service';
import { SkippedService } from './skipped.service'; import { SkippedService } from './skipped.service';
import { REDDocumentViewer } from '../../pdf-viewer/services/document-viewer.service'; import { REDDocumentViewer } from '../../pdf-viewer/services/document-viewer.service';
import { RemoveRedactionData, RemoveRedactionResult } from '../dialogs/remove-redaction-dialog/remove-redaction-dialog.component'; import {
RemoveRedactionDialogComponent,
RemoveRedactionPermissions,
} from '../dialogs/remove-redaction-dialog/remove-redaction-dialog.component';
import { RemoveRedactionOptions } from '../dialogs/remove-redaction-dialog/remove-redaction-options'; import { RemoveRedactionOptions } from '../dialogs/remove-redaction-dialog/remove-redaction-options';
import { IqserDialog } from '../../../../../../../libs/common-ui/src/lib/dialog/iqser-dialog.service';
import { AnnotationPermissions } from '@models/file/annotation.permissions';
@Injectable() @Injectable()
export class AnnotationActionsService { export class AnnotationActionsService {
@ -39,6 +44,7 @@ export class AnnotationActionsService {
private readonly _manualRedactionService: ManualRedactionService, private readonly _manualRedactionService: ManualRedactionService,
private readonly _dialogService: FilePreviewDialogService, private readonly _dialogService: FilePreviewDialogService,
private readonly _dialog: MatDialog, private readonly _dialog: MatDialog,
private readonly _iqserDialog: IqserDialog,
private readonly _pdf: PdfViewer, private readonly _pdf: PdfViewer,
private readonly _documentViewer: REDDocumentViewer, private readonly _documentViewer: REDDocumentViewer,
private readonly _annotationManager: REDAnnotationManager, private readonly _annotationManager: REDAnnotationManager,
@ -131,21 +137,32 @@ export class AnnotationActionsService {
}); });
} }
removeOrSuggestRemoveRedaction(redaction: AnnotationWrapper) { async removeOrSuggestRemoveRedaction(redaction: AnnotationWrapper, permissions) {
const data: RemoveRedactionData = { const removePermissions: RemoveRedactionPermissions = {
redaction, canRemoveOrSuggestToRemoveOnlyHere: permissions.canRemoveOrSuggestToRemoveOnlyHere,
dossier: this._state.dossier(), canRemoveOrSuggestToRemoveFromDictionary: permissions.canRemoveOrSuggestToRemoveFromDictionary,
falsePositiveContext: this._getFalsePositiveText(redaction), canMarkAsFalsePositive: permissions.canMarkAsFalsePositive,
}; };
this._dialogService.openDialog('removeRedaction', data, (result: RemoveRedactionResult) => { const result = await this._iqserDialog
.openDefault(RemoveRedactionDialogComponent, {
data: {
redaction,
dossier: this._state.dossier(),
falsePositiveContext: this._getFalsePositiveText(redaction),
permissions: removePermissions,
},
})
.result();
if (result) {
if (result.option.value === RemoveRedactionOptions.FALSE_POSITIVE) { if (result.option.value === RemoveRedactionOptions.FALSE_POSITIVE) {
this.#setAsFalsePositive(redaction, result.comment); this.#setAsFalsePositive(redaction, result.comment);
} else { } else {
const removeFromDictionary = result.option.value === RemoveRedactionOptions.IN_DOSSIER; const removeFromDictionary = result.option.value === RemoveRedactionOptions.IN_DOSSIER;
this.#removeRedaction(redaction, result.comment, removeFromDictionary); this.#removeRedaction(redaction, result.comment, removeFromDictionary);
} }
}); }
} }
recategorizeImages(annotations: AnnotationWrapper[]) { recategorizeImages(annotations: AnnotationWrapper[]) {

View File

@ -11,8 +11,6 @@ import { ResizeAnnotationDialogComponent } from '../dialogs/resize-annotation-di
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'; import { FalsePositiveDialogComponent } from '../dialogs/false-positive-dialog/false-positive-dialog.component';
import { RedactTextDialogComponent } from '../dialogs/redact-text-dialog/redact-text-dialog.component';
import { RemoveRedactionDialogComponent } from '../dialogs/remove-redaction-dialog/remove-redaction-dialog.component';
type DialogType = type DialogType =
| 'confirm' | 'confirm'
@ -25,9 +23,7 @@ type DialogType =
| 'forceAnnotation' | 'forceAnnotation'
| 'manualAnnotation' | 'manualAnnotation'
| 'highlightAction' | 'highlightAction'
| 'falsePositive' | 'falsePositive';
| 'redactText'
| 'removeRedaction';
@Injectable() @Injectable()
export class FilePreviewDialogService extends DialogService<DialogType> { export class FilePreviewDialogService extends DialogService<DialogType> {
@ -69,12 +65,6 @@ export class FilePreviewDialogService extends DialogService<DialogType> {
falsePositive: { falsePositive: {
component: FalsePositiveDialogComponent, component: FalsePositiveDialogComponent,
}, },
redactText: {
component: RedactTextDialogComponent,
},
removeRedaction: {
component: RemoveRedactionDialogComponent,
},
}; };
constructor(protected readonly _dialog: MatDialog) { constructor(protected readonly _dialog: MatDialog) {

View File

@ -62,14 +62,14 @@ export class PdfAnnotationActionsService {
availableActions.push(recategorizeButton); availableActions.push(recategorizeButton);
} }
if (permissions.canRemoveOrSuggestToRemoveFromDictionary) { // if (permissions.canRemoveOrSuggestToRemoveFromDictionary) {
const removeFromDictButton = this.#getButton( // const removeFromDictButton = this.#getButton(
'remove-from-dict', // 'remove-from-dict',
_('annotation-actions.remove-annotation.remove-from-dict'), // _('annotation-actions.remove-annotation.remove-from-dict'),
() => this.#annotationActionsService.removeOrSuggestRemoveAnnotation(annotations, true), // () => this.#annotationActionsService.removeOrSuggestRemoveAnnotation(annotations, true),
); // );
availableActions.push(removeFromDictButton); // availableActions.push(removeFromDictButton);
} // }
if (permissions.canAcceptRecommendation) { if (permissions.canAcceptRecommendation) {
const acceptRecommendationButton = this.#getButton('check', _('annotation-actions.accept-recommendation.label'), () => const acceptRecommendationButton = this.#getButton('check', _('annotation-actions.accept-recommendation.label'), () =>
@ -92,12 +92,12 @@ export class PdfAnnotationActionsService {
availableActions.push(undoButton); availableActions.push(undoButton);
} }
if (permissions.canMarkAsFalsePositive) { // if (permissions.canMarkAsFalsePositive) {
const markAsFalsePositiveButton = this.#getButton('thumb-down', _('annotation-actions.remove-annotation.false-positive'), () => // const markAsFalsePositiveButton = this.#getButton('thumb-down', _('annotation-actions.remove-annotation.false-positive'), () =>
this.#annotationActionsService.markAsFalsePositive(annotations), // this.#annotationActionsService.markAsFalsePositive(annotations),
); // );
availableActions.push(markAsFalsePositiveButton); // availableActions.push(markAsFalsePositiveButton);
} // }
if (permissions.canForceRedaction) { if (permissions.canForceRedaction) {
const forceRedactionButton = this.#getButton('thumb-up', _('annotation-actions.force-redaction.label'), () => const forceRedactionButton = this.#getButton('thumb-up', _('annotation-actions.force-redaction.label'), () =>
@ -120,18 +120,18 @@ export class PdfAnnotationActionsService {
availableActions.push(rejectSuggestionButton); availableActions.push(rejectSuggestionButton);
} }
if (permissions.canRemoveOrSuggestToRemoveOnlyHere) { // if (permissions.canRemoveOrSuggestToRemoveOnlyHere) {
const removeOrSuggestToRemoveOnlyHereButton = this.#getButton( // const removeOrSuggestToRemoveOnlyHereButton = this.#getButton(
'trash', // 'trash',
_('annotation-actions.remove-annotation.only-here'), // _('annotation-actions.remove-annotation.only-here'),
() => this.#annotationActionsService.removeOrSuggestRemoveAnnotation(annotations, false), // () => this.#annotationActionsService.removeOrSuggestRemoveAnnotation(annotations, false),
); // );
availableActions.push(removeOrSuggestToRemoveOnlyHereButton); // availableActions.push(removeOrSuggestToRemoveOnlyHereButton);
} // }
if (permissions.canRemoveOrSuggestToRemoveOnlyHere) { if (permissions.canRemoveOrSuggestToRemoveRedaction) {
const removeOrSuggestToRemoveButton = this.#getButton('trash', _('annotation-actions.remove-annotation.remove-redaction'), () => const removeOrSuggestToRemoveButton = this.#getButton('trash', _('annotation-actions.remove-annotation.remove-redaction'), () =>
this.#annotationActionsService.removeOrSuggestRemoveRedaction(annotations[0]), this.#annotationActionsService.removeOrSuggestRemoveRedaction(annotations[0], permissions),
); );
availableActions.push(removeOrSuggestToRemoveButton); availableActions.push(removeOrSuggestToRemoveButton);
} }
@ -171,6 +171,7 @@ export class PdfAnnotationActionsService {
canForceHint: permissions.reduce((acc, next) => acc && next.canForceHint, true), canForceHint: permissions.reduce((acc, next) => acc && next.canForceHint, true),
canRejectSuggestion: permissions.reduce((acc, next) => acc && next.canRejectSuggestion, true), canRejectSuggestion: permissions.reduce((acc, next) => acc && next.canRejectSuggestion, true),
canRemoveOrSuggestToRemoveOnlyHere: permissions.reduce((acc, next) => acc && next.canRemoveOrSuggestToRemoveOnlyHere, true), canRemoveOrSuggestToRemoveOnlyHere: permissions.reduce((acc, next) => acc && next.canRemoveOrSuggestToRemoveOnlyHere, true),
canRemoveOrSuggestToRemoveRedaction: permissions.reduce((acc, next) => acc && next.canRemoveOrSuggestToRemoveRedaction, true),
}; };
} }
} }

View File

@ -172,23 +172,23 @@ export class PdfProxyService {
onClick: () => this._ngZone.run(() => this._redactText(ManualRedactionEntryTypes.HINT)), onClick: () => this._ngZone.run(() => this._redactText(ManualRedactionEntryTypes.HINT)),
}); });
popups.push({ // popups.push({
type: 'actionButton', // type: 'actionButton',
dataElement: TextPopups.ADD_REDACTION, // dataElement: TextPopups.ADD_REDACTION,
img: this.#addRedactionIcon, // img: this.#addRedactionIcon,
title: this.#getTitle(ManualRedactionEntryTypes.REDACTION), // title: this.#getTitle(ManualRedactionEntryTypes.REDACTION),
onClick: () => this._ngZone.run(() => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION)), // onClick: () => this._ngZone.run(() => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION)),
}); // });
//
if (!this._iqserPermissionsService.has(Roles.getRss)) { // if (!this._iqserPermissionsService.has(Roles.getRss)) {
popups.push({ // popups.push({
type: 'actionButton', // type: 'actionButton',
dataElement: TextPopups.ADD_DICTIONARY, // dataElement: TextPopups.ADD_DICTIONARY,
img: this.#addDictIcon, // img: this.#addDictIcon,
title: this.#getTitle(ManualRedactionEntryTypes.DICTIONARY), // title: this.#getTitle(ManualRedactionEntryTypes.DICTIONARY),
onClick: () => this._ngZone.run(() => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY)), // onClick: () => this._ngZone.run(() => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY)),
}); // });
} // }
} }
} }

View File

@ -150,7 +150,7 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
this._dictionariesMapService.get(dossierTemplateId).forEach((d: Dictionary) => { this._dictionariesMapService.get(dossierTemplateId).forEach((d: Dictionary) => {
if (!hintTypes) { if (!hintTypes) {
if (!d.virtual && !d.hint && !d.systemManaged) { if (!d.hint) {
possibleDictionaries.push(d); possibleDictionaries.push(d);
} }
} else if (d.hint) { } else if (d.hint) {

View File

@ -1,7 +1,7 @@
{ {
"ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null, "ADMIN_CONTACT_URL": null,
"API_URL": "https://dev-08.iqser.cloud/redaction-gateway-v1", "API_URL": "https://dev-04.iqser.cloud/redaction-gateway-v1",
"APP_NAME": "RedactManager", "APP_NAME": "RedactManager",
"AUTO_READ_TIME": 3, "AUTO_READ_TIME": 3,
"BACKEND_APP_VERSION": "4.4.40", "BACKEND_APP_VERSION": "4.4.40",
@ -11,7 +11,7 @@
"MAX_RETRIES_ON_SERVER_ERROR": 3, "MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction", "OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null, "OAUTH_IDP_HINT": null,
"OAUTH_URL": "https://dev-08.iqser.cloud/auth", "OAUTH_URL": "https://dev-04.iqser.cloud/auth",
"RECENT_PERIOD_IN_HOURS": 24, "RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural", "SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",

@ -1 +1 @@
Subproject commit afd750015e73c1fc35a76ed21a9a42432cf15277 Subproject commit 6b45d4aa70554b5f41e59d689094d6dad8291c8e