From e9c60015aeb1422d8d70cb048fdf942208e86d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Sat, 17 Oct 2020 01:53:36 +0300 Subject: [PATCH] File preview right panel & annotation icons --- apps/red-ui/src/app/app.module.ts | 2 + .../annotation-icon.component.html | 3 + .../annotation-icon.component.scss | 52 ++++ .../annotation-icon.component.ts | 16 ++ .../file-preview-screen.component.html | 174 +++++--------- .../file-preview-screen.component.scss | 223 +++++++++--------- .../file-preview-screen.component.ts | 169 ++++--------- .../screens/file/service/filters.service.ts | 10 +- .../project-overview-screen.component.html | 4 +- .../project-overview-screen.component.ts | 1 - apps/red-ui/src/app/utils/annotation-utils.ts | 57 +++++ apps/red-ui/src/app/utils/types.d.ts | 14 +- apps/red-ui/src/assets/i18n/en.json | 14 +- .../src/assets/styles/red-components.scss | 7 - .../src/assets/styles/red-variables.scss | 11 +- 15 files changed, 373 insertions(+), 384 deletions(-) create mode 100644 apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.html create mode 100644 apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.scss create mode 100644 apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.ts diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 7f674df20..da16ff037 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -53,6 +53,7 @@ import { SimpleDoughnutChartComponent } from './components/simple-doughnut-chart import { ManualRedactionDialogComponent } from './screens/file/manual-redaction-dialog/manual-redaction-dialog.component'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { AnnotationIconComponent } from './components/annotation-icon/annotation-icon.component'; export function HttpLoaderFactory(httpClient: HttpClient) { return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json'); @@ -76,6 +77,7 @@ export function HttpLoaderFactory(httpClient: HttpClient) { LogoComponent, SimpleDoughnutChartComponent, ManualRedactionDialogComponent, + AnnotationIconComponent, ], imports: [ BrowserModule, 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 new file mode 100644 index 000000000..73d7131ff --- /dev/null +++ b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.html @@ -0,0 +1,3 @@ +
+ {{ 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 new file mode 100644 index 000000000..5563fd6d6 --- /dev/null +++ b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.scss @@ -0,0 +1,52 @@ +@import "../../../assets/styles/red-variables"; + +.icon { + height: 16px; + width: 16px; + font-size: 11px; + line-height: 14px; + font-weight: 600; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + text-transform: uppercase; + color: $white; +} + +.suggestion { + width: 0; + height: 0; + border: 9px solid transparent; + border-bottom-color: $grey-1; + position: relative; + top: -9px; + + &:after { + content: ''; + position: absolute; + left: -9px; + top: 9px; + width: 0; + height: 0; + border: 9px solid transparent; + border-top-color: $grey-1; + } + + span { + transform: translateY(9px); + z-index: 2; + } +} + +.hint, .comment, .ignore { + border-radius: 50%; +} + +.hint, .redaction, .comment { + background-color: $grey-1; +} + +.ignore { + background-color: $grey-5; +} 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 new file mode 100644 index 000000000..fbc913620 --- /dev/null +++ b/apps/red-ui/src/app/components/annotation-icon/annotation-icon.component.ts @@ -0,0 +1,16 @@ +import { Component, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'redaction-annotation-icon', + templateUrl: './annotation-icon.component.html', + styleUrls: ['./annotation-icon.component.scss'] +}) +export class AnnotationIconComponent implements OnInit { + @Input() public type: 'hint' | 'redaction' | 'suggestion' | 'ignore' | 'comment'; + + constructor() { + } + + ngOnInit(): void { + } +} 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 b5a729533..2201134f7 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 @@ -42,134 +42,76 @@
- - -
-
-
- -
- -
-
-
-
-
-
+
+
+ +
+ +
+
+
+
+
-
- -
- {{ filters[key].symbol }} -
- {{filters[key].label | translate }} -
-
- -
-
- -
- +
+ + + {{"file-preview.filter-menu."+ key + ".label" | translate }} + +
+
- -
-
- +
+
+
+ {{pageNumber}} +
-
-
-
Type: {{getType(annotation.Id)}}
-
Dictionary: {{getDictionary(annotation.Id)}}
-
Page: {{annotation.getPageNumber()}}
-
Content: {{annotation.getContents()}}
- -
- +
+
+
+ {{page}}
-
-
-
- -
-
- -
+
-
- + +
+
{{getType(annotation) | translate}}
+
: {{getDictionary(annotation)}}
+
: + {{annotation.getContents()}}
+
-
-
- - {{appStateService.activeFile.numberOfPages}}
-
- - {{annotations.length}}
-
+
+ {{annotation.getPageNumber()}} +
-
- - -
- -
-
-
- {{appStateService.activeFile.added | date:'medium'}} -
- -
-
-
- {{user.name}} -
- -
-
-
- {{appStateService.activeFile.lastUpdated | date:'medium'}} +
+ +
+
diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss index 2b6f7c5a8..b4080f61c 100644 --- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss +++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.scss @@ -13,142 +13,129 @@ redaction-pdf-viewer { .right-fixed-container { padding: 0; - width: calc(#{$right-container-width} - 1px); - display: flex; + width: $right-container-width; + box-sizing: border-box; - .vertical { - height: 100%; - border-right: 1px solid $separator; + .right-title { + height: 70px; + display: flex; + border-bottom: 1px solid $separator; + align-items: center; + justify-content: space-between; + padding: 0 24px; - &.active { - width: calc(#{$right-container-width} - 80px); - padding-top: 0; + > div { + position: relative; - .tab-title { - height: 70px; - display: flex; + .dot { + background: $primary; + height: 10px; + width: 10px; + border-radius: 50%; + position: absolute; + top: 0; + left: 0; + } + } + + .close-icon { + height: 14px; + width: 14px; + cursor: pointer; + } + } + + .right-content { + height: calc(100vh - 110px - 72px); + box-sizing: border-box; + display: flex; + + .pages, .annotations { + overflow-y: scroll; + + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE 10+ */ + &::-webkit-scrollbar { + width: 0; + background: transparent; /* Chrome/Safari/Webkit */ + } + } + + .pages { + border-right: 1px solid $separator; + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + padding: 16px; + min-width: 28px; + } + + .annotations { + width: 100%; + + .page-separator { border-bottom: 1px solid $separator; - align-items: center; - justify-content: space-between; - padding: 0 25px; + height: 40px; + box-sizing: border-box; + padding: 8px 10px; + display: flex; + align-items: flex-end; + background-color: $grey-6; + } - > div { - position: relative; + .annotation { + border-bottom: 1px solid $separator; + padding: 10px; + font-size: 12px; + cursor: pointer; + position: relative; + display: flex; + gap: 10px; - .dot { - background: $primary; - height: 10px; - width: 10px; - border-radius: 50%; - position: absolute; - top: 0; - left: 0; + redaction-annotation-icon { + margin-top: 6px; + } + + &:hover { + background-color: #F9FAFB; + + .annotation-actions { + display: flex; } } - .close-icon { - height: 14px; - width: 14px; - cursor: pointer; + &.active { + border-left: 2px solid $primary; + } + + .annotation-actions { + position: absolute; + right: 0; + top: 0; + bottom: 0; + display: none; + width: 40px; } } - - .tab-content { - overflow-y: scroll; - overflow-x: hidden; - height: calc(100vh - 110px - 73px); - box-sizing: border-box; - - scrollbar-width: none; /* Firefox */ - -ms-overflow-style: none; /* IE 10+ */ - &::-webkit-scrollbar { - width: 0; - background: transparent; /* Chrome/Safari/Webkit */ - } - } - - .info-container { - padding: 15px; - } - } - - &:not(.active) { - width: 40px; - padding-top: 15px; - cursor: pointer; - - .tab-title { - transform: translateX(27px) rotate(90deg); - transform-origin: 0 0; - position: absolute; - } } } - .assign-reviewer { - margin-left: 12px; - } - - .annotation { - border-bottom: 1px solid $separator; - padding: 14px; - font-size: 12px; - cursor: pointer; - position: relative; - - &:hover { - background-color: #F9FAFB; - - .annotation-actions { - display: flex; - } - } - - &.active { - border-left: 2px solid $primary; - } - - .annotation-actions { - position: absolute; - right: 0; - top: 0; - bottom: 0; - display: none; - width: 40px; - } - } - - .page-navigation { + .page-number { + border: 1px solid $separator; + padding: 5px 10px; display: flex; + justify-content: center; align-items: center; - gap: 12px; - cursor: pointer; - border-bottom: 1px solid $separator; - padding: 14px; - border-left: 4px solid transparent; - - &:hover { - background-color: $grey-2; - } - - .page-number { - border: 1px solid $separator; - padding: 7px; - margin-right: 3px; - width: 14px; - text-align: center; - } - - .page-stats { - display: flex; - justify-content: center; - align-items: center; - gap: 6px; - opacity: 1; - } + height: 28px; + min-height: 28px; + min-width: 14px; + opacity: 0.7; + font-size: 11px; + line-height: 14px; &.active { - border-left: 4px solid $primary; + border: 1px solid $primary; } } } 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 97fded2d9..324ec58c0 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 @@ -1,5 +1,5 @@ -import {ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; +import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; import { AddRedactionRequest, FileUploadControllerService, @@ -8,34 +8,25 @@ import { ProjectControllerService, StatusControllerService } from '@redaction/red-ui-http'; -import {TranslateService} from '@ngx-translate/core'; -import {NotificationService, NotificationType} from '../../../notification/notification.service'; -import {MatDialog} from '@angular/material/dialog'; -import {AppStateService} from '../../../state/app-state.service'; -import {FileDetailsDialogComponent} from './file-details-dialog/file-details-dialog.component'; -import {ViewerSyncService} from '../service/viewer-sync.service'; -import {Annotations} from '@pdftron/webviewer'; -import {PdfViewerComponent} from '../pdf-viewer/pdf-viewer.component'; -import {AnnotationUtils} from '../../../utils/annotation-utils'; -import {ManualRedactionDialogComponent} from '../manual-redaction-dialog/manual-redaction-dialog.component'; -import {UserService} from '../../../user/user.service'; -import {debounce} from '../../../utils/debounce'; +import { TranslateService } from '@ngx-translate/core'; +import { NotificationService, NotificationType } from '../../../notification/notification.service'; +import { MatDialog } from '@angular/material/dialog'; +import { AppStateService } from '../../../state/app-state.service'; +import { FileDetailsDialogComponent } from './file-details-dialog/file-details-dialog.component'; +import { ViewerSyncService } from '../service/viewer-sync.service'; +import { Annotations } from '@pdftron/webviewer'; +import { PdfViewerComponent } from '../pdf-viewer/pdf-viewer.component'; +import { AnnotationUtils } from '../../../utils/annotation-utils'; +import { ManualRedactionDialogComponent } from '../manual-redaction-dialog/manual-redaction-dialog.component'; +import { UserService } from '../../../user/user.service'; +import { debounce } from '../../../utils/debounce'; import scrollIntoView from 'scroll-into-view-if-needed'; -import {ConfirmationDialogComponent} from '../../../common/confirmation-dialog/confirmation-dialog.component'; -import {AnnotationFilters} from '../../../utils/types'; -import {FiltersService} from '../service/filters.service'; -import {FileDownloadService} from "../service/file-download.service"; -import {saveAs} from 'file-saver'; -import {FileType} from "../model/file-type"; - -class QuickNavigationItem { - pageNumber: number; - hints: number; - redactions: number; - comments: number; - suggestions: number; - ignored: number; -} +import { AnnotationFilters } from '../../../utils/types'; +import { FiltersService } from '../service/filters.service'; +import { FileDownloadService } from '../service/file-download.service'; +import { saveAs } from 'file-saver'; +import { FileType } from '../model/file-type'; +import { ConfirmationDialogComponent } from '../../../common/confirmation-dialog/confirmation-dialog.component'; @Component({ selector: 'redaction-file-preview-screen', @@ -45,28 +36,19 @@ class QuickNavigationItem { export class FilePreviewScreenComponent implements OnInit { private _readyViewers: string[] = []; private projectId: string; - private _selectedTab: 'NAVIGATION' | 'ANNOTATIONS' | 'INFO' = 'NAVIGATION'; private _activeViewer: 'ANNOTATED' | 'REDACTED' = 'ANNOTATED'; + private _manualRedactionEntry: ManualRedactionEntry; - @ViewChild(PdfViewerComponent) - private _viewerComponent: PdfViewerComponent; - - @ViewChild('annotationsContainer') - private _annotationsContainer: ElementRef; - - @ViewChild('navigationTabElement') - private _navigationTabElement: ElementRef; + @ViewChild(PdfViewerComponent) private _viewerComponent: PdfViewerComponent; + @ViewChild('annotations') private _annotationsElement: ElementRef; + @ViewChild('quickNavigation') private _quickNavigationElement: ElementRef; public fileId: string; public annotations: Annotations.Annotation[] = []; + public displayedAnnotations: { [key: number]: { annotations: Annotations.Annotation[] } } = {}; public selectedAnnotation: Annotations.Annotation; - public quickNavigation: QuickNavigationItem[] = []; - public filters: AnnotationFilters; - - public get filterKeys() { - return Object.keys(this.filters); - } + public activeViewerPage: number; private _manualRedactionEntry: AddRedactionRequest; @@ -96,10 +78,14 @@ export class FilePreviewScreenComponent implements OnInit { this.filters = _filtersService.filters; } - get user() { + public get user() { return this._userService.user; } + public get filterKeys() { + return Object.keys(this.filters); + } + public get redactedView() { return this._activeViewer === 'REDACTED'; } @@ -141,56 +127,22 @@ export class FilePreviewScreenComponent implements OnInit { this._viewerSyncService.activateViewer(value); } - public selectTab(value: 'ANNOTATIONS' | 'INFO' | 'NAVIGATION', $event?: MouseEvent) { - if ($event) { - $event.stopPropagation(); - } - if (value !== this._selectedTab) { - this._selectedTab = value; - setTimeout(() => { - this._scrollViews(); - }, 50); - } + public applyFilters() { + this.displayedAnnotations = AnnotationUtils.parseAnnotations(this.annotations, this.filters); } public handleAnnotationsAdded(annotations: Annotations.Annotation[]) { this._changeDetectorRef.detectChanges(); - for (const annotation of annotations) { - if (annotation.Id.indexOf(':') > 0) { - this.annotations.push(annotation); - const pageNumber = annotation.getPageNumber(); - let el = this.quickNavigation.find((page) => page.pageNumber === pageNumber); - if (!el) { - el = {pageNumber, redactions: 0, hints: 0, ignored: 0, comments: 0, suggestions: 0}; - this.quickNavigation.push(el); - } - if (annotation.Id.startsWith('hint:')) { - el.hints++; - } - if (annotation.Id.startsWith('ignore:')) { - el.ignored++; - } - if (annotation.Id.startsWith('redaction:')) { - el.redactions++; - } - } - } - this.annotations = AnnotationUtils.sortAnnotations(this.annotations); + AnnotationUtils.addAnnotations(this.annotations, annotations); + this.applyFilters(); } - public showQuickNavigationItem(item: QuickNavigationItem): boolean { - let showItem = false; - Object.keys(this.filters).map((key) => { - if (this.showAnnotations(item, key)) { - showItem = true; - } - }) - return showItem; + public get displayedPages(): number[] { + return Object.keys(this.displayedAnnotations).map(key => Number(key)); } public handleAnnotationSelected(annotation: Annotations.Annotation) { this.selectedAnnotation = annotation; - this.selectTab('ANNOTATIONS'); this.scrollToSelectedAnnotation(); this._changeDetectorRef.detectChanges(); } @@ -204,22 +156,10 @@ export class FilePreviewScreenComponent implements OnInit { if (!this.selectedAnnotation) { return; } - const elements: any[] = this._annotationsContainer.nativeElement.querySelectorAll(`div[annotation-id="${this.selectedAnnotation.Id}"].active`); + const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[annotation-id="${this.selectedAnnotation.Id}"].active`); this._scrollToFirstElement(elements); } - public get navigationTab() { - return this._selectedTab === 'NAVIGATION'; - } - - public get annotationsTab() { - return this._selectedTab === 'ANNOTATIONS'; - } - - public get infoTab() { - return this._selectedTab === 'INFO'; - } - public selectPage(pageNumber: number) { this._viewerComponent.navigateToPage(pageNumber); } @@ -241,7 +181,7 @@ export class FilePreviewScreenComponent implements OnInit { }); } - viewerPageChanged(pageNumber: number) { + public viewerPageChanged(pageNumber: number) { if (Number.isInteger(pageNumber)) { this.activeViewerPage = this._viewerSyncService.activeViewerPage; this._scrollViews(); @@ -251,13 +191,12 @@ export class FilePreviewScreenComponent implements OnInit { @debounce() private _scrollViews() { - console.log('scroll views'); this._scrollQuickNavigation(); this._scrollAnnotations(); } private _scrollQuickNavigation() { - const elements: any[] = this._navigationTabElement.nativeElement.querySelectorAll(`#quick-nav-page-${this.activeViewerPage}`); + const elements: any[] = this._quickNavigationElement.nativeElement.querySelectorAll(`#quick-nav-page-${this.activeViewerPage}`); this._scrollToFirstElement(elements); } @@ -265,7 +204,7 @@ export class FilePreviewScreenComponent implements OnInit { if (this.selectedAnnotation?.getPageNumber() === this.activeViewerPage) { return; } - const elements: any[] = this._annotationsContainer.nativeElement.querySelectorAll(`div[annotation-page="${this.activeViewerPage}"]`); + const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[annotation-page="${this.activeViewerPage}"]`); this._scrollToFirstElement(elements); } @@ -280,14 +219,12 @@ export class FilePreviewScreenComponent implements OnInit { } } - getType(id: string) { - const parts = id.split(':'); - return parts.length >= 1 ? parts[0] : 'n/a'; + getType(annotation: Annotations.Annotation): string { + return AnnotationUtils.getType(annotation); } - getDictionary(id: string) { - const parts = id.split(':'); - return parts.length >= 2 ? parts[1] : 'n/a'; + getDictionary(annotation: Annotations.Annotation): string { + return AnnotationUtils.getDictionary(annotation); } // async getText(pageNumber: number, rect) { @@ -332,26 +269,16 @@ export class FilePreviewScreenComponent implements OnInit { public downloadFile(type: FileType | string) { this._fileDownloadService.loadFile(type, this.fileId).subscribe(data => { saveAs(data, this.appStateService.activeFile.filename); - }) + }); } public setAllFilters(value: boolean) { Object.keys(this.filters).map((key) => { - this.filters[key].value = value; + this.filters[key] = value; }); } public get hasActiveFilters(): boolean { - let activeFilters = false; - Object.keys(this.filters).map((key) => { - if (this.filters[key].value) { - activeFilters = true; - } - }); - return activeFilters; - } - - public showAnnotations(item: QuickNavigationItem, type: string): boolean { - return item[type] && (!this.hasActiveFilters || (this.hasActiveFilters && this.filters[type]?.value)); + return AnnotationUtils.hasActiveFilters(this.filters); } } 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 cc5a7bf90..986fe5d94 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 @@ -9,11 +9,11 @@ export class FiltersService { } private _filters: AnnotationFilters = { - hints: { label: 'file-preview.filter-menu.hint.label', value: false, class: 'oval darkgray-white', symbol: 'H' }, - redactions: { label: 'file-preview.filter-menu.redaction.label', value: false, class: 'square darkgray-white', symbol: 'R' }, - comments: { label: 'file-preview.filter-menu.comment.label', value: false, class: 'oval darkgray-white', symbol: 'C' }, - suggestions: { label: 'file-preview.filter-menu.suggestion.label', value: false, class: 'oval red-white', symbol: 'S' }, - ignored: { label: 'file-preview.filter-menu.ignored.label', value: false, class: 'oval lightgray-white', symbol: 'I' }, + hint: false, + redaction: false, + comment: false, + suggestion: false, + ignore: false, } public get filters(): AnnotationFilters { diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html index 8af169d8b..b01f6a8b9 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html @@ -70,8 +70,8 @@
-
R
-
S
+ +
diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts index cd1d40493..cd90da7a9 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts @@ -131,7 +131,6 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { private _calculateChartConfig() { const obj = this.appStateService.activeProject.files.reduce((acc, file) => { - console.log(file.status); acc[file.status === 'PROCESSED' ? 'finished' : file.status === 'ERROR' ? 'under-approval' : 'under-review']++; return acc; }, { 'finished': 0, 'under-approval': 0, 'under-review': 0 }); diff --git a/apps/red-ui/src/app/utils/annotation-utils.ts b/apps/red-ui/src/app/utils/annotation-utils.ts index d12a5bf59..9d6fdfa92 100644 --- a/apps/red-ui/src/app/utils/annotation-utils.ts +++ b/apps/red-ui/src/app/utils/annotation-utils.ts @@ -1,4 +1,5 @@ import { Annotations } from '@pdftron/webviewer'; +import { AnnotationFilters } from './types'; export class AnnotationUtils { public static sortAnnotations(annotations: Annotations.Annotation[]): Annotations.Annotation[] { @@ -15,4 +16,60 @@ export class AnnotationUtils { return ann1.getPageNumber() < ann2.getPageNumber() ? -1 : 1; }); } + + public static hasActiveFilters(filters: AnnotationFilters): boolean { + return Object.keys(filters).filter(type => filters[type]).length > 0; + } + + public static parseAnnotations(annotations: Annotations.Annotation[], filters: AnnotationFilters): + { [key: number]: { annotations: Annotations.Annotation[] } } { + const obj = {}; + + for (const ann of annotations) { + const pageNumber = ann.getPageNumber(); + const type = this.getType(ann); + + if (this.hasActiveFilters(filters) && !filters[type]) { + continue; + } + + if (!obj[pageNumber]) { + obj[pageNumber] = { + annotations: [], + hint: 0, + redaction: 0, + comment: 0, + suggestion: 0, + ignore: 0 + }; + } + obj[pageNumber].annotations.push(ann); + obj[pageNumber][type]++; + } + + Object.keys(obj).map(page => { + obj[page].annotations = this.sortAnnotations(obj[page].annotations); + }); + + return obj; + } + + + public static addAnnotations(initialAnnotations: Annotations.Annotation[], addedAnnotations: Annotations.Annotation[]) { + for (const annotation of addedAnnotations) { + if (annotation.Id.indexOf(':') > 0) { + initialAnnotations.push(annotation); + } + } + } + + public static getType(annotation: Annotations.Annotation): string { + const parts = annotation.Id.split(':'); + return parts.length >= 1 ? parts[0] : 'n/a'; + } + + public static getDictionary(annotation: Annotations.Annotation): string { + const parts = annotation.Id.split(':'); + return parts.length >= 2 ? parts[1] : 'n/a'; + } } diff --git a/apps/red-ui/src/app/utils/types.d.ts b/apps/red-ui/src/app/utils/types.d.ts index d68b9a903..1409dc7ec 100644 --- a/apps/red-ui/src/app/utils/types.d.ts +++ b/apps/red-ui/src/app/utils/types.d.ts @@ -9,6 +9,13 @@ export type Color = 'active' | 'archived'; +export type AnnotationType = + 'hint' | + 'redaction' | + 'suggestion' | + 'comment' | + 'ignore' + export class SortingOption { label: string; order: string; @@ -16,10 +23,5 @@ export class SortingOption { } export class AnnotationFilters { - [key: string]: { - label: string, - value: boolean, - class: string, - symbol: string - } + [key: AnnotationType]: boolean } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 6f6c8388e..134f76839 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -368,12 +368,12 @@ "label": "Redaction" }, "comment": { - "label": "Comment" + "label": "Comment annotation" }, "suggestion": { "label": "Suggested redaction" }, - "ignored": { + "ignore": { "label": "Ignored redaction" } }, @@ -428,5 +428,13 @@ "approved": "Approved", "submitted": "Submitted", "active": "Active", - "archived": "Archived" + "archived": "Archived", + "hint": "Hint", + "ignore": "Ignore", + "redaction": "Redaction", + "comment": "Comment", + "suggestion": "Suggestion for redaction", + "dictionary": "Dictionary", + "content": "Content", + "page": "Page" } diff --git a/apps/red-ui/src/assets/styles/red-components.scss b/apps/red-ui/src/assets/styles/red-components.scss index 0ffb1d62c..bfec999e1 100644 --- a/apps/red-ui/src/assets/styles/red-components.scss +++ b/apps/red-ui/src/assets/styles/red-components.scss @@ -19,13 +19,6 @@ font-size: 13px; } - &.x-small { - height: 16px; - width: 16px; - font-size: 11px; - line-height: 14px; - } - &.lightgray-dark { background-color: $grey-4; } diff --git a/apps/red-ui/src/assets/styles/red-variables.scss b/apps/red-ui/src/assets/styles/red-variables.scss index 55ef43b4e..6815af85e 100644 --- a/apps/red-ui/src/assets/styles/red-variables.scss +++ b/apps/red-ui/src/assets/styles/red-variables.scss @@ -1,16 +1,12 @@ $white: #FFF; $black: #000; -$primary: #DD4D50; -$accent: #283241; -$light: #FFF; -$dark: #000; - $grey-1: #283241; $grey-2: #F4F5F7; $grey-3: #AAACB3; $grey-4: #E2E4E9; $grey-5: #D3D5DA; +$grey-6: #F0F1F4; $blue-1: #4875F7; $blue-2: #48C9F7; @@ -21,6 +17,11 @@ $yellow-1: #FFB83B; $green-1: #46CE7D; $green-2: #5CE594; +$primary: $red-1; +$accent: $grey-1; +$light: $white; +$dark: $black; + $separator: rgba(226,228,233,0.9); $right-container-inside-width: 340px;