RED-5219: add button to load all annotations in dev mode

This commit is contained in:
Dan Percic 2022-09-19 17:08:14 +03:00
parent 78fa79cdfa
commit ef85665985
10 changed files with 112 additions and 42 deletions

View File

@ -5,7 +5,6 @@ import {
Component,
ElementRef,
HostListener,
Injector,
NgZone,
OnDestroy,
OnInit,
@ -28,6 +27,7 @@ import {
OnAttach,
OnDetach,
processFilters,
Toaster,
} from '@iqser/common-ui';
import { MatDialogState } from '@angular/material/dialog';
import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
@ -60,12 +60,13 @@ import { StampService } from './services/stamp.service';
import { PdfViewer } from '../pdf-viewer/services/pdf-viewer.service';
import { REDAnnotationManager } from '../pdf-viewer/services/annotation-manager.service';
import { ViewerHeaderService } from '../pdf-viewer/services/viewer-header.service';
import { ROTATION_ACTION_BUTTONS } from '../pdf-viewer/utils/constants';
import { ROTATION_ACTION_BUTTONS, ViewerEvents } from '../pdf-viewer/utils/constants';
import { SkippedService } from './services/skipped.service';
import { REDDocumentViewer } from '../pdf-viewer/services/document-viewer.service';
import { AnnotationsListingService } from './services/annotations-listing.service';
import { PdfProxyService } from './services/pdf-proxy.service';
import { ConfigService } from '@services/config.service';
import { TranslateService } from '@ngx-translate/core';
import Annotation = Core.Annotations.Annotation;
const textActions = [TextPopups.ADD_DICTIONARY, TextPopups.ADD_FALSE_POSITIVE];
@ -122,7 +123,12 @@ export class FilePreviewScreenComponent
private readonly _annotationDrawService: AnnotationDrawService,
private readonly _annotationProcessingService: AnnotationProcessingService,
private readonly _stampService: StampService,
private readonly _injector: Injector,
private readonly _reanalysisService: ReanalysisService,
private readonly _toaster: Toaster,
private readonly _manualRedactionService: ManualRedactionService,
private readonly _filesService: FilesService,
private readonly _fileManagementService: FileManagementService,
private readonly _translateService: TranslateService,
) {
super();
document.documentElement.addEventListener('fullscreenchange', () => {
@ -278,8 +284,7 @@ export class FilePreviewScreenComponent
this._subscribeToFileUpdates();
if (file?.analysisRequired && !file.excludedFromAutomaticAnalysis) {
const reanalysisService = this._injector.get(ReanalysisService);
const reanalyzeFiles = reanalysisService.reanalyzeFilesForDossier([file], this.dossierId, { force: true });
const reanalyzeFiles = this._reanalysisService.reanalyzeFilesForDossier([file], this.dossierId, { force: true });
await firstValueFrom(reanalyzeFiles);
}
@ -306,15 +311,15 @@ export class FilePreviewScreenComponent
if (selectedAnnotations.length > 0) {
this._annotationManager.delete([selectedAnnotations[0].Id]);
}
const manualRedactionService = this._injector.get(ManualRedactionService);
const add$ = manualRedactionService.addAnnotation(
const add$ = this._manualRedactionService.addAnnotation(
result.annotations.map(w => w.manualRedactionEntry).filter(e => e.positions[0].page <= file.numberOfPages),
this.dossierId,
this.fileId,
result.dictionary?.label,
);
const filesService = this._injector.get(FilesService);
const addAndReload$ = add$.pipe(switchMap(() => filesService.reload(this.dossierId, file)));
const addAndReload$ = add$.pipe(switchMap(() => this._filesService.reload(this.dossierId, file)));
return firstValueFrom(addAndReload$.pipe(catchError(() => of(undefined))));
},
);
@ -389,8 +394,7 @@ export class FilePreviewScreenComponent
}
async downloadOriginalFile({ cacheIdentifier, dossierId, fileId, filename }: File) {
const fileManagementService = this._injector.get(FileManagementService);
const originalFile = fileManagementService.downloadOriginal(dossierId, fileId, 'response', cacheIdentifier);
const originalFile = this._fileManagementService.downloadOriginal(dossierId, fileId, 'response', cacheIdentifier);
download(await firstValueFrom(originalFile), filename);
}
@ -610,7 +614,25 @@ export class FilePreviewScreenComponent
this.addActiveScreenSubscription = this.pdfProxyService.pageChanged$.subscribe(page =>
this._ngZone.run(() => this.#updateQueryParamsPage(page)),
);
this.addActiveScreenSubscription = this.pdfProxyService.annotationSelected$.subscribe();
this.addActiveScreenSubscription = this._viewerHeaderService.events$
.pipe(
filter(event => event.type === ViewerEvents.LOAD_ALL_ANNOTATIONS),
switchMap(() => this._fileDataService.annotations),
tap(annotations => {
if (annotations.length >= this.configService.values.ANNOTATIONS_THRESHOLD) {
this._toaster.warning(_('load-all-annotations-threshold-exceeded'), {
params: {
threshold: this.configService.values.ANNOTATIONS_THRESHOLD,
},
});
}
}),
switchMap(annotations => this.drawChangedAnnotations([], annotations)),
)
.subscribe();
}
private _handleDeletedDossier(): void {

View File

@ -1,4 +1,4 @@
import { List } from '@iqser/common-ui';
import { List, ValuesOf } from '@iqser/common-ui';
export const ActionsHelpModeKeys = {
redaction: 'redaction_text',
@ -13,27 +13,20 @@ export const ActionsHelpModeKeys = {
export const ALL_HOTKEYS: List = ['Escape', 'F', 'f', 'ArrowUp', 'ArrowDown'] as const;
export type HeaderElementType =
| 'SHAPE_TOOL_GROUP_BUTTON'
| 'ROTATE_LEFT_BUTTON'
| 'ROTATE_RIGHT_BUTTON'
| 'APPLY_ROTATION'
| 'DISCARD_ROTATION'
| 'TOGGLE_TOOLTIPS'
| 'COMPARE_BUTTON'
| 'CLOSE_COMPARE_BUTTON';
export const HeaderElements: Record<HeaderElementType, HeaderElementType> = {
export const HeaderElements = {
SHAPE_TOOL_GROUP_BUTTON: 'SHAPE_TOOL_GROUP_BUTTON',
ROTATE_LEFT_BUTTON: 'ROTATE_LEFT_BUTTON',
ROTATE_RIGHT_BUTTON: 'ROTATE_RIGHT_BUTTON',
APPLY_ROTATION: 'APPLY_ROTATION',
DISCARD_ROTATION: 'DISCARD_ROTATION',
TOGGLE_TOOLTIPS: 'TOGGLE_TOOLTIPS',
COMPARE_BUTTON: 'COMPARE_BUTTON',
CLOSE_COMPARE_BUTTON: 'CLOSE_COMPARE_BUTTON',
TOGGLE_TOOLTIPS: 'TOGGLE_TOOLTIPS',
LOAD_ALL_ANNOTATIONS: 'LOAD_ALL_ANNOTATIONS',
} as const;
export type HeaderElementType = ValuesOf<typeof HeaderElements>;
export const TextPopups = {
ADD_REDACTION: 'add-redaction',
ADD_DICTIONARY: 'add-dictionary',

View File

@ -1,4 +1,4 @@
import { Inject, Injectable, Injector } from '@angular/core';
import { Inject, Injectable } from '@angular/core';
import { IHeaderElement, RotationTypes } from '@red/domain';
import { HeaderElements, HeaderElementType } from '../../file-preview/utils/constants';
import { TranslateService } from '@ngx-translate/core';
@ -6,9 +6,13 @@ import { BASE_HREF_FN, BaseHrefFn } from '@iqser/common-ui';
import { TooltipsService } from './tooltips.service';
import { PageRotationService } from './page-rotation.service';
import { PdfViewer } from './pdf-viewer.service';
import { ROTATION_ACTION_BUTTONS } from '../utils/constants';
import { ROTATION_ACTION_BUTTONS, ViewerEvents } from '../utils/constants';
import { FilesMapService } from '@services/files/files-map.service';
import { REDDocumentViewer } from './document-viewer.service';
import { UserPreferenceService } from '@users/user-preference.service';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable, Subject } from 'rxjs';
import { ViewerEvent } from '../utils/types';
const divider: IHeaderElement = {
type: 'divider',
@ -16,10 +20,12 @@ const divider: IHeaderElement = {
@Injectable()
export class ViewerHeaderService {
readonly events$: Observable<ViewerEvent>;
#buttons: Map<HeaderElementType, IHeaderElement>;
readonly #config = new Map<HeaderElementType, boolean>([
[HeaderElements.SHAPE_TOOL_GROUP_BUTTON, true],
[HeaderElements.TOGGLE_TOOLTIPS, true],
[HeaderElements.LOAD_ALL_ANNOTATIONS, false],
[HeaderElements.COMPARE_BUTTON, true],
[HeaderElements.CLOSE_COMPARE_BUTTON, false],
[HeaderElements.ROTATE_LEFT_BUTTON, true],
@ -28,16 +34,22 @@ export class ViewerHeaderService {
[HeaderElements.DISCARD_ROTATION, false],
]);
#docBeforeCompare: Blob;
readonly #events$ = new Subject<ViewerEvent>();
constructor(
@Inject(BASE_HREF_FN) private readonly _convertPath: BaseHrefFn,
private readonly _injector: Injector,
private readonly _filesMapService: FilesMapService,
private readonly _translateService: TranslateService,
private readonly _pdf: PdfViewer,
private readonly _documentViewer: REDDocumentViewer,
private readonly _rotationService: PageRotationService,
private readonly _tooltipsService: TooltipsService,
) {}
private readonly _userPreferenceService: UserPreferenceService,
private readonly _activatedRoute: ActivatedRoute,
private readonly _router: Router,
) {
this.events$ = this.#events$.asObservable();
}
private get _rectangle(): IHeaderElement {
return {
@ -62,6 +74,17 @@ export class ViewerHeaderService {
};
}
private get _loadAllAnnotations(): IHeaderElement {
return {
type: 'actionButton',
element: HeaderElements.LOAD_ALL_ANNOTATIONS,
dataElement: HeaderElements.LOAD_ALL_ANNOTATIONS,
title: this._translateService.instant('viewer-header.load-all-annotations'),
img: this._tooltipsService.toggleTooltipsBtnIcon,
onClick: () => this.#events$.next({ type: ViewerEvents.LOAD_ALL_ANNOTATIONS }),
};
}
private get _closeCompare(): IHeaderElement {
return {
type: 'actionButton',
@ -167,11 +190,16 @@ export class ViewerHeaderService {
[HeaderElements.APPLY_ROTATION, this._applyRotation],
[HeaderElements.DISCARD_ROTATION, this._discardRotation],
[HeaderElements.TOGGLE_TOOLTIPS, this._toggleTooltips],
[HeaderElements.LOAD_ALL_ANNOTATIONS, this._loadAllAnnotations],
[HeaderElements.COMPARE_BUTTON, this._compare],
[HeaderElements.CLOSE_COMPARE_BUTTON, this._closeCompare],
]);
this.updateElements();
if (this._userPreferenceService.areDevFeaturesEnabled) {
this.enable([HeaderElements.LOAD_ALL_ANNOTATIONS]);
}
}
enable(elements: HeaderElementType[]): void {
@ -186,7 +214,7 @@ export class ViewerHeaderService {
this._pdf.instance?.UI.setHeaderItems(header => {
const enabledItems: IHeaderElement[] = [];
const groups: HeaderElementType[][] = [
[HeaderElements.COMPARE_BUTTON, HeaderElements.CLOSE_COMPARE_BUTTON],
[HeaderElements.COMPARE_BUTTON, HeaderElements.CLOSE_COMPARE_BUTTON, HeaderElements.LOAD_ALL_ANNOTATIONS],
[HeaderElements.TOGGLE_TOOLTIPS],
[HeaderElements.SHAPE_TOOL_GROUP_BUTTON],
[
@ -217,7 +245,7 @@ export class ViewerHeaderService {
private _closeCompareMode() {
this._pdf.closeCompareMode();
const { dossierId, fileId } = this._pdf;
const file = this._injector.get(FilesMapService).get(dossierId, fileId);
const file = this._filesMapService.get(dossierId, fileId);
const filename = file.filename ?? 'document.pdf';
this._pdf.instance.UI.loadDocument(this.#docBeforeCompare, { filename });

View File

@ -31,6 +31,10 @@ export const SEARCH_OPTIONS = {
ambientString: true, // return ambient string as part of the result
};
export const ViewerEvents = {
LOAD_ALL_ANNOTATIONS: 'LOAD_ALL_ANNOTATIONS',
} as const;
export const USELESS_ELEMENTS = [
'pageNavOverlay',
'menuButton',

View File

@ -15,3 +15,7 @@ export interface DeleteAnnotationsOptions {
}
export type AnnotationPredicate = (value: Annotation) => boolean;
export interface ViewerEvent {
readonly type: string;
}

View File

@ -15,5 +15,6 @@
"RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
"RSS_ENABLED": true
"RSS_ENABLED": true,
"ANNOTATIONS_THRESHOLD": 1000
}

View File

@ -787,7 +787,6 @@
},
"quick-filters": {
"member": "",
"my-dossiers": "Meine Dossiers",
"owner": ""
},
"reanalyse": {
@ -1314,6 +1313,7 @@
"no-data": {
"title": "Auf dieser Seite gibt es keine Anmerkungen."
},
"open-rss-view": "",
"quick-nav": {
"jump-first": "Zur ersten Seite springen",
"jump-last": "Zur letzten Seite springen"
@ -1615,6 +1615,7 @@
"usage-details": "Nutzungsdetails"
},
"license-information": "Lizenzinformationen",
"load-all-annotations-threshold-exceeded": "",
"loading": "",
"manual-annotation": {
"dialog": {
@ -1906,6 +1907,14 @@
"red-user-admin": "Benutzer-Admin",
"regular": "Regulär"
},
"rss-dialog": {
"actions": {
"close": "",
"export-json": "",
"export-xml": ""
},
"title": ""
},
"rules-screen": {
"error": {
"generic": "Es ist ein Fehler aufgetreten ... Die Regeln konnten nicht aktualisiert werden!"
@ -2094,6 +2103,9 @@
"view-as": "Ansicht als:",
"workflow": "Arbeitsablauf"
},
"viewer-header": {
"load-all-annotations": ""
},
"watermark-screen": {
"action": {
"change-success": "Das Wasserzeichen wurde aktualisiert!",

View File

@ -787,7 +787,6 @@
},
"quick-filters": {
"member": "Dossier Member",
"my-dossiers": "My Dossiers",
"owner": "Dossier Owner"
},
"reanalyse": {
@ -1295,14 +1294,6 @@
},
"upload-csv": "Upload File Attributes Configuration"
},
"rss-dialog": {
"title": "Structured Component Management",
"actions": {
"export-json": "Export JSON",
"export-xml": "Export XML",
"close": "Close"
}
},
"file-preview": {
"assign-me": "Assign to me",
"assign-reviewer": "Assign User",
@ -1311,7 +1302,6 @@
"delta-tooltip": "The Delta View shows the unseen changes since your last visit to the page. This view is only available if there is at least 1 change.",
"document-info": "Document Info",
"download-original-file": "Download Original File",
"open-rss-view": "Open Structured Component Management View",
"exclude-pages": "Exclude pages from redaction",
"excluded-from-redaction": "excluded",
"fullscreen": "Full Screen (F)",
@ -1323,6 +1313,7 @@
"no-data": {
"title": "There have been no changes to this page."
},
"open-rss-view": "Open Structured Component Management View",
"quick-nav": {
"jump-first": "Jump to first page",
"jump-last": "Jump to last page"
@ -1624,6 +1615,7 @@
"usage-details": "Usage Details"
},
"license-information": "License Information",
"load-all-annotations-threshold-exceeded": "Caution, document contains more than {threshold} annotations. Drawing all annotations will affect the performance of the app and could even block it.",
"loading": "Loading",
"manual-annotation": {
"dialog": {
@ -1915,6 +1907,14 @@
"red-user-admin": "Users Admin",
"regular": "Regular"
},
"rss-dialog": {
"actions": {
"close": "Close",
"export-json": "Export JSON",
"export-xml": "Export XML"
},
"title": "Structured Component Management"
},
"rules-screen": {
"error": {
"generic": "Something went wrong... Rules update failed!"
@ -2103,6 +2103,9 @@
"view-as": "View as:",
"workflow": "Workflow"
},
"viewer-header": {
"load-all-annotations": "Load all annotations"
},
"watermark-screen": {
"action": {
"change-success": "Watermark has been updated!",

View File

@ -18,6 +18,7 @@ RECENT_PERIOD_IN_HOURS="${RECENT_PERIOD_IN_HOURS:-24}"
SELECTION_MODE="${SELECTION_MODE:-structural}"
MANUAL_BASE_URL="${MANUAL_BASE_URL:-https://docs.redactmanager.com/preview}"
RSS_ENABLED="${RSS_ENABLED:-false}"
ANNOTATIONS_THRESHOLD="${ANNOTATIONS_THRESHOLD:-1000}"
@ -39,6 +40,7 @@ echo '{
"SELECTION_MODE":"'"$SELECTION_MODE"'",
"MANUAL_BASE_URL":"'"$MANUAL_BASE_URL"'",
"RSS_ENABLED":'"$RSS_ENABLED"'
"ANNOTATIONS_THRESHOLD":'"$ANNOTATIONS_THRESHOLD"'
}' > /usr/share/nginx/html/ui/assets/config/config.json
echo 'Env variables: '

View File

@ -16,4 +16,5 @@ export interface AppConfig {
SELECTION_MODE: string;
MANUAL_BASE_URL: string;
RSS_ENABLED: boolean;
ANNOTATIONS_THRESHOLD: number;
}