diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html index 8e2cb6aee..bac1fd33f 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.html @@ -29,34 +29,34 @@ + + + + + + @@ -129,10 +156,10 @@ @@ -148,34 +175,34 @@ diff --git a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts index 57b5a5910..91ab897ec 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/annotation-actions/annotation-actions.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { PermissionsService } from '@services/permissions.service'; import { AnnotationPermissions } from '@models/file/annotation.permissions'; @@ -11,6 +11,7 @@ import { HelpModeService, ScrollableParentView, ScrollableParentViews } from '@i import { PdfViewer } from '../../services/pdf-viewer.service'; import { FileDataService } from '../../services/file-data.service'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; +import { ViewModeService } from '../../services/view-mode.service'; export const AnnotationButtonTypes = { dark: 'dark', @@ -34,9 +35,11 @@ export class AnnotationActionsComponent implements OnChanges { constructor( readonly multiSelectService: MultiSelectService, + readonly viewModeService: ViewModeService, readonly annotationActionsService: AnnotationActionsService, readonly annotationReferencesService: AnnotationReferencesService, readonly helpModeService: HelpModeService, + private readonly _changeRef: ChangeDetectorRef, private readonly _userService: UserService, private readonly _pdf: PdfViewer, private readonly _state: FilePreviewStateService, @@ -52,8 +55,8 @@ export class AnnotationActionsComponent implements OnChanges { } @Input() - set annotations(value: AnnotationWrapper[]) { - this._annotations = value.filter(a => a !== undefined); + set annotations(annotations: AnnotationWrapper[]) { + this._annotations = annotations.filter(a => a !== undefined); } get viewerAnnotations() { @@ -86,6 +89,7 @@ export class AnnotationActionsComponent implements OnChanges { async ngOnChanges(): Promise { await this._setPermissions(); + this._changeRef.markForCheck(); } removeOrSuggestRemoveAnnotation($event: MouseEvent, removeFromDict: boolean) { diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html index 8f2ec9122..3fa4d9473 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.html @@ -5,24 +5,34 @@
-
- - -
-
+ +
+ + +
+
-
- - - {{ translations[option] | translate }} - - -
+
+ + + {{ translations[option] | translate }} + + +
+
+ + +
+ + {{ translations[data.operation].confirmation | translate: { count: data.highlights.length } }} + +
+
diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts index 6fcf33d99..ec26760b3 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/highlight-action-dialog/highlight-action-dialog.component.ts @@ -39,11 +39,14 @@ export class HighlightActionDialogComponent extends BaseDialogComponent { async save(): Promise { this._loadingService.start(); - const { dossierId, fileId, operation, highlights, pageNumber } = this.data; + const { dossierId, fileId, operation, highlights, pageNumber, color } = this.data; + + // !color means we are in bulk select mode, so we don't need to apply additional page filters const filteredHighlights = - this.form.get('option').value === TextHighlightOperationPages.ALL_PAGES + !color || this.form.get('option').value === TextHighlightOperationPages.ALL_PAGES ? highlights : highlights.filter(h => h.pageNumber === pageNumber); + const ids = filteredHighlights.map(h => h.id); await firstValueFrom(this._textHighlightService.performHighlightsAction(ids, dossierId, fileId, operation)); this._loadingService.stop(); @@ -51,9 +54,15 @@ export class HighlightActionDialogComponent extends BaseDialogComponent { } private _getForm(): FormGroup { - return this._formBuilder.group({ - color: [{ value: this.data.color, disabled: true }, Validators.required], - option: [null, Validators.required], - }); + if (this.data.color) { + return this._formBuilder.group({ + color: [{ value: this.data.color, disabled: true }, Validators.required], + option: [null, Validators.required], + }); + } else { + return this._formBuilder.group({ + confirmation: [false, Validators.requiredTrue], + }); + } } } diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts index 61c219508..5b39e9bb9 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts @@ -17,6 +17,7 @@ import { IRecategorizationRequest, IRectangle, IResizeRequest, + TextHighlightOperation, } from '@red/domain'; import { toPosition } from '../../dossier/utils/pdf-calculation.utils'; import { AnnotationDrawService } from './annotation-draw.service'; @@ -71,6 +72,16 @@ export class AnnotationActionsService { ); } + removeHighlights(highlights: AnnotationWrapper[]): void { + const data = this._getHighlightOperationData(TextHighlightOperation.REMOVE, highlights); + this._dialogService.openDialog('highlightAction', null, data); + } + + convertHighlights(highlights: AnnotationWrapper[]): void { + const data = this._getHighlightOperationData(TextHighlightOperation.CONVERT, highlights); + this._dialogService.openDialog('highlightAction', null, data); + } + rejectSuggestion($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter) { $event?.stopPropagation(); const { dossierId, fileId } = this._state; @@ -485,6 +496,15 @@ export class AnnotationActionsService { this._processObsAndEmit(this._manualRedactionService.addAnnotation(requests, dossierId, fileId), annotations, annotationsChanged); } + private _getHighlightOperationData(operation: TextHighlightOperation, highlights: AnnotationWrapper[]) { + return { + dossierId: this._state.dossierId, + fileId: this._state.fileId, + operation, + highlights, + }; + } + private _processObsAndEmit( obs: Observable, annotations: AnnotationWrapper[], diff --git a/apps/red-ui/src/app/modules/file-preview/services/multi-select.service.ts b/apps/red-ui/src/app/modules/file-preview/services/multi-select.service.ts index 59db5bc89..f918f5b59 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/multi-select.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/multi-select.service.ts @@ -4,6 +4,9 @@ import { boolFactory } from '@iqser/common-ui'; import { ViewModeService } from './view-mode.service'; import { map, tap } from 'rxjs/operators'; import { FilePreviewStateService } from './file-preview-state.service'; +import { ViewMode, ViewModes } from '@red/domain'; + +const ENABLED_MULTISELECT: ViewMode[] = [ViewModes.STANDARD, ViewModes.TEXT_HIGHLIGHTS]; @Injectable() export class MultiSelectService { @@ -15,8 +18,8 @@ export class MultiSelectService { constructor(private readonly _viewModeService: ViewModeService, private readonly _state: FilePreviewStateService) { [this.active$, this.inactive$] = boolFactory(this.#active$.asObservable()); - this.enabled$ = combineLatest([this._viewModeService.isStandard$, _state.isWritable$]).pipe( - map((result: boolean[]) => !result.some(res => !res)), + this.enabled$ = combineLatest([this._viewModeService.viewMode$, _state.isWritable$]).pipe( + map(([viewMode, isWritable]) => isWritable && ENABLED_MULTISELECT.includes(viewMode)), tap(enabled => this.#enabled$.next(enabled)), ); } diff --git a/apps/red-ui/src/app/translations/highlights-translations.ts b/apps/red-ui/src/app/translations/highlights-translations.ts index e3077dace..4b52df343 100644 --- a/apps/red-ui/src/app/translations/highlights-translations.ts +++ b/apps/red-ui/src/app/translations/highlights-translations.ts @@ -6,11 +6,13 @@ export const highlightsTranslations = { title: _('highlight-action-dialog.convert.title'), details: _('highlight-action-dialog.convert.details'), save: _('highlight-action-dialog.convert.save'), + confirmation: _('highlight-action-dialog.convert.confirmation'), }, [TextHighlightOperation.REMOVE]: { title: _('highlight-action-dialog.remove.title'), details: _('highlight-action-dialog.remove.details'), save: _('highlight-action-dialog.remove.save'), + confirmation: _('highlight-action-dialog.remove.confirmation'), }, [TextHighlightOperationPages.ALL_PAGES]: _('highlight-action-dialog.all-pages'), [TextHighlightOperationPages.THIS_PAGE]: _('highlight-action-dialog.this-page'), diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index 36c4dbaa9..cf9aac978 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -195,6 +195,9 @@ "accept-suggestion": { "label": "Genehmigen und zum Wörterbuch hinzufügen" }, + "convert-highlights": { + "label": "" + }, "edit-reason": { "label": "Begründung bearbeiten" }, @@ -299,6 +302,9 @@ "only-here": "nur hier entfernen", "remove-from-dict": "Aus dem Wörterbuch entfernen" }, + "remove-highlights": { + "label": "" + }, "resize-accept": { "label": "Größe speichern" }, @@ -1421,6 +1427,7 @@ }, "all-pages": "", "convert": { + "confirmation": "", "details": "", "save": "", "title": "" @@ -1431,6 +1438,7 @@ } }, "remove": { + "confirmation": "", "details": "", "save": "", "title": "" diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index f31c3f0c1..b9a940b85 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -195,6 +195,9 @@ "accept-suggestion": { "label": "Approve Suggestion" }, + "convert-highlights": { + "label": "Convert Selected Highlights" + }, "edit-reason": { "label": "Edit Reason" }, @@ -299,6 +302,9 @@ "only-here": "Remove only here", "remove-from-dict": "Remove from dictionary" }, + "remove-highlights": { + "label": "Remove Selected Highlights" + }, "resize-accept": { "label": "Save Resize" }, @@ -1421,6 +1427,7 @@ }, "all-pages": "For all pages in this document", "convert": { + "confirmation": "The {count} selected {count, plural, one{highlight} other{highlights}} will be converted", "details": "All highlights from the document will be converted to Imported Redactions, using the color set up in the Default Colors section of the app.", "save": "Convert Highlights", "title": "Convert highlights to imported redactions" @@ -1431,6 +1438,7 @@ } }, "remove": { + "confirmation": "The {count} selected {count, plural, one{highlight} other{highlights}} will be removed from the document", "details": "Removing highlights from the document will delete all the rectangles and leave a white background behind the highlighted text.", "save": "Remove Highlights", "title": "Remove highlights"