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/models/file/annotation.wrapper.ts b/apps/red-ui/src/app/models/file/annotation.wrapper.ts index 46d25d634..268c5efa5 100644 --- a/apps/red-ui/src/app/models/file/annotation.wrapper.ts +++ b/apps/red-ui/src/app/models/file/annotation.wrapper.ts @@ -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'; 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..87ec5e4cf 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,115 +1,131 @@ -
+
- + + + + + + + +
diff --git a/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.scss b/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.scss index c7dfd10cf..a9168e3ac 100644 --- a/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.scss +++ b/apps/red-ui/src/app/modules/dossier/components/annotation-actions/annotation-actions.component.scss @@ -14,4 +14,8 @@ > *:not(:last-child) { margin-right: 2px; } + + &.always-visible { + display: flex; + } } 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..790c99fbe 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 @@ -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(); @@ -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 + ); + } } 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..29cd7505d 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 @@ -1,8 +1,4 @@ -
+
-
+
{{ selectedAnnotations?.length || 0 }} selected - + >
- +
{{ activeViewerPage }} - {{ activeAnnotationsLength || 0 }} - +
@@ -142,25 +129,11 @@ redactionHasScrollbar tabindex="1" > - - - + + + {{ 'file-preview.tabs.annotations.page-is' | translate }} - + . @@ -175,9 +148,7 @@ >
- -
- + +
+
{{ annotation.typeLabel | translate }} @@ -222,8 +182,7 @@ >{{ annotation.dictionary | humanize: false }}
- : {{ annotation.shortContent }} + : {{ annotation.shortContent }}
@@ -269,14 +228,9 @@
- + - + {{ filter.key | humanize: false }} diff --git a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts index 1603de47d..a90d7dac6 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.ts @@ -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; + @Input() viewer: WebViewerInstance; @Output() shouldDeselectAnnotationsOnPageChangeChange = new EventEmitter(); - @Output() selectAnnotations = new EventEmitter< - AnnotationWrapper[] | { annotations: AnnotationWrapper[]; multiSelect: boolean } - >(); + @Output() selectAnnotations = new EventEmitter(); @Output() deselectAnnotations = new EventEmitter(); @Output() selectPage = new EventEmitter(); @Output() toggleSkipped = new EventEmitter(); @@ -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); } } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts index 5a62738d6..2c6d72c7e 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component.ts @@ -30,11 +30,13 @@ export class ChangeLegalBasisDialogComponent 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.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..f00f3a050 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 @@ -32,8 +32,7 @@
- - +
{{ status | translate }} @@ -84,10 +83,7 @@
- +
@@ -153,12 +149,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) { diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index 4b001a0b1..6cfc820ed 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -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",