From 378ab3f92627627ccbfde78680c739ff7c5240b0 Mon Sep 17 00:00:00 2001 From: Timo Date: Wed, 14 Jul 2021 17:26:33 +0300 Subject: [PATCH] finished modifications for annotation changed events --- .../app/models/file/annotation.permissions.ts | 101 +++++++++++------- .../annotation-actions.component.html | 85 ++++++++++----- .../annotation-actions.component.ts | 68 ++++++++++-- .../annotation-remove-actions.component.html | 29 ----- .../annotation-remove-actions.component.scss | 7 -- .../annotation-remove-actions.component.ts | 93 ---------------- .../file-workload.component.html | 6 +- .../change-legal-basis-dialog.component.ts | 8 +- .../recategorize-image-dialog.component.ts | 6 +- .../app/modules/dossier/dossiers.module.ts | 2 - .../file-preview-screen.component.html | 2 +- .../services/annotation-actions.service.ts | 50 +++++---- .../services/dossiers-dialog.service.ts | 8 +- 13 files changed, 225 insertions(+), 240 deletions(-) delete mode 100644 apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.html delete mode 100644 apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.scss delete mode 100644 apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.ts diff --git a/apps/red-ui/src/app/models/file/annotation.permissions.ts b/apps/red-ui/src/app/models/file/annotation.permissions.ts index 55dc11761..81c805e68 100644 --- a/apps/red-ui/src/app/models/file/annotation.permissions.ts +++ b/apps/red-ui/src/app/models/file/annotation.permissions.ts @@ -1,24 +1,25 @@ import { UserWrapper } from '@services/user.service'; import { AnnotationWrapper } from './annotation.wrapper'; +import { isArray } from 'rxjs/internal-compatibility'; export class AnnotationPermissions { - canUndo: boolean; + canUndo = true; - canAcceptRecommendation: boolean; - canMarkTextOnlyAsFalsePositive: boolean; - canMarkAsFalsePositive: boolean; + canAcceptRecommendation = true; + canMarkTextOnlyAsFalsePositive = true; + canMarkAsFalsePositive = true; - canRemoveOrSuggestToRemoveOnlyHere: boolean; - canRemoveOrSuggestToRemoveFromDictionary: boolean; + canRemoveOrSuggestToRemoveOnlyHere = true; + canRemoveOrSuggestToRemoveFromDictionary = true; - canAcceptSuggestion: boolean; - canRejectSuggestion: boolean; + canAcceptSuggestion = true; + canRejectSuggestion = true; - canForceRedaction: boolean; + canForceRedaction = true; - canChangeLegalBasis: boolean; + canChangeLegalBasis = true; - canRecategorizeImage: boolean; + canRecategorizeImage = true; get canPerformMultipleRemoveActions() { return ( @@ -30,42 +31,64 @@ export class AnnotationPermissions { ); } - static forUser(isApprover: boolean, user: UserWrapper, annotation: AnnotationWrapper) { - const permissions: AnnotationPermissions = new AnnotationPermissions(); + static forUser( + isApprover: boolean, + user: UserWrapper, + annotations: AnnotationWrapper | AnnotationWrapper[] + ) { + if (!isArray(annotations)) { + annotations = [annotations]; + } - permissions.canUndo = - (!isApprover && annotation.isSuggestion) || - (isApprover && annotation.isUndoableActionForApprover); + const summedPermissions: AnnotationPermissions = new AnnotationPermissions(); - permissions.canForceRedaction = annotation.isSkipped && !permissions.canUndo; + for (const annotation of annotations) { + const permissions: AnnotationPermissions = new AnnotationPermissions(); + permissions.canUndo = + (!isApprover && annotation.isSuggestion) || + (isApprover && annotation.isUndoableActionForApprover); - permissions.canAcceptRecommendation = annotation.isRecommendation; + permissions.canForceRedaction = annotation.isSkipped && !permissions.canUndo; - permissions.canMarkAsFalsePositive = - annotation.canBeMarkedAsFalsePositive && !annotation.force; - permissions.canMarkTextOnlyAsFalsePositive = - annotation.canBeMarkedAsFalsePositiveWithTextOnly && !annotation.force; + permissions.canAcceptRecommendation = annotation.isRecommendation; - permissions.canRemoveOrSuggestToRemoveOnlyHere = annotation.isRedacted && !annotation.force; - permissions.canRemoveOrSuggestToRemoveFromDictionary = - annotation.isRedacted && - !annotation.isManualRedaction && - annotation.isModifyDictionary && - !annotation.force; + permissions.canMarkAsFalsePositive = + annotation.canBeMarkedAsFalsePositive && !annotation.force; + permissions.canMarkTextOnlyAsFalsePositive = + annotation.canBeMarkedAsFalsePositiveWithTextOnly && !annotation.force; - permissions.canAcceptSuggestion = - isApprover && (annotation.isSuggestion || annotation.isDeclinedSuggestion); - permissions.canRejectSuggestion = - isApprover && - (annotation.isSuggestion || - (annotation.isReadyForAnalysis && - !permissions.canUndo && - annotation.superType !== 'pending-analysis')); + permissions.canRemoveOrSuggestToRemoveOnlyHere = + annotation.isRedacted && !annotation.force; + permissions.canRemoveOrSuggestToRemoveFromDictionary = + annotation.isRedacted && + !annotation.isManualRedaction && + annotation.isModifyDictionary && + !annotation.force; - permissions.canChangeLegalBasis = !annotation.isManualRedaction && annotation.isRedacted; + permissions.canAcceptSuggestion = + isApprover && (annotation.isSuggestion || annotation.isDeclinedSuggestion); + permissions.canRejectSuggestion = + isApprover && + (annotation.isSuggestion || + (annotation.isReadyForAnalysis && + !permissions.canUndo && + annotation.superType !== 'pending-analysis')); - permissions.canRecategorizeImage = annotation.isImage; + permissions.canChangeLegalBasis = + !annotation.isManualRedaction && annotation.isRedacted; - return permissions; + permissions.canRecategorizeImage = annotation.isImage; + + summedPermissions._merge(permissions); + } + return summedPermissions; + } + + private _merge(permissions: AnnotationPermissions) { + for (const key of Object.keys(this)) { + if (typeof this[key] === 'boolean') { + this[key] = this[key] && permissions[key]; + } + } } } diff --git a/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.html b/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.html index 46c3227c9..6d1c0f80e 100644 --- a/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.html @@ -1,10 +1,13 @@
@@ -12,64 +15,69 @@ (action)=" annotationActionsService.convertRecommendationToAnnotation( $event, - [annotation], + annotations, annotationsChanged ) " *ngIf="annotationPermissions.canAcceptRecommendation" icon="red:check" tooltip="annotation-actions.accept-recommendation.label" - type="dark-bg" + [tooltipPosition]="tooltipPosition" + [type]="btnType" > - + + + + + + + +
diff --git a/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.ts b/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.ts index 63e9b72ba..365438847 100644 --- a/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.ts @@ -12,7 +12,10 @@ import { Annotations, WebViewerInstance } from '@pdftron/webviewer'; styleUrls: ['./annotation-actions.component.scss'] }) export class AnnotationActionsComponent implements OnInit { - @Input() annotation: AnnotationWrapper; + @Input() btnType: 'dark-bg' | 'primary' = 'dark-bg'; + @Input() tooltipPosition: 'before' | 'above' = 'before'; + + @Input() _annotations: AnnotationWrapper[]; @Input() canPerformAnnotationActions: boolean; @Input() viewer: WebViewerInstance; @@ -20,33 +23,80 @@ export class AnnotationActionsComponent implements OnInit { annotationPermissions: AnnotationPermissions; + viewerAnnotations: Annotations.Annotation[]; + constructor( public appStateService: AppStateService, public annotationActionsService: AnnotationActionsService, private _permissionsService: PermissionsService ) {} - get viewerAnnotation(): Annotations.Annotation { - return this.viewer.annotManager.getAnnotationById(this.annotation.id); + get annotations(): AnnotationWrapper[] { + return this._annotations; + } + + @Input() + set annotations(value: AnnotationWrapper[]) { + this._annotations = value.filter(a => a !== undefined); + this.viewerAnnotations = this._annotations.map(a => + this.viewer.annotManager.getAnnotationById(a.id) + ); + this._setPermissions(); + } + + get isVisible() { + return this.viewerAnnotations.reduce( + (accumulator, annotation) => annotation.isVisible() && accumulator, + true + ); + } + + get isImage() { + return this.annotations.reduce( + (accumulator, annotation) => annotation.isImage && accumulator, + true + ); } ngOnInit(): void { - this.annotationPermissions = AnnotationPermissions.forUser( - this._permissionsService.isApprover(), - this._permissionsService.currentUser, - this.annotation + this._setPermissions(); + } + + suggestRemoveAnnotations($event, removeFromDict: boolean) { + $event.stopPropagation(); + this.annotationActionsService.suggestRemoveAnnotation( + $event, + this.annotations, + removeFromDict, + this.annotationsChanged + ); + } + + markAsFalsePositive($event) { + this.annotationActionsService.markAsFalsePositive( + $event, + this.annotations, + this.annotationsChanged ); } hideAnnotation($event: MouseEvent) { $event.stopPropagation(); - this.viewer.annotManager.hideAnnotations([this.viewerAnnotation]); + this.viewer.annotManager.hideAnnotations(this.viewerAnnotations); this.viewer.annotManager.deselectAllAnnotations(); } showAnnotation($event: MouseEvent) { $event.stopPropagation(); - this.viewer.annotManager.showAnnotations([this.viewerAnnotation]); + this.viewer.annotManager.showAnnotations(this.viewerAnnotations); this.viewer.annotManager.deselectAllAnnotations(); } + + private _setPermissions() { + this.annotationPermissions = AnnotationPermissions.forUser( + this._permissionsService.isApprover(), + this._permissionsService.currentUser, + this.annotations + ); + } } diff --git a/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.html b/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.html deleted file mode 100644 index 89cf90056..000000000 --- a/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.scss b/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.scss deleted file mode 100644 index 6a6a6408d..000000000 --- a/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -:host { - display: flex; - - > *:not(:last-child) { - margin-right: 2px; - } -} diff --git a/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.ts b/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.ts deleted file mode 100644 index fdf89b446..000000000 --- a/apps/red-ui/src/app/modules/dossier/components/annotation-remove-actions/annotation-remove-actions.component.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; -import { AppStateService } from '@state/app-state.service'; -import { AnnotationWrapper } from '@models/file/annotation.wrapper'; -import { AnnotationActionsService } from '../../services/annotation-actions.service'; -import { AnnotationPermissions } from '@models/file/annotation.permissions'; -import { PermissionsService } from '@services/permissions.service'; -import { MatMenuTrigger } from '@angular/material/menu'; - -@Component({ - selector: 'redaction-annotation-remove-actions', - templateUrl: './annotation-remove-actions.component.html', - styleUrls: ['./annotation-remove-actions.component.scss'] -}) -export class AnnotationRemoveActionsComponent { - @Output() menuOpenChange = new EventEmitter(); - @Input() annotationsChanged: EventEmitter; - @Input() menuOpen: boolean; - @Input() btnType: 'dark-bg' | 'primary' = 'dark-bg'; - @Input() tooltipPosition: 'before' | 'above' = 'before'; - - @ViewChild(MatMenuTrigger) matMenuTrigger: MatMenuTrigger; - permissions: { - canRemoveOrSuggestToRemoveOnlyHere: boolean; - canRemoveOrSuggestToRemoveFromDictionary: boolean; - canMarkAsFalsePositive: boolean; - }; - - constructor( - readonly appStateService: AppStateService, - private readonly _annotationActionsService: AnnotationActionsService, - private readonly _permissionsService: PermissionsService - ) {} - - private _annotations: AnnotationWrapper[]; - - get annotations(): AnnotationWrapper[] { - return this._annotations; - } - - @Input() - set annotations(value: AnnotationWrapper[]) { - this._annotations = value.filter(a => a !== undefined); - this._setPermissions(); - } - - suggestRemoveAnnotations($event, removeFromDict: boolean) { - $event.stopPropagation(); - this._annotationActionsService.suggestRemoveAnnotation( - $event, - this.annotations, - removeFromDict, - this.annotationsChanged - ); - } - - markAsFalsePositive($event) { - this._annotationActionsService.markAsFalsePositive( - $event, - this.annotations, - this.annotationsChanged - ); - } - - private _setPermissions() { - this.permissions = { - canRemoveOrSuggestToRemoveOnlyHere: this._annotationsPermissions([ - 'canRemoveOrSuggestToRemoveOnlyHere' - ]), - canRemoveOrSuggestToRemoveFromDictionary: this._annotationsPermissions([ - 'canRemoveOrSuggestToRemoveFromDictionary' - ]), - canMarkAsFalsePositive: this._annotationsPermissions([ - 'canMarkAsFalsePositive', - 'canMarkTextOnlyAsFalsePositive' - ]) - }; - } - - private _annotationsPermissions(keys: string[]): boolean { - return this.annotations.reduce((prevValue, annotation) => { - const annotationPermissions = AnnotationPermissions.forUser( - this._permissionsService.isApprover(), - this._permissionsService.currentUser, - annotation - ); - const hasAtLeastOnePermission = keys.reduce( - (acc, key) => acc || annotationPermissions[key], - false - ); - return prevValue && hasAtLeastOnePermission; - }, true); - } -} diff --git a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html index c44947014..e1a80526d 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html @@ -53,13 +53,13 @@ type="red-bg" > {{ selectedAnnotations?.length || 0 }} selected - + > , - @Inject(MAT_DIALOG_DATA) public annotation: AnnotationWrapper + @Inject(MAT_DIALOG_DATA) public annotations: AnnotationWrapper[] ) {} get changed(): boolean { - return this.legalBasisForm.get('reason').value.legalBasis !== this.annotation.legalBasis; + return ( + this.legalBasisForm.get('reason').value.legalBasis !== this.annotations[0].legalBasis + ); } async ngOnInit() { @@ -58,7 +60,7 @@ export class ChangeLegalBasisDialogComponent implements OnInit { this.legalBasisForm.patchValue({ reason: this.legalOptions.find( - option => option.legalBasis === this.annotation.legalBasis + option => option.legalBasis === this.annotations[0].legalBasis ) }); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts index e803cd26a..6a58fdb94 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/recategorize-image-dialog/recategorize-image-dialog.component.ts @@ -18,18 +18,18 @@ export class RecategorizeImageDialogComponent implements OnInit { private readonly _permissionsService: PermissionsService, private readonly _formBuilder: FormBuilder, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public annotation: AnnotationWrapper + @Inject(MAT_DIALOG_DATA) public annotations: AnnotationWrapper[] ) {} get changed(): boolean { - return this.recategorizeImageForm.get('type').value !== this.annotation.dictionary; + return this.recategorizeImageForm.get('type').value !== this.annotations[0].dictionary; } async ngOnInit() { this.isDocumentAdmin = this._permissionsService.isApprover(); this.recategorizeImageForm = this._formBuilder.group({ - type: [this.annotation.dictionary, Validators.required], + type: [this.annotations[0].dictionary, Validators.required], comment: this.isDocumentAdmin ? [null] : [null, Validators.required] }); } diff --git a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts index 1d5031442..a1a7c7482 100644 --- a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts +++ b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts @@ -34,7 +34,6 @@ import { PdfViewerDataService } from './services/pdf-viewer-data.service'; import { ManualAnnotationService } from './services/manual-annotation.service'; import { AnnotationDrawService } from './services/annotation-draw.service'; import { AnnotationProcessingService } from './services/annotation-processing.service'; -import { AnnotationRemoveActionsComponent } from './components/annotation-remove-actions/annotation-remove-actions.component'; import { DossierDictionaryDialogComponent } from './dialogs/dossier-dictionary-dialog/dossier-dictionary-dialog.component'; import { EditDossierDialogComponent } from './dialogs/edit-dossier-dialog/edit-dossier-dialog.component'; import { EditDossierGeneralInfoComponent } from './dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component'; @@ -84,7 +83,6 @@ const components = [ DossierListingActionsComponent, DocumentInfoComponent, FileWorkloadComponent, - AnnotationRemoveActionsComponent, EditDossierGeneralInfoComponent, EditDossierDownloadPackageComponent, EditDossierDictionaryComponent, diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html index 5f574af01..29c0e82a0 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html @@ -201,7 +201,7 @@ diff --git a/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts index ebaf549c2..477033369 100644 --- a/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/annotation-actions.service.ts @@ -76,22 +76,24 @@ export class AnnotationActionsService { changeLegalBasis( $event: MouseEvent, - annotation: AnnotationWrapper, + annotations: AnnotationWrapper[], annotationsChanged: EventEmitter ) { this._dialogService.openChangeLegalBasisDialog( $event, - annotation, + annotations, (data: { comment: string; legalBasis: string }) => { - this._processObsAndEmit( - this._manualAnnotationService.changeLegalBasis( - annotation.annotationId, - data.legalBasis, - data.comment - ), - annotation, - annotationsChanged - ); + annotations.forEach(annotation => { + this._processObsAndEmit( + this._manualAnnotationService.changeLegalBasis( + annotation.annotationId, + data.legalBasis, + data.comment + ), + annotation, + annotationsChanged + ); + }); } ); } @@ -142,22 +144,24 @@ export class AnnotationActionsService { recategorizeImage( $event: MouseEvent, - annotation: AnnotationWrapper, + annotations: AnnotationWrapper[], annotationsChanged: EventEmitter ) { this._dialogService.openRecategorizeImageDialog( $event, - annotation, + annotations, (data: { type: string; comment: string }) => { - this._processObsAndEmit( - this._manualAnnotationService.recategorizeImage( - annotation.annotationId, - data.type, - data.comment - ), - annotation, - annotationsChanged - ); + annotations.forEach(annotation => { + this._processObsAndEmit( + this._manualAnnotationService.recategorizeImage( + annotation.annotationId, + data.type, + data.comment + ), + annotation, + annotationsChanged + ); + }); } ); } @@ -218,7 +222,7 @@ export class AnnotationActionsService { title: this._translateService.instant('annotation-actions.recategorize-image'), onClick: () => { this._ngZone.run(() => { - this.recategorizeImage(null, annotations[0], annotationsChanged); + this.recategorizeImage(null, annotations, annotationsChanged); }); } }); diff --git a/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts b/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts index f1aa10c3a..01e4ce2d8 100644 --- a/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts @@ -150,13 +150,13 @@ export class DossiersDialogService extends DialogService { openChangeLegalBasisDialog( $event: MouseEvent, - annotation: AnnotationWrapper, + annotations: AnnotationWrapper[], cb?: Function ): MatDialogRef { $event?.stopPropagation(); const ref = this._dialog.open(ChangeLegalBasisDialogComponent, { ...dialogConfig, - data: annotation + data: annotations }); ref.afterClosed().subscribe(async result => { if (result && cb) { @@ -168,13 +168,13 @@ export class DossiersDialogService extends DialogService { openRecategorizeImageDialog( $event: MouseEvent, - annotation: AnnotationWrapper, + annotations: AnnotationWrapper[], cb?: Function ): MatDialogRef { $event?.stopPropagation(); const ref = this._dialog.open(RecategorizeImageDialogComponent, { ...dialogConfig, - data: annotation + data: annotations }); ref.afterClosed().subscribe(async result => { if (result && cb) {