From 912fa000ffadd6878e84e3ce0fc03bbd330dcb6b Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Tue, 10 Nov 2020 21:28:43 +0200 Subject: [PATCH] fixed lint err --- .../file-preview-screen.component.html | 2 +- .../file-preview-screen.component.ts | 34 ++-- .../screens/file/model/annotation.wrapper.ts | 186 ++++++++++-------- .../app/screens/file/model/file-data.model.ts | 65 +++++- .../file/service/annotation-draw.service.ts | 41 ++-- 5 files changed, 192 insertions(+), 136 deletions(-) diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html index 9bbb97652..c93edcf27 100644 --- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html @@ -88,7 +88,7 @@ >
diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts index 6870bafb3..e08c31d30 100644 --- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts @@ -119,23 +119,22 @@ export class FilePreviewScreenComponent implements OnInit { private _loadFileData() { return this._fileDownloadService.loadActiveFileData().pipe( tap((fileDataModel) => { - this.fileData = fileDataModel; - this._rebuildFilters(); + if (fileDataModel.fileStatus.isWorkable) { + this.fileData = fileDataModel; + this._rebuildFilters(); + } else { + if (fileDataModel.fileStatus.isError) { + this._router.navigate(['/ui/projects/' + this.appStateService.activeProjectId]); + } else { + this.loadingMessage = 'file-preview.reanalyse-file'; + } + } }) ); } private _rebuildFilters() { - const manualRedactionAnnotations = this.fileData.entriesToAdd.map((mr) => - AnnotationWrapper.fromManualRedaction(mr, this.fileData.manualRedactions, this.appStateService.dictionaryData, this.permissionsService.currentUser) - ); - const redactionLogAnnotations = this.fileData.redactionLogEntry.map((rde) => - AnnotationWrapper.fromRedactionLog(rde, this.fileData.manualRedactions, this.permissionsService.currentUser) - ); - - this.annotations = []; - this.annotations.push(...manualRedactionAnnotations); - this.annotations.push(...redactionLogAnnotations); + this.annotations = this.fileData.getAnnotations(this.appStateService.dictionaryData, this.permissionsService.currentUser); this.filters = this._annotationProcessingService.getAnnotationFilter(this.annotations); this.filtersChanged(this.filters); } @@ -371,17 +370,20 @@ export class FilePreviewScreenComponent implements OnInit { private _cleanupAndRedrawManualAnnotations() { this._fileDownloadService.loadActiveFileManualAnnotations().subscribe((manualRedactions) => { const annotationsToRemove = []; - this.fileData.entriesToAdd.forEach((manuallyAddedEntry) => { - const annotation = this.activeViewer.annotManager.getAnnotationById(manuallyAddedEntry.id); + const previouslyDrawnAnnotations = this.annotations.filter((a) => a.shouldDraw); + previouslyDrawnAnnotations.forEach((annotationWrapper) => { + const annotation = this.activeViewer.annotManager.getAnnotationById(annotationWrapper.id); if (annotation) { annotationsToRemove.push(annotation); } }); this.activeViewer.annotManager.deleteAnnotations(annotationsToRemove, false, true); - this.fileData.manualRedactions = manualRedactions; - this._annotationDrawService.drawAnnotations(this.instance, this.fileData.entriesToAdd); this._rebuildFilters(); + this._annotationDrawService.drawAnnotations( + this.instance, + this.annotations.filter((a) => a.shouldDraw) + ); }); } diff --git a/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts b/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts index cb2441843..222f5b2af 100644 --- a/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts +++ b/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts @@ -1,5 +1,6 @@ -import { Comment, ManualRedactionEntry, ManualRedactions, Point, RedactionLogEntry, TypeValue } from '@redaction/red-ui-http'; +import { Comment, FileStatus, IdRemoval, ManualRedactionEntry, Point, Rectangle, RedactionLogEntry, TypeValue } from '@redaction/red-ui-http'; import { UserWrapper } from '../../../user/user.service'; +import { FileStatusWrapper } from './file-status.wrapper'; export const SuperTypeSorter = { redaction: 1, @@ -14,71 +15,120 @@ export class AnnotationWrapper { dictionary: string; color: string; comments: Comment[] = []; - manualRedactionEntry: ManualRedactionEntry; firstTopLeftPoint: Point; id: string; content: string; manual: boolean; userId: string; canUndo: boolean; - manualAddToDictionary: boolean; + modifyDictionary: boolean; typeLabel: string; pageNumber: number; hint: boolean; + shouldDraw: boolean; redaction: boolean; + positions: Rectangle[]; - static fromRedactionLog(redactionLogEntry: RedactionLogEntry, manualRedactions: ManualRedactions, user: UserWrapper) { - const comments: { [key: string]: Array } = manualRedactions.comments; + static fromData( + user: UserWrapper, + dictionaryData: { [p: string]: TypeValue }, + fileStatus: FileStatusWrapper, + redactionLogEntry?: RedactionLogEntry, + manualRedactionEntry?: ManualRedactionEntry, + idRemoval?: IdRemoval, + comments?: Comment[] + ) { const annotationWrapper = new AnnotationWrapper(); - annotationWrapper.id = redactionLogEntry.id; - annotationWrapper.superType = redactionLogEntry.redacted ? 'redaction' : redactionLogEntry.hint ? 'hint' : 'ignore'; - annotationWrapper.redaction = redactionLogEntry.redacted; - annotationWrapper.hint = redactionLogEntry.hint; - annotationWrapper.dictionary = redactionLogEntry.type; - annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; - annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; - annotationWrapper.manual = false; - annotationWrapper.content = - annotationWrapper.superType === 'redaction' || annotationWrapper.superType === 'ignore' - ? AnnotationWrapper.createAnnotationContentForRedactionLogEntry(redactionLogEntry) - : null; + annotationWrapper.comments = comments ? comments : []; + + if (redactionLogEntry) { + annotationWrapper.id = redactionLogEntry.id; + annotationWrapper.redaction = redactionLogEntry.redacted; + annotationWrapper.hint = redactionLogEntry.hint; + annotationWrapper.dictionary = redactionLogEntry.type; + annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; + annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; + annotationWrapper.positions = redactionLogEntry.positions; + annotationWrapper.content = AnnotationWrapper.createContentForRedactionLog(redactionLogEntry); + // either marked as manual or idRemove or manualRedactionEntry exists + annotationWrapper.manual = redactionLogEntry.manual || !!manualRedactionEntry || !!idRemoval; + annotationWrapper.modifyDictionary = !!manualRedactionEntry?.addToDictionary || !!idRemoval?.removeFromDictionary; + switch (redactionLogEntry.status) { + case 'REQUESTED': + annotationWrapper.superType = idRemoval?.status === 'REQUESTED' || idRemoval?.status === 'APPROVED' ? 'suggestion-remove' : 'suggestion'; + break; + case 'APPROVED': + annotationWrapper.superType = annotationWrapper.redaction ? 'redaction' : annotationWrapper.hint ? 'hint' : 'ignore'; + break; + case 'DECLINED': + // TODO check this + annotationWrapper.superType = 'ignore'; + break; + default: + annotationWrapper.superType = + idRemoval?.status === 'REQUESTED' || idRemoval?.status === 'APPROVED' + ? 'suggestion-remove' + : annotationWrapper.redaction + ? 'redaction' + : annotationWrapper.hint + ? 'hint' + : 'ignore'; + break; + } + } else { + const dictionary = dictionaryData[manualRedactionEntry.type]; + annotationWrapper.id = manualRedactionEntry.id; + annotationWrapper.redaction = !dictionary.hint; + annotationWrapper.hint = dictionary.hint; + annotationWrapper.dictionary = manualRedactionEntry.type; + annotationWrapper.firstTopLeftPoint = manualRedactionEntry.positions[0]?.topLeft; + annotationWrapper.pageNumber = manualRedactionEntry.positions[0]?.page; + annotationWrapper.positions = manualRedactionEntry.positions; + annotationWrapper.content = manualRedactionEntry.addToDictionary ? null : AnnotationWrapper.createContentForManualRedaction(manualRedactionEntry); + annotationWrapper.manual = true; + annotationWrapper.comments = comments[manualRedactionEntry.id] ? comments[manualRedactionEntry.id] : []; + annotationWrapper.userId = manualRedactionEntry.user; + annotationWrapper.canUndo = manualRedactionEntry?.user === user.id; + annotationWrapper.shouldDraw = AnnotationWrapper._shouldDraw(manualRedactionEntry, fileStatus); + annotationWrapper.modifyDictionary = manualRedactionEntry.addToDictionary; + switch (manualRedactionEntry.status) { + case 'REQUESTED': + annotationWrapper.superType = idRemoval?.status === 'REQUESTED' || idRemoval?.status === 'APPROVED' ? 'suggestion-remove' : 'suggestion'; + break; + case 'APPROVED': + annotationWrapper.superType = redactionLogEntry.redacted ? 'redaction' : redactionLogEntry.hint ? 'hint' : 'ignore'; + break; + case 'DECLINED': + // TODO check this + annotationWrapper.superType = 'ignore'; + break; + default: + annotationWrapper.superType = + idRemoval?.status === 'REQUESTED' || idRemoval?.status === 'APPROVED' + ? 'suggestion-remove' + : annotationWrapper.redaction + ? 'redaction' + : annotationWrapper.hint + ? 'hint' + : 'ignore'; + break; + } + } - const toRemove = AnnotationWrapper._handleRemoveSuperType(annotationWrapper, manualRedactions, user); - annotationWrapper.manualAddToDictionary = toRemove ? toRemove.removeFromDictionary : false; - annotationWrapper.comments = comments[redactionLogEntry.id] ? comments[redactionLogEntry.id] : []; AnnotationWrapper._setTypeLabel(annotationWrapper); + return annotationWrapper; } - static fromManualRedaction( - manualRedactionEntry: ManualRedactionEntry, - manualRedactions: ManualRedactions, - dictionaryData: { [p: string]: TypeValue }, - user: UserWrapper - ) { - const comments: { [key: string]: Array } = manualRedactions.comments; - const annotationWrapper = new AnnotationWrapper(); - annotationWrapper.id = manualRedactionEntry.id; - annotationWrapper.superType = AnnotationWrapper.getManualRedactionSuperType(manualRedactionEntry, dictionaryData); - const dictionary = dictionaryData[manualRedactionEntry.type]; - annotationWrapper.redaction = !dictionary.hint; - annotationWrapper.hint = dictionary.hint; - AnnotationWrapper._handleRemoveSuperType(annotationWrapper, manualRedactions, user); - annotationWrapper.dictionary = manualRedactionEntry.type; - annotationWrapper.firstTopLeftPoint = manualRedactionEntry.positions[0]?.topLeft; - annotationWrapper.pageNumber = manualRedactionEntry.positions[0]?.page; - annotationWrapper.content = manualRedactionEntry.addToDictionary - ? null - : AnnotationWrapper.createAnnotationContentForManualRedaction(manualRedactionEntry); - annotationWrapper.manual = true; - annotationWrapper.comments = comments[manualRedactionEntry.id] ? comments[manualRedactionEntry.id] : []; - annotationWrapper.userId = manualRedactionEntry.user; - annotationWrapper.canUndo = !manualRedactionEntry.processedDate && manualRedactionEntry.user === user.id; + private static _shouldDraw(manualRedaction: ManualRedactionEntry, fileStatus: FileStatus): boolean { + const isRequested = + manualRedaction.status === 'REQUESTED' && new Date(manualRedaction.requestDate).getTime() > new Date(fileStatus.lastProcessed).getTime(); + const isApprovedOrDeclined = + (manualRedaction.status === 'APPROVED' || manualRedaction.status === 'DECLINED') && + new Date(manualRedaction.requestDate).getTime() > new Date(fileStatus.lastProcessed).getTime(); - annotationWrapper.manualAddToDictionary = manualRedactionEntry.addToDictionary; - AnnotationWrapper._setTypeLabel(annotationWrapper); - return annotationWrapper; + return isRequested || isApprovedOrDeclined; } private static _setTypeLabel(annotationWrapper: AnnotationWrapper) { @@ -91,7 +141,7 @@ export class AnnotationWrapper { } if (annotationWrapper.redaction) { label += '-redaction'; - if (annotationWrapper.manualAddToDictionary) { + if (annotationWrapper.modifyDictionary) { label += '-dictionary'; } } @@ -100,35 +150,8 @@ export class AnnotationWrapper { annotationWrapper.typeLabel = label; } - private static _handleRemoveSuperType(annotationWrapper: AnnotationWrapper, manualRedactions: ManualRedactions, user: UserWrapper) { - const toRemove = manualRedactions.idsToRemove.find((trm) => trm.id === annotationWrapper.id); - - // change super-type based on toRemove - annotationWrapper.superType = toRemove - ? toRemove.status === 'REQUESTED' - ? 'suggestion-remove' - : toRemove.status === 'APPROVED' - ? 'ignore' - : annotationWrapper.superType - : annotationWrapper.superType; - - if (toRemove) { - annotationWrapper.canUndo = !toRemove.processedDate && toRemove.user === user.id; - } - return toRemove; - } - - static getManualRedactionSuperType(manualRedactionEntry: ManualRedactionEntry, dictionaryData: { [p: string]: TypeValue }) { - const dictionary = dictionaryData[manualRedactionEntry.type]; - return manualRedactionEntry.status === 'REQUESTED' ? 'suggestion' : dictionary.hint ? 'hint' : 'redaction'; - } - constructor() {} - get manualRedactionOwner() { - return this.manualRedactionEntry?.user; - } - get x() { return this.firstTopLeftPoint.x; } @@ -137,14 +160,13 @@ export class AnnotationWrapper { return this.firstTopLeftPoint.y; } - private static createAnnotationContentForManualRedaction(entry: ManualRedactionEntry) { - return entry.reason; - // + '\n\nLegal basis:' + - // entry.legalBasis + private static createContentForRedactionLog(entry: RedactionLogEntry) { + if (entry.redacted) { + return entry.reason + '\n\nLegal basis:' + entry.legalBasis + '\n\nIn section: "' + entry.section + '"'; + } } - private static createAnnotationContentForRedactionLogEntry(entry: RedactionLogEntry) { - // return "\nRule " + entry.matchedRule + " matched\n\n" + entry.reason + "\n\nLegal basis:" + entry.legalBasis + "\n\nIn section: \"" + entry.section + "\""; - return entry.reason + '\n\nLegal basis:' + entry.legalBasis + '\n\nIn section: "' + entry.section + '"'; + private static createContentForManualRedaction(entry: ManualRedactionEntry) { + return entry.reason + '\n\nLegal basis:' + entry.legalBasis; } } diff --git a/apps/red-ui/src/app/screens/file/model/file-data.model.ts b/apps/red-ui/src/app/screens/file/model/file-data.model.ts index 5c4b4a2eb..ed841df3e 100644 --- a/apps/red-ui/src/app/screens/file/model/file-data.model.ts +++ b/apps/red-ui/src/app/screens/file/model/file-data.model.ts @@ -1,5 +1,14 @@ -import { ManualRedactionEntry, ManualRedactions, RedactionLog, RedactionLogEntry, ViewedPages } from '@redaction/red-ui-http'; +import { Comment, IdRemoval, ManualRedactionEntry, ManualRedactions, RedactionLog, RedactionLogEntry, TypeValue, ViewedPages } from '@redaction/red-ui-http'; import { FileStatusWrapper } from './file-status.wrapper'; +import { UserWrapper } from '../../../user/user.service'; +import { AnnotationWrapper } from './annotation.wrapper'; + +export interface AnnotationPair { + redactionLogEntry?: RedactionLogEntry; + manualRedactionEntry?: ManualRedactionEntry; + idRemoval?: IdRemoval; + comments?: Comment[]; +} export class FileDataModel { constructor( @@ -12,18 +21,54 @@ export class FileDataModel { ) {} get redactionLogEntry(): RedactionLogEntry[] { - return this.redactionLog.redactionLogEntry.filter((r) => r.status !== 'REQUESTED'); + return this.redactionLog.redactionLogEntry; } - get entriesToAdd(): ManualRedactionEntry[] { - return this.manualRedactions.entriesToAdd.filter((manualRedaction) => { - const isRequested = - manualRedaction.status === 'REQUESTED' && new Date(manualRedaction.requestDate).getTime() > new Date(this.fileStatus.lastProcessed).getTime(); - const isApprovedOrDeclined = - (manualRedaction.status === 'APPROVED' || manualRedaction.status === 'DECLINED') && - new Date(manualRedaction.requestDate).getTime() > new Date(this.fileStatus.lastProcessed).getTime(); + getAnnotations(dictionaryData: { [p: string]: TypeValue }, currentUser: UserWrapper): AnnotationWrapper[] { + const annotations = []; - return isRequested || isApprovedOrDeclined; + const pairs: AnnotationPair[] = this._createPairs(); + + pairs.forEach((pair) => { + const annotation = AnnotationWrapper.fromData( + currentUser, + dictionaryData, + this.fileStatus, + pair.redactionLogEntry, + pair.manualRedactionEntry, + pair.idRemoval, + pair.comments + ); + annotations.push(annotation); }); + + return annotations; + } + + private _createPairs(): AnnotationPair[] { + const pairs: AnnotationPair[] = []; + + this.redactionLog.redactionLogEntry.forEach((rdl) => { + pairs.push({ + redactionLogEntry: rdl, + manualRedactionEntry: this.manualRedactions.entriesToAdd.find((eta) => eta.id === rdl.id), + idRemoval: this.manualRedactions.idsToRemove.find((idr) => idr.id === rdl.id), + comments: this.manualRedactions.comments[rdl.id] + }); + }); + + this.manualRedactions.entriesToAdd.forEach((eta) => { + const redactionLogEntry = this.redactionLog.redactionLogEntry.find((rdl) => rdl.id === eta.id); + if (!redactionLogEntry) { + pairs.push({ + redactionLogEntry: null, + manualRedactionEntry: eta, + idRemoval: this.manualRedactions.idsToRemove.find((idr) => idr.id === eta.id), + comments: this.manualRedactions.comments[eta.id] + }); + } + }); + + return pairs; } } diff --git a/apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts b/apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts index e6344018b..a590745e9 100644 --- a/apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts +++ b/apps/red-ui/src/app/screens/file/service/annotation-draw.service.ts @@ -11,55 +11,42 @@ import { AnnotationWrapper } from '../model/annotation.wrapper'; export class AnnotationDrawService { constructor(private readonly _appStateService: AppStateService) {} - public drawAnnotations(activeViewer: WebViewerInstance, mres: ManualRedactionEntry[]) { - mres.forEach((mre) => { + public drawAnnotations(activeViewer: WebViewerInstance, annotationWrappers: AnnotationWrapper[]) { + annotationWrappers.forEach((mre) => { this.drawAnnotation(activeViewer, mre); }); } - public drawAnnotation(activeViewer: WebViewerInstance, mre: ManualRedactionEntry) { - const pageNumber = mre.positions[0].page; + public drawAnnotation(activeViewer: WebViewerInstance, annotationWrapper: AnnotationWrapper) { + const pageNumber = annotationWrapper.pageNumber; const highlight = new activeViewer.Annotations.TextHighlightAnnotation(); highlight.PageNumber = pageNumber; - highlight.StrokeColor = this._getColor(activeViewer, mre); - highlight.setContents(mre.reason); - highlight.Quads = this._rectanglesToQuads(mre.positions, activeViewer, pageNumber); - highlight.Id = mre.id; + highlight.StrokeColor = this._getColor(activeViewer, annotationWrapper); + highlight.setContents(annotationWrapper.content); + highlight.Quads = this._rectanglesToQuads(annotationWrapper.positions, activeViewer, pageNumber); + highlight.Id = annotationWrapper.id; const annotationManager = activeViewer.annotManager; annotationManager.addAnnotation(highlight, true); annotationManager.redrawAnnotation(highlight); } - private _getColor(activeViewer: WebViewerInstance, manualRedactionEntry: ManualRedactionEntry) { - // if you're the owner, use the request color, otherwise use the actual dict color - const superType = AnnotationWrapper.getManualRedactionSuperType( - manualRedactionEntry, - this._appStateService.dictionaryData - ); + private _getColor(activeViewer: WebViewerInstance, annotationWrapper: AnnotationWrapper) { const color = - superType === 'suggestion' - ? this._appStateService.getDictionaryColor(superType) - : this._appStateService.getDictionaryColor(manualRedactionEntry.type); + annotationWrapper.superType === 'suggestion' || annotationWrapper.superType === 'suggestion-remove' + ? this._appStateService.getDictionaryColor(annotationWrapper.superType) + : this._appStateService.getDictionaryColor(annotationWrapper.dictionary); const rgbColor = hexToRgb(color); return new activeViewer.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b); } - private _rectanglesToQuads( - positions: Rectangle[], - activeViewer: WebViewerInstance, - pageNumber: number - ): any[] { + private _rectanglesToQuads(positions: Rectangle[], activeViewer: WebViewerInstance, pageNumber: number): any[] { const pageHeight = activeViewer.docViewer.getPageHeight(pageNumber); return positions.map((p) => this._rectangleToQuad(p, activeViewer, pageHeight)); } - private _rectangleToQuad( - rectangle: Rectangle, - activeViewer: WebViewerInstance, - pageHeight: number - ): any { + private _rectangleToQuad(rectangle: Rectangle, activeViewer: WebViewerInstance, pageHeight: number): any { const x1 = rectangle.topLeft.x; const y1 = pageHeight - (rectangle.topLeft.y + rectangle.height);