From 63c8a496860bf97f708b9a8d8e8d8f5a3b8bd379 Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Fri, 2 Dec 2022 18:50:52 +0200 Subject: [PATCH] RED-5401 - convert remove suggestions to redactions for preview mode in case "display suggestions" option is disabled in preferences --- .../file-workload/file-workload.component.ts | 6 +-- .../file-preview-screen.component.ts | 11 ++-- .../file-preview/file-preview.module.ts | 3 +- .../services/file-data.service.ts | 22 +++++++- .../services/suggestions.service.ts | 52 +++++++++++++++++++ .../services/annotation-draw.service.ts | 8 +-- 6 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 apps/red-ui/src/app/modules/file-preview/services/suggestions.service.ts diff --git a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts index a39aaed3e..29be6a15d 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/file-workload/file-workload.component.ts @@ -41,6 +41,7 @@ import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-ma import { AnnotationsListingService } from '../../services/annotations-listing.service'; import { REDDocumentViewer } from '../../../pdf-viewer/services/document-viewer.service'; import { UserPreferenceService } from '@users/user-preference.service'; +import { SuggestionsService } from '../../services/suggestions.service'; const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape']; const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; @@ -87,6 +88,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy private readonly _annotationProcessingService: AnnotationProcessingService, private readonly _viewModeService: ViewModeService, private readonly _userPreferencesService: UserPreferenceService, + private readonly _suggestionsService: SuggestionsService, ) { super(); @@ -386,9 +388,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy if (this._viewModeService.isRedacted) { annotations = annotations.filter(a => !bool(a.isChangeLogRemoved)); - if (!this._userPreferencesService.getDisplaySuggestionsInPreview()) { - annotations = annotations.filter(a => !a.isSuggestion); - } + annotations = this._suggestionsService.convertWorkloadRemoveSuggestionsToRedactions(annotations); } this.displayedAnnotations = this._annotationProcessingService.filterAndGroupAnnotations(annotations, primary, secondary); diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts index 80e5577f9..1285ff101 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview-screen.component.ts @@ -71,6 +71,7 @@ import { ConfigService } from '@services/config.service'; import { ReadableRedactionsService } from '../pdf-viewer/services/readable-redactions.service'; import { ROLES } from '@users/roles'; import Annotation = Core.Annotations.Annotation; +import { SuggestionsService } from './services/suggestions.service'; const textActions = [TextPopups.ADD_DICTIONARY, TextPopups.ADD_FALSE_POSITIVE]; @@ -137,6 +138,7 @@ export class FilePreviewScreenComponent private readonly _fileManagementService: FileManagementService, private readonly _readableRedactionsService: ReadableRedactionsService, private readonly _helpModeService: HelpModeService, + private readonly _suggestionsService: SuggestionsService, ) { super(); document.documentElement.addEventListener('fullscreenchange', () => { @@ -256,7 +258,7 @@ export class FilePreviewScreenComponent this._annotationManager.show(redactions); this._annotationManager.hide(nonRedactionEntries); - await this.#hideSuggestions(redactions); + this._suggestionsService.hideSuggestionsInPreview(redactions); break; } @@ -756,11 +758,4 @@ export class FilePreviewScreenComponent const annotations = this._annotationManager.get(selected); this._annotationManager.select(annotations); } - - async #hideSuggestions(redactions: Annotation[]): Promise { - if (!this.userPreferenceService.getDisplaySuggestionsInPreview()) { - const currentPageSuggestions = redactions.filter(a => bool(a.getCustomData('suggestion'))); - this._annotationManager.hide(currentPageSuggestions); - } - } } diff --git a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts index 2b5e148c3..792a0cb22 100644 --- a/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts +++ b/apps/red-ui/src/app/modules/file-preview/file-preview.module.ts @@ -53,6 +53,7 @@ import { DocumentUnloadedGuard } from './services/document-unloaded.guard'; import { FilePreviewRightContainerComponent } from './components/right-container/file-preview-right-container.component'; import { RssDialogComponent } from './dialogs/rss-dialog/rss-dialog.component'; import { ReadonlyBannerComponent } from './components/readonly-banner/readonly-banner.component'; +import { SuggestionsService } from './services/suggestions.service'; const routes: Routes = [ { @@ -122,6 +123,6 @@ const components = [ IqserScrollbarModule, IqserPermissionsModule, ], - providers: [FilePreviewDialogService, ManualRedactionService, DocumentUnloadedGuard], + providers: [FilePreviewDialogService, ManualRedactionService, DocumentUnloadedGuard, SuggestionsService], }) export class FilePreviewModule {} diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts index 984735983..0bc2609ae 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-data.service.ts @@ -1,4 +1,4 @@ -import { ChangeType, File, IRedactionLog, IRedactionLogEntry, IViewedPage, ViewMode, ViewModes } from '@red/domain'; +import { ChangeType, File, IRedactionLog, IRedactionLogEntry, IViewedPage, ManualRedactionType, ViewMode, ViewModes } from '@red/domain'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { BehaviorSubject, firstValueFrom, iif, Observable, Subject } from 'rxjs'; import { RedactionLogEntry } from '@models/file/redaction-log.entry'; @@ -19,6 +19,7 @@ import { MultiSelectService } from './multi-select.service'; import { FilesService } from '@services/files/files.service'; import { DefaultColorsService } from '@services/entity-services/default-colors.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; +import { SuggestionsService } from './suggestions.service'; const DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes; @@ -42,6 +43,7 @@ export class FileDataService extends EntitiesService this.#buildRemovedRedactions(redactionLog, file)), switchMap(([redactionLog, file]) => this.#buildAnnotations(redactionLog, file)), tap(() => this.#checkMissingTypes()), map(annotations => @@ -175,6 +178,23 @@ export class FileDataService extends EntitiesService ann.manual || !file.excludedPages.includes(ann.pageNumber)); } + async #buildRemovedRedactions(redactionLog: IRedactionLog, file: File): Promise { + const redactionLogCopy = JSON.parse(JSON.stringify(redactionLog)); + redactionLogCopy.redactionLogEntry = redactionLogCopy.redactionLogEntry.reduce((filtered, entry) => { + const isRemoveChange = entry.manualChanges.find(c => this.#isRemoveChange(c.manualRedactionType)); + if (isRemoveChange) { + entry.manualChanges = entry.manualChanges.filter(c => !this.#isRemoveChange(c.manualRedactionType)); + filtered.push(entry); + } + return filtered; + }, []); + this._suggestionsService.removedRedactions = await this.#buildAnnotations(redactionLogCopy, file); + } + + #isRemoveChange(type: ManualRedactionType) { + return type === 'REMOVE_LOCALLY' || type === 'REMOVE_FROM_DICTIONARY'; + } + async #convertData(redactionLog: IRedactionLog, file: File) { const result: RedactionLogEntry[] = []; const sourceIdAnnotationIds: { [key: string]: RedactionLogEntry[] } = {}; diff --git a/apps/red-ui/src/app/modules/file-preview/services/suggestions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/suggestions.service.ts new file mode 100644 index 000000000..988f22ca0 --- /dev/null +++ b/apps/red-ui/src/app/modules/file-preview/services/suggestions.service.ts @@ -0,0 +1,52 @@ +import { Injectable } from '@angular/core'; +import { AnnotationWrapper } from '@models/file/annotation.wrapper'; +import { bool } from '@iqser/common-ui'; +import { Core } from '@pdftron/webviewer'; +import Annotation = Core.Annotations.Annotation; +import { REDAnnotationManager } from '../../pdf-viewer/services/annotation-manager.service'; +import { UserPreferenceService } from '@users/user-preference.service'; +import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service'; + +@Injectable() +export class SuggestionsService { + #removedRedactions: AnnotationWrapper[] = []; + + constructor( + private readonly _annotationManager: REDAnnotationManager, + private readonly _userPreferenceService: UserPreferenceService, + private readonly _annotationDrawService: AnnotationDrawService, + ) {} + + set removedRedactions(removedRedactions: AnnotationWrapper[]) { + this.#removedRedactions = removedRedactions; + } + + hideSuggestionsInPreview(annotations: Annotation[]): void { + if (!this._userPreferenceService.getDisplaySuggestionsInPreview()) { + const suggestions = annotations.filter(a => bool(a.getCustomData('suggestion'))); + this._annotationManager.hide(suggestions); + this.#convertRemoveSuggestionsToRedactions(suggestions); + } + } + + convertWorkloadRemoveSuggestionsToRedactions(annotations: AnnotationWrapper[]): AnnotationWrapper[] { + if (!this._userPreferenceService.getDisplaySuggestionsInPreview()) { + annotations = annotations.filter(a => !a.isSuggestion); + annotations = [...annotations, ...this.#removedRedactions]; + } + return annotations; + } + + #convertRemoveSuggestionsToRedactions(suggestions: Annotation[]): void { + const removeSuggestions = suggestions.filter(a => bool(a.getCustomData('suggestionRemove'))); + + removeSuggestions.forEach(suggestion => { + const color = this._annotationDrawService.convertColor(suggestion.getCustomData('redactionColor')); + suggestion['Opacity'] = 1; + suggestion['StrokeColor'] = color; + suggestion['FillColor'] = color; + }); + + this._annotationManager.show(removeSuggestions); + } +} diff --git a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts index aee2b013f..0cd30eccc 100644 --- a/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts +++ b/apps/red-ui/src/app/modules/pdf-viewer/services/annotation-draw.service.ts @@ -153,14 +153,16 @@ export class AnnotationDrawService { annotation.setCustomData('redact-manager', 'true'); annotation.setCustomData('redaction', String(annotationWrapper.previewAnnotation)); annotation.setCustomData('suggestion', String(annotationWrapper.isSuggestion)); + annotation.setCustomData('suggestionRemove', String(annotationWrapper.isSuggestionRemove)); annotation.setCustomData('skipped', String(annotationWrapper.isSkipped)); annotation.setCustomData('changeLog', String(annotationWrapper.isChangeLogEntry)); annotation.setCustomData('changeLogRemoved', String(annotationWrapper.isChangeLogRemoved)); annotation.setCustomData('opacity', String(annotation.Opacity)); - const redactionColor = annotationWrapper.isSuggestion - ? this._defaultColorsService.getColor(dossierTemplateId, 'requestAddColor') - : this._defaultColorsService.getColor(dossierTemplateId, 'previewColor'); + const redactionColor = + annotationWrapper.isSuggestion && this._userPreferenceService.getDisplaySuggestionsInPreview() + ? this._defaultColorsService.getColor(dossierTemplateId, 'requestAddColor') + : this._defaultColorsService.getColor(dossierTemplateId, 'previewColor'); annotation.setCustomData('redactionColor', String(redactionColor)); annotation.setCustomData('annotationColor', String(annotationWrapper.color));