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
- 0"
- [annotationsChanged]="annotationsChanged"
+ (annotationsChanged)="annotationsChanged.emit($event)"
[annotations]="selectedAnnotations"
btnType="primary"
tooltipPosition="above"
- >
+ >
,
- @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) {