diff --git a/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts b/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts index 6c40fb94a..411e58904 100644 --- a/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts @@ -8,6 +8,7 @@ import { TranslateService } from '@ngx-translate/core'; import { UserService } from '../../user/user.service'; import { ManualRedactionEntryWrapper } from '../../screens/file/model/manual-redaction-entry.wrapper'; import { ManualAnnotationService } from '../../screens/file/service/manual-annotation.service'; +import { ManualAnnotationResponse } from '../../screens/file/model/manual-annotation-response'; @Component({ selector: 'redaction-manual-annotation-dialog', @@ -63,7 +64,9 @@ export class ManualAnnotationDialogComponent implements OnInit { .makeDictionaryEntry(this.manualRedactionEntryWrapper.manualRedactionEntry) .subscribe( (response) => { - this.dialogRef.close(this.manualRedactionEntryWrapper); + this.dialogRef.close( + new ManualAnnotationResponse(this.manualRedactionEntryWrapper, response) + ); }, () => { this.dialogRef.close(); @@ -74,7 +77,9 @@ export class ManualAnnotationDialogComponent implements OnInit { .makeRedaction(this.manualRedactionEntryWrapper.manualRedactionEntry) .subscribe( (response) => { - this.dialogRef.close(this.manualRedactionEntryWrapper); + this.dialogRef.close( + new ManualAnnotationResponse(this.manualRedactionEntryWrapper, response) + ); }, () => { this.dialogRef.close(); 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 36cadd258..fb97c259d 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 @@ -268,6 +268,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 a22e09cfa..8e483ef8e 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 @@ -27,6 +27,7 @@ import { ManualRedactionEntryWrapper } from '../model/manual-redaction-entry.wra import { hexToRgb } from '../../../utils/functions'; import { AnnotationWrapper } from '../model/annotation.wrapper'; import { ManualAnnotationService } from '../service/manual-annotation.service'; +import { ManualAnnotationResponse } from '../model/manual-annotation-response'; @Component({ selector: 'redaction-file-preview-screen', @@ -195,9 +196,9 @@ export class FilePreviewScreenComponent implements OnInit { this.ngZone.run(() => { this._dialogRef = this._dialogService.openManualRedactionDialog( $event, - (response: ManualRedactionEntryWrapper) => { + (response: ManualAnnotationResponse) => { const manualRedactionEntry: ManualRedactionEntry = - response.manualRedactionEntry; + response.manualRedactionEntryWrapper.manualRedactionEntry; const annotManager = this.activeViewer.annotManager; const originalQuads = $event.quads; @@ -208,7 +209,7 @@ export class FilePreviewScreenComponent implements OnInit { highlight.StrokeColor = this._getColor(manualRedactionEntry); highlight.setContents(manualRedactionEntry.reason); highlight.Quads = originalQuads[key]; - highlight.Id = this._computeId(response.type, manualRedactionEntry); + highlight.Id = this._computeId(response); annotManager.addAnnotation(highlight, true); annotManager.redrawAnnotation(highlight); } @@ -470,20 +471,20 @@ export class FilePreviewScreenComponent implements OnInit { this._changeDetectorRef.detectChanges(); } - private _computeId(type: 'DICTIONARY' | 'REDACTION', request: ManualRedactionEntry) { + private _computeId(response: ManualAnnotationResponse) { // if owner or not set the request prefix in the id const prefix = this.appStateService.isActiveProjectOwner ? '' : 'request:add:'; if (prefix.length > 0) { - return prefix + request.type + ':' + new Date().getTime(); + return prefix + response.dictionary + ':' + response.annotationId; } else { const dictionaryType: 'hint' | 'redaction' = - type === 'REDACTION' + response.manualRedactionEntryWrapper.type === 'REDACTION' ? 'redaction' - : this.appStateService.getDictionaryTypeValue(request.type).hint + : this.appStateService.getDictionaryTypeValue(response.dictionary).hint ? 'hint' : 'redaction'; - return dictionaryType + ':' + request.type + ':' + new Date().getTime(); + return dictionaryType + ':' + response.dictionary + ':' + response.annotationId; } } 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 73308dda8..07174c644 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,4 +1,5 @@ import { Annotations } from '@pdftron/webviewer'; +import { ManualRedactionEntry } from '@redaction/red-ui-http'; export class AnnotationWrapper { superType: 'request' | 'redaction' | 'hint' | 'ignore'; @@ -6,8 +7,12 @@ export class AnnotationWrapper { color: string; comments: string[] = []; uuid: string; + manualRedactionEntry: ManualRedactionEntry; - constructor(public annotation: Annotations.Annotation) { + constructor( + public annotation: Annotations.Annotation, + manualRedactionEntries?: ManualRedactionEntry[] + ) { this.comments = annotation['Mi'] ? annotation['Mi'].map((m) => m.eC) : []; const parts = annotation.Id.split(':'); // first part is always the superType @@ -19,6 +24,13 @@ export class AnnotationWrapper { this.dictionary = parts[2] !== 'only_here' ? parts[2] : undefined; } this.uuid = parts[parts.length - 1]; + this.manualRedactionEntry = manualRedactionEntries + ? manualRedactionEntries.find((e) => e.id === this.uuid) + : undefined; + } + + get manualRedactionOwner() { + return this.manualRedactionEntry?.user; } get x() { diff --git a/apps/red-ui/src/app/screens/file/model/manual-annotation-response.ts b/apps/red-ui/src/app/screens/file/model/manual-annotation-response.ts new file mode 100644 index 000000000..6902baf78 --- /dev/null +++ b/apps/red-ui/src/app/screens/file/model/manual-annotation-response.ts @@ -0,0 +1,23 @@ +import { ManualRedactionEntryWrapper } from './manual-redaction-entry.wrapper'; +import { ManualAddResponse } from '@redaction/red-ui-http'; + +export class ManualAnnotationResponse { + annotationId; + commentId; + + constructor( + public manualRedactionEntryWrapper: ManualRedactionEntryWrapper, + public manualAddResponse: ManualAddResponse + ) { + this.annotationId = manualAddResponse?.annotationId + ? manualAddResponse.annotationId + : new Date().getTime(); + this.commentId = manualAddResponse?.commentId + ? manualAddResponse.commentId + : new Date().getTime(); + } + + get dictionary() { + return this.manualRedactionEntryWrapper.manualRedactionEntry.type; + } +} diff --git a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts index ba38c9247..072f94464 100644 --- a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts +++ b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts @@ -81,7 +81,8 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges { this._annotationEventDebouncer.pipe(throttleTime(300)).subscribe((value) => { this.annotationsAdded.emit( AnnotationUtils.filterAndConvertAnnotations( - this.instance.annotManager.getAnnotationsList() + this.instance.annotManager.getAnnotationsList(), + this._manualAnnotationService.manualEntries ) ); // nasty double-emit fix, the annotationList is not updated when the event is fired @@ -89,15 +90,14 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges { () => this.annotationsAdded.emit( AnnotationUtils.filterAndConvertAnnotations( - this.instance.annotManager.getAnnotationsList() + this.instance.annotManager.getAnnotationsList(), + this._manualAnnotationService.manualEntries ) ), 200 ); }); - this._manualAnnotationService.getManualAnnotations().subscribe((manualAnnotation) => { - this._manualAnnotations = manualAnnotation; - }); + this._manualAnnotationService.loadManualAnnotationsForActiveFile().subscribe(() => {}); } ngOnChanges(changes: SimpleChanges): void { diff --git a/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts b/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts index a1be2f032..dd2c4cb50 100644 --- a/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts +++ b/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts @@ -3,19 +3,28 @@ import { AppStateService } from '../../../state/app-state.service'; import { DictionaryControllerService, ManualRedactionControllerService, - ManualRedactionEntry + ManualRedactionEntry, + ManualRedactions } from '@redaction/red-ui-http'; import { AnnotationWrapper } from '../model/annotation.wrapper'; import { NotificationService, NotificationType } from '../../../notification/notification.service'; import { TranslateService } from '@ngx-translate/core'; -import { tap } from 'rxjs/operators'; +import { map, mergeMap, tap } from 'rxjs/operators'; +import { UserService } from '../../../user/user.service'; @Injectable({ providedIn: 'root' }) export class ManualAnnotationService { + private _manualAnnotationsResponse: ManualRedactions; + + get manualEntries(): ManualRedactionEntry[] { + return this._manualAnnotationsResponse ? this._manualAnnotationsResponse.entriesToAdd : []; + } + constructor( private readonly _appStateService: AppStateService, + private readonly _userService: UserService, private readonly _translateService: TranslateService, private readonly _notificationService: NotificationService, private readonly _manualRedactionControllerService: ManualRedactionControllerService, @@ -49,20 +58,7 @@ export class ManualAnnotationService { .pipe( tap( () => { - // if approved - and not only here, make a dictionary entry - if (annotationWrapper.id.indexOf(':only_here:') < 0) { - this.getManualAnnotations().subscribe((annotations) => { - annotations.entriesToAdd.forEach((a) => { - // found the annotation - if (annotationWrapper.id.indexOf(a.id) >= 0) { - console.log(a); - this._makeDictionaryEntry(a).subscribe(() => {}); - } - }); - }); - } else { - this._notify('manual-annotation.reject-request.success'); - } + this._notify('manual-annotation.reject-request.success'); }, () => { this._notify('manual-annotation.reject-request.error'); @@ -72,12 +68,22 @@ export class ManualAnnotationService { } public rejectSuggestion(annotationWrapper: AnnotationWrapper) { - return this._manualRedactionControllerService - .undo( - this._appStateService.activeProjectId, - this._appStateService.activeFile.fileId, - annotationWrapper.uuid - ) + console.log(annotationWrapper); + // if you're the owner, you undo, otherwise you reject + const observable = + annotationWrapper.manualRedactionOwner === this._userService.userId + ? this._manualRedactionControllerService.undo( + this._appStateService.activeProjectId, + this._appStateService.activeFile.fileId, + annotationWrapper.uuid + ) + : this._manualRedactionControllerService.declineRequest( + this._appStateService.activeProjectId, + this._appStateService.activeFile.fileId, + annotationWrapper.uuid + ); + + return observable .pipe( tap( () => { @@ -87,6 +93,11 @@ export class ManualAnnotationService { this._notify('manual-annotation.reject-request.error'); } ) + ) + .pipe( + mergeMap((result) => { + return this.loadManualAnnotationsForActiveFile().pipe(map(() => result)); + }) ); } @@ -129,6 +140,11 @@ export class ManualAnnotationService { ); } ) + ) + .pipe( + mergeMap((result) => { + return this.loadManualAnnotationsForActiveFile().pipe(map(() => result)); + }) ); } @@ -149,6 +165,11 @@ export class ManualAnnotationService { ); } ) + ) + .pipe( + mergeMap((result) => { + return this.loadManualAnnotationsForActiveFile().pipe(map(() => result)); + }) ); } @@ -176,10 +197,16 @@ export class ManualAnnotationService { } } - getManualAnnotations() { - return this._manualRedactionControllerService.getManualRedaction( - this._appStateService.activeProject.project.projectId, - this._appStateService.activeFile.fileId - ); + loadManualAnnotationsForActiveFile() { + return this._manualRedactionControllerService + .getManualRedaction( + this._appStateService.activeProject.project.projectId, + this._appStateService.activeFile.fileId + ) + .pipe( + tap((response) => { + this._manualAnnotationsResponse = response; + }) + ); } } diff --git a/apps/red-ui/src/app/utils/annotation-utils.ts b/apps/red-ui/src/app/utils/annotation-utils.ts index 2f749b773..0b4ca1ffc 100644 --- a/apps/red-ui/src/app/utils/annotation-utils.ts +++ b/apps/red-ui/src/app/utils/annotation-utils.ts @@ -1,6 +1,7 @@ import { Annotations } from '@pdftron/webviewer'; import { AnnotationFilters } from './types'; import { AnnotationWrapper } from '../screens/file/model/annotation.wrapper'; +import { ManualRedactionEntry } from '@redaction/red-ui-http'; export class AnnotationUtils { public static sortAnnotations(annotations: AnnotationWrapper[]): AnnotationWrapper[] { @@ -88,11 +89,14 @@ export class AnnotationUtils { return obj; } - public static filterAndConvertAnnotations(annotations: Annotations.Annotation[]) { + public static filterAndConvertAnnotations( + annotations: Annotations.Annotation[], + manualRedactions: ManualRedactionEntry[] + ) { const convertedAnnotations: AnnotationWrapper[] = []; for (const annotation of annotations) { if (annotation.Id.indexOf(':') > 0) { - convertedAnnotations.push(new AnnotationWrapper(annotation)); + convertedAnnotations.push(new AnnotationWrapper(annotation, manualRedactions)); } } return convertedAnnotations;