Multi-Select Annotations
This commit is contained in:
parent
06debdfc7a
commit
79e568abbf
@ -111,6 +111,7 @@ import { EditColorDialogComponent } from './screens/admin/default-colors-screen/
|
||||
import { DownloadsListScreenComponent } from './screens/downloads-list-screen/downloads-list-screen.component';
|
||||
import { DigitalSignatureScreenComponent } from './screens/admin/digital-signature-screen/digital-signature-screen.component';
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { RemoveAnnotationsDialogComponent } from './dialogs/remove-annotations-dialog/remove-annotations-dialog.component';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
|
||||
@ -369,7 +370,8 @@ const matImports = [
|
||||
DefaultColorsScreenComponent,
|
||||
EditColorDialogComponent,
|
||||
DownloadsListScreenComponent,
|
||||
DigitalSignatureScreenComponent
|
||||
DigitalSignatureScreenComponent,
|
||||
RemoveAnnotationsDialogComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@ -21,43 +21,63 @@ export class AnnotationActionsService {
|
||||
private readonly _dialogService: DialogService
|
||||
) {}
|
||||
|
||||
public acceptSuggestion($event: MouseEvent, annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
public acceptSuggestion($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
$event?.stopPropagation();
|
||||
this._processObsAndEmit(this._manualAnnotationService.approveRequest(annotation.id, annotation.isModifyDictionary), annotation, annotationsChanged);
|
||||
annotations.forEach((annotation) => {
|
||||
this._processObsAndEmit(this._manualAnnotationService.approveRequest(annotation.id, annotation.isModifyDictionary), annotation, annotationsChanged);
|
||||
});
|
||||
}
|
||||
|
||||
public rejectSuggestion($event: MouseEvent, annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
public rejectSuggestion($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
$event?.stopPropagation();
|
||||
this._processObsAndEmit(this._manualAnnotationService.declineOrRemoveRequest(annotation), annotation, annotationsChanged);
|
||||
annotations.forEach((annotation) => {
|
||||
this._processObsAndEmit(this._manualAnnotationService.declineOrRemoveRequest(annotation), annotation, annotationsChanged);
|
||||
});
|
||||
}
|
||||
|
||||
public suggestRemoveAnnotation(
|
||||
$event: MouseEvent,
|
||||
annotation: AnnotationWrapper,
|
||||
annotations: AnnotationWrapper[],
|
||||
removeFromDictionary: boolean,
|
||||
annotationsChanged: EventEmitter<AnnotationWrapper>
|
||||
) {
|
||||
this._dialogService.openRemoveFromDictionaryDialog($event, annotation, removeFromDictionary, () => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.removeOrSuggestRemoveAnnotation(annotation, removeFromDictionary),
|
||||
annotation,
|
||||
annotationsChanged
|
||||
);
|
||||
this._dialogService.openRemoveFromDictionaryDialog($event, annotations, removeFromDictionary, () => {
|
||||
annotations.forEach((annotation) => {
|
||||
this._processObsAndEmit(
|
||||
this._manualAnnotationService.removeOrSuggestRemoveAnnotation(annotation, removeFromDictionary),
|
||||
annotation,
|
||||
annotationsChanged
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public markAsFalsePositive($event: MouseEvent, annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
this._markAsFalsePositive($event, annotation, this._getFalsePositiveText(annotation), annotationsChanged);
|
||||
public markAsFalsePositive($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
annotations.forEach((annotation) => {
|
||||
this._markAsFalsePositive($event, annotation, this._getFalsePositiveText(annotation), annotationsChanged);
|
||||
});
|
||||
}
|
||||
|
||||
public undoDirectAction($event: MouseEvent, annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
public undoDirectAction($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
$event?.stopPropagation();
|
||||
this._processObsAndEmit(this._manualAnnotationService.undoRequest(annotation), annotation, annotationsChanged);
|
||||
|
||||
annotations.forEach((annotation) => {
|
||||
this._processObsAndEmit(this._manualAnnotationService.undoRequest(annotation), annotation, annotationsChanged);
|
||||
});
|
||||
}
|
||||
|
||||
public convertRecommendationToAnnotation($event: any, annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
public convertRecommendationToAnnotation($event: any, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
$event?.stopPropagation();
|
||||
this._processObsAndEmit(this._manualAnnotationService.addRecommendation(annotation), annotation, annotationsChanged);
|
||||
|
||||
annotations.forEach((annotation) => {
|
||||
this._processObsAndEmit(this._manualAnnotationService.addRecommendation(annotation), annotation, annotationsChanged);
|
||||
});
|
||||
}
|
||||
|
||||
public markTextOnlyAsFalsePositive($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
annotations.forEach((annotation) => {
|
||||
this._markAsFalsePositive($event, annotation, annotation.value, annotationsChanged);
|
||||
});
|
||||
}
|
||||
|
||||
private _processObsAndEmit(obs: Observable<any>, annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
@ -71,110 +91,126 @@ export class AnnotationActionsService {
|
||||
);
|
||||
}
|
||||
|
||||
public getViewerAvailableActions(annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>): {}[] {
|
||||
public getViewerAvailableActions(annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>): {}[] {
|
||||
const availableActions = [];
|
||||
|
||||
const annotationPermissions = AnnotationPermissions.forUser(this._permissionsService.currentUser, annotation);
|
||||
const annotationPermissions = annotations.map((a) => {
|
||||
return { annotation: a, permissions: AnnotationPermissions.forUser(this._permissionsService.currentUser, a) };
|
||||
});
|
||||
|
||||
if (annotationPermissions.canAcceptRecommendation) {
|
||||
const canAcceptRecommendation = annotationPermissions.reduce((acc, next) => acc && next.permissions.canAcceptRecommendation, true);
|
||||
if (canAcceptRecommendation) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/check-alt.svg',
|
||||
title: this._translateService.instant('annotation-actions.accept-recommendation.label'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.convertRecommendationToAnnotation(null, annotation, annotationsChanged);
|
||||
this.convertRecommendationToAnnotation(null, annotations, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (annotationPermissions.canMarkTextOnlyAsFalsePositive) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/thumb-down.svg',
|
||||
title: this._translateService.instant('annotation-actions.remove-annotation.false-positive'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.markTextOnlyAsFalsePositive(null, annotation, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (annotationPermissions.canAcceptSuggestion) {
|
||||
const canAcceptSuggestion = annotationPermissions.reduce((acc, next) => acc && next.permissions.canAcceptSuggestion, true);
|
||||
if (canAcceptSuggestion) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/check-alt.svg',
|
||||
title: this._translateService.instant('annotation-actions.accept-suggestion.label'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.acceptSuggestion(null, annotation, annotationsChanged);
|
||||
this.acceptSuggestion(null, annotations, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (annotationPermissions.canUndo) {
|
||||
const canUndo = annotationPermissions.reduce((acc, next) => acc && next.permissions.canUndo, true);
|
||||
if (canUndo) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/undo.svg',
|
||||
title: this._translateService.instant('annotation-actions.undo'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.undoDirectAction(null, annotation, annotationsChanged);
|
||||
this.undoDirectAction(null, annotations, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (annotationPermissions.canRejectSuggestion) {
|
||||
const canRejectSuggestion = annotationPermissions.reduce((acc, next) => acc && next.permissions.canRejectSuggestion, true);
|
||||
if (canRejectSuggestion) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/close.svg',
|
||||
title: this._translateService.instant('annotation-actions.reject-suggestion'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.rejectSuggestion(null, annotation, annotationsChanged);
|
||||
this.rejectSuggestion(null, annotations, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere) {
|
||||
const canRemoveOrSuggestToRemoveOnlyHere = annotationPermissions.reduce(
|
||||
(acc, next) => acc && next.permissions.canRemoveOrSuggestToRemoveOnlyHere,
|
||||
true
|
||||
);
|
||||
if (canRemoveOrSuggestToRemoveOnlyHere) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/close.svg',
|
||||
title: this._translateService.instant('annotation-actions.suggest-remove-annotation'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.suggestRemoveAnnotation(null, annotation, false, annotationsChanged);
|
||||
this.suggestRemoveAnnotation(null, annotations, false, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (annotationPermissions.canRemoveOrSuggestToRemoveFromDictionary) {
|
||||
const canRemoveOrSuggestToRemoveFromDictionary = annotationPermissions.reduce(
|
||||
(acc, next) => acc && next.permissions.canRemoveOrSuggestToRemoveFromDictionary,
|
||||
true
|
||||
);
|
||||
if (canRemoveOrSuggestToRemoveFromDictionary) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/trash.svg',
|
||||
title: this._translateService.instant('annotation-actions.remove-annotation.remove-from-dict'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.suggestRemoveAnnotation(null, annotation, true, annotationsChanged);
|
||||
this.suggestRemoveAnnotation(null, annotations, true, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (annotationPermissions.canMarkAsFalsePositive) {
|
||||
const canMarkTextOnlyAsFalsePositive = annotationPermissions.reduce((acc, next) => acc && next.permissions.canMarkTextOnlyAsFalsePositive, true);
|
||||
if (canMarkTextOnlyAsFalsePositive) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/thumb-down.svg',
|
||||
title: this._translateService.instant('annotation-actions.remove-annotation.false-positive'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.markAsFalsePositive(null, annotation, annotationsChanged);
|
||||
this.markTextOnlyAsFalsePositive(null, annotations, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const canMarkAsFalsePositive = annotationPermissions.reduce((acc, next) => acc && next.permissions.canMarkAsFalsePositive, true);
|
||||
if (canMarkAsFalsePositive) {
|
||||
availableActions.push({
|
||||
type: 'actionButton',
|
||||
img: '/assets/icons/general/thumb-down.svg',
|
||||
title: this._translateService.instant('annotation-actions.remove-annotation.false-positive'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.markAsFalsePositive(null, annotations, annotationsChanged);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -183,10 +219,6 @@ export class AnnotationActionsService {
|
||||
return availableActions;
|
||||
}
|
||||
|
||||
markTextOnlyAsFalsePositive($event: MouseEvent, annotation: AnnotationWrapper, annotationsChanged: EventEmitter<AnnotationWrapper>) {
|
||||
this._markAsFalsePositive($event, annotation, annotation.value, annotationsChanged);
|
||||
}
|
||||
|
||||
private _getFalsePositiveText(annotation: AnnotationWrapper) {
|
||||
if (annotation.canBeMarkedAsFalsePositive) {
|
||||
let text;
|
||||
|
||||
@ -25,6 +25,7 @@ import { AddEditDictionaryDialogComponent } from '../screens/admin/dictionary-li
|
||||
import { AddEditRuleSetDialogComponent } from '../screens/admin/rule-sets-listing-screen/add-edit-rule-set-dialog/add-edit-rule-set-dialog.component';
|
||||
import { OverwriteFilesDialogComponent } from './overwrite-files-dialog/overwrite-files-dialog.component';
|
||||
import { EditColorDialogComponent } from '../screens/admin/default-colors-screen/edit-color-dialog/edit-color-dialog.component';
|
||||
import { RemoveAnnotationsDialogComponent } from './remove-annotations-dialog/remove-annotations-dialog.component';
|
||||
|
||||
const dialogConfig = {
|
||||
width: '662px',
|
||||
@ -143,26 +144,27 @@ export class DialogService {
|
||||
|
||||
public openRemoveFromDictionaryDialog(
|
||||
$event: MouseEvent,
|
||||
annotation: AnnotationWrapper,
|
||||
annotations: AnnotationWrapper[],
|
||||
removeFromDictionary: boolean,
|
||||
cb?: Function
|
||||
): MatDialogRef<ConfirmationDialogComponent> {
|
||||
): MatDialogRef<RemoveAnnotationsDialogComponent> {
|
||||
$event?.stopPropagation();
|
||||
const ref = this._dialog.open(ConfirmationDialogComponent, {
|
||||
const ref = this._dialog.open(RemoveAnnotationsDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: new ConfirmationDialogInput({
|
||||
title: annotation.isManualRedaction
|
||||
? 'confirmation-dialog.remove-manual-redaction.title'
|
||||
: removeFromDictionary
|
||||
? 'confirmation-dialog.remove-from-dictionary.title'
|
||||
: 'confirmation-dialog.remove-only-here.title',
|
||||
question: annotation.isManualRedaction
|
||||
? 'confirmation-dialog.remove-manual-redaction.question'
|
||||
: removeFromDictionary
|
||||
? 'confirmation-dialog.remove-from-dictionary.question'
|
||||
: 'confirmation-dialog.remove-only-here.question',
|
||||
translateParams: { entry: annotation.value, dictionary: annotation.dictionary }
|
||||
})
|
||||
data: annotations
|
||||
// new ConfirmationDialogInput({
|
||||
// title: annotation.isManualRedaction
|
||||
// ? 'confirmation-dialog.remove-manual-redaction.title'
|
||||
// : removeFromDictionary
|
||||
// ? 'confirmation-dialog.remove-from-dictionary.title'
|
||||
// : 'confirmation-dialog.remove-only-here.title',
|
||||
// question: annotation.isManualRedaction
|
||||
// ? 'confirmation-dialog.remove-manual-redaction.question'
|
||||
// : removeFromDictionary
|
||||
// ? 'confirmation-dialog.remove-from-dictionary.question'
|
||||
// : 'confirmation-dialog.remove-only-here.question',
|
||||
// translateParams: { entry: annotation.value, dictionary: annotation.dictionary }
|
||||
// })
|
||||
});
|
||||
ref.afterClosed().subscribe(async (result) => {
|
||||
if (result) {
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
<!-- {{ confirmationDialogInput.title | translate: confirmationDialogInput.translateParams }}-->
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<!-- <p [innerHTML]="confirmationDialogInput.question | translate: confirmationDialogInput.translateParams"></p>-->
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button (click)="confirm()" color="primary" mat-flat-button>
|
||||
<!-- {{ confirmationDialogInput.confirmationText | translate: confirmationDialogInput.translateParams }}-->
|
||||
</button>
|
||||
<button (click)="deny()" color="primary" mat-flat-button>
|
||||
<!-- {{ confirmationDialogInput.denyText | translate: confirmationDialogInput.translateParams }}-->
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<redaction-circle-button icon="red:close" mat-dialog-close class="dialog-close"></redaction-circle-button>
|
||||
</section>
|
||||
@ -0,0 +1,28 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { AnnotationWrapper } from '../../screens/file/model/annotation.wrapper';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ConfirmationDialogInput } from '../confirmation-dialog/confirmation-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-remove-annotations-dialog',
|
||||
templateUrl: './remove-annotations-dialog.component.html',
|
||||
styleUrls: ['./remove-annotations-dialog.component.scss']
|
||||
})
|
||||
export class RemoveAnnotationsDialogComponent implements OnInit {
|
||||
constructor(
|
||||
private readonly _translateService: TranslateService,
|
||||
public dialogRef: MatDialogRef<RemoveAnnotationsDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public annotationsToRemove: AnnotationWrapper[]
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
deny() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
confirm() {
|
||||
this.dialogRef.close(true);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
<redaction-hidden-action (action)="logAnnotation(annotation)">
|
||||
<div [class.visible]="menuOpen" *ngIf="canPerformAnnotationActions" class="annotation-actions">
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.convertRecommendationToAnnotation($event, annotation, annotationsChanged)"
|
||||
(action)="annotationActionsService.convertRecommendationToAnnotation($event, [annotation], annotationsChanged)"
|
||||
type="dark-bg"
|
||||
*ngIf="annotationPermissions.canAcceptRecommendation"
|
||||
tooltipPosition="before"
|
||||
@ -11,7 +11,7 @@
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.markTextOnlyAsFalsePositive($event, annotation, annotationsChanged)"
|
||||
(action)="annotationActionsService.markTextOnlyAsFalsePositive($event, [annotation], annotationsChanged)"
|
||||
type="dark-bg"
|
||||
*ngIf="annotationPermissions.canMarkTextOnlyAsFalsePositive"
|
||||
tooltipPosition="before"
|
||||
@ -21,7 +21,7 @@
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.acceptSuggestion($event, annotation, annotationsChanged)"
|
||||
(action)="annotationActionsService.acceptSuggestion($event, [annotation], annotationsChanged)"
|
||||
type="dark-bg"
|
||||
*ngIf="annotationPermissions.canAcceptSuggestion"
|
||||
tooltipPosition="before"
|
||||
@ -31,7 +31,7 @@
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.undoDirectAction($event, annotation, annotationsChanged)"
|
||||
(action)="annotationActionsService.undoDirectAction($event, [annotation], annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canUndo"
|
||||
type="dark-bg"
|
||||
icon="red:undo"
|
||||
@ -61,7 +61,7 @@
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.rejectSuggestion($event, annotation, annotationsChanged)"
|
||||
(action)="annotationActionsService.rejectSuggestion($event, [annotation], annotationsChanged)"
|
||||
type="dark-bg"
|
||||
icon="red:close"
|
||||
*ngIf="annotationPermissions.canRejectSuggestion"
|
||||
@ -71,7 +71,7 @@
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.suggestRemoveAnnotation($event, annotation, false, annotationsChanged)"
|
||||
(action)="annotationActionsService.suggestRemoveAnnotation($event, [annotation], false, annotationsChanged)"
|
||||
type="dark-bg"
|
||||
icon="red:trash"
|
||||
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere && !annotationPermissions.canPerformMultipleRemoveActions"
|
||||
@ -94,7 +94,7 @@
|
||||
|
||||
<mat-menu #menu="matMenu" (closed)="onMenuClosed()" xPosition="before">
|
||||
<div
|
||||
(click)="annotationActionsService.suggestRemoveAnnotation($event, annotation, true, annotationsChanged)"
|
||||
(click)="annotationActionsService.suggestRemoveAnnotation($event, [annotation], true, annotationsChanged)"
|
||||
mat-menu-item
|
||||
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveFromDictionary"
|
||||
>
|
||||
@ -102,7 +102,7 @@
|
||||
<div [translate]="'annotation-actions.remove-annotation.remove-from-dict'"></div>
|
||||
</div>
|
||||
<div
|
||||
(click)="annotationActionsService.suggestRemoveAnnotation($event, annotation, false, annotationsChanged)"
|
||||
(click)="annotationActionsService.suggestRemoveAnnotation($event, [annotation], false, annotationsChanged)"
|
||||
mat-menu-item
|
||||
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere"
|
||||
>
|
||||
@ -111,7 +111,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
(click)="annotationActionsService.markAsFalsePositive($event, annotation, annotationsChanged)"
|
||||
(click)="annotationActionsService.markAsFalsePositive($event, [annotation], annotationsChanged)"
|
||||
mat-menu-item
|
||||
*ngIf="annotationPermissions.canMarkAsFalsePositive"
|
||||
>
|
||||
@ -119,7 +119,7 @@
|
||||
<div translate="annotation-actions.remove-annotation.false-positive"></div>
|
||||
</div>
|
||||
<div
|
||||
(click)="annotationActionsService.markTextOnlyAsFalsePositive($event, annotation, annotationsChanged)"
|
||||
(click)="annotationActionsService.markTextOnlyAsFalsePositive($event, [annotation], annotationsChanged)"
|
||||
mat-menu-item
|
||||
*ngIf="annotationPermissions.canMarkTextOnlyAsFalsePositive"
|
||||
>
|
||||
|
||||
@ -23,8 +23,8 @@ export class AnnotationActionsComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
public appStateService: AppStateService,
|
||||
private _permissionsService: PermissionsService,
|
||||
public annotationActionsService: AnnotationActionsService
|
||||
public annotationActionsService: AnnotationActionsService,
|
||||
private _permissionsService: PermissionsService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
@ -240,7 +240,7 @@
|
||||
<div
|
||||
(click)="annotationClicked(annotation)"
|
||||
*ngFor="let annotation of displayedAnnotations[activeViewerPage]?.annotations"
|
||||
[ngClass]="{ active: selectedAnnotation?.id === annotation.id }"
|
||||
[class.active]="annotationIsSelected(annotation)"
|
||||
attr.annotation-id="{{ annotation.id }}"
|
||||
attr.annotation-page="{{ activeViewerPage }}"
|
||||
class="annotation"
|
||||
|
||||
@ -123,7 +123,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
annotationData: AnnotationData;
|
||||
|
||||
displayedAnnotations: { [key: number]: { annotations: AnnotationWrapper[] } } = {};
|
||||
selectedAnnotation: AnnotationWrapper;
|
||||
selectedAnnotations: AnnotationWrapper[];
|
||||
pagesPanelActive = true;
|
||||
viewReady = false;
|
||||
annotationFilters: FilterModel[];
|
||||
@ -267,8 +267,8 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
handleAnnotationSelected(annotationId: string) {
|
||||
this.selectedAnnotation = this.annotations.find((a) => a.id === annotationId);
|
||||
handleAnnotationSelected(annotationIds: string[]) {
|
||||
this.selectedAnnotations = annotationIds.map((annotationId) => this.annotations.find((annotationWrapper) => annotationWrapper.id === annotationId));
|
||||
this.scrollToSelectedAnnotation();
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
@ -282,15 +282,6 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
this._viewerComponent.selectAnnotation(annotation);
|
||||
}
|
||||
|
||||
@debounce()
|
||||
private scrollToSelectedAnnotation() {
|
||||
if (!this.selectedAnnotation) {
|
||||
return;
|
||||
}
|
||||
const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[annotation-id="${this.selectedAnnotation.id}"].active`);
|
||||
this._scrollToFirstElement(elements);
|
||||
}
|
||||
|
||||
selectPage(pageNumber: number) {
|
||||
this._viewerComponent.navigateToPage(pageNumber);
|
||||
this._scrollAnnotationsToPage(pageNumber, 'always');
|
||||
@ -312,19 +303,40 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
annotationIsSelected(annotation: AnnotationWrapper) {
|
||||
return this.selectedAnnotations?.find((a) => a.id === annotation.id);
|
||||
}
|
||||
|
||||
private get firstSelectedAnnotation() {
|
||||
return this.selectedAnnotations?.length ? this.selectedAnnotations[0] : null;
|
||||
}
|
||||
|
||||
private get lastSelectedAnnotation() {
|
||||
return this.selectedAnnotations?.length ? this.selectedAnnotations[this.selectedAnnotations.length - 1] : null;
|
||||
}
|
||||
|
||||
@debounce()
|
||||
private _scrollViews() {
|
||||
this._scrollQuickNavigation();
|
||||
this._scrollAnnotations();
|
||||
}
|
||||
|
||||
@debounce()
|
||||
private scrollToSelectedAnnotation() {
|
||||
if (!this.selectedAnnotations || this.selectedAnnotations.length === 0) {
|
||||
return;
|
||||
}
|
||||
const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[annotation-id="${this.firstSelectedAnnotation.id}"].active`);
|
||||
this._scrollToFirstElement(elements);
|
||||
}
|
||||
|
||||
private _scrollQuickNavigation() {
|
||||
const elements: any[] = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${this.activeViewerPage}`);
|
||||
this._scrollToFirstElement(elements);
|
||||
}
|
||||
|
||||
private _scrollAnnotations() {
|
||||
if (this.selectedAnnotation?.pageNumber === this.activeViewerPage) {
|
||||
if (this.firstSelectedAnnotation?.pageNumber === this.activeViewerPage) {
|
||||
return;
|
||||
}
|
||||
this._scrollAnnotationsToPage(this.activeViewerPage, 'always');
|
||||
@ -402,7 +414,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
|
||||
private _selectFirstAnnotationOnCurrentPageIfNecessary() {
|
||||
if (
|
||||
(!this.selectedAnnotation || this.activeViewerPage !== this.selectedAnnotation.pageNumber) &&
|
||||
(!this.firstSelectedAnnotation || this.activeViewerPage !== this.firstSelectedAnnotation.pageNumber) &&
|
||||
this.displayedPages.indexOf(this.activeViewerPage) >= 0
|
||||
) {
|
||||
this.selectAnnotation(this.displayedAnnotations[this.activeViewerPage].annotations[0]);
|
||||
@ -410,7 +422,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private _navigateAnnotations($event: KeyboardEvent) {
|
||||
if (!this.selectedAnnotation || this.activeViewerPage !== this.selectedAnnotation.pageNumber) {
|
||||
if (!this.firstSelectedAnnotation || this.activeViewerPage !== this.firstSelectedAnnotation.pageNumber) {
|
||||
const pageIdx = this.displayedPages.indexOf(this.activeViewerPage);
|
||||
if (pageIdx !== -1) {
|
||||
// Displayed page has annotations
|
||||
@ -429,10 +441,10 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const page = this.selectedAnnotation.pageNumber;
|
||||
const page = this.firstSelectedAnnotation.pageNumber;
|
||||
const pageIdx = this.displayedPages.indexOf(page);
|
||||
const annotationsOnPage = this.displayedAnnotations[page].annotations;
|
||||
const idx = annotationsOnPage.findIndex((a) => a.id === this.selectedAnnotation.id);
|
||||
const idx = annotationsOnPage.findIndex((a) => a.id === this.firstSelectedAnnotation.id);
|
||||
|
||||
if ($event.key === 'ArrowDown') {
|
||||
if (idx + 1 !== annotationsOnPage.length) {
|
||||
@ -669,16 +681,6 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
this.viewMode = $event.value;
|
||||
this.updateViewMode();
|
||||
}
|
||||
|
||||
// <!-- Dev Mode Features-->
|
||||
async openSSRFilePreview() {
|
||||
window.open(`/pdf-preview/${this.projectId}/${this.fileId}`, '_blank');
|
||||
}
|
||||
|
||||
async openHTMLDebug() {
|
||||
window.open(`/html-debug/${this.projectId}/${this.fileId}`, '_blank');
|
||||
}
|
||||
|
||||
downloadOriginalFile() {
|
||||
this._fileManagementControllerService
|
||||
.downloadOriginalFile(this.projectId, this.fileId, true, this.fileData.fileStatus.lastUploaded, 'response')
|
||||
@ -697,6 +699,15 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
return false;
|
||||
}
|
||||
|
||||
// <!-- Dev Mode Features-->
|
||||
async openSSRFilePreview() {
|
||||
window.open(`/pdf-preview/${this.projectId}/${this.fileId}`, '_blank');
|
||||
}
|
||||
|
||||
async openHTMLDebug() {
|
||||
window.open(`/html-debug/${this.projectId}/${this.fileId}`, '_blank');
|
||||
}
|
||||
|
||||
private _handleIgnoreAnnotationsDrawing() {
|
||||
const allAnnotations = this._instance.annotManager.getAnnotationsList();
|
||||
const ignoreAnnotations = allAnnotations.filter((a) => a.getCustomData('skipped'));
|
||||
|
||||
@ -46,7 +46,7 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
|
||||
@Input() shouldDeselectAnnotationsOnPageChange = true;
|
||||
|
||||
@Output() fileReady = new EventEmitter();
|
||||
@Output() annotationSelected = new EventEmitter<string>();
|
||||
@Output() annotationSelected = new EventEmitter<string[]>();
|
||||
@Output() manualAnnotationRequested = new EventEmitter<ManualRedactionEntryWrapper>();
|
||||
@Output() pageChanged = new EventEmitter<number>();
|
||||
@Output() keyUp = new EventEmitter<KeyboardEvent>();
|
||||
@ -107,12 +107,12 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
|
||||
|
||||
instance.annotManager.on('annotationSelected', (annotationList, action) => {
|
||||
if (action === 'deselected') {
|
||||
this.annotationSelected.emit(null);
|
||||
this.annotationSelected.emit([]);
|
||||
this._toggleRectangleAnnotationAction(true);
|
||||
} else {
|
||||
this._configureAnnotationSpecificActions(annotationList[0]);
|
||||
this._toggleRectangleAnnotationAction(annotationList[0].ReadOnly);
|
||||
this.annotationSelected.emit(annotationList[0].Id);
|
||||
this._configureAnnotationSpecificActions(annotationList);
|
||||
this._toggleRectangleAnnotationAction(annotationList.length === 1 && annotationList[0].ReadOnly);
|
||||
this.annotationSelected.emit(annotationList.map((a) => a.Id));
|
||||
}
|
||||
});
|
||||
|
||||
@ -215,18 +215,19 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
|
||||
}));
|
||||
}
|
||||
|
||||
private _configureAnnotationSpecificActions(viewerAnnotation: Annotations.Annotation) {
|
||||
private _configureAnnotationSpecificActions(viewerAnnotations: Annotations.Annotation[]) {
|
||||
if (this.canPerformActions) {
|
||||
const annotation = this.annotations.find((a) => a.id === viewerAnnotation.Id);
|
||||
const annotationWrappers = viewerAnnotations.map((va) => this.annotations.find((a) => a.id === va.Id)).filter((va) => !!va);
|
||||
this.instance.annotationPopup.update([]);
|
||||
|
||||
if (!annotation) {
|
||||
if (annotationWrappers.length === 0) {
|
||||
this._configureRectangleAnnotationPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
// Add hide action as last item
|
||||
if (annotation.isImage) {
|
||||
const allAnnotationsHaveImageAction = annotationWrappers.reduce((acc, next) => acc && next.isImage, true);
|
||||
if (allAnnotationsHaveImageAction) {
|
||||
this.instance.annotationPopup.add([
|
||||
{
|
||||
type: 'actionButton',
|
||||
@ -234,14 +235,14 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
|
||||
title: this._translateService.instant('annotation-actions.hide'),
|
||||
onClick: () => {
|
||||
this._ngZone.run(() => {
|
||||
this.instance.annotManager.hideAnnotation(viewerAnnotation);
|
||||
this.instance.annotManager.hideAnnotations(viewerAnnotations);
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
this.instance.annotationPopup.add(this._annotationActionsService.getViewerAvailableActions(annotation, this.annotationsChanged));
|
||||
this.instance.annotationPopup.add(this._annotationActionsService.getViewerAvailableActions(annotationWrappers, this.annotationsChanged));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user