RED-3791: use existing convert recommendation to annotation action

This commit is contained in:
Dan Percic 2022-07-06 13:53:43 +03:00
parent f4b9595725
commit b7d926046d
5 changed files with 205 additions and 259 deletions

View File

@ -14,6 +14,7 @@ import { FileDataService } from './services/file-data.service';
import { AnnotationsListingService } from './services/annotations-listing.service'; import { AnnotationsListingService } from './services/annotations-listing.service';
import { StampService } from './services/stamp.service'; import { StampService } from './services/stamp.service';
import { PdfProxyService } from './services/pdf-proxy.service'; import { PdfProxyService } from './services/pdf-proxy.service';
import { PdfAnnotationActionsService } from './services/pdf-annotation-actions.service';
export const filePreviewScreenProviders = [ export const filePreviewScreenProviders = [
FilterService, FilterService,
@ -24,6 +25,7 @@ export const filePreviewScreenProviders = [
CommentingService, CommentingService,
SkippedService, SkippedService,
AnnotationActionsService, AnnotationActionsService,
PdfAnnotationActionsService,
FilePreviewStateService, FilePreviewStateService,
AnnotationReferencesService, AnnotationReferencesService,
AnnotationProcessingService, AnnotationProcessingService,

View File

@ -1,19 +1,13 @@
import { Inject, Injectable, NgZone } from '@angular/core'; import { Injectable } from '@angular/core';
import { PermissionsService } from '@services/permissions.service';
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 { Observable } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { getFirstRelevantTextPart } from '../../../utils'; import { getFirstRelevantTextPart } from '../../../utils';
import { AnnotationPermissions } from '@models/file/annotation.permissions';
import { BASE_HREF } from '../../../tokens';
import { UserService } from '@services/user.service';
import { Core } from '@pdftron/webviewer'; import { Core } from '@pdftron/webviewer';
import { import {
DictionaryEntryTypes, DictionaryEntryTypes,
Dossier, Dossier,
IAddRedactionRequest, IAddRedactionRequest,
IHeaderElement,
ILegalBasisChangeRequest, ILegalBasisChangeRequest,
IRecategorizationRequest, IRecategorizationRequest,
IRectangle, IRectangle,
@ -33,23 +27,16 @@ 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';
import { FilePreviewDialogService } from './file-preview-dialog.service'; import { FilePreviewDialogService } from './file-preview-dialog.service';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { FileDataService } from './file-data.service'; import { FileDataService } from './file-data.service';
import { PdfViewer } from '../../pdf-viewer/services/pdf-viewer.service'; 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 { AnnotationsListingService } from './annotations-listing.service';
@Injectable() @Injectable()
export class AnnotationActionsService { export class AnnotationActionsService {
constructor( constructor(
@Inject(BASE_HREF) private readonly _baseHref: string,
private readonly _ngZone: NgZone,
private readonly _userService: UserService,
private readonly _permissionsService: PermissionsService,
private readonly _manualRedactionService: ManualRedactionService, private readonly _manualRedactionService: ManualRedactionService,
private readonly _translateService: TranslateService,
private readonly _dialogService: FilePreviewDialogService, private readonly _dialogService: FilePreviewDialogService,
private readonly _dialog: MatDialog, private readonly _dialog: MatDialog,
private readonly _pdf: PdfViewer, private readonly _pdf: PdfViewer,
@ -57,11 +44,9 @@ export class AnnotationActionsService {
private readonly _annotationManager: REDAnnotationManager, private readonly _annotationManager: REDAnnotationManager,
private readonly _annotationDrawService: AnnotationDrawService, private readonly _annotationDrawService: AnnotationDrawService,
private readonly _activeDossiersService: ActiveDossiersService, private readonly _activeDossiersService: ActiveDossiersService,
private readonly _dictionariesMapService: DictionariesMapService,
private readonly _state: FilePreviewStateService, private readonly _state: FilePreviewStateService,
private readonly _fileDataService: FileDataService, private readonly _fileDataService: FileDataService,
private readonly _skippedService: SkippedService, private readonly _skippedService: SkippedService,
private readonly _listingService: AnnotationsListingService,
) {} ) {}
private get _dossier(): Dossier { private get _dossier(): Dossier {
@ -71,29 +56,25 @@ export class AnnotationActionsService {
acceptSuggestion($event: MouseEvent, annotations: AnnotationWrapper[]) { acceptSuggestion($event: MouseEvent, annotations: AnnotationWrapper[]) {
$event?.stopPropagation(); $event?.stopPropagation();
const { dossierId, fileId } = this._state; const { dossierId, fileId } = this._state;
this._processObsAndEmit( const ids = annotations.map(a => a.id);
this._manualRedactionService.approve( const request = this._manualRedactionService.approve(ids, dossierId, fileId);
annotations.map(a => a.id), this.#processObsAndEmit(request);
dossierId,
fileId,
),
);
} }
removeHighlights(highlights: AnnotationWrapper[]): void { removeHighlights(highlights: AnnotationWrapper[]): void {
const data = this._getHighlightOperationData(TextHighlightOperation.REMOVE, highlights); const data = this.#getHighlightOperationData(TextHighlightOperation.REMOVE, highlights);
this._dialogService.openDialog('highlightAction', null, data); this._dialogService.openDialog('highlightAction', null, data);
} }
convertHighlights(highlights: AnnotationWrapper[]): void { convertHighlights(highlights: AnnotationWrapper[]): void {
const data = this._getHighlightOperationData(TextHighlightOperation.CONVERT, highlights); const data = this.#getHighlightOperationData(TextHighlightOperation.CONVERT, highlights);
this._dialogService.openDialog('highlightAction', null, data); this._dialogService.openDialog('highlightAction', null, data);
} }
rejectSuggestion($event: MouseEvent, annotations: AnnotationWrapper[]) { rejectSuggestion($event: MouseEvent, annotations: AnnotationWrapper[]) {
$event?.stopPropagation(); $event?.stopPropagation();
const { dossierId, fileId } = this._state; const { dossierId, fileId } = this._state;
this._processObsAndEmit( this.#processObsAndEmit(
this._manualRedactionService.declineOrRemove( this._manualRedactionService.declineOrRemove(
annotations.map(a => a.id), annotations.map(a => a.id),
dossierId, dossierId,
@ -107,7 +88,7 @@ export class AnnotationActionsService {
const { dossierId, fileId } = this._state; const { dossierId, fileId } = this._state;
const data = { dossier: this._dossier, annotations, hint }; const data = { dossier: this._dossier, annotations, hint };
this._dialogService.openDialog('forceAnnotation', $event, data, (request: ILegalBasisChangeRequest) => { this._dialogService.openDialog('forceAnnotation', $event, data, (request: ILegalBasisChangeRequest) => {
this._processObsAndEmit( this.#processObsAndEmit(
this._manualRedactionService.bulkForce( this._manualRedactionService.bulkForce(
annotations.map(a => ({ ...request, annotationId: a.id })), annotations.map(a => ({ ...request, annotationId: a.id })),
dossierId, dossierId,
@ -132,7 +113,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));
}, },
); );
} }
@ -151,7 +132,7 @@ export class AnnotationActionsService {
removeFromDictionary, removeFromDictionary,
comment: result.comment, comment: result.comment,
})); }));
this._processObsAndEmit(this._manualRedactionService.removeOrSuggestRemove(body, dossierId, fileId, removeFromDictionary)); this.#processObsAndEmit(this._manualRedactionService.removeOrSuggestRemove(body, dossierId, fileId, removeFromDictionary));
}); });
} }
@ -164,7 +145,7 @@ export class AnnotationActionsService {
type, type,
comment, comment,
})); }));
this._processObsAndEmit(this._manualRedactionService.recategorizeImage(body, dossierId, fileId)); this.#processObsAndEmit(this._manualRedactionService.recategorizeImage(body, dossierId, fileId));
}); });
} }
@ -173,7 +154,7 @@ export class AnnotationActionsService {
const { dossierId, fileId } = this._state; const { dossierId, fileId } = this._state;
const modifyDictionary = annotations[0].isModifyDictionary; const modifyDictionary = annotations[0].isModifyDictionary;
this._processObsAndEmit( this.#processObsAndEmit(
this._manualRedactionService.undoRequest( this._manualRedactionService.undoRequest(
annotations.map(a => a.id), annotations.map(a => a.id),
dossierId, dossierId,
@ -194,205 +175,10 @@ export class AnnotationActionsService {
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 }) => { dialogClosed.subscribe(({ annotations, comment: commentText }) => {
const comment = commentText ? { text: commentText } : undefined; const comment = commentText ? { text: commentText } : undefined;
this._processObsAndEmit(this._manualRedactionService.addRecommendation(annotations, dossierId, fileId, comment)); this.#processObsAndEmit(this._manualRedactionService.addRecommendation(annotations, dossierId, fileId, comment));
}); });
} }
getViewerAvailableActions(annotations: AnnotationWrapper[]): IHeaderElement[] {
const dossier = this._state.dossier;
const availableActions: IHeaderElement[] = [];
const annotationPermissions = annotations.map(annotation => ({
annotation,
permissions: AnnotationPermissions.forUser(
this._permissionsService.isApprover(dossier),
this._userService.currentUser,
annotation,
this._dictionariesMapService.get(dossier.dossierTemplateId),
),
}));
// you can only resize one annotation at a time
const canResize = annotationPermissions.length === 1 && annotationPermissions[0].permissions.canResizeAnnotation;
if (canResize) {
const firstAnnotation = annotations[0];
// if we already entered resize-mode previously
if (firstAnnotation.resizing) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/check.svg'),
title: this._translateService.instant('annotation-actions.resize-accept.label'),
onClick: () =>
this._ngZone.run(async () => {
await this.acceptResize(null, firstAnnotation);
}),
});
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/close.svg'),
title: this._translateService.instant('annotation-actions.resize-cancel.label'),
onClick: () => this._ngZone.run(() => this.cancelResize(null, firstAnnotation)),
});
return availableActions;
}
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/resize.svg'),
title: this._translateService.instant('annotation-actions.resize.label'),
onClick: () => this._ngZone.run(() => this.resize(null, annotations[0])),
});
}
const canChangeLegalBasis = annotationPermissions.reduce((acc, next) => acc && next.permissions.canChangeLegalBasis, true);
if (canChangeLegalBasis) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/edit.svg'),
title: this._translateService.instant('annotation-actions.edit-reason.label'),
onClick: () =>
this._ngZone.run(() => {
this.changeLegalBasis(null, annotations);
}),
});
}
const canRecategorizeImage = annotationPermissions.reduce((acc, next) => acc && next.permissions.canRecategorizeImage, true);
if (canRecategorizeImage) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-down.svg'),
title: this._translateService.instant('annotation-actions.recategorize-image'),
onClick: () =>
this._ngZone.run(() => {
this.recategorizeImages(null, annotations);
}),
});
}
const canRemoveOrSuggestToRemoveFromDictionary = annotationPermissions.reduce(
(acc, next) => acc && next.permissions.canRemoveOrSuggestToRemoveFromDictionary,
true,
);
if (canRemoveOrSuggestToRemoveFromDictionary) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/remove-from-dict.svg'),
title: this._translateService.instant('annotation-actions.remove-annotation.remove-from-dict'),
onClick: () =>
this._ngZone.run(() => {
this.removeOrSuggestRemoveAnnotation(null, annotations, true);
}),
});
}
const canAcceptRecommendation = annotationPermissions.reduce((acc, next) => acc && next.permissions.canAcceptRecommendation, true);
if (canAcceptRecommendation) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/check.svg'),
title: this._translateService.instant('annotation-actions.accept-recommendation.label'),
onClick: () =>
this._ngZone.run(() => {
this.convertRecommendationToAnnotation(null, annotations);
}),
});
}
const canAcceptSuggestion = annotationPermissions.reduce((acc, next) => acc && next.permissions.canAcceptSuggestion, true);
if (canAcceptSuggestion) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/check.svg'),
title: this._translateService.instant('annotation-actions.accept-suggestion.label'),
onClick: () =>
this._ngZone.run(() => {
this.acceptSuggestion(null, annotations);
}),
});
}
const canUndo = annotationPermissions.reduce((acc, next) => acc && next.permissions.canUndo, true);
if (canUndo) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/undo.svg'),
title: this._translateService.instant('annotation-actions.undo'),
onClick: () =>
this._ngZone.run(() => {
this.undoDirectAction(null, annotations);
}),
});
}
const canMarkAsFalsePositive = annotationPermissions.reduce((acc, next) => acc && next.permissions.canMarkAsFalsePositive, true);
if (canMarkAsFalsePositive) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-down.svg'),
title: this._translateService.instant('annotation-actions.remove-annotation.false-positive'),
onClick: () =>
this._ngZone.run(() => {
this.markAsFalsePositive(null, annotations);
}),
});
}
const canForceRedaction = annotationPermissions.reduce((acc, next) => acc && next.permissions.canForceRedaction, true);
if (canForceRedaction) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-up.svg'),
title: this._translateService.instant('annotation-actions.force-redaction.label'),
onClick: () =>
this._ngZone.run(() => {
this.forceAnnotation(null, annotations);
}),
});
}
const canForceHint = annotationPermissions.reduce((acc, next) => acc && next.permissions.canForceHint, true);
if (canForceHint) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/thumb-up.svg'),
title: this._translateService.instant('annotation-actions.force-hint.label'),
onClick: () =>
this._ngZone.run(() => {
this.forceAnnotation(null, annotations, true);
}),
});
}
const canRejectSuggestion = annotationPermissions.reduce((acc, next) => acc && next.permissions.canRejectSuggestion, true);
if (canRejectSuggestion) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/close.svg'),
title: this._translateService.instant('annotation-actions.reject-suggestion'),
onClick: () => this._ngZone.run(() => this.rejectSuggestion(null, annotations)),
});
}
const canRemoveOrSuggestToRemoveOnlyHere = annotationPermissions.reduce(
(acc, next) => acc && next.permissions.canRemoveOrSuggestToRemoveOnlyHere,
true,
);
if (canRemoveOrSuggestToRemoveOnlyHere) {
availableActions.push({
type: 'actionButton',
img: this._convertPath('/assets/icons/general/trash.svg'),
title: this._translateService.instant('annotation-actions.remove-annotation.only-here'),
onClick: () =>
this._ngZone.run(() => {
this.removeOrSuggestRemoveAnnotation(null, annotations, false);
}),
});
}
return availableActions;
}
async resize($event: MouseEvent, annotationWrapper: AnnotationWrapper) { async resize($event: MouseEvent, annotationWrapper: AnnotationWrapper) {
$event?.stopPropagation(); $event?.stopPropagation();
@ -415,10 +201,19 @@ export class AnnotationActionsService {
} }
async acceptResize($event: MouseEvent, annotation: AnnotationWrapper): Promise<void> { async acceptResize($event: MouseEvent, annotation: AnnotationWrapper): Promise<void> {
const fileId = this._state.fileId; const textAndPositions = await this.#extractTextAndPositions(annotation.id);
const textAndPositions = await this._extractTextAndPositions(annotation.id); if (annotation.isRecommendation) {
const recommendation = {
...annotation,
value: textAndPositions.text,
positions: textAndPositions.positions,
} as AnnotationWrapper;
return this.convertRecommendationToAnnotation($event, [recommendation]);
}
const text = annotation.rectangle ? annotation.value : annotation.isImage ? 'Image' : textAndPositions.text; const text = annotation.rectangle ? annotation.value : annotation.isImage ? 'Image' : textAndPositions.text;
const data = { annotation, text }; const data = { annotation, text };
this._dialogService.openDialog('resizeAnnotation', $event, data, (result: { comment: string; updateDictionary: boolean }) => { this._dialogService.openDialog('resizeAnnotation', $event, data, (result: { comment: string; updateDictionary: boolean }) => {
const resizeRequest: IResizeRequest = { const resizeRequest: IResizeRequest = {
annotationId: annotation.id, annotationId: annotation.id,
@ -428,14 +223,9 @@ export class AnnotationActionsService {
updateDictionary: result.updateDictionary, updateDictionary: result.updateDictionary,
}; };
let obs; const { fileId, dossierId } = this._state;
if (annotation.isRecommendation) { const request = this._manualRedactionService.resizeOrSuggestResize([resizeRequest], dossierId, fileId);
obs = this.#convertRecommendationToRedaction(resizeRequest, annotation, fileId); this.#processObsAndEmit(request);
} else {
obs = this._manualRedactionService.resizeOrSuggestResize([resizeRequest], this._dossier.id, fileId);
}
this._processObsAndEmit(obs);
}); });
} }
@ -466,17 +256,7 @@ export class AnnotationActionsService {
})); }));
const { dossierId, fileId } = this._state; const { dossierId, fileId } = this._state;
this._processObsAndEmit(this._manualRedactionService.addAnnotation(requests, dossierId, fileId)); this.#processObsAndEmit(this._manualRedactionService.addAnnotation(requests, dossierId, fileId));
}
#convertRecommendationToRedaction(resizeRequest: IResizeRequest, annotation: AnnotationWrapper, fileId: string) {
const addRequest: IAddRedactionRequest = {
...resizeRequest,
comment: resizeRequest.comment ? { text: resizeRequest.comment } : null,
reason: 'Dictionary Request',
type: annotation.type,
};
return this._manualRedactionService.add([addRequest], this._dossier.id, fileId);
} }
#generateRectangle(annotationWrapper: AnnotationWrapper) { #generateRectangle(annotationWrapper: AnnotationWrapper) {
@ -504,7 +284,7 @@ export class AnnotationActionsService {
return annotation; return annotation;
} }
private _getHighlightOperationData(operation: TextHighlightOperation, highlights: AnnotationWrapper[]) { #getHighlightOperationData(operation: TextHighlightOperation, highlights: AnnotationWrapper[]) {
return { return {
dossierId: this._state.dossierId, dossierId: this._state.dossierId,
fileId: this._state.fileId, fileId: this._state.fileId,
@ -516,7 +296,7 @@ export class AnnotationActionsService {
}; };
} }
private _processObsAndEmit(obs: Observable<unknown>) { #processObsAndEmit(obs: Observable<unknown>) {
obs.subscribe({ obs.subscribe({
next: () => this._fileDataService.annotationsChanged(), next: () => this._fileDataService.annotationsChanged(),
error: () => this._fileDataService.annotationsChanged(), error: () => this._fileDataService.annotationsChanged(),
@ -546,11 +326,7 @@ export class AnnotationActionsService {
return annotation.value; return annotation.value;
} }
private _convertPath(path: string): string { async #extractTextAndPositions(annotationId: string) {
return this._baseHref + path;
}
private async _extractTextAndPositions(annotationId: string) {
const viewerAnnotation = this._annotationManager.get(annotationId); const viewerAnnotation = this._annotationManager.get(annotationId);
const document = await this._documentViewer.PDFDoc; const document = await this._documentViewer.PDFDoc;

View File

@ -68,7 +68,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
addToDictionary: true, addToDictionary: true,
sourceId: annotation.annotationId, sourceId: annotation.annotationId,
value: annotation.value, value: annotation.value,
reason: annotation.legalBasis, reason: annotation.legalBasis ?? 'Dictionary Request',
positions: annotation.positions, positions: annotation.positions,
type: annotation.recommendationType, type: annotation.recommendationType,
comment, comment,

View File

@ -0,0 +1,168 @@
import { inject, Injectable, NgZone } from '@angular/core';
import { AnnotationWrapper } from '../../../models/file/annotation.wrapper';
import { AnnotationPermissions } from '../../../models/file/annotation.permissions';
import { PermissionsService } from '../../../services/permissions.service';
import { UserService } from '../../../services/user.service';
import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.service';
import { FilePreviewStateService } from './file-preview-state.service';
import { TranslateService } from '@ngx-translate/core';
import { AnnotationActionsService } from './annotation-actions.service';
import { BASE_HREF_FN } from '../../../tokens';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { IHeaderElement } from '@red/domain';
@Injectable()
export class PdfAnnotationActionsService {
readonly #permissionsService = inject(PermissionsService);
readonly #currentUser = inject(UserService).currentUser;
readonly #dictionariesMapService = inject(DictionariesMapService);
readonly #state = inject(FilePreviewStateService);
readonly #translateService = inject(TranslateService);
readonly #ngZone = inject(NgZone);
readonly #convertPath = inject(BASE_HREF_FN);
readonly #annotationActionsService = inject(AnnotationActionsService);
get(annotations: AnnotationWrapper[]): IHeaderElement[] {
const availableActions: IHeaderElement[] = [];
const permissions = this.#getAnnotationsPermissions(annotations);
// you can only resize one annotation at a time
if (permissions.canResize) {
const firstAnnotation = annotations[0];
// if we already entered resize-mode previously
if (firstAnnotation.resizing) {
const acceptResizeButton = this.#getButton('check', _('annotation-actions.resize-accept.label'), () =>
this.#annotationActionsService.acceptResize(null, firstAnnotation),
);
const cancelResizeButton = this.#getButton('close', _('annotation-actions.resize-cancel.label'), () =>
this.#annotationActionsService.cancelResize(null, firstAnnotation),
);
return [acceptResizeButton, cancelResizeButton];
}
const resizeButton = this.#getButton('resize', _('annotation-actions.resize.label'), () =>
this.#annotationActionsService.resize(null, firstAnnotation),
);
availableActions.push(resizeButton);
}
if (permissions.canChangeLegalBasis) {
const editButton = this.#getButton('edit', _('annotation-actions.edit-reason.label'), () =>
this.#annotationActionsService.changeLegalBasis(null, annotations),
);
availableActions.push(editButton);
}
if (permissions.canRecategorizeImage) {
const recategorizeButton = this.#getButton('thumb-down', _('annotation-actions.recategorize-image'), () =>
this.#annotationActionsService.recategorizeImages(null, annotations),
);
availableActions.push(recategorizeButton);
}
if (permissions.canRemoveOrSuggestToRemoveFromDictionary) {
const removeFromDictButton = this.#getButton(
'remove-from-dict',
_('annotation-actions.remove-annotation.remove-from-dict'),
() => this.#annotationActionsService.removeOrSuggestRemoveAnnotation(null, annotations, true),
);
availableActions.push(removeFromDictButton);
}
if (permissions.canAcceptRecommendation) {
const acceptRecommendationButton = this.#getButton('check', _('annotation-actions.accept-recommendation.label'), () =>
this.#annotationActionsService.convertRecommendationToAnnotation(null, annotations),
);
availableActions.push(acceptRecommendationButton);
}
if (permissions.canAcceptSuggestion) {
const acceptSuggestionButton = this.#getButton('check', _('annotation-actions.accept-suggestion.label'), () =>
this.#annotationActionsService.acceptSuggestion(null, annotations),
);
availableActions.push(acceptSuggestionButton);
}
if (permissions.canUndo) {
const undoButton = this.#getButton('undo', _('annotation-actions.undo'), () =>
this.#annotationActionsService.undoDirectAction(null, annotations),
);
availableActions.push(undoButton);
}
if (permissions.canMarkAsFalsePositive) {
const markAsFalsePositiveButton = this.#getButton('thumb-down', _('annotation-actions.remove-annotation.false-positive'), () =>
this.#annotationActionsService.markAsFalsePositive(null, annotations),
);
availableActions.push(markAsFalsePositiveButton);
}
if (permissions.canForceRedaction) {
const forceRedactionButton = this.#getButton('thumb-up', _('annotation-actions.force-redaction.label'), () =>
this.#annotationActionsService.forceAnnotation(null, annotations),
);
availableActions.push(forceRedactionButton);
}
if (permissions.canForceHint) {
const forceHintButton = this.#getButton('thumb-up', _('annotation-actions.force-hint.label'), () =>
this.#annotationActionsService.forceAnnotation(null, annotations, true),
);
availableActions.push(forceHintButton);
}
if (permissions.canRejectSuggestion) {
const rejectSuggestionButton = this.#getButton('close', _('annotation-actions.reject-suggestion'), () =>
this.#annotationActionsService.rejectSuggestion(null, annotations),
);
availableActions.push(rejectSuggestionButton);
}
if (permissions.canRemoveOrSuggestToRemoveOnlyHere) {
const removeOrSuggestToRemoveOnlyHereButton = this.#getButton(
'trash',
_('annotation-actions.remove-annotation.only-here'),
() => this.#annotationActionsService.removeOrSuggestRemoveAnnotation(null, annotations, false),
);
availableActions.push(removeOrSuggestToRemoveOnlyHereButton);
}
return availableActions;
}
#getButton(icon: string, title: string, action: () => void | Promise<void>): IHeaderElement {
return {
type: 'actionButton',
img: this.#convertPath(`/assets/icons/general/${icon}.svg`),
title: this.#translateService.instant(title),
onClick: () => this.#ngZone.run(async () => action()),
};
}
#getAnnotationsPermissions(annotations: AnnotationWrapper[]) {
const dossier = this.#state.dossier;
const isApprover = this.#permissionsService.isApprover(dossier);
const dictionaries = this.#dictionariesMapService.get(dossier.dossierTemplateId);
const permissions = annotations.map(a => AnnotationPermissions.forUser(isApprover, this.#currentUser, a, dictionaries));
return {
canResize: permissions.length === 1 && permissions[0].canResizeAnnotation,
canChangeLegalBasis: permissions.reduce((acc, next) => acc && next.canChangeLegalBasis, true),
canRecategorizeImage: permissions.reduce((acc, next) => acc && next.canRecategorizeImage, true),
canRemoveOrSuggestToRemoveFromDictionary: permissions.reduce(
(acc, next) => acc && next.canRemoveOrSuggestToRemoveFromDictionary,
true,
),
canAcceptRecommendation: permissions.reduce((acc, next) => acc && next.canAcceptRecommendation, true),
canAcceptSuggestion: permissions.reduce((acc, next) => acc && next.canAcceptSuggestion, true),
canUndo: permissions.reduce((acc, next) => acc && next.canUndo, true),
canMarkAsFalsePositive: permissions.reduce((acc, next) => acc && next.canMarkAsFalsePositive, true),
canForceRedaction: permissions.reduce((acc, next) => acc && next.canForceRedaction, true),
canForceHint: permissions.reduce((acc, next) => acc && next.canForceHint, true),
canRejectSuggestion: permissions.reduce((acc, next) => acc && next.canRejectSuggestion, true),
canRemoveOrSuggestToRemoveOnlyHere: permissions.reduce((acc, next) => acc && next.canRemoveOrSuggestToRemoveOnlyHere, true),
};
}
}

