integrated comments and fixed some flows for manual redactions

This commit is contained in:
Timo Bejan 2020-11-01 22:34:47 +02:00
parent ad43c3d53a
commit 8925841f91
9 changed files with 123 additions and 47 deletions

View File

@ -1,13 +1,17 @@
<div class="comments">
<ng-container *ngFor="let comment of comments; let idx = index">
<div class="comments" *ngIf="annotation.manual">
<ng-container *ngFor="let comment of annotation.comments; let idx = index">
<div class="comment" *ngIf="idx < 2 || expanded">
<div class="comment-icon">
<mat-icon svgIcon="red:comment"></mat-icon>
</div>
<div class="trash-icon" (click)="deleteComment(comment)">
<div class="trash-icon red" (click)="deleteComment(comment)">
<mat-icon svgIcon="red:trash"></mat-icon>
</div>
<div>{{ comment }}</div>
<!-- <div class="trash-icon" *ngIf="!canDeleteComment(comment)">-->
<!-- <mat-icon svgIcon="red:comment"></mat-icon>-->
<!-- </div>-->
<div>{{ comment.text }}</div>
</div>
</ng-container>
@ -16,10 +20,10 @@
<span [translate]="'comments.show-' + (expanded ? 'less' : 'more')"></span>
</div>
<!-- <form [formGroup]="commentForm" (submit)="addComment()">-->
<!-- <div class="red-input-group">-->
<!-- <input formControlName="comment" name="comment" type="text" />-->
<!-- <mat-icon svgIcon="red:check-alt" class="check-icon" (click)="addComment()"></mat-icon>-->
<!-- </div>-->
<!-- </form>-->
<form [formGroup]="commentForm" (submit)="addComment()">
<div class="red-input-group">
<input formControlName="comment" name="comment" type="text" />
<mat-icon svgIcon="red:check-alt" class="check-icon" (click)="addComment()"></mat-icon>
</div>
</form>
</div>

View File

