From b7d926046d3a5a62f14fbb06b43b2e1ba39987fb Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Wed, 6 Jul 2022 13:53:43 +0300 Subject: [PATCH] RED-3791: use existing convert recommendation to annotation action --- .../file-preview/file-preview-providers.ts | 2 + .../services/annotation-actions.service.ts | 286 ++---------------- .../services/manual-redaction.service.ts | 2 +- .../pdf-annotation-actions.service.ts | 168 ++++++++++ .../services/pdf-proxy.service.ts | 6 +- 5 files changed, 205 insertions(+), 259 deletions(-) create mode 100644 apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts index 3222fc1af..0c09a41c3 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-providers.ts @@ -14,6 +14,7 @@ import { FileDataService } from './services/file-data.service'; import { AnnotationsListingService } from './services/annotations-listing.service'; import { StampService } from './services/stamp.service'; import { PdfProxyService } from './services/pdf-proxy.service'; +import { PdfAnnotationActionsService } from './services/pdf-annotation-actions.service'; export const filePreviewScreenProviders = [ FilterService, @@ -24,6 +25,7 @@ export const filePreviewScreenProviders = [ CommentingService, SkippedService, AnnotationActionsService, + PdfAnnotationActionsService, FilePreviewStateService, AnnotationReferencesService, AnnotationProcessingService, diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts index 6ddc64e5d..c9b2ea501 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts @@ -1,19 +1,13 @@ -import { Inject, Injectable, NgZone } from '@angular/core'; -import { PermissionsService } from '@services/permissions.service'; +import { Injectable } from '@angular/core'; import { ManualRedactionService } from './manual-redaction.service'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Observable } from 'rxjs'; -import { TranslateService } from '@ngx-translate/core'; 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 { DictionaryEntryTypes, Dossier, IAddRedactionRequest, - IHeaderElement, ILegalBasisChangeRequest, IRecategorizationRequest, IRectangle, @@ -33,23 +27,16 @@ import { filter } from 'rxjs/operators'; import { MatDialog } from '@angular/material/dialog'; import { FilePreviewStateService } from './file-preview-state.service'; import { FilePreviewDialogService } from './file-preview-dialog.service'; -import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { FileDataService } from './file-data.service'; import { PdfViewer } from '../../pdf-viewer/services/pdf-viewer.service'; import { REDAnnotationManager } from '../../pdf-viewer/services/annotation-manager.service'; import { SkippedService } from './skipped.service'; import { REDDocumentViewer } from '../../pdf-viewer/services/document-viewer.service'; -import { AnnotationsListingService } from './annotations-listing.service'; @Injectable() export class AnnotationActionsService { 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 _translateService: TranslateService, private readonly _dialogService: FilePreviewDialogService, private readonly _dialog: MatDialog, private readonly _pdf: PdfViewer, @@ -57,11 +44,9 @@ export class AnnotationActionsService { private readonly _annotationManager: REDAnnotationManager, private readonly _annotationDrawService: AnnotationDrawService, private readonly _activeDossiersService: ActiveDossiersService, - private readonly _dictionariesMapService: DictionariesMapService, private readonly _state: FilePreviewStateService, private readonly _fileDataService: FileDataService, private readonly _skippedService: SkippedService, - private readonly _listingService: AnnotationsListingService, ) {} private get _dossier(): Dossier { @@ -71,29 +56,25 @@ export class AnnotationActionsService { acceptSuggestion($event: MouseEvent, annotations: AnnotationWrapper[]) { $event?.stopPropagation(); const { dossierId, fileId } = this._state; - this._processObsAndEmit( - this._manualRedactionService.approve( - annotations.map(a => a.id), - dossierId, - fileId, - ), - ); + const ids = annotations.map(a => a.id); + const request = this._manualRedactionService.approve(ids, dossierId, fileId); + this.#processObsAndEmit(request); } removeHighlights(highlights: AnnotationWrapper[]): void { - const data = this._getHighlightOperationData(TextHighlightOperation.REMOVE, highlights); + const data = this.#getHighlightOperationData(TextHighlightOperation.REMOVE, highlights); this._dialogService.openDialog('highlightAction', null, data); } convertHighlights(highlights: AnnotationWrapper[]): void { - const data = this._getHighlightOperationData(TextHighlightOperation.CONVERT, highlights); + const data = this.#getHighlightOperationData(TextHighlightOperation.CONVERT, highlights); this._dialogService.openDialog('highlightAction', null, data); } rejectSuggestion($event: MouseEvent, annotations: AnnotationWrapper[]) { $event?.stopPropagation(); const { dossierId, fileId } = this._state; - this._processObsAndEmit( + this.#processObsAndEmit( this._manualRedactionService.declineOrRemove( annotations.map(a => a.id), dossierId, @@ -107,7 +88,7 @@ export class AnnotationActionsService { const { dossierId, fileId } = this._state; const data = { dossier: this._dossier, annotations, hint }; this._dialogService.openDialog('forceAnnotation', $event, data, (request: ILegalBasisChangeRequest) => { - this._processObsAndEmit( + this.#processObsAndEmit( this._manualRedactionService.bulkForce( annotations.map(a => ({ ...request, annotationId: a.id })), dossierId, @@ -132,7 +113,7 @@ export class AnnotationActionsService { 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, 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, 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 modifyDictionary = annotations[0].isModifyDictionary; - this._processObsAndEmit( + this.#processObsAndEmit( this._manualRedactionService.undoRequest( annotations.map(a => a.id), dossierId, @@ -194,205 +175,10 @@ export class AnnotationActionsService { const dialogClosed = dialogRef.afterClosed().pipe(filter(value => !!value && !!value.annotations)); dialogClosed.subscribe(({ annotations, comment: commentText }) => { 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) { $event?.stopPropagation(); @@ -415,10 +201,19 @@ export class AnnotationActionsService { } async acceptResize($event: MouseEvent, annotation: AnnotationWrapper): Promise { - 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 data = { annotation, text }; + this._dialogService.openDialog('resizeAnnotation', $event, data, (result: { comment: string; updateDictionary: boolean }) => { const resizeRequest: IResizeRequest = { annotationId: annotation.id, @@ -428,14 +223,9 @@ export class AnnotationActionsService { updateDictionary: result.updateDictionary, }; - let obs; - if (annotation.isRecommendation) { - obs = this.#convertRecommendationToRedaction(resizeRequest, annotation, fileId); - } else { - obs = this._manualRedactionService.resizeOrSuggestResize([resizeRequest], this._dossier.id, fileId); - } - - this._processObsAndEmit(obs); + const { fileId, dossierId } = this._state; + const request = this._manualRedactionService.resizeOrSuggestResize([resizeRequest], dossierId, fileId); + this.#processObsAndEmit(request); }); } @@ -466,17 +256,7 @@ export class AnnotationActionsService { })); const { dossierId, fileId } = this._state; - 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); + this.#processObsAndEmit(this._manualRedactionService.addAnnotation(requests, dossierId, fileId)); } #generateRectangle(annotationWrapper: AnnotationWrapper) { @@ -504,7 +284,7 @@ export class AnnotationActionsService { return annotation; } - private _getHighlightOperationData(operation: TextHighlightOperation, highlights: AnnotationWrapper[]) { + #getHighlightOperationData(operation: TextHighlightOperation, highlights: AnnotationWrapper[]) { return { dossierId: this._state.dossierId, fileId: this._state.fileId, @@ -516,7 +296,7 @@ export class AnnotationActionsService { }; } - private _processObsAndEmit(obs: Observable) { + #processObsAndEmit(obs: Observable) { obs.subscribe({ next: () => this._fileDataService.annotationsChanged(), error: () => this._fileDataService.annotationsChanged(), @@ -546,11 +326,7 @@ export class AnnotationActionsService { return annotation.value; } - private _convertPath(path: string): string { - return this._baseHref + path; - } - - private async _extractTextAndPositions(annotationId: string) { + async #extractTextAndPositions(annotationId: string) { const viewerAnnotation = this._annotationManager.get(annotationId); const document = await this._documentViewer.PDFDoc; diff --git a/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts b/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts index 033cc3591..d457fba40 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/manual-redaction.service.ts @@ -68,7 +68,7 @@ export class ManualRedactionService extends GenericService { addToDictionary: true, sourceId: annotation.annotationId, value: annotation.value, - reason: annotation.legalBasis, + reason: annotation.legalBasis ?? 'Dictionary Request', positions: annotation.positions, type: annotation.recommendationType, comment, diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts new file mode 100644 index 000000000..def05c947 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-annotation-actions.service.ts @@ -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): 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), + }; + } +} diff --git a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts index 437200340..09cd49b87 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/pdf-proxy.service.ts @@ -8,7 +8,6 @@ import { ManualRedactionEntryWrapper, } from '../../../models/file/manual-redaction-entry.wrapper'; import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service'; -import { AnnotationActionsService } from './annotation-actions.service'; import { UserPreferenceService } from '../../../services/user-preference.service'; import { BASE_HREF_FN, BaseHrefFn } from '../../../tokens'; import { shareDistinctLast } from '@iqser/common-ui'; @@ -28,6 +27,7 @@ import { combineLatest, Observable, Subject } from 'rxjs'; import { ViewModeService } from './view-mode.service'; import { PermissionsService } from '../../../services/permissions.service'; import { AnnotationsListingService } from './annotations-listing.service'; +import { PdfAnnotationActionsService } from './pdf-annotation-actions.service'; import Annotation = Core.Annotations.Annotation; import Quad = Core.Math.Quad; @@ -57,7 +57,7 @@ export class PdfProxyService { private readonly _ngZone: NgZone, private readonly _userPreferenceService: UserPreferenceService, private readonly _annotationDrawService: AnnotationDrawService, - private readonly _annotationActionsService: AnnotationActionsService, + private readonly _pdfAnnotationActionsService: PdfAnnotationActionsService, private readonly _fileDataService: FileDataService, private readonly _viewerHeaderService: ViewerHeaderService, 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); }