View File

@ -8,7 +8,6 @@ import {
ManualRedactionEntryWrapper, ManualRedactionEntryWrapper,
} from '../../../models/file/manual-redaction-entry.wrapper'; } from '../../../models/file/manual-redaction-entry.wrapper';
import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service'; import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service';
import { AnnotationActionsService } from './annotation-actions.service';
import { UserPreferenceService } from '../../../services/user-preference.service'; import { UserPreferenceService } from '../../../services/user-preference.service';
import { BASE_HREF_FN, BaseHrefFn } from '../../../tokens'; import { BASE_HREF_FN, BaseHrefFn } from '../../../tokens';
import { shareDistinctLast } from '@iqser/common-ui'; import { shareDistinctLast } from '@iqser/common-ui';
@ -28,6 +27,7 @@ import { combineLatest, Observable, Subject } from 'rxjs';
import { ViewModeService } from './view-mode.service'; import { ViewModeService } from './view-mode.service';
import { PermissionsService } from '../../../services/permissions.service'; import { PermissionsService } from '../../../services/permissions.service';
import { AnnotationsListingService } from './annotations-listing.service'; import { AnnotationsListingService } from './annotations-listing.service';
import { PdfAnnotationActionsService } from './pdf-annotation-actions.service';
import Annotation = Core.Annotations.Annotation; import Annotation = Core.Annotations.Annotation;
import Quad = Core.Math.Quad; import Quad = Core.Math.Quad;
@ -57,7 +57,7 @@ export class PdfProxyService {
private readonly _ngZone: NgZone, private readonly _ngZone: NgZone,
private readonly _userPreferenceService: UserPreferenceService, private readonly _userPreferenceService: UserPreferenceService,
private readonly _annotationDrawService: AnnotationDrawService, private readonly _annotationDrawService: AnnotationDrawService,
private readonly _annotationActionsService: AnnotationActionsService, private readonly _pdfAnnotationActionsService: PdfAnnotationActionsService,
private readonly _fileDataService: FileDataService, private readonly _fileDataService: FileDataService,
private readonly _viewerHeaderService: ViewerHeaderService, private readonly _viewerHeaderService: ViewerHeaderService,
private readonly _viewModeService: ViewModeService, private readonly _viewModeService: ViewModeService,
@ -191,7 +191,7 @@ export class PdfProxyService {
]); ]);
} }
const actions = this._annotationActionsService.getViewerAvailableActions(annotationWrappers); const actions = this._pdfAnnotationActionsService.get(annotationWrappers);
this.instance.UI.annotationPopup.add(actions); this.instance.UI.annotationPopup.add(actions);
} }