@ -37,8 +37,11 @@
}
.trash-icon {
color: $primary;
display: none;
&.red {
color: $primary;
}
}
&:hover {

View File

@ -1,19 +1,26 @@
import { ChangeDetectorRef, Component, Input } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Comment } from '@redaction/red-ui-http';
import { ManualAnnotationService } from '../../screens/file/service/manual-annotation.service';
import { AnnotationWrapper } from '../../screens/file/model/annotation.wrapper';
import { UserService } from '../../user/user.service';
import { AppStateService } from '../../state/app-state.service';
@Component({
selector: 'redaction-comments',
templateUrl: './comments.component.html',
styleUrls: ['./comments.component.scss']
})
export class CommentsComponent {
@Input() public comments: string[] = [];
@Input() public annotation: AnnotationWrapper;
public expanded = false;
public commentForm: FormGroup;
constructor(
private readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _formBuilder: FormBuilder
private readonly _appStateService: AppStateService,
private readonly _formBuilder: FormBuilder,
private readonly _userService: UserService,
private readonly _manualAnnotationService: ManualAnnotationService
) {
this.commentForm = this._formBuilder.group({
comment: ['', Validators.required]
@ -21,7 +28,7 @@ export class CommentsComponent {
}
public get more(): boolean {
return this.comments.length > 2;
return this.annotation?.comments?.length > 2;
}
public toggleSeeMore($event: MouseEvent): void {
@ -31,11 +38,30 @@ export class CommentsComponent {
}
public addComment(): void {
console.log(`Adding comment "${this.commentForm.value.comment}"...`);
const value = this.commentForm.value.comment;
if (value) {
this._manualAnnotationService
.addComment(value, this.annotation.id)
.subscribe((commentResponse) => {
this.annotation.comments.push({
text: value,
id: commentResponse.commentId,
user: this._userService.userId
});
});
}
this.commentForm.reset();
}
public deleteComment(comment: string): void {
console.log(`Deleting comment "${comment}"...`);
public deleteComment(comment: Comment): void {
this._manualAnnotationService
.deleteComment(comment.id, this.annotation.id)
.subscribe(() => {
this.annotation.comments.splice(this.annotation.comments.indexOf(comment), 1);
});
}
canDeleteComment(comment: Comment) {
return comment.user === this._userService.userId;
}
}

View File

@ -159,14 +159,12 @@
</div>
</div>
<div class="page-number">
{{ annotation.pageNumber }}
</div>
<!-- <div class="page-number">-->
<!-- {{ annotation.pageNumber }}-->
<!-- </div>-->
</div>
<redaction-comments
[comments]="annotation.comments"
></redaction-comments>
<redaction-comments [annotation]="annotation"></redaction-comments>
<div
*ngIf="annotation.superType === 'request'"

View File

@ -116,7 +116,7 @@ redaction-pdf-viewer {
position: absolute;
right: 0;
top: 0;
bottom: 0;
height: 40px;
display: none;
align-items: center;
justify-content: flex-end;

View File

@ -120,11 +120,19 @@ export class FilePreviewScreenComponent implements OnInit {
.loadFileData(this.appStateService.activeProjectId, this.fileId)
.subscribe((fileDataModel) => {
this.fileData = fileDataModel;
const manualRedactionAnnotations = fileDataModel.manualRedactions.entriesToAdd.map(
(mr) => AnnotationWrapper.fromManualRedaction(mr)
const manualRedactionAnnotations = fileDataModel.entriesToAdd.map((mr) =>
AnnotationWrapper.fromManualRedaction(
mr,
fileDataModel.manualRedactions.comments
)
);
const redactionLogAnnotations = fileDataModel.redactionLog.redactionLogEntry.map(
(rde) => AnnotationWrapper.fromRedactionLog(rde)
(rde) =>
AnnotationWrapper.fromRedactionLog(
rde,
fileDataModel.manualRedactions.comments
)
);
this.annotations.push(...manualRedactionAnnotations);
@ -132,6 +140,7 @@ export class FilePreviewScreenComponent implements OnInit {
this.filters = this._annotationProcessingService.getAnnotationFilter(
this.annotations
);
this.filtersChanged(this.filters);
this._changeDetectorRef.detectChanges();
});
}
@ -424,10 +433,7 @@ export class FilePreviewScreenComponent implements OnInit {
viewerReady($event: WebViewerInstance) {
this.instance = $event;
this.viewReady = true;
this._annotationDrawService.drawAnnotations(
this.instance,
this.fileData.manualRedactions.entriesToAdd
);
this._annotationDrawService.drawAnnotations(this.instance, this.fileData.entriesToAdd);
}
filtersChanged(filters: FilterModel[]) {

View File

@ -1,18 +1,21 @@
import { ManualRedactionEntry, Point, RedactionLogEntry } from '@redaction/red-ui-http';
import { Comment, ManualRedactionEntry, Point, RedactionLogEntry } from '@redaction/red-ui-http';
export class AnnotationWrapper {
superType: 'request' | 'redaction' | 'hint' | 'ignore';
dictionary: string;
color: string;
comments: string[] = [];
uuid: string;
comments: Comment[] = [];
manualRedactionEntry: ManualRedactionEntry;
firstTopLeftPoint: Point;
id: string;
content: string;
manual: boolean;
pageNumber;
static fromRedactionLog(redactionLogEntry: RedactionLogEntry) {
static fromRedactionLog(
redactionLogEntry: RedactionLogEntry,
comments: { [key: string]: Array<Comment> }
) {
const annotationWrapper = new AnnotationWrapper();
annotationWrapper.superType = redactionLogEntry.redacted
? 'redaction'
@ -23,16 +26,24 @@ export class AnnotationWrapper {
annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft;
annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page;
annotationWrapper.id = redactionLogEntry.id;
annotationWrapper.manual = false;
annotationWrapper.content =
annotationWrapper.superType === 'redaction' || annotationWrapper.superType === 'ignore'
? AnnotationWrapper.createAnnotationContentForRedactionLogEntry(redactionLogEntry)
: null;
annotationWrapper.comments = comments[redactionLogEntry.id]
? comments[redactionLogEntry.id]
: [];
return annotationWrapper;
}
static fromManualRedaction(manualRedactionEntry: ManualRedactionEntry) {
static fromManualRedaction(
manualRedactionEntry: ManualRedactionEntry,
comments: { [key: string]: Array<Comment> }
) {
console.log(manualRedactionEntry);
const annotationWrapper = new AnnotationWrapper();
annotationWrapper.superType = 'request';
annotationWrapper.superType = !manualRedactionEntry.addToDictionary ? 'request' : 'request';
annotationWrapper.dictionary = manualRedactionEntry.type;
annotationWrapper.firstTopLeftPoint = manualRedactionEntry.positions[0]?.topLeft;
annotationWrapper.pageNumber = manualRedactionEntry.positions[0]?.page;
@ -40,6 +51,10 @@ export class AnnotationWrapper {
annotationWrapper.content = manualRedactionEntry.addToDictionary
? null
: AnnotationWrapper.createAnnotationContentForManualRedaction(manualRedactionEntry);
annotationWrapper.manual = true;
annotationWrapper.comments = comments[manualRedactionEntry.id]
? comments[manualRedactionEntry.id]
: [];
return annotationWrapper;
}

View File

@ -1,4 +1,4 @@
import { ManualRedactions, RedactionLog } from '@redaction/red-ui-http';
import { ManualRedactionEntry, ManualRedactions, RedactionLog } from '@redaction/red-ui-http';
export class FileDataModel {
constructor(
@ -7,4 +7,10 @@ export class FileDataModel {
public redactionLog: RedactionLog,
public manualRedactions: ManualRedactions
) {}
get entriesToAdd(): ManualRedactionEntry[] {
return this.manualRedactions.entriesToAdd.filter(
(e) => !this.redactionLog.redactionLogEntry.find((r) => r.id === e.id)
);
}
}

View File

@ -25,12 +25,30 @@ export class ManualAnnotationService {
private readonly _dictionaryControllerService: DictionaryControllerService
) {}
public addComment(comment: string, annotationId: string) {
return this._manualRedactionControllerService.addComment(
{ text: comment },
this._appStateService.activeProjectId,
this._appStateService.activeFileId,
annotationId
);
}
deleteComment(commentId: string, annotationId: string) {
return this._manualRedactionControllerService.undoComment(
this._appStateService.activeProjectId,
this._appStateService.activeFileId,
annotationId,
commentId
);
}
public makeDictionaryEntry(manualRedactionEntry: ManualRedactionEntry) {
if (this._appStateService.isActiveProjectOwner) {
return this._makeDictionaryEntry(manualRedactionEntry);
} else {
return this._makeDictionaryRequest(manualRedactionEntry);
}
// if (this._appStateService.isActiveProjectOwner) {
// return this._makeDictionaryEntry(manualRedactionEntry);
// } else {
return this._makeDictionaryRequest(manualRedactionEntry);
// }
}
public makeRedaction(manualRedactionEntry: ManualRedactionEntry) {
@ -47,7 +65,7 @@ export class ManualAnnotationService {
.approveRequest(
this._appStateService.activeProjectId,
this._appStateService.activeFile.fileId,
annotationWrapper.uuid
annotationWrapper.id
)
.pipe(
tap(
@ -68,12 +86,12 @@ export class ManualAnnotationService {
? this._manualRedactionControllerService.undo(
this._appStateService.activeProjectId,
this._appStateService.activeFile.fileId,
annotationWrapper.uuid
annotationWrapper.id
)
: this._manualRedactionControllerService.declineRequest(
this._appStateService.activeProjectId,
this._appStateService.activeFile.fileId,
annotationWrapper.uuid
annotationWrapper.id
);
return observable.pipe(