From 7575b01b7ea5c3e740c698afc1ed221a766abafb Mon Sep 17 00:00:00 2001 From: Timo Date: Tue, 27 Apr 2021 16:16:33 +0300 Subject: [PATCH] File Details --- apps/red-ui/src/app/app-routing.module.ts | 18 ---- apps/red-ui/src/app/app.module.ts | 4 +- .../html-debug-screen.component.html | 2 - .../html-debug-screen.component.scss | 7 -- .../html-debug-screen.component.ts | 59 ------------- .../pdf-viewer-screen.component.html | 1 - .../pdf-viewer-screen.component.scss | 4 - .../pdf-viewer-screen.component.ts | 87 ------------------- .../app/models/file/file-status.wrapper.ts | 31 ++++++- .../file-preview-screen.component.html | 18 ---- .../project-overview-screen.component.html | 11 +++ .../project-overview-screen.component.scss | 4 + .../project-overview-screen.component.ts | 3 +- .../red-ui/src/app/state/app-state.service.ts | 55 +++++++----- apps/red-ui/src/assets/i18n/en.json | 1 + libs/red-ui-http/src/lib/model/fileStatus.ts | 21 +++-- 16 files changed, 96 insertions(+), 230 deletions(-) delete mode 100644 apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.html delete mode 100644 apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.scss delete mode 100644 apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.ts delete mode 100644 apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.html delete mode 100644 apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.scss delete mode 100644 apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.ts diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index 71b80cfc7..4ccfaae0d 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -1,9 +1,7 @@ import { AuthErrorComponent } from './components/auth-error/auth-error.component'; import { AuthGuard } from './modules/auth/auth.guard'; -import { PdfViewerScreenComponent } from './components/pdf-viewer-screen/pdf-viewer-screen.component'; import { CompositeRouteGuard } from './guards/composite-route.guard'; import { RedRoleGuard } from './modules/auth/red-role.guard'; -import { HtmlDebugScreenComponent } from './components/html-debug-screen/html-debug-screen.component'; import { BaseScreenComponent } from './components/base-screen/base-screen.component'; import { RouteReuseStrategy, RouterModule } from '@angular/router'; import { NgModule } from '@angular/core'; @@ -23,22 +21,6 @@ const routes = [ component: AuthErrorComponent, canActivate: [AuthGuard] }, - { - path: 'pdf-preview/:projectId/:fileId', - component: PdfViewerScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard] - } - }, - { - path: 'html-debug/:projectId/:fileId', - component: HtmlDebugScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard] - } - }, { path: 'main/my-profile', component: BaseScreenComponent, diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 639cdd333..daf5d79f8 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -22,8 +22,6 @@ import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/materia import { ToastComponent } from './components/toast/toast.component'; import { HttpCacheInterceptor } from '@redaction/red-cache'; import { NotificationsComponent } from './components/notifications/notifications.component'; -import { PdfViewerScreenComponent } from './components/pdf-viewer-screen/pdf-viewer-screen.component'; -import { HtmlDebugScreenComponent } from './components/html-debug-screen/html-debug-screen.component'; import { KeycloakService } from 'keycloak-angular'; import { DownloadsListScreenComponent } from './components/downloads-list-screen/downloads-list-screen.component'; import { AppRoutingModule } from './app-routing.module'; @@ -49,7 +47,7 @@ function cleanupBaseUrl(baseUrl: string) { } } -const screens = [BaseScreenComponent, PdfViewerScreenComponent, HtmlDebugScreenComponent, DownloadsListScreenComponent, UserProfileScreenComponent]; +const screens = [BaseScreenComponent, DownloadsListScreenComponent, UserProfileScreenComponent]; const components = [AppComponent, LogoComponent, AuthErrorComponent, ToastComponent, NotificationsComponent, ...screens]; diff --git a/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.html b/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.html deleted file mode 100644 index 64c7852a3..000000000 --- a/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.html +++ /dev/null @@ -1,2 +0,0 @@ -
- diff --git a/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.scss b/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.scss deleted file mode 100644 index ec70e8d52..000000000 --- a/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -section { - height: calc(100vh - 40px); - display: flex; - flex-direction: column; - align-items: center; - padding: 20px; -} diff --git a/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.ts b/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.ts deleted file mode 100644 index fbecf52a1..000000000 --- a/apps/red-ui/src/app/components/html-debug-screen/html-debug-screen.component.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { ChangeDetectorRef, Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { DebugControllerService, FileManagementControllerService } from '@redaction/red-ui-http'; -import { FileStatusWrapper } from '../../models/file/file-status.wrapper'; -import { mergeMap } from 'rxjs/operators'; - -@Component({ - selector: 'redaction-html-debug-screen', - templateUrl: './html-debug-screen.component.html', - styleUrls: ['./html-debug-screen.component.scss'] -}) -export class HtmlDebugScreenComponent { - private _fileId: string; - private _projectId: string; - - htmlData: any; - loading: boolean; - - constructor( - private readonly _activatedRoute: ActivatedRoute, - private readonly _changeDetectorRef: ChangeDetectorRef, - private readonly _debugControllerService: DebugControllerService, - private readonly _fileManagementControllerService: FileManagementControllerService - ) { - this._activatedRoute.params.subscribe((params) => { - this._fileId = params.fileId; - this._projectId = params.projectId; - this._loadDebugHTML(); - }); - } - - private _loadDebugHTML() { - this.loading = true; - const fileStatus = new FileStatusWrapper( - { - projectId: this._projectId, - fileId: this._fileId, - lastProcessed: new Date().toISOString() - }, - null - ); - - this._fileManagementControllerService - .downloadAnnotatedFile(fileStatus.projectId, fileStatus.fileId, true, fileStatus.lastUploaded, 'body') - .pipe( - mergeMap((fileData) => { - return this._debugControllerService.debugHtmlTablesForm(fileData, true); - }) - ) - .subscribe((data) => { - const reader = new FileReader(); - reader.onload = () => { - this.htmlData = reader.result; - this.loading = false; - }; - reader.readAsText(data); - }); - } -} diff --git a/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.html b/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.html deleted file mode 100644 index 534e12c77..000000000 --- a/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.scss b/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.scss deleted file mode 100644 index c5aa1aa0f..000000000 --- a/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -.viewer { - width: 100vw; - height: 100vh; -} diff --git a/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.ts b/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.ts deleted file mode 100644 index 30b0521ad..000000000 --- a/apps/red-ui/src/app/components/pdf-viewer-screen/pdf-viewer-screen.component.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { ChangeDetectorRef, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; -import WebViewer, { WebViewerInstance } from '@pdftron/webviewer'; -import { environment } from '../../../environments/environment'; -import { ActivatedRoute } from '@angular/router'; -import { FileStatusWrapper } from '../../models/file/file-status.wrapper'; -import { FileManagementControllerService } from '@redaction/red-ui-http'; -import { BASE_HREF } from '../../tokens'; - -@Component({ - selector: 'redaction-pdf-viewer-screen', - templateUrl: './pdf-viewer-screen.component.html', - styleUrls: ['./pdf-viewer-screen.component.scss'] -}) -export class PdfViewerScreenComponent implements OnInit { - private _instance: WebViewerInstance; - @ViewChild('viewer', { static: true }) - private _viewer: ElementRef; - - private _fileId: string; - private _projectId: string; - private _fileData: any; - - constructor( - @Inject(BASE_HREF) private readonly _baseHref: string, - private readonly _activatedRoute: ActivatedRoute, - private readonly _changeDetectorRef: ChangeDetectorRef, - private readonly _fileManagementControllerService: FileManagementControllerService - ) { - this._activatedRoute.params.subscribe((params) => { - this._fileId = params.fileId; - this._projectId = params.projectId; - this._loadFile(); - }); - } - - ngOnInit(): void { - this._loadViewer(); - } - - private _loadViewer() { - WebViewer( - { - licenseKey: environment.licenseKey ? atob(environment.licenseKey) : null, - isReadOnly: true, - path: this._baseHref + '/assets/wv-resources', - css: this._baseHref + '/assets/pdftron/stylesheet.css' - }, - this._viewer.nativeElement - ).then((instance) => { - this._instance = instance; - - instance.docViewer.on('documentLoaded', () => { - this._changeDetectorRef.detectChanges(); - }); - - if (this._fileData) { - this._loadDocumentIntoViewer(); - } - }); - } - - private _loadFile() { - const fileStatus = new FileStatusWrapper( - { - projectId: this._projectId, - fileId: this._fileId, - lastProcessed: new Date().toISOString() - }, - null - ); - - this._fileManagementControllerService - .downloadAnnotatedFile(fileStatus.projectId, fileStatus.fileId, true, fileStatus.lastUploaded, 'body') - .subscribe((data) => { - this._fileData = data; - this._loadDocumentIntoViewer(); - }); - } - - private _loadDocumentIntoViewer() { - if (this._instance) { - this._instance.loadDocument(this._fileData, { - filename: 'document.pdf' - }); - } - } -} diff --git a/apps/red-ui/src/app/models/file/file-status.wrapper.ts b/apps/red-ui/src/app/models/file/file-status.wrapper.ts index 74aea75e4..0fa149b9e 100644 --- a/apps/red-ui/src/app/models/file/file-status.wrapper.ts +++ b/apps/red-ui/src/app/models/file/file-status.wrapper.ts @@ -1,8 +1,27 @@ -import { FileStatus } from '@redaction/red-ui-http'; +import { FileAttributeConfig, FileStatus } from '@redaction/red-ui-http'; import { StatusSorter } from '../../utils/sorters/status-sorter'; export class FileStatusWrapper { - constructor(public fileStatus: FileStatus, public reviewerName: string) {} + primaryAttribute: string; + + searchField: string; + + constructor(public fileStatus: FileStatus, public reviewerName: string, fileAttributesConfig?: FileAttributeConfig[]) { + this.searchField = fileStatus.filename; + + if (fileAttributesConfig) { + const primary = fileAttributesConfig.find((c) => c.primaryAttribute); + if (primary && fileStatus.fileAttributes?.attributeIdToValue) { + this.primaryAttribute = fileStatus.fileAttributes?.attributeIdToValue[primary.id]; + this.searchField += ' ' + this.primaryAttribute; + } + + if (!this.primaryAttribute) { + // Fallback here + this.primaryAttribute = '-'; + } + } + } get analysisDuration() { return this.fileStatus.analysisDuration; @@ -52,6 +71,14 @@ export class FileStatusWrapper { return this.fileStatus.filename; } + get hasAnnotationComments() { + return this.fileStatus.hasAnnotationComments; + } + + get ocrTime() { + return this.fileStatus.lastOCRTime; + } + get hasHints() { return this.fileStatus.hasHints; } diff --git a/apps/red-ui/src/app/modules/projects/screens/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/modules/projects/screens/file-preview-screen/file-preview-screen.component.html index 1aef2499d..e2418b5c2 100644 --- a/apps/red-ui/src/app/modules/projects/screens/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/projects/screens/file-preview-screen/file-preview-screen.component.html @@ -158,24 +158,6 @@ tooltip="file-preview.download-original-file" tooltipPosition="below" > - - +
+
+ {{ fileStatus.primaryAttribute }} +
+
+
+
+ + {{ fileStatus.ocrTime ? (fileStatus.ocrTime | date: 'mediumDate') : ('project-overview.no-ocr' | translate) }} +
+
diff --git a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.scss b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.scss index dd6c59430..a1719e9b1 100644 --- a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.scss +++ b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.scss @@ -121,3 +121,7 @@ cdk-virtual-scroll-viewport { color: initial; } } + +.primary-attribute { + padding-top: 6px; +} diff --git a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts index 165fb0164..aa59ddc6f 100644 --- a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts @@ -34,7 +34,7 @@ import { OnAttach, OnDetach } from '../../../../utils/custom-route-reuse.strateg styleUrls: ['./project-overview-screen.component.scss'] }) export class ProjectOverviewScreenComponent extends BaseListingComponent implements OnInit, OnDestroy, OnDetach, OnAttach { - protected readonly _searchKey = 'filename'; + protected readonly _searchKey = 'searchField'; protected readonly _selectionKey = 'fileId'; protected readonly _sortKey = 'project-overview'; @@ -42,7 +42,6 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent p.projectId)).toPromise(); + for (const projectId of Object.keys(fileData)) { - this._processFiles( - mappedProjects.find((p) => p.projectId === projectId), - fileData[projectId], - emitEvents - ); + const project = mappedProjects.find((p) => p.projectId === projectId); + const fileAttributesConfig = await this._fileAttributesService + .getFileAttributesConfiguration(project.ruleSetId) + .pipe(catchError(() => of({}))) + .toPromise(); + + console.log(fileAttributesConfig); + + this._processFiles(project, fileData[projectId], emitEvents, fileAttributesConfig); } this._appState.projects = mappedProjects; @@ -266,7 +272,11 @@ export class AppStateService { const oldProcessedDate = this.activeFile.lastProcessed; const activeFile = await this._statusControllerService.getFileStatus(this.activeProjectId, this.activeFileId).toPromise(); - const activeFileWrapper = new FileStatusWrapper(activeFile, this._userService.getNameForId(activeFile.currentReviewer)); + const activeFileWrapper = new FileStatusWrapper( + activeFile, + this._userService.getNameForId(activeFile.currentReviewer), + this._appState.activeFileAttributesConfig + ); this.activeProject.files = this.activeProject.files.map((file) => (file.fileId === activeFileWrapper.fileId ? activeFileWrapper : file)); await this.updateDictionaryVersion(); @@ -282,12 +292,17 @@ export class AppStateService { if (!project) { project = this.activeProject; } - const files = await this._statusControllerService.getProjectStatus(project.project.projectId).toPromise(); + const files = await this._statusControllerService.getProjectStatus(project.projectId).toPromise(); - return this._processFiles(project, files, emitEvents); + const fileAttributesConfig = await this._fileAttributesService + .getFileAttributesConfiguration(project.ruleSetId) + .pipe(catchError(() => of({}))) + .toPromise(); + + return this._processFiles(project, files, emitEvents, fileAttributesConfig); } - private _processFiles(project: ProjectWrapper, files: FileStatus[], emitEvents: boolean = true) { + private _processFiles(project: ProjectWrapper, files: FileStatus[], emitEvents: boolean = true, fileAttributesConfig: FileAttributesConfig) { const oldFiles = [...project.files]; const fileStatusChangedEvent = []; @@ -298,7 +313,11 @@ export class AppStateService { for (const oldFile of oldFiles) { if (oldFile.fileId === file.fileId) { // emit when analysis count changed - const fileStatusWrapper = new FileStatusWrapper(file, this._userService.getNameForId(file.currentReviewer)); + const fileStatusWrapper = new FileStatusWrapper( + file, + this._userService.getNameForId(file.currentReviewer), + fileAttributesConfig?.fileAttributeConfigs + ); if (JSON.stringify(oldFile) !== JSON.stringify(fileStatusWrapper)) { fileStatusChangedEvent.push(fileStatusWrapper); } @@ -311,12 +330,14 @@ export class AppStateService { } // emit for new file if (!found) { - const fsw = new FileStatusWrapper(file, this._userService.getNameForId(file.currentReviewer)); + const fsw = new FileStatusWrapper(file, this._userService.getNameForId(file.currentReviewer), fileAttributesConfig?.fileAttributeConfigs); fileStatusChangedEvent.push(fsw); } } - project.files = files.map((f) => new FileStatusWrapper(f, this._userService.getNameForId(f.currentReviewer))); + project.files = files.map( + (f) => new FileStatusWrapper(f, this._userService.getNameForId(f.currentReviewer), fileAttributesConfig?.fileAttributeConfigs) + ); this._computeStats(); if (emitEvents) { @@ -343,12 +364,6 @@ export class AppStateService { this._router.navigate(['/main/projects']); return; } - this._fileAttributesService - .getFileAttributesConfiguration(this.getProjectById(projectId).ruleSetId) - .toPromise() - .then((data) => { - this._appState.activeFileAttributesConfig = data.fileAttributeConfigs; - }); } activateFile(projectId: string, fileId: string) { diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index be4efa650..78d5e9526 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -192,6 +192,7 @@ "collapse": "Hide Details" }, "project-overview": { + "no-ocr": "No OCR", "no-data": { "title": "There are no documents yet.", "action": "Upload Document" diff --git a/libs/red-ui-http/src/lib/model/fileStatus.ts b/libs/red-ui-http/src/lib/model/fileStatus.ts index 6b8569577..9e9b88431 100644 --- a/libs/red-ui-http/src/lib/model/fileStatus.ts +++ b/libs/red-ui-http/src/lib/model/fileStatus.ts @@ -48,6 +48,10 @@ export interface FileStatus { * The file's name. */ filename?: string; + /** + * Shows if this file has comments on annotations. + */ + hasAnnotationComments?: boolean; /** * Shows if any hints were found during the analysis. */ @@ -68,6 +72,10 @@ export interface FileStatus { * Shows if there is any change between the previous and current analysis. */ hasUpdates?: boolean; + /** + * Shows if this file has been OCRed by us. Last Time of OCR. + */ + lastOCRTime?: string; /** * Shows the last date of a successful analysis. */ @@ -109,31 +117,30 @@ export interface FileStatus { */ uploader?: string; } - export namespace FileStatus { export type StatusEnum = | 'UNPROCESSED' | 'REPROCESS' - | 'FULLREPROCESS' | 'PROCESSING' - | 'OCR_PROCESSING' | 'ERROR' | 'UNASSIGNED' | 'UNDER_REVIEW' - | 'EXCLUDED' | 'UNDER_APPROVAL' - | 'APPROVED'; + | 'APPROVED' + | 'FULLREPROCESS' + | 'OCR_PROCESSING' + | 'EXCLUDED'; export const StatusEnum = { UNPROCESSED: 'UNPROCESSED' as StatusEnum, - FULLREPROCESS: 'FULLREPROCESS' as StatusEnum, REPROCESS: 'REPROCESS' as StatusEnum, PROCESSING: 'PROCESSING' as StatusEnum, - OCR_PROCESSING: 'OCR_PROCESSING' as StatusEnum, ERROR: 'ERROR' as StatusEnum, UNASSIGNED: 'UNASSIGNED' as StatusEnum, UNDERREVIEW: 'UNDER_REVIEW' as StatusEnum, UNDERAPPROVAL: 'UNDER_APPROVAL' as StatusEnum, APPROVED: 'APPROVED' as StatusEnum, + FULLREPROCESS: 'FULLREPROCESS' as StatusEnum, + OCR_PROCESSING: 'OCR_PROCESSING' as StatusEnum, EXCLUDED: 'EXCLUDED' as StatusEnum }; }