Pull request #241: RED-1768
Merge in RED/ui from RED-1768 to master * commit '17222b058da32644a1f4b6d163c7f62c998bffd3': Show hide bulk action, and bulk action availability in general for all new actions RED-1768 finished modifications for annotation changed events
This commit is contained in:
commit
2a1b80664c
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,28 +76,15 @@ export class AnnotationWrapper {
|
||||
}
|
||||
|
||||
get canBeMarkedAsFalsePositive() {
|
||||
return (
|
||||
(this.isRecommendation || this.superType === 'redaction') &&
|
||||
(this.hasTextAfter || this.hasTextBefore) &&
|
||||
!this.isImage
|
||||
);
|
||||
return (this.isRecommendation || this.superType === 'redaction') && (this.hasTextAfter || this.hasTextBefore) && !this.isImage;
|
||||
}
|
||||
|
||||
get canBeMarkedAsFalsePositiveWithTextOnly() {
|
||||
return (
|
||||
!this.canBeMarkedAsFalsePositive &&
|
||||
(this.isRecommendation || this.superType === 'redaction') &&
|
||||
!this.isImage
|
||||
);
|
||||
return !this.canBeMarkedAsFalsePositive && (this.isRecommendation || this.superType === 'redaction') && !this.isImage;
|
||||
}
|
||||
|
||||
get isSuperTypeBasedColor() {
|
||||
return (
|
||||
this.isSkipped ||
|
||||
this.isSuggestion ||
|
||||
this.isReadyForAnalysis ||
|
||||
this.isDeclinedSuggestion
|
||||
);
|
||||
return this.isSkipped || this.isSuggestion || this.isReadyForAnalysis || this.isDeclinedSuggestion;
|
||||
}
|
||||
|
||||
get isSkipped() {
|
||||
@ -115,9 +102,7 @@ export class AnnotationWrapper {
|
||||
get isFalsePositive() {
|
||||
return (
|
||||
this.dictionary?.toLowerCase() === 'false_positive' &&
|
||||
(this.superType === 'skipped' ||
|
||||
this.superType === 'hint' ||
|
||||
this.superType === 'redaction')
|
||||
(this.superType === 'skipped' || this.superType === 'hint' || this.superType === 'redaction')
|
||||
);
|
||||
}
|
||||
|
||||
@ -168,10 +153,7 @@ export class AnnotationWrapper {
|
||||
}
|
||||
|
||||
get isSuggestionRemove() {
|
||||
return (
|
||||
this.superType === 'suggestion-remove' ||
|
||||
this.superType === 'suggestion-remove-dictionary'
|
||||
);
|
||||
return this.superType === 'suggestion-remove' || this.superType === 'suggestion-remove-dictionary';
|
||||
}
|
||||
|
||||
get isModifyDictionary() {
|
||||
@ -179,10 +161,7 @@ export class AnnotationWrapper {
|
||||
}
|
||||
|
||||
get isConvertedRecommendation() {
|
||||
return (
|
||||
this.isRecommendation &&
|
||||
(this.superType === 'suggestion-add-dictionary' || this.superType === 'add-dictionary')
|
||||
);
|
||||
return this.isRecommendation && (this.superType === 'suggestion-add-dictionary' || this.superType === 'add-dictionary');
|
||||
}
|
||||
|
||||
get isRecommendation() {
|
||||
@ -234,21 +213,13 @@ export class AnnotationWrapper {
|
||||
return annotationWrapper;
|
||||
}
|
||||
|
||||
private static _handleRecommendations(
|
||||
annotationWrapper: AnnotationWrapper,
|
||||
redactionLogEntry: RedactionLogEntryWrapper
|
||||
) {
|
||||
private static _handleRecommendations(annotationWrapper: AnnotationWrapper, redactionLogEntry: RedactionLogEntryWrapper) {
|
||||
if (annotationWrapper.superType === 'recommendation') {
|
||||
annotationWrapper.recommendationType = redactionLogEntry.type.substr(
|
||||
'recommendation_'.length
|
||||
);
|
||||
annotationWrapper.recommendationType = redactionLogEntry.type.substr('recommendation_'.length);
|
||||
}
|
||||
}
|
||||
|
||||
private static _setSuperType(
|
||||
annotationWrapper: AnnotationWrapper,
|
||||
redactionLogEntryWrapper: RedactionLogEntryWrapper
|
||||
) {
|
||||
private static _setSuperType(annotationWrapper: AnnotationWrapper, redactionLogEntryWrapper: RedactionLogEntryWrapper) {
|
||||
if (redactionLogEntryWrapper.recommendation) {
|
||||
if (redactionLogEntryWrapper.redacted) {
|
||||
annotationWrapper.superType = 'recommendation';
|
||||
@ -288,9 +259,14 @@ export class AnnotationWrapper {
|
||||
if (annotationWrapper.dictionary?.toLowerCase() === 'false_positive') {
|
||||
if (redactionLogEntryWrapper.status === 'REQUESTED') {
|
||||
annotationWrapper.superType = 'suggestion-add-dictionary';
|
||||
return;
|
||||
}
|
||||
if (redactionLogEntryWrapper.status === 'APPROVED') {
|
||||
annotationWrapper.superType = 'add-dictionary';
|
||||
return;
|
||||
}
|
||||
if (!redactionLogEntryWrapper.manual) {
|
||||
annotationWrapper.superType = 'skipped';
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -299,16 +275,20 @@ export class AnnotationWrapper {
|
||||
if (redactionLogEntryWrapper.dictionaryEntry) {
|
||||
if (redactionLogEntryWrapper.status === 'REQUESTED') {
|
||||
annotationWrapper.superType = 'suggestion-add-dictionary';
|
||||
return;
|
||||
}
|
||||
if (redactionLogEntryWrapper.status === 'APPROVED') {
|
||||
annotationWrapper.superType = 'add-dictionary';
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (redactionLogEntryWrapper.status === 'REQUESTED') {
|
||||
annotationWrapper.superType = 'suggestion-add';
|
||||
return;
|
||||
}
|
||||
if (redactionLogEntryWrapper.status === 'APPROVED') {
|
||||
annotationWrapper.superType = 'manual-redaction';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -322,40 +302,29 @@ export class AnnotationWrapper {
|
||||
: 'suggestion-remove-dictionary';
|
||||
} else {
|
||||
annotationWrapper.superType =
|
||||
redactionLogEntryWrapper.manualRedactionType === 'ADD'
|
||||
? 'suggestion-add'
|
||||
: 'suggestion-remove';
|
||||
redactionLogEntryWrapper.manualRedactionType === 'ADD' ? 'suggestion-add' : 'suggestion-remove';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (redactionLogEntryWrapper.status === 'APPROVED') {
|
||||
if (redactionLogEntryWrapper.dictionaryEntry) {
|
||||
annotationWrapper.superType =
|
||||
redactionLogEntryWrapper.manualRedactionType === 'ADD'
|
||||
? 'add-dictionary'
|
||||
: 'remove-dictionary';
|
||||
redactionLogEntryWrapper.manualRedactionType === 'ADD' ? 'add-dictionary' : 'remove-dictionary';
|
||||
} else {
|
||||
annotationWrapper.superType =
|
||||
redactionLogEntryWrapper.manualRedactionType === 'ADD'
|
||||
? 'manual-redaction'
|
||||
: 'remove-only-here';
|
||||
redactionLogEntryWrapper.manualRedactionType === 'ADD' ? 'manual-redaction' : 'remove-only-here';
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!annotationWrapper.superType) {
|
||||
annotationWrapper.superType = annotationWrapper.redaction
|
||||
? 'redaction'
|
||||
: annotationWrapper.hint
|
||||
? 'hint'
|
||||
: 'skipped';
|
||||
annotationWrapper.superType = annotationWrapper.redaction ? 'redaction' : annotationWrapper.hint ? 'hint' : 'skipped';
|
||||
}
|
||||
}
|
||||
|
||||
private static _createContent(
|
||||
annotationWrapper: AnnotationWrapper,
|
||||
entry: RedactionLogEntryWrapper
|
||||
) {
|
||||
private static _createContent(annotationWrapper: AnnotationWrapper, entry: RedactionLogEntryWrapper) {
|
||||
let content = '';
|
||||
if (entry.matchedRule) {
|
||||
content += 'Rule ' + entry.matchedRule + ' matched \n\n';
|
||||
|
||||
@ -1,115 +1,131 @@
|
||||
<div *ngIf="canPerformAnnotationActions" class="annotation-actions">
|
||||
<div *ngIf="canPerformAnnotationActions" class="annotation-actions" [class.always-visible]="alwaysVisible">
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.changeLegalBasis($event, annotation, annotationsChanged)"
|
||||
(action)="annotationActionsService.changeLegalBasis($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canChangeLegalBasis"
|
||||
icon="red:edit"
|
||||
tooltip="annotation-actions.edit-reason.label"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="
|
||||
annotationActionsService.convertRecommendationToAnnotation(
|
||||
$event,
|
||||
[annotation],
|
||||
annotationsChanged
|
||||
)
|
||||
"
|
||||
(action)="annotationActionsService.convertRecommendationToAnnotation($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canAcceptRecommendation"
|
||||
icon="red:check"
|
||||
tooltip="annotation-actions.accept-recommendation.label"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="
|
||||
annotationActionsService.acceptSuggestion($event, [annotation], annotationsChanged)
|
||||
"
|
||||
(action)="annotationActionsService.acceptSuggestion($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canAcceptSuggestion"
|
||||
icon="red:check"
|
||||
tooltip="annotation-actions.accept-suggestion.label"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="
|
||||
annotationActionsService.undoDirectAction($event, [annotation], annotationsChanged)
|
||||
"
|
||||
(action)="annotationActionsService.undoDirectAction($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canUndo"
|
||||
icon="red:undo"
|
||||
tooltip="annotation-actions.undo"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="
|
||||
annotationActionsService.rejectSuggestion($event, [annotation], annotationsChanged)
|
||||
"
|
||||
(action)="annotationActionsService.rejectSuggestion($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canRejectSuggestion"
|
||||
icon="red:trash"
|
||||
tooltip="annotation-actions.reject-suggestion"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="
|
||||
annotationActionsService.recategorizeImage($event, annotation, annotationsChanged)
|
||||
"
|
||||
(action)="annotationActionsService.recategorizeImage($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canRecategorizeImage"
|
||||
icon="red:thumb-down"
|
||||
tooltip="annotation-actions.recategorize-image"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="
|
||||
annotationActionsService.markAsFalsePositive($event, [annotation], annotationsChanged)
|
||||
"
|
||||
*ngIf="
|
||||
annotationPermissions.canMarkTextOnlyAsFalsePositive &&
|
||||
!annotationPermissions.canPerformMultipleRemoveActions
|
||||
"
|
||||
(action)="annotationActionsService.markAsFalsePositive($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canMarkTextOnlyAsFalsePositive && !annotationPermissions.canPerformMultipleRemoveActions"
|
||||
icon="red:thumb-down"
|
||||
tooltip="annotation-actions.remove-annotation.false-positive"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="annotationActionsService.forceRedaction($event, [annotation], annotationsChanged)"
|
||||
(action)="annotationActionsService.forceRedaction($event, annotations, annotationsChanged)"
|
||||
*ngIf="annotationPermissions.canForceRedaction"
|
||||
icon="red:thumb-up"
|
||||
tooltip="annotation-actions.force-redaction.label"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="hideAnnotation($event)"
|
||||
*ngIf="annotation.isImage && viewerAnnotation?.isVisible()"
|
||||
*ngIf="isImage && isVisible"
|
||||
icon="red:visibility-off"
|
||||
tooltip="annotation-actions.hide"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="showAnnotation($event)"
|
||||
*ngIf="annotation.isImage && !viewerAnnotation?.isVisible()"
|
||||
*ngIf="isImage && !isVisible"
|
||||
icon="red:visibility"
|
||||
tooltip="annotation-actions.show"
|
||||
type="dark-bg"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-annotation-remove-actions
|
||||
[annotationsChanged]="annotationsChanged"
|
||||
[annotations]="[annotation]"
|
||||
></redaction-annotation-remove-actions>
|
||||
<redaction-circle-button
|
||||
(action)="suggestRemoveAnnotations($event, true)"
|
||||
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveFromDictionary"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
icon="red:remove-from-dict"
|
||||
tooltip="annotation-actions.remove-annotation.remove-from-dict"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="markAsFalsePositive($event)"
|
||||
*ngIf="annotationPermissions.canMarkAsFalsePositive"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
icon="red:thumb-down"
|
||||
tooltip="annotation-actions.remove-annotation.false-positive"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="suggestRemoveAnnotations($event, false)"
|
||||
*ngIf="annotationPermissions.canRemoveOrSuggestToRemoveOnlyHere"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
icon="red:trash"
|
||||
tooltip="annotation-actions.remove-annotation.only-here"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
</div>
|
||||
|
||||
@ -14,4 +14,8 @@
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
&.always-visible {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import { AppStateService } from '@state/app-state.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { AnnotationPermissions } from '@models/file/annotation.permissions';
|
||||
import { AnnotationActionsService } from '../../services/annotation-actions.service';
|
||||
import { Annotations, WebViewerInstance } from '@pdftron/webviewer';
|
||||
import { WebViewerInstance } from '@pdftron/webviewer';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-annotation-actions',
|
||||
@ -12,9 +12,13 @@ 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;
|
||||
@Input() alwaysVisible: boolean;
|
||||
|
||||
@Output() annotationsChanged = new EventEmitter<AnnotationWrapper>();
|
||||
|
||||
@ -26,27 +30,62 @@ export class AnnotationActionsComponent implements OnInit {
|
||||
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._setPermissions();
|
||||
}
|
||||
|
||||
get viewerAnnotations() {
|
||||
if (this.viewer?.annotManager) {
|
||||
return this._annotations.map(a => this.viewer?.annotManager?.getAnnotationById(a.id));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
<redaction-circle-button
|
||||
(action)="suggestRemoveAnnotations($event, true)"
|
||||
*ngIf="permissions.canRemoveOrSuggestToRemoveFromDictionary"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
icon="red:remove-from-dict"
|
||||
tooltip="annotation-actions.remove-annotation.remove-from-dict"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="markAsFalsePositive($event)"
|
||||
*ngIf="permissions.canMarkAsFalsePositive"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
icon="red:thumb-down"
|
||||
tooltip="annotation-actions.remove-annotation.false-positive"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="suggestRemoveAnnotations($event, false)"
|
||||
*ngIf="permissions.canRemoveOrSuggestToRemoveOnlyHere"
|
||||
[tooltipPosition]="tooltipPosition"
|
||||
[type]="btnType"
|
||||
icon="red:trash"
|
||||
tooltip="annotation-actions.remove-annotation.only-here"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
@ -1,7 +0,0 @@
|
||||
:host {
|
||||
display: flex;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
@ -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<boolean>();
|
||||
@Input() annotationsChanged: EventEmitter<AnnotationWrapper>;
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,4 @@
|
||||
<div
|
||||
*ngIf="!excludePages"
|
||||
class="right-title heading"
|
||||
translate="file-preview.tabs.annotations.label"
|
||||
>
|
||||
<div *ngIf="!excludePages" class="right-title heading" translate="file-preview.tabs.annotations.label">
|
||||
<div>
|
||||
<div
|
||||
(click)="multiSelectActive = true"
|
||||
@ -20,11 +16,7 @@
|
||||
></redaction-popup-filter>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="excludePages"
|
||||
class="right-title heading"
|
||||
translate="file-preview.tabs.exclude-pages.label"
|
||||
>
|
||||
<div *ngIf="excludePages" class="right-title heading" translate="file-preview.tabs.exclude-pages.label">
|
||||
<div>
|
||||
<redaction-circle-button
|
||||
(action)="actionPerformed.emit('view-exclude-pages')"
|
||||
@ -53,19 +45,18 @@
|
||||
type="red-bg"
|
||||
></redaction-round-checkbox>
|
||||
<span class="all-caps-label">{{ selectedAnnotations?.length || 0 }} selected </span>
|
||||
<redaction-annotation-remove-actions
|
||||
<redaction-annotation-actions
|
||||
*ngIf="selectedAnnotations?.length > 0"
|
||||
[annotationsChanged]="annotationsChanged"
|
||||
(annotationsChanged)="annotationsChanged.emit($event)"
|
||||
[canPerformAnnotationActions]="!isReadOnly"
|
||||
[annotations]="selectedAnnotations"
|
||||
[viewer]="viewer"
|
||||
[alwaysVisible]="true"
|
||||
btnType="primary"
|
||||
tooltipPosition="above"
|
||||
></redaction-annotation-remove-actions>
|
||||
></redaction-annotation-actions>
|
||||
</div>
|
||||
<redaction-circle-button
|
||||
(action)="multiSelectActive = false"
|
||||
icon="red:close"
|
||||
type="primary"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button (action)="multiSelectActive = false" icon="red:close" type="primary"></redaction-circle-button>
|
||||
</div>
|
||||
<div [class.lower-height]="multiSelectActive || isReadOnly" class="annotations-wrapper">
|
||||
<div
|
||||
@ -112,11 +103,7 @@
|
||||
<span *ngIf="!!activeViewerPage" class="all-caps-label">
|
||||
<span translate="page"></span> {{ activeViewerPage }} -
|
||||
{{ activeAnnotationsLength || 0 }}
|
||||
<span
|
||||
[translate]="
|
||||
activeAnnotationsLength === 1 ? 'annotation' : 'annotations'
|
||||
"
|
||||
></span>
|
||||
<span [translate]="activeAnnotationsLength === 1 ? 'annotation' : 'annotations'"></span>
|
||||
</span>
|
||||
|
||||
<div *ngIf="multiSelectActive">
|
||||
@ -142,25 +129,11 @@
|
||||
redactionHasScrollbar
|
||||
tabindex="1"
|
||||
>
|
||||
<ng-container
|
||||
*ngIf="activeViewerPage && !displayedAnnotations[activeViewerPage]"
|
||||
>
|
||||
<redaction-empty-state
|
||||
[horizontalPadding]="24"
|
||||
[verticalPadding]="40"
|
||||
icon="red:document"
|
||||
screen="file-preview"
|
||||
>
|
||||
<ng-container
|
||||
*ngIf="
|
||||
fileData?.fileStatus?.excludedPages?.includes(activeViewerPage)
|
||||
"
|
||||
>
|
||||
<ng-container *ngIf="activeViewerPage && !displayedAnnotations[activeViewerPage]">
|
||||
<redaction-empty-state [horizontalPadding]="24" [verticalPadding]="40" icon="red:document" screen="file-preview">
|
||||
<ng-container *ngIf="fileData?.fileStatus?.excludedPages?.includes(activeViewerPage)">
|
||||
{{ 'file-preview.tabs.annotations.page-is' | translate }}
|
||||
<a
|
||||
(click)="actionPerformed.emit('view-exclude-pages')"
|
||||
translate="file-preview.excluded-from-redaction"
|
||||
>
|
||||
<a (click)="actionPerformed.emit('view-exclude-pages')" translate="file-preview.excluded-from-redaction">
|
||||
</a
|
||||
>.
|
||||
</ng-container>
|
||||
@ -175,9 +148,7 @@
|
||||
></redaction-icon-button>
|
||||
<redaction-icon-button
|
||||
(action)="jumpToNextWithAnnotations()"
|
||||
[disabled]="
|
||||
activeViewerPage >= displayedPages[displayedPages.length - 1]
|
||||
"
|
||||
[disabled]="activeViewerPage >= displayedPages[displayedPages.length - 1]"
|
||||
class="mt-8"
|
||||
icon="red:nav-next"
|
||||
text="file-preview.tabs.annotations.jump-to-next"
|
||||
@ -188,9 +159,7 @@
|
||||
|
||||
<div
|
||||
(click)="annotationClicked(annotation, $event)"
|
||||
*ngFor="
|
||||
let annotation of displayedAnnotations[activeViewerPage]?.annotations
|
||||
"
|
||||
*ngFor="let annotation of displayedAnnotations[activeViewerPage]?.annotations"
|
||||
[class.active]="isSelected(annotation)"
|
||||
[class.multi-select-active]="multiSelectActive"
|
||||
attr.annotation-id="{{ annotation.id }}"
|
||||
@ -199,18 +168,9 @@
|
||||
>
|
||||
<div class="active-bar-marker"></div>
|
||||
<div [class.removed]="annotation.isChangeLogRemoved" class="annotation">
|
||||
<redaction-hidden-action
|
||||
(action)="logAnnotation(annotation)"
|
||||
[requiredClicks]="2"
|
||||
>
|
||||
<div
|
||||
[matTooltip]="annotation.content"
|
||||
class="details"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<redaction-type-annotation-icon
|
||||
[annotation]="annotation"
|
||||
></redaction-type-annotation-icon>
|
||||
<redaction-hidden-action (action)="logAnnotation(annotation)" [requiredClicks]="2">
|
||||
<div [matTooltip]="annotation.content" class="details" matTooltipPosition="above">
|
||||
<redaction-type-annotation-icon [annotation]="annotation"></redaction-type-annotation-icon>
|
||||
<div class="flex-1">
|
||||
<div>
|
||||
<strong>{{ annotation.typeLabel | translate }}</strong>
|
||||
@ -222,8 +182,7 @@
|
||||
>{{ annotation.dictionary | humanize: false }}
|
||||
</div>
|
||||
<div *ngIf="annotation.shortContent && !annotation.isHint">
|
||||
<strong><span translate="content"></span>: </strong
|
||||
>{{ annotation.shortContent }}
|
||||
<strong><span translate="content"></span>: </strong>{{ annotation.shortContent }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -269,14 +228,9 @@
|
||||
</div>
|
||||
|
||||
<ng-template #annotationFilterTemplate let-filter="filter">
|
||||
<redaction-type-filter
|
||||
*ngIf="_(filter).topLevelFilter"
|
||||
[filter]="filter"
|
||||
></redaction-type-filter>
|
||||
<redaction-type-filter *ngIf="_(filter).topLevelFilter" [filter]="filter"></redaction-type-filter>
|
||||
<ng-container *ngIf="!_(filter).topLevelFilter">
|
||||
<redaction-dictionary-annotation-icon
|
||||
[dictionaryKey]="filter.key"
|
||||
></redaction-dictionary-annotation-icon>
|
||||
<redaction-dictionary-annotation-icon [dictionaryKey]="filter.key"></redaction-dictionary-annotation-icon>
|
||||
{{ filter.key | humanize: false }}
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
|
||||
@ -21,6 +21,7 @@ import { FilterModel } from '@shared/components/filters/popup-filter/model/filte
|
||||
import { CommentsComponent } from '../comments/comments.component';
|
||||
import { PermissionsService } from '../../../../services/permissions.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { WebViewerInstance } from '@pdftron/webviewer';
|
||||
|
||||
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
|
||||
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
||||
@ -42,10 +43,9 @@ export class FileWorkloadComponent {
|
||||
@Input() hideSkipped: boolean;
|
||||
@Input() excludePages: boolean;
|
||||
@Input() annotationActionsTemplate: TemplateRef<any>;
|
||||
@Input() viewer: WebViewerInstance;
|
||||
@Output() shouldDeselectAnnotationsOnPageChangeChange = new EventEmitter<boolean>();
|
||||
@Output() selectAnnotations = new EventEmitter<
|
||||
AnnotationWrapper[] | { annotations: AnnotationWrapper[]; multiSelect: boolean }
|
||||
>();
|
||||
@Output() selectAnnotations = new EventEmitter<AnnotationWrapper[] | { annotations: AnnotationWrapper[]; multiSelect: boolean }>();
|
||||
@Output() deselectAnnotations = new EventEmitter<AnnotationWrapper[]>();
|
||||
@Output() selectPage = new EventEmitter<number>();
|
||||
@Output() toggleSkipped = new EventEmitter<any>();
|
||||
@ -103,10 +103,7 @@ export class FileWorkloadComponent {
|
||||
return this.selectedAnnotations?.length ? this.selectedAnnotations[0] : null;
|
||||
}
|
||||
|
||||
private static _scrollToFirstElement(
|
||||
elements: HTMLElement[],
|
||||
mode: 'always' | 'if-needed' = 'if-needed'
|
||||
) {
|
||||
private static _scrollToFirstElement(elements: HTMLElement[], mode: 'always' | 'if-needed' = 'if-needed') {
|
||||
if (elements.length > 0) {
|
||||
scrollIntoView(elements[0], {
|
||||
behavior: 'smooth',
|
||||
@ -128,9 +125,7 @@ export class FileWorkloadComponent {
|
||||
|
||||
toggleExpandComments(annotation: AnnotationWrapper, $event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this.annotationCommentsComponents
|
||||
.find(c => c.annotation === annotation)
|
||||
.toggleExpandComments();
|
||||
this.annotationCommentsComponents.find(c => c.annotation === annotation).toggleExpandComments();
|
||||
}
|
||||
|
||||
logAnnotation(annotation: AnnotationWrapper) {
|
||||
@ -138,9 +133,7 @@ export class FileWorkloadComponent {
|
||||
}
|
||||
|
||||
pageHasSelection(page: number) {
|
||||
return (
|
||||
this.multiSelectActive && !!this.selectedAnnotations?.find(a => a.pageNumber === page)
|
||||
);
|
||||
return this.multiSelectActive && !!this.selectedAnnotations?.find(a => a.pageNumber === page);
|
||||
}
|
||||
|
||||
selectAllOnActivePage() {
|
||||
@ -227,20 +220,14 @@ export class FileWorkloadComponent {
|
||||
|
||||
scrollAnnotationsToPage(page: number, mode: 'always' | 'if-needed' = 'if-needed') {
|
||||
if (this._annotationsElement) {
|
||||
const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(
|
||||
`div[anotation-page-header="${page}"]`
|
||||
);
|
||||
const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[anotation-page-header="${page}"]`);
|
||||
FileWorkloadComponent._scrollToFirstElement(elements, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@debounce()
|
||||
scrollToSelectedAnnotation() {
|
||||
if (
|
||||
!this.selectedAnnotations ||
|
||||
this.selectedAnnotations.length === 0 ||
|
||||
!this._annotationsElement
|
||||
) {
|
||||
if (!this.selectedAnnotations || this.selectedAnnotations.length === 0 || !this._annotationsElement) {
|
||||
return;
|
||||
}
|
||||
const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(
|
||||
@ -251,10 +238,7 @@ export class FileWorkloadComponent {
|
||||
|
||||
scrollQuickNavigation() {
|
||||
let quickNavPageIndex = this.displayedPages.findIndex(p => p >= this.activeViewerPage);
|
||||
if (
|
||||
quickNavPageIndex === -1 ||
|
||||
this.displayedPages[quickNavPageIndex] !== this.activeViewerPage
|
||||
) {
|
||||
if (quickNavPageIndex === -1 || this.displayedPages[quickNavPageIndex] !== this.activeViewerPage) {
|
||||
quickNavPageIndex = Math.max(0, quickNavPageIndex - 1);
|
||||
}
|
||||
this._scrollQuickNavigationToPage(this.displayedPages[quickNavPageIndex]);
|
||||
@ -274,10 +258,7 @@ export class FileWorkloadComponent {
|
||||
}
|
||||
|
||||
preventKeyDefault($event: KeyboardEvent) {
|
||||
if (
|
||||
COMMAND_KEY_ARRAY.includes($event.key) &&
|
||||
!(($event.target as any).localName === 'input')
|
||||
) {
|
||||
if (COMMAND_KEY_ARRAY.includes($event.key) && !(($event.target as any).localName === 'input')) {
|
||||
$event.preventDefault();
|
||||
}
|
||||
}
|
||||
@ -296,26 +277,18 @@ export class FileWorkloadComponent {
|
||||
|
||||
private _selectFirstAnnotationOnCurrentPageIfNecessary() {
|
||||
if (
|
||||
(!this._firstSelectedAnnotation ||
|
||||
this.activeViewerPage !== this._firstSelectedAnnotation.pageNumber) &&
|
||||
(!this._firstSelectedAnnotation || this.activeViewerPage !== this._firstSelectedAnnotation.pageNumber) &&
|
||||
this.displayedPages.indexOf(this.activeViewerPage) >= 0
|
||||
) {
|
||||
this.selectAnnotations.emit([
|
||||
this.displayedAnnotations[this.activeViewerPage].annotations[0]
|
||||
]);
|
||||
this.selectAnnotations.emit([this.displayedAnnotations[this.activeViewerPage].annotations[0]]);
|
||||
}
|
||||
}
|
||||
|
||||
private _navigateAnnotations($event: KeyboardEvent) {
|
||||
if (
|
||||
!this._firstSelectedAnnotation ||
|
||||
this.activeViewerPage !== this._firstSelectedAnnotation.pageNumber
|
||||
) {
|
||||
if (!this._firstSelectedAnnotation || this.activeViewerPage !== this._firstSelectedAnnotation.pageNumber) {
|
||||
if (this.displayedPages.indexOf(this.activeViewerPage) !== -1) {
|
||||
// Displayed page has annotations
|
||||
return this.selectAnnotations.emit([
|
||||
this.displayedAnnotations[this.activeViewerPage].annotations[0]
|
||||
]);
|
||||
return this.selectAnnotations.emit([this.displayedAnnotations[this.activeViewerPage].annotations[0]]);
|
||||
}
|
||||
// Displayed page doesn't have annotations
|
||||
if ($event.key === 'ArrowDown') {
|
||||
@ -345,8 +318,7 @@ export class FileWorkloadComponent {
|
||||
this.selectAnnotations.emit([annotationsOnPage[idx + 1]]);
|
||||
} else if (pageIdx + 1 < this.displayedPages.length) {
|
||||
// If not last page
|
||||
const nextPageAnnotations =
|
||||
this.displayedAnnotations[this.displayedPages[pageIdx + 1]].annotations;
|
||||
const nextPageAnnotations = this.displayedAnnotations[this.displayedPages[pageIdx + 1]].annotations;
|
||||
this.shouldDeselectAnnotationsOnPageChange = false;
|
||||
this.shouldDeselectAnnotationsOnPageChangeChange.emit(false);
|
||||
this.selectAnnotations.emit([nextPageAnnotations[0]]);
|
||||
@ -356,8 +328,7 @@ export class FileWorkloadComponent {
|
||||
this.selectAnnotations.emit([annotationsOnPage[idx - 1]]);
|
||||
} else if (pageIdx) {
|
||||
// If not first page
|
||||
const prevPageAnnotations =
|
||||
this.displayedAnnotations[this.displayedPages[pageIdx - 1]].annotations;
|
||||
const prevPageAnnotations = this.displayedAnnotations[this.displayedPages[pageIdx - 1]].annotations;
|
||||
this.shouldDeselectAnnotationsOnPageChange = false;
|
||||
this.shouldDeselectAnnotationsOnPageChangeChange.emit(false);
|
||||
this.selectAnnotations.emit([prevPageAnnotations[prevPageAnnotations.length - 1]]);
|
||||
@ -421,9 +392,7 @@ export class FileWorkloadComponent {
|
||||
|
||||
private _scrollQuickNavigationToPage(page: number) {
|
||||
if (this._quickNavigationElement) {
|
||||
const elements: any[] = this._quickNavigationElement.nativeElement.querySelectorAll(
|
||||
`#quick-nav-page-${page}`
|
||||
);
|
||||
const elements: any[] = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${page}`);
|
||||
FileWorkloadComponent._scrollToFirstElement(elements);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,11 +30,13 @@ export class ChangeLegalBasisDialogComponent implements OnInit {
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
public dialogRef: MatDialogRef<ChangeLegalBasisDialogComponent>,
|
||||
@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
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@ -18,18 +18,18 @@ export class RecategorizeImageDialogComponent implements OnInit {
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
public dialogRef: MatDialogRef<RecategorizeImageDialogComponent>,
|
||||
@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]
|
||||
});
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -32,8 +32,7 @@
|
||||
<div *ngIf="viewReady" class="flex-1 actions-container">
|
||||
<ng-container *ngIf="!appStateService.activeFile.isExcluded">
|
||||
<ng-container *ngIf="!appStateService.activeFile.isProcessing">
|
||||
<redaction-status-bar [config]="statusBarConfig" [small]="true">
|
||||
</redaction-status-bar>
|
||||
<redaction-status-bar [config]="statusBarConfig" [small]="true"> </redaction-status-bar>
|
||||
|
||||
<div class="all-caps-label mr-16 ml-8">
|
||||
{{ status | translate }}
|
||||
@ -84,10 +83,7 @@
|
||||
<ng-container *ngIf="permissionsService.isApprover() && !!lastReviewer">
|
||||
<div class="vertical-line"></div>
|
||||
<div class="all-caps-label mr-16 ml-8" translate="file-preview.last-reviewer"></div>
|
||||
<redaction-initials-avatar
|
||||
[userId]="lastReviewer"
|
||||
[withName]="true"
|
||||
></redaction-initials-avatar>
|
||||
<redaction-initials-avatar [userId]="lastReviewer" [withName]="true"></redaction-initials-avatar>
|
||||
</ng-container>
|
||||
<div class="vertical-line"></div>
|
||||
|
||||
@ -153,12 +149,7 @@
|
||||
|
||||
<div class="right-container">
|
||||
<redaction-empty-state
|
||||
*ngIf="
|
||||
viewReady &&
|
||||
appStateService.activeFile.isExcluded &&
|
||||
!viewDocumentInfo &&
|
||||
!excludePages
|
||||
"
|
||||
*ngIf="viewReady && appStateService.activeFile.isExcluded && !viewDocumentInfo && !excludePages"
|
||||
[horizontalPadding]="40"
|
||||
icon="red:needs-work"
|
||||
text="file-preview.tabs.is-excluded"
|
||||
@ -186,6 +177,7 @@
|
||||
[dialogRef]="dialogRef"
|
||||
[excludePages]="excludePages"
|
||||
[fileData]="fileData"
|
||||
[viewer]="activeViewer"
|
||||
[hideSkipped]="hideSkipped"
|
||||
[primaryFilters]="primaryFilters"
|
||||
[secondaryFilters]="secondaryFilters"
|
||||
@ -195,13 +187,12 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<redaction-full-page-loading-indicator [displayed]="!viewReady">
|
||||
</redaction-full-page-loading-indicator>
|
||||
<redaction-full-page-loading-indicator [displayed]="!viewReady"> </redaction-full-page-loading-indicator>
|
||||
|
||||
<ng-template #annotationActionsTemplate let-annotation="annotation">
|
||||
<redaction-annotation-actions
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
[annotation]="annotation"
|
||||
[annotations]="[annotation]"
|
||||
[canPerformAnnotationActions]="canPerformAnnotationActions"
|
||||
[viewer]="activeViewer"
|
||||
></redaction-annotation-actions>
|
||||
|
||||
@ -76,22 +76,24 @@ export class AnnotationActionsService {
|
||||
|
||||
changeLegalBasis(
|
||||
$event: MouseEvent,
|
||||
annotation: AnnotationWrapper,
|
||||
annotations: AnnotationWrapper[],
|
||||
annotationsChanged: EventEmitter<AnnotationWrapper>
|
||||
) {
|
||||
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<AnnotationWrapper>
|
||||
) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -150,13 +150,13 @@ export class DossiersDialogService extends DialogService<DialogType> {
|
||||
|
||||
openChangeLegalBasisDialog(
|
||||
$event: MouseEvent,
|
||||
annotation: AnnotationWrapper,
|
||||
annotations: AnnotationWrapper[],
|
||||
cb?: Function
|
||||
): MatDialogRef<ChangeLegalBasisDialogComponent> {
|
||||
$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<DialogType> {
|
||||
|
||||
openRecategorizeImageDialog(
|
||||
$event: MouseEvent,
|
||||
annotation: AnnotationWrapper,
|
||||
annotations: AnnotationWrapper[],
|
||||
cb?: Function
|
||||
): MatDialogRef<RecategorizeImageDialogComponent> {
|
||||
$event?.stopPropagation();
|
||||
const ref = this._dialog.open(RecategorizeImageDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: annotation
|
||||
data: annotations
|
||||
});
|
||||
ref.afterClosed().subscribe(async result => {
|
||||
if (result && cb) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"OAUTH_URL": "https://red-staging.iqser.cloud/auth/realms/redaction",
|
||||
"API_URL": "https://red-staging.iqser.cloud/redaction-gateway-v1",
|
||||
"OAUTH_URL": "https://dev-06.iqser.cloud/auth/realms/redaction",
|
||||
"API_URL": "https://dev-06.iqser.cloud/redaction-gateway-v1",
|
||||
"OAUTH_CLIENT_ID": "redaction",
|
||||
"BACKEND_APP_VERSION": "4.4.40",
|
||||
"FRONTEND_APP_VERSION": "1.1",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user