From f1f3dda4e36ab1d2d553b8528bdf5b47ec758b76 Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Tue, 27 Oct 2020 23:38:16 +0200 Subject: [PATCH] linked redaction file screen to backend colors and dictionary data --- apps/red-ui/proxy.conf.json | 6 ++ .../annotation-icon.component.html | 4 +- .../annotation-icon.component.scss | 23 ------ .../annotation-icon.component.ts | 3 +- .../manual-redaction-dialog.component.ts | 5 +- .../file-preview-screen.component.html | 21 +++--- .../file-preview-screen.component.ts | 13 ++-- .../screens/file/service/filters.service.ts | 26 ++++--- apps/red-ui/src/app/state/app-state.guard.ts | 1 + .../red-ui/src/app/state/app-state.service.ts | 71 ++++++++++++++++++- apps/red-ui/src/app/utils/annotation-utils.ts | 3 +- apps/red-ui/src/app/utils/functions.ts | 8 +++ apps/red-ui/src/app/utils/types.d.ts | 4 +- apps/red-ui/src/assets/i18n/en.json | 20 ++---- docker/common/nginx/nginx.conf.template | 3 + 15 files changed, 135 insertions(+), 76 deletions(-) diff --git a/apps/red-ui/proxy.conf.json b/apps/red-ui/proxy.conf.json index 91033ed01..53049ec45 100644 --- a/apps/red-ui/proxy.conf.json +++ b/apps/red-ui/proxy.conf.json @@ -52,5 +52,11 @@ "secure": false, "changeOrigin": true, "logLevel": "debug" + }, + "/color": { + "target": "https://timo-redaction-dev.iqser.cloud/", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" } } diff --git a/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.html b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.html index f5fe7f12d..b42260938 100644 --- a/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.html +++ b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.html @@ -1,3 +1,3 @@ -
- {{ type[0] }} +
+ {{ typeValue.type[0] }}
diff --git a/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.scss b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.scss index 360662073..cb9a7dd42 100644 --- a/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.scss +++ b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.scss @@ -40,33 +40,10 @@ } .hint, -.comment, .ignore { border-radius: 50%; } -.hint, -.redaction, -.comment { - background-color: $grey-1; -} - -.request { - background-color: $blue-1; -} - .ignore { background-color: $grey-5; } - -.hint_only { - background-color: $orange-1; -} - -.vertebrate { - background-color: $green-1; -} - -.names { - background-color: $yellow-2; -} 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 b317716b9..35dc28774 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,5 @@ import { Component, Input, OnInit } from '@angular/core'; +import { TypeValue } from '@redaction/red-ui-http'; @Component({ selector: 'redaction-annotation-icon', @@ -6,7 +7,7 @@ import { Component, Input, OnInit } from '@angular/core'; styleUrls: ['./annotation-icon.component.scss'] }) export class AnnotationIconComponent implements OnInit { - @Input() public type: 'hint' | 'redaction' | 'suggestion' | 'ignore' | 'comment' | 'request'; + @Input() typeValue: TypeValue; constructor() {} diff --git a/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-redaction-dialog.component.ts b/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-redaction-dialog.component.ts index 9fe639c75..57274bfca 100644 --- a/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-redaction-dialog.component.ts +++ b/apps/red-ui/src/app/dialogs/manual-redaction-dialog/manual-redaction-dialog.component.ts @@ -38,9 +38,8 @@ export class ManualRedactionDialogComponent implements OnInit { async ngOnInit() { this.isDocumentAdmin = - (this._appStateService.isActiveProjectOwner || - this._appStateService.isActiveFileDocumentReviewer) && - this._userService.user.isManager; + this._appStateService.isActiveProjectOwner && this._userService.user.isManager; + this.isDocumentAdmin = false; const commentField = this.isDocumentAdmin ? [null] : [null, Validators.required]; this.redactionForm = this._formBuilder.group({ addToDictionary: [false], 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 0a09f089f..84e6a33fa 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 @@ -145,8 +145,9 @@ color="primary" > + {{ 'file-preview.filter-menu.' + key + '.label' | translate }}
@@ -162,15 +163,11 @@ color="primary" > - {{ - 'file-preview.filter-menu.' + - key + - '.' + - subkey + - '.label' | translate - }} + {{ appStateService.getDictionaryLabel(subkey) }} @@ -223,7 +220,11 @@ (click)="selectAnnotation(annotation)" >
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 890ddf6d3..a150195aa 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 @@ -8,7 +8,12 @@ import { ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { ManualRedactionEntry, ReanalysisControllerService } from '@redaction/red-ui-http'; +import { + DictionaryControllerService, + ManualRedactionEntry, + ReanalysisControllerService, + TypeValue +} from '@redaction/red-ui-http'; import { AppStateService } from '../../../state/app-state.service'; import { Annotations, WebViewerInstance } from '@pdftron/webviewer'; import { PdfViewerComponent } from '../pdf-viewer/pdf-viewer.component'; @@ -56,6 +61,7 @@ export class FilePreviewScreenComponent implements OnInit { private readonly _activatedRoute: ActivatedRoute, private readonly _dialogService: DialogService, private readonly _router: Router, + private readonly _dictionaryControllerService: DictionaryControllerService, private readonly _userService: UserService, private readonly _fileDownloadService: FileDownloadService, private readonly _reanalysisControllerService: ReanalysisControllerService, @@ -67,7 +73,6 @@ export class FilePreviewScreenComponent implements OnInit { this.fileId = params.fileId; this.appStateService.activateFile(this.projectId, this.fileId); }); - this.filters = _filtersService.filters; } public get user() { @@ -91,7 +96,7 @@ export class FilePreviewScreenComponent implements OnInit { } public ngOnInit(): void { - // PDFTRON cache fix + this.filters = this._filtersService.getFilters(this.appStateService.dictionaryData); this._reloadFiles(); this.appStateService.fileStatusChanged.subscribe((fileStatus) => { if (fileStatus.fileId === this.fileId) { @@ -273,7 +278,7 @@ export class FilePreviewScreenComponent implements OnInit { }); } - public setAllFilters(filter: AnnotationFilters, value: boolean, rootKey?: string) { + public setAllFilters(filter: string, value: boolean, rootKey?: string) { if (rootKey) { this.filters[rootKey] = value; } else { diff --git a/apps/red-ui/src/app/screens/file/service/filters.service.ts b/apps/red-ui/src/app/screens/file/service/filters.service.ts index 406d0f58c..a1ab6b48a 100644 --- a/apps/red-ui/src/app/screens/file/service/filters.service.ts +++ b/apps/red-ui/src/app/screens/file/service/filters.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { AnnotationFilters } from '../../../utils/types'; +import { TypeValue } from '@redaction/red-ui-http'; @Injectable({ providedIn: 'root' @@ -8,18 +9,23 @@ export class FiltersService { constructor() {} private _filters: AnnotationFilters = { - hint: { - hint_only: false, - vertebrate: false, - names: false - }, - redaction: false, - comment: false, - suggestion: false, + hint: {}, + redaction: {}, + request: false, ignore: false }; - public get filters(): AnnotationFilters { - return JSON.parse(JSON.stringify(this._filters)); + public getFilters(dictionaryData: { [key: string]: TypeValue }): AnnotationFilters { + const filtersCopy = JSON.parse(JSON.stringify(this._filters)); + for (let key of Object.keys(dictionaryData)) { + const typeValue = dictionaryData[key]; + if (typeValue.hint === true) { + filtersCopy.hint[key] = false; + } + if (typeValue.hint === false) { + filtersCopy.redaction[key] = false; + } + } + return filtersCopy; } } diff --git a/apps/red-ui/src/app/state/app-state.guard.ts b/apps/red-ui/src/app/state/app-state.guard.ts index 9ba4ff530..0813c2472 100644 --- a/apps/red-ui/src/app/state/app-state.guard.ts +++ b/apps/red-ui/src/app/state/app-state.guard.ts @@ -15,6 +15,7 @@ export class AppStateGuard implements CanActivate { async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { await this._userService.loadAllUsersIfNecessary(); await this._appStateService.loadAllProjectsIfNecessary(); + await this._appStateService.loadDictionaryDataIfNecessary(); return true; } diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index faedae0cc..f42edd9dc 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -1,19 +1,22 @@ import { EventEmitter, Injectable } from '@angular/core'; import { + DictionaryControllerService, FileStatus, FileUploadControllerService, Project, ProjectControllerService, ReanalysisControllerService, - StatusControllerService + StatusControllerService, + TypeValue } from '@redaction/red-ui-http'; import { NotificationService, NotificationType } from '../notification/notification.service'; import { TranslateService } from '@ngx-translate/core'; import { Router } from '@angular/router'; import { UserService } from '../user/user.service'; -import { interval } from 'rxjs'; +import { forkJoin, interval } from 'rxjs'; import { tap } from 'rxjs/operators'; import { download } from '../utils/file-download-utils'; +import { humanize } from '../utils/functions'; export interface AppState { projects: ProjectWrapper[]; @@ -37,6 +40,7 @@ export class ProjectWrapper { }) export class AppStateService { private _appState: AppState; + private _dictionaryData: { [key: string]: TypeValue } = null; public fileStatusChanged = new EventEmitter(); @@ -48,6 +52,7 @@ export class AppStateService { private readonly _notificationService: NotificationService, private readonly _reanalysisControllerService: ReanalysisControllerService, private readonly _translateService: TranslateService, + private readonly _dictionaryControllerService: DictionaryControllerService, private readonly _statusControllerService: StatusControllerService ) { this._appState = { @@ -90,6 +95,19 @@ export class AppStateService { ); } + get dictionaryData() { + return this._dictionaryData; + } + + getDictionaryColor(type: string) { + const color = this._dictionaryData[type].hexColor; + return color ? color : this._dictionaryData['default'].hexColor; + } + + getDictionaryLabel(type: string) { + return this._dictionaryData[type]['label']; + } + get isActiveFileDocumentReviewer() { return this._appState.activeFile?.currentReviewer === this._userService.userId; } @@ -331,4 +349,53 @@ export class AppStateService { download(data, 'redaction-report-' + file.filename + '.docx'); }); } + + async loadDictionaryDataIfNecessary() { + if (!this._dictionaryData) { + this._dictionaryData = {}; + const typeObs = this._dictionaryControllerService.getAllTypes().pipe( + tap((typesResponse) => { + for (let type of typesResponse.types) { + this._dictionaryData[type.type] = type; + } + }) + ); + const colorsObs = this._dictionaryControllerService.getColors().pipe( + tap((colors) => { + this._dictionaryData['request'] = { + hexColor: colors.requestAdd, + type: 'request' + }; + this._dictionaryData['ignore'] = { + hexColor: colors.notRedacted, + type: 'ignore' + }; + this._dictionaryData['default'] = { + hexColor: colors.defaultColor, + type: 'default' + }; + this._dictionaryData['add'] = { hexColor: colors.requestAdd, type: 'add' }; + this._dictionaryData['remove'] = { + hexColor: colors.requestRemove, + type: 'remove' + }; + }) + ); + + const result = await forkJoin([typeObs, colorsObs]).toPromise(); + + this._dictionaryData['hint'] = { hexColor: '#283241', type: 'hint' }; + this._dictionaryData['redaction'] = { hexColor: '#283241', type: 'redaction' }; + for (let key of Object.keys(this._dictionaryData)) { + this._dictionaryData[key]['label'] = humanize(key); + } + } else { + return this._dictionaryData; + } + } + + getDictionaryTypeValue(key: string) { + const data = this._dictionaryData[key]; + return data ? data : this._dictionaryData['default']; + } } diff --git a/apps/red-ui/src/app/utils/annotation-utils.ts b/apps/red-ui/src/app/utils/annotation-utils.ts index 8ac39c182..ece0ddb0d 100644 --- a/apps/red-ui/src/app/utils/annotation-utils.ts +++ b/apps/red-ui/src/app/utils/annotation-utils.ts @@ -72,8 +72,7 @@ export class AnnotationUtils { annotations: [], hint: 0, redaction: 0, - comment: 0, - suggestion: 0, + request: 0, ignore: 0 }; } diff --git a/apps/red-ui/src/app/utils/functions.ts b/apps/red-ui/src/app/utils/functions.ts index 1ce38d109..87ebe129c 100644 --- a/apps/red-ui/src/app/utils/functions.ts +++ b/apps/red-ui/src/app/utils/functions.ts @@ -4,3 +4,11 @@ export function groupBy(xs: any[], key: string) { return rv; }, {}); } + +export function humanize(str: string) { + let frags = str.split(/[ \-_]+/); + for (let i = 0; i < frags.length; i++) { + frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1); + } + return frags.join(' '); +} diff --git a/apps/red-ui/src/app/utils/types.d.ts b/apps/red-ui/src/app/utils/types.d.ts index 9c0ad57e7..40d6aa603 100644 --- a/apps/red-ui/src/app/utils/types.d.ts +++ b/apps/red-ui/src/app/utils/types.d.ts @@ -2,8 +2,6 @@ import { FileStatus } from '@redaction/red-ui-http'; export type Color = FileStatus.StatusEnum | ProjectStatus.StatusEnum; -export type AnnotationType = 'hint' | 'redaction' | 'suggestion' | 'comment' | 'ignore'; - export class SortingOption { label: string; order: string; @@ -11,5 +9,5 @@ export class SortingOption { } export class AnnotationFilters { - [key: AnnotationType]: boolean; + [key: string]: boolean | {}; } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index a058d158f..c5fe5854b 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -442,26 +442,14 @@ "filter-types": { "label": "Filter types" }, - "hint": { - "label": "Hint annotation", - "hint_only": { - "label": "Hint only" - }, - "vertebrate": { - "label": "Vertebrate" - }, - "names": { - "label": "Names" - } - }, "redaction": { "label": "Redaction" }, - "comment": { - "label": "Comment annotation" + "hint": { + "label": "Hint" }, - "suggestion": { - "label": "Suggested redaction" + "request": { + "label": "Redaction Request" }, "ignore": { "label": "Ignored redaction" diff --git a/docker/common/nginx/nginx.conf.template b/docker/common/nginx/nginx.conf.template index 23ae4c03a..a76a14591 100644 --- a/docker/common/nginx/nginx.conf.template +++ b/docker/common/nginx/nginx.conf.template @@ -17,6 +17,9 @@ server { location /project { proxy_pass $API_URL; } + location /color { + proxy_pass $API_URL; + } location /user { proxy_pass $API_URL; }