linked redaction file screen to backend colors and dictionary data
This commit is contained in:
parent
b4888b49ce
commit
f1f3dda4e3
@ -52,5 +52,11 @@
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
"logLevel": "debug"
|
||||
},
|
||||
"/color": {
|
||||
"target": "https://timo-redaction-dev.iqser.cloud/",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
"logLevel": "debug"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<div [ngClass]="type" class="icon">
|
||||
<span>{{ type[0] }}</span>
|
||||
<div class="icon" [class.hint]="typeValue.hint" [style.background-color]="typeValue.hexColor">
|
||||
<span>{{ typeValue.type[0] }}</span>
|
||||
</div>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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() {}
|
||||
|
||||
|
||||
@ -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],
|
||||
|
||||
@ -145,8 +145,9 @@
|
||||
color="primary"
|
||||
>
|
||||
<redaction-annotation-icon
|
||||
[type]="key"
|
||||
[typeValue]="appStateService.getDictionaryTypeValue(key)"
|
||||
></redaction-annotation-icon>
|
||||
|
||||
{{ 'file-preview.filter-menu.' + key + '.label' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
@ -162,15 +163,11 @@
|
||||
color="primary"
|
||||
>
|
||||
<redaction-annotation-icon
|
||||
[type]="key + ' ' + subkey"
|
||||
[typeValue]="
|
||||
appStateService.getDictionaryTypeValue(subkey)
|
||||
"
|
||||
></redaction-annotation-icon>
|
||||
{{
|
||||
'file-preview.filter-menu.' +
|
||||
key +
|
||||
'.' +
|
||||
subkey +
|
||||
'.label' | translate
|
||||
}}
|
||||
{{ appStateService.getDictionaryLabel(subkey) }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
@ -223,7 +220,11 @@
|
||||
(click)="selectAnnotation(annotation)"
|
||||
>
|
||||
<redaction-annotation-icon
|
||||
[type]="getType(annotation) + ' ' + getDictionary(annotation)"
|
||||
[typeValue]="
|
||||
appStateService.getDictionaryTypeValue(
|
||||
getDictionary(annotation)
|
||||
)
|
||||
"
|
||||
></redaction-annotation-icon>
|
||||
<div class="flex-1">
|
||||
<div>
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ export class AppStateGuard implements CanActivate {
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||
await this._userService.loadAllUsersIfNecessary();
|
||||
await this._appStateService.loadAllProjectsIfNecessary();
|
||||
await this._appStateService.loadDictionaryDataIfNecessary();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -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<FileStatus>();
|
||||
|
||||
@ -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'];
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,8 +72,7 @@ export class AnnotationUtils {
|
||||
annotations: [],
|
||||
hint: 0,
|
||||
redaction: 0,
|
||||
comment: 0,
|
||||
suggestion: 0,
|
||||
request: 0,
|
||||
ignore: 0
|
||||
};
|
||||
}
|
||||
|
||||
@ -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(' ');
|
||||
}
|
||||
|
||||
4
apps/red-ui/src/app/utils/types.d.ts
vendored
4
apps/red-ui/src/app/utils/types.d.ts
vendored
@ -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 | {};
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -17,6 +17,9 @@ server {
|
||||
location /project {
|
||||
proxy_pass $API_URL;
|
||||
}
|
||||
location /color {
|
||||
proxy_pass $API_URL;
|
||||
}
|
||||
location /user {
|
||||
proxy_pass $API_URL;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user