diff --git a/apps/red-ui/src/app/common/service/annotation-actions.service.ts b/apps/red-ui/src/app/common/service/annotation-actions.service.ts index 84a9068d2..d9bc61ec6 100644 --- a/apps/red-ui/src/app/common/service/annotation-actions.service.ts +++ b/apps/red-ui/src/app/common/service/annotation-actions.service.ts @@ -26,19 +26,13 @@ export class AnnotationActionsService { public canRejectSuggestion(annotation: AnnotationWrapper): boolean { // i can reject whatever i may not undo - return ( - !this.canUndoAnnotation(annotation) && - ((this.canAcceptSuggestion(annotation) && !annotation.isDeclinedSuggestion) || (annotation.isModifyDictionary && !annotation.isDeclinedSuggestion)) - ); + return !this.canUndoAnnotation(annotation) && this.canAcceptSuggestion(annotation) && !annotation.isDeclinedSuggestion; } public canDirectlySuggestToRemoveAnnotation(annotation: AnnotationWrapper): boolean { return ( // annotation.isHint || // HINTS CAN NO LONGER BE REMOVED DIRECTLY ONLY VIA DICTIONARY ACTION - annotation.isManual && - this._permissionsService.isManagerAndOwner() && - !this.canUndoAnnotation(annotation) && - !annotation.isRecommendation + annotation.isManualRedaction && this._permissionsService.isManagerAndOwner() && !this.canUndoAnnotation(annotation) && !annotation.isRecommendation ); } @@ -47,7 +41,8 @@ export class AnnotationActionsService { } public canConvertRecommendationToAnnotation(annotation: AnnotationWrapper): boolean { - return annotation.isRecommendation; + // recommendations that have not already been turned into a suggestion + return annotation.isRecommendation && !annotation.isConvertedRecommendation; } public canUndoAnnotation(annotation: AnnotationWrapper): boolean { @@ -60,6 +55,7 @@ export class AnnotationActionsService { public acceptSuggestion($event: MouseEvent, annotation: AnnotationWrapper, annotationsChanged: EventEmitter) { $event?.stopPropagation(); + console.log(annotation.isModifyDictionary); this._processObsAndEmit(this._manualAnnotationService.approveRequest(annotation.id, annotation.isModifyDictionary), annotation, annotationsChanged); } diff --git a/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.ts b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.ts index 9b292121d..b6afbba75 100644 --- a/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.ts +++ b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { TypeValue } from '@redaction/red-ui-http'; @Component({ diff --git a/apps/red-ui/src/app/components/type-annotation-icon/type-annotation-icon.component.ts b/apps/red-ui/src/app/components/type-annotation-icon/type-annotation-icon.component.ts index 7e11ff1fe..465b74038 100644 --- a/apps/red-ui/src/app/components/type-annotation-icon/type-annotation-icon.component.ts +++ b/apps/red-ui/src/app/components/type-annotation-icon/type-annotation-icon.component.ts @@ -18,13 +18,7 @@ export class TypeAnnotationIconComponent implements OnChanges { ngOnChanges(): void { if (this.annotation) { - if ( - this.annotation.isSuggestion || - this.annotation.isDeclinedSuggestion || - this.annotation.isModifyDictionary || - this.annotation.isIgnored || - this.annotation.isReadyForAnalysis - ) { + if (this.annotation.isSuperTypeBasedColor) { this.color = this._appStateService.getDictionaryColor(this.annotation.superType); } else { this.color = this._appStateService.getDictionaryColor(this.annotation.dictionary); diff --git a/apps/red-ui/src/app/dialogs/dialog.service.ts b/apps/red-ui/src/app/dialogs/dialog.service.ts index ca58650da..6c39092b4 100644 --- a/apps/red-ui/src/app/dialogs/dialog.service.ts +++ b/apps/red-ui/src/app/dialogs/dialog.service.ts @@ -150,12 +150,12 @@ export class DialogService { const ref = this._dialog.open(ConfirmationDialogComponent, { ...dialogConfig, data: new ConfirmationDialogInput({ - title: annotation.isManual + title: annotation.isManualRedaction ? 'confirmation-dialog.remove-manual-redaction.title' : removeFromDictionary ? 'confirmation-dialog.remove-from-dictionary.title' : 'confirmation-dialog.remove-only-here.title', - question: annotation.isManual + question: annotation.isManualRedaction ? 'confirmation-dialog.remove-manual-redaction.question' : removeFromDictionary ? 'confirmation-dialog.remove-from-dictionary.question' 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 8901854c4..51955bdef 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 @@ -206,7 +206,7 @@ -
+
{{ activeViewerPage }} - {{ displayedAnnotations[activeViewerPage]?.annotations?.length || 0 }} 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 9b69f725b..7901cfe63 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,6 +1,5 @@ -import { Comment, IdRemoval, ManualRedactionEntry, Point, Rectangle, RedactionLogEntry, TypeValue } from '@redaction/red-ui-http'; -import { UserWrapper } from '../../../user/user.service'; -import { FileStatusWrapper } from './file-status.wrapper'; +import { Comment, Point, Rectangle } from '@redaction/red-ui-http'; +import { RedactionLogEntryWrapper } from './redaction-log-entry.wrapper'; export class AnnotationWrapper { superType: @@ -12,17 +11,16 @@ export class AnnotationWrapper { | 'suggestion-remove' | 'ignore' | 'redaction' - | 'manual' + | 'manual-redaction' | 'hint' | 'declined-suggestion'; dictionary: string; color: string; comments: Comment[] = []; firstTopLeftPoint: Point; - id: string; + annotationId: string; content: string; value: string; - manual: boolean; userId: string; typeLabel: string; pageNumber: number; @@ -30,14 +28,19 @@ export class AnnotationWrapper { redaction: boolean; status: string; dictionaryOperation: boolean; - recommendation: boolean; positions: Rectangle[]; + + recommendation: boolean; recommendationType: string; + pendingRecommendationAnnotationId: string; + textAfter?: string; textBefore?: string; + constructor() {} + get isDictionaryBased() { - return (this.isHint || this.isRedacted) && !this.isManual; + return (this.isHint || this.isRedacted) && !this.isManualRedaction; } get descriptor() { @@ -58,6 +61,10 @@ export class AnnotationWrapper { return this.isRedacted && (this.hasTextAfter || this.hasTextBefore); } + get isSuperTypeBasedColor() { + return this.isIgnored || this.isSuggestion || this.isReadyForAnalysis || this.isDeclinedSuggestion; + } + get isIgnored() { return this.superType === 'ignore'; } @@ -66,8 +73,8 @@ export class AnnotationWrapper { return this.dictionary === 'false_positive' && (this.superType === 'ignore' || this.superType === 'hint' || this.superType === 'redaction'); } - get isManual() { - return this.superType === 'manual'; + get isManualRedaction() { + return this.superType === 'manual-redaction'; } get isRedactedOrIgnored() { @@ -110,127 +117,18 @@ export class AnnotationWrapper { return this.dictionaryOperation; } + get isConvertedRecommendation() { + return this.isRecommendation && (this.superType === 'suggestion-add-dictionary' || this.superType === 'add-dictionary'); + } + get isRecommendation() { return this.recommendation; } - static fromData( - user: UserWrapper, - dictionaryData: { [p: string]: TypeValue }, - fileStatus: FileStatusWrapper, - redactionLogEntry?: RedactionLogEntry, - manualRedactionEntry?: ManualRedactionEntry, - idRemoval?: IdRemoval, - comments?: Comment[] - ) { - // manual annotations that have been undone - if (redactionLogEntry?.type === 'manual' && redactionLogEntry?.manual === true && !manualRedactionEntry) { - return; - } - - // for declined manual add to dict requests - if (manualRedactionEntry?.status === 'DECLINED' && manualRedactionEntry?.type !== 'manual') { - manualRedactionEntry.addToDictionary = true; - } - - // there has been an undo on a redaction remove - if (redactionLogEntry?.manualRedactionType === 'REMOVE' && !idRemoval && !redactionLogEntry.hint) { - redactionLogEntry.redacted = true; - } - - const annotationWrapper = new AnnotationWrapper(); - - annotationWrapper.recommendation = redactionLogEntry ? redactionLogEntry.recommendation : false; - if (annotationWrapper.recommendation) { - // if we have a manual redaction entry for a recommendation, hide the recommendation - if (manualRedactionEntry) { - return; - } - annotationWrapper.recommendationType = redactionLogEntry.type.substr('recommendation_'.length); - } - annotationWrapper.comments = comments ? comments : []; - annotationWrapper.userId = manualRedactionEntry?.user || idRemoval?.user; - - if (redactionLogEntry) { - annotationWrapper.id = redactionLogEntry.id; - annotationWrapper.redaction = redactionLogEntry.redacted; - annotationWrapper.hint = redactionLogEntry.hint; - annotationWrapper.dictionary = redactionLogEntry.type; - annotationWrapper.value = redactionLogEntry.value; - annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; - annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; - annotationWrapper.positions = redactionLogEntry.positions; - annotationWrapper.content = AnnotationWrapper.createContent(redactionLogEntry); - annotationWrapper.status = redactionLogEntry.status; - annotationWrapper.textBefore = redactionLogEntry.textBefore; - annotationWrapper.textAfter = redactionLogEntry.textAfter; - } else { - // no redaction log entry - not yet processed - 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.createContent(manualRedactionEntry); - annotationWrapper.manual = true; - annotationWrapper.userId = manualRedactionEntry.user; - } - - AnnotationWrapper._setSuperType(annotationWrapper, redactionLogEntry, manualRedactionEntry, idRemoval); - - annotationWrapper.typeLabel = 'annotation-type.' + annotationWrapper.superType; - - return annotationWrapper; + get id() { + return this.isConvertedRecommendation ? this.pendingRecommendationAnnotationId : this.annotationId; } - private static _setSuperType( - annotationWrapper: AnnotationWrapper, - redactionLogEntry?: RedactionLogEntry, - manualRedactionEntry?: ManualRedactionEntry, - idRemoval?: IdRemoval - ) { - if (idRemoval) { - annotationWrapper.dictionaryOperation = idRemoval.removeFromDictionary; - if (idRemoval.status === 'DECLINED') { - annotationWrapper.superType = 'declined-suggestion'; - } else { - if (idRemoval.removeFromDictionary) { - annotationWrapper.superType = idRemoval.status === 'REQUESTED' ? 'suggestion-remove-dictionary' : 'remove-dictionary'; - } else { - // TODO check me - annotationWrapper.superType = idRemoval.status === 'REQUESTED' ? 'suggestion-remove' : 'ignore'; - } - } - } - - if (manualRedactionEntry) { - annotationWrapper.dictionaryOperation = manualRedactionEntry.addToDictionary; - if (manualRedactionEntry.status === 'DECLINED') { - annotationWrapper.superType = 'declined-suggestion'; - } else { - if (manualRedactionEntry.addToDictionary) { - annotationWrapper.superType = manualRedactionEntry.status === 'REQUESTED' ? 'suggestion-add-dictionary' : 'add-dictionary'; - } else { - // TODO check me - annotationWrapper.superType = manualRedactionEntry.status === 'REQUESTED' ? 'suggestion-add' : 'manual'; - } - } - } - - if (!annotationWrapper.superType) { - annotationWrapper.superType = annotationWrapper.redaction ? 'redaction' : annotationWrapper.hint ? 'hint' : 'ignore'; - } - } - - private static _setTypeLabel(annotationWrapper: AnnotationWrapper) { - annotationWrapper.typeLabel = annotationWrapper.superType; - } - - constructor() {} - get x() { return this.firstTopLeftPoint.x; } @@ -239,6 +137,76 @@ export class AnnotationWrapper { return this.firstTopLeftPoint.y; } + static fromData(redactionLogEntry?: RedactionLogEntryWrapper) { + const annotationWrapper = new AnnotationWrapper(); + + annotationWrapper.annotationId = redactionLogEntry.id; + annotationWrapper.redaction = redactionLogEntry.redacted; + annotationWrapper.hint = redactionLogEntry.hint; + annotationWrapper.dictionary = redactionLogEntry.type; + annotationWrapper.value = redactionLogEntry.value; + annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; + annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; + annotationWrapper.positions = redactionLogEntry.positions; + annotationWrapper.status = redactionLogEntry.status; + annotationWrapper.textBefore = redactionLogEntry.textBefore; + annotationWrapper.textAfter = redactionLogEntry.textAfter; + annotationWrapper.dictionaryOperation = redactionLogEntry.dictionaryEntry; + annotationWrapper.userId = redactionLogEntry.userId; + annotationWrapper.content = AnnotationWrapper.createContent(redactionLogEntry); + AnnotationWrapper._setSuperType(annotationWrapper, redactionLogEntry); + AnnotationWrapper._handleRecommendations(annotationWrapper, redactionLogEntry); + + annotationWrapper.content = annotationWrapper.id; + + if (annotationWrapper.dictionary === 'PII') { + annotationWrapper.content = annotationWrapper.id; + console.log(annotationWrapper, redactionLogEntry, annotationWrapper.id); + } + + return annotationWrapper; + } + + private static _handleRecommendations(annotationWrapper: AnnotationWrapper, redactionLogEntry: RedactionLogEntryWrapper) { + annotationWrapper.recommendation = !!redactionLogEntry?.recommendation; + if (annotationWrapper.recommendation) { + annotationWrapper.recommendationType = redactionLogEntry.type.substr('recommendation_'.length); + if (annotationWrapper.isConvertedRecommendation) { + annotationWrapper.dictionary = annotationWrapper.recommendationType; + annotationWrapper.pendingRecommendationAnnotationId = redactionLogEntry.pendingRecommendationAnnotationId; + } + } + } + + private static _setSuperType(annotationWrapper: AnnotationWrapper, redactionLogEntryWrapper: RedactionLogEntryWrapper) { + if (redactionLogEntryWrapper.manual && redactionLogEntryWrapper.status === 'DECLINED') { + annotationWrapper.superType = 'declined-suggestion'; + return; + } + + if (redactionLogEntryWrapper.type === 'manual') { + annotationWrapper.superType = redactionLogEntryWrapper.status === 'REQUESTED' ? 'suggestion-add' : 'manual-redaction'; + } else { + if (redactionLogEntryWrapper.status === 'REQUESTED') { + if (redactionLogEntryWrapper.dictionaryEntry) { + annotationWrapper.superType = + redactionLogEntryWrapper.manualRedactionType === 'ADD' ? 'suggestion-add-dictionary' : 'suggestion-remove-dictionary'; + } else { + annotationWrapper.superType = redactionLogEntryWrapper.manualRedactionType === 'ADD' ? 'suggestion-add' : 'suggestion-remove'; + } + } + if (redactionLogEntryWrapper.status === 'APPROVED') { + annotationWrapper.superType = redactionLogEntryWrapper.manualRedactionType === 'ADD' ? 'add-dictionary' : 'remove-dictionary'; + } + } + + if (!annotationWrapper.superType) { + annotationWrapper.superType = annotationWrapper.redaction ? 'redaction' : annotationWrapper.hint ? 'hint' : 'ignore'; + } + + annotationWrapper.typeLabel = 'annotation-type.' + annotationWrapper.superType; + } + private static createContent(entry: any) { let content = ''; if (entry.matchedRule) { 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 3f918b584..d031d391e 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 @@ -2,6 +2,7 @@ import { Comment, IdRemoval, ManualRedactionEntry, ManualRedactions, RedactionLo import { FileStatusWrapper } from './file-status.wrapper'; import { UserWrapper } from '../../../user/user.service'; import { AnnotationWrapper } from './annotation.wrapper'; +import { RedactionLogEntryWrapper } from './redaction-log-entry.wrapper'; export interface AnnotationPair { redactionLogEntry?: RedactionLogEntry; @@ -26,85 +27,149 @@ export class FileDataModel { } getAnnotations(dictionaryData: { [p: string]: TypeValue }, currentUser: UserWrapper, areDevFeaturesEnabled: boolean): AnnotationWrapper[] { - const annotations = []; + const entries: RedactionLogEntryWrapper[] = this._convertData(dictionaryData); - const pairs: AnnotationPair[] = this._createPairs(); + let annotations = entries.map((entry) => AnnotationWrapper.fromData(entry)); - pairs.forEach((pair) => { - const annotation = AnnotationWrapper.fromData( - currentUser, - dictionaryData, - this.fileStatus, - pair.redactionLogEntry, - pair.manualRedactionEntry, - pair.idRemoval, - pair.comments - ); - if (annotation) { - // skip annotations that were marked as false positive - if (pair.manualRedactionEntry?.type === 'false_positive' && pair.redactionLogEntry) { - return; - } - - if (annotation.isIgnored && !areDevFeaturesEnabled) { - return; - } - - if (annotation.isFalsePositive && !areDevFeaturesEnabled) { - return; - } - - if (annotation.isReadyForAnalysis && annotation.isApproved) { - // - } else { - annotations.push(annotation); - } + // filter based on dev-mode + annotations = annotations.filter((annotation) => { + if (!areDevFeaturesEnabled) { + return !annotation.isIgnored && !annotation.isFalsePositive; + } else { + return true; } }); return annotations; } - private _createPairs(): AnnotationPair[] { - const pairs: AnnotationPair[] = []; + private _convertData(dictionaryData: { [p: string]: TypeValue }): RedactionLogEntryWrapper[] { + let result: RedactionLogEntryWrapper[] = []; - this.redactionLog.redactionLogEntry.forEach((rdl) => { - pairs.push({ - redactionLogEntry: rdl, - // only not declined - manualRedactionEntry: this.manualRedactions.entriesToAdd.find( - (eta) => (eta.id === rdl.id || eta.reason === rdl.id) && this._validateEntry(eta) - ), - // only not declined - idRemoval: this.manualRedactions.idsToRemove.find((idr) => idr.id === rdl.id && this._dateValid(idr)), - comments: this.manualRedactions.comments[rdl.id] - }); + this.redactionLog.redactionLogEntry.forEach((redactionLogEntry) => { + // copy the redactionLog Entry + const wrapper: RedactionLogEntryWrapper = {}; + Object.assign(wrapper, redactionLogEntry); + wrapper.comments = this.manualRedactions.comments[wrapper.id]; + result.push(wrapper); }); - this.manualRedactions.entriesToAdd.forEach((eta) => { - // only not declined - if (this._dateValid(eta)) { - const redactionLogEntry = this.redactionLog.redactionLogEntry.find((rdl) => rdl.id === eta.id); - if (!redactionLogEntry) { - pairs.push({ - redactionLogEntry: null, - manualRedactionEntry: eta, - // only not declined - idRemoval: this.manualRedactions.idsToRemove.find((idr) => idr.id === eta.id), - comments: this.manualRedactions.comments[eta.id] - }); + this.manualRedactions.entriesToAdd.forEach((manual) => { + if (this._hasAlreadyBeenProcessed(manual) && this._isAcceptedOrRejected(manual)) { + let wrapper = result.find((r) => r.id === manual.id); + if (wrapper) { + wrapper.userId = manual.user; + } else { + wrapper = result.find((r) => r.id === manual.reason); + // if we found it + if (wrapper) { + wrapper.userId = manual.user; + } } + return; + } + + // normal case + let wrapper = result.find((r) => r.id === manual.id); + if (!wrapper) { + // false positive and recommendation case + // if we mark Annotation N as false positive -> it's reason is the original annotations Id + // if we confirm a recommendation, it's reason is the original annotations Id + wrapper = result.find((r) => r.id === manual.reason); + // if we found it + if (wrapper) { + // it's a recommendation if it's not a false positive + + wrapper.recommendation = manual.type !== 'false_positive'; + if (wrapper.recommendation) { + wrapper.pendingRecommendationAnnotationId = manual.id; + } + wrapper.manual = true; + wrapper.manualRedactionType = 'ADD'; + wrapper.status = manual.status; + } else { + const dictionary = dictionaryData[manual.type]; + + wrapper = {}; + + wrapper.id = manual.id; + wrapper.dictionaryEntry = manual.addToDictionary; + wrapper.legalBasis = manual.legalBasis; + wrapper.positions = manual.positions; + wrapper.reason = manual.reason; + wrapper.status = manual.status; + wrapper.type = manual.type; + wrapper.userId = manual.user; + wrapper.value = manual.value; + wrapper.redacted = !dictionary.hint; + wrapper.hint = dictionary.hint; + wrapper.manualRedactionType = 'ADD'; + wrapper.manual = true; + wrapper.comments = this.manualRedactions.comments[wrapper.id]; + + result.push(wrapper); + } + } else { + wrapper.confirmed = true; } }); - return pairs; + this.manualRedactions.idsToRemove.forEach((idToRemove) => { + if (this._hasAlreadyBeenProcessed(idToRemove) && this._isAcceptedOrRejected(idToRemove)) { + const wrapper = result.find((r) => r.id === idToRemove.id); + if (wrapper && wrapper.dictionaryEntry) { + wrapper.manual = false; + wrapper.manualRedactionType = null; + wrapper.status = null; + } + return; + } + + const wrapper = result.find((r) => r.id === idToRemove.id); + if (wrapper) { + wrapper.manual = true; + wrapper.dictionaryEntry = idToRemove.removeFromDictionary; + wrapper.userId = idToRemove.user; + wrapper.status = idToRemove.status; + wrapper.manualRedactionType = 'REMOVE'; + } + }); + + result.forEach((id) => { + if (id.id === '57205cfd183653d4d159dc8d07f86a4c') { + console.log(' ========= ', id); + } + }); + + // remove undone entriesToAdd and idsToRemove + result = result.filter((redactionLogEntry) => { + if (redactionLogEntry.manual) { + if (redactionLogEntry.manualRedactionType === 'ADD') { + const foundManualEntry = this.manualRedactions.entriesToAdd.find((me) => me.id === redactionLogEntry.id); + if (!foundManualEntry) { + return false; + } + } + if (redactionLogEntry.manualRedactionType === 'REMOVE') { + const foundManualEntry = this.manualRedactions.idsToRemove.find((me) => me.id === redactionLogEntry.id); + if (!foundManualEntry) { + redactionLogEntry.manual = false; + redactionLogEntry.manualRedactionType = null; + redactionLogEntry.status = null; + } + } + } + return true; + }); + + return result; } - private _validateEntry(entry: ManualRedactionEntry): boolean { - return this._dateValid(entry) || entry.type === 'manual'; + private _isAcceptedOrRejected(entry: ManualRedactionEntry | IdRemoval): boolean { + return entry.status === 'APPROVED' || entry.status === 'DECLINED'; } - private _dateValid(entry: ManualRedactionEntry | IdRemoval): boolean { - return new Date(entry.processedDate).getTime() > new Date(this.fileStatus.lastProcessed).getTime() || !entry.processedDate; + private _hasAlreadyBeenProcessed(entry: ManualRedactionEntry | IdRemoval): boolean { + return !entry.processedDate ? false : new Date(entry.processedDate).getTime() < new Date(this.fileStatus.lastProcessed).getTime(); } } diff --git a/apps/red-ui/src/app/screens/file/model/redaction-log-entry.wrapper.ts b/apps/red-ui/src/app/screens/file/model/redaction-log-entry.wrapper.ts new file mode 100644 index 000000000..b7ba39dfe --- /dev/null +++ b/apps/red-ui/src/app/screens/file/model/redaction-log-entry.wrapper.ts @@ -0,0 +1,27 @@ +import { Rectangle, Comment } from '@redaction/red-ui-http'; + +export interface RedactionLogEntryWrapper { + color?: Array; + dictionaryEntry?: boolean; + hint?: boolean; + id?: string; + legalBasis?: string; + manual?: boolean; + manualRedactionType?: 'ADD' | 'REMOVE'; + matchedRule?: number; + positions?: Array; + reason?: string; + recommendation?: boolean; + pendingRecommendationAnnotationId?: string; + redacted?: boolean; + section?: string; + sectionNumber?: number; + status?: 'REQUESTED' | 'APPROVED' | 'DECLINED'; + textAfter?: string; + textBefore?: string; + type?: string; + value?: string; + userId?: string; + comments?: Comment[]; + confirmed?: boolean; +} diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 7ee1d2de0..6a012eb97 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -463,7 +463,7 @@ "ignore": "Ignore", "hint": "Hint", "redaction": "Redaction", - "manual": "Manual Redaction", + "manual-redaction": "Manual Redaction", "declined-suggestion": "Declined Suggestion" }, "manual-annotation": {