@@ -199,7 +117,7 @@
div {
- position: relative;
-
- .dot {
- background: $primary;
- height: 10px;
- width: 10px;
- border-radius: 50%;
- position: absolute;
- top: 0;
- left: 0;
- }
- }
-
.close-icon {
height: 14px;
width: 14px;
@@ -165,15 +151,3 @@ redaction-pdf-viewer {
}
}
}
-
-.filter-menu-header {
- display: flex;
- justify-content: space-between;
- padding: 7px 15px 15px;
- width: 350px;
-
- .actions {
- display: flex;
- gap: 8px;
- }
-}
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 aa9f42429..3fa3b37c1 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
@@ -16,7 +16,6 @@ import { AnnotationUtils } from '../../../utils/annotation-utils';
import { UserService } from '../../../user/user.service';
import { debounce } from '../../../utils/debounce';
import scrollIntoView from 'scroll-into-view-if-needed';
-import { FiltersService } from '../service/filters.service';
import { FileDownloadService } from '../service/file-download.service';
import { saveAs } from 'file-saver';
import { FileType } from '../model/file-type';
@@ -42,7 +41,7 @@ export class FilePreviewScreenComponent implements OnInit {
private _dialogRef: MatDialogRef
;
@ViewChild(PdfViewerComponent) private _viewerComponent: PdfViewerComponent;
- @ViewChild('annotations') private _annotationsElement: ElementRef;
+ @ViewChild('annotationsElement') private _annotationsElement: ElementRef;
@ViewChild('quickNavigation') private _quickNavigationElement: ElementRef;
public fileData: FileDataModel;
@@ -50,7 +49,6 @@ export class FilePreviewScreenComponent implements OnInit {
public annotations: AnnotationWrapper[] = [];
public displayedAnnotations: { [key: number]: { annotations: AnnotationWrapper[] } } = {};
public selectedAnnotation: AnnotationWrapper;
- public filters: AnnotationFilter[];
public pagesPanelActive = true;
public viewReady = false;
@@ -64,7 +62,6 @@ export class FilePreviewScreenComponent implements OnInit {
private readonly _manualAnnotationService: ManualAnnotationService,
private readonly _fileDownloadService: FileDownloadService,
private readonly _reanalysisControllerService: ReanalysisControllerService,
- private readonly _filtersService: FiltersService,
private ngZone: NgZone
) {
this._activatedRoute.params.subscribe((params) => {
@@ -78,14 +75,6 @@ export class FilePreviewScreenComponent implements OnInit {
return this.userService.user;
}
- public filterKeys(key?: string) {
- if (key) {
- return Object.keys(this.filters[key]);
- }
-
- return Object.keys(this.filters);
- }
-
public get redactedView() {
return this._activeViewer === 'REDACTED';
}
@@ -95,7 +84,6 @@ export class FilePreviewScreenComponent implements OnInit {
}
public ngOnInit(): void {
- this.filters = this._filtersService.getFilters(this.appStateService.dictionaryData);
this._loadFileData();
this.appStateService.fileStatusChanged.subscribe((fileStatus) => {
if (fileStatus.fileId === this.fileId) {
@@ -106,19 +94,15 @@ export class FilePreviewScreenComponent implements OnInit {
}
private _loadFileData() {
- this._fileDownloadService.loadFileData(this.fileId).subscribe((fileDataModel) => {
- this.fileData = fileDataModel;
- this.annotations = fileDataModel.redactionLog.redactionLogEntry.map(
- (rde) => new AnnotationWrapper(rde, null)
- );
- this.filters = this._filtersService.getFilters(
- this.appStateService.dictionaryData,
- this.annotations
- );
- this.applyFilters();
- this._changeDetectorRef.detectChanges();
- console.log(this.annotations);
- });
+ this._fileDownloadService
+ .loadFileData(this.appStateService.activeProjectId, this.fileId)
+ .subscribe((fileDataModel) => {
+ this.fileData = fileDataModel;
+ this.annotations = fileDataModel.redactionLog.redactionLogEntry.map(
+ (rde) => new AnnotationWrapper(rde, null)
+ );
+ this._changeDetectorRef.detectChanges();
+ });
}
public openFileDetailsDialog($event: MouseEvent) {
@@ -157,13 +141,6 @@ export class FilePreviewScreenComponent implements OnInit {
return this.instance;
}
- public applyFilters() {
- this.displayedAnnotations = AnnotationUtils.parseAnnotations(
- this.annotations,
- this.filters
- );
- }
-
public get displayedPages(): number[] {
return Object.keys(this.displayedAnnotations).map((key) => Number(key));
}
@@ -221,7 +198,7 @@ export class FilePreviewScreenComponent implements OnInit {
}
get activeViewerPage() {
- return this.instance.docViewer.getCurrentPage();
+ return this.instance?.docViewer?.getCurrentPage();
}
@debounce()
@@ -286,43 +263,6 @@ export class FilePreviewScreenComponent implements OnInit {
});
}
- public setAllFilters(filter: any, value: boolean, rootKey?: string) {
- if (rootKey) {
- this.filters[rootKey] = value;
- } else {
- for (const key of Object.keys(filter)) {
- if (AnnotationUtils.hasSubsections(filter[key])) {
- this.setAllFilters(filter[key], value);
- } else {
- filter[key] = value;
- }
- }
- }
- }
-
- public isChecked(key: string): boolean {
- return AnnotationUtils.isChecked(this.filters[key]);
- }
-
- public isIndeterminate(key: string): boolean {
- return AnnotationUtils.isIndeterminate(this.filters[key]);
- }
-
- public get hasActiveFilters(): boolean {
- // return AnnotationUtils.hasActiveFilters(this.filters);
- return true;
- }
-
- public hasSubsections(filter: AnnotationFilter[]) {
- // return AnnotationUtils.hasSubsections(filter);
- }
-
- public setExpanded(key: string, value: boolean, $event: MouseEvent) {
- $event.stopPropagation();
- //this.expandedFilters[key] = value;
- this._changeDetectorRef.detectChanges();
- }
-
@HostListener('window:keyup', ['$event'])
handleKeyEvent($event: KeyboardEvent) {
const keyArray = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
@@ -491,15 +431,11 @@ export class FilePreviewScreenComponent implements OnInit {
return new this.activeViewer.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b);
}
- filterClicked($event: MouseEvent, key: string, subkey?: string) {
- $event.preventDefault();
- $event.stopPropagation();
- if (subkey) {
- this.filters[key][subkey] = !this.filters[key][subkey];
- } else {
- //this.setAllFilters(this.filters[key],)
- this.filters[key] = !this.filters[key];
- }
- return false;
+ filtersChanged(filters: AnnotationFilter[]) {
+ this.displayedAnnotations = AnnotationUtils.filterAndGroupAnnotations(
+ this.annotations,
+ filters
+ );
+ this._changeDetectorRef.detectChanges();
}
}
diff --git a/apps/red-ui/src/app/screens/file/model/file-data.model.ts b/apps/red-ui/src/app/screens/file/model/file-data.model.ts
index c15915b92..902219f23 100644
--- a/apps/red-ui/src/app/screens/file/model/file-data.model.ts
+++ b/apps/red-ui/src/app/screens/file/model/file-data.model.ts
@@ -1,9 +1,10 @@
-import { RedactionLog } from '@redaction/red-ui-http';
+import { ManualRedactions, RedactionLog } from '@redaction/red-ui-http';
export class FileDataModel {
constructor(
public annotatedFileData: Blob,
public redactedFileData: Blob,
- public redactionLog: RedactionLog
+ public redactionLog: RedactionLog,
+ public manualRedactions: ManualRedactions
) {}
}
diff --git a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts
index 9acb10c61..b36e4999f 100644
--- a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts
+++ b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts
@@ -74,7 +74,6 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
ngOnInit() {
this._restoreViewerState = this._restoreViewerState.bind(this);
- this._manualAnnotationService.loadManualAnnotationsForActiveFile().subscribe(() => {});
}
ngOnChanges(changes: SimpleChanges): void {
diff --git a/apps/red-ui/src/app/screens/file/service/file-download.service.ts b/apps/red-ui/src/app/screens/file/service/file-download.service.ts
index 8a2b51918..d01693296 100644
--- a/apps/red-ui/src/app/screens/file/service/file-download.service.ts
+++ b/apps/red-ui/src/app/screens/file/service/file-download.service.ts
@@ -1,7 +1,11 @@
import { Injectable } from '@angular/core';
import { forkJoin, Observable, of } from 'rxjs';
import { map, tap } from 'rxjs/operators';
-import { FileUploadControllerService, RedactionLogControllerService } from '@redaction/red-ui-http';
+import {
+ FileUploadControllerService,
+ ManualRedactionControllerService,
+ RedactionLogControllerService
+} from '@redaction/red-ui-http';
import { FileType } from '../model/file-type';
import { FileDataModel } from '../model/file-data.model';
@@ -11,15 +15,20 @@ import { FileDataModel } from '../model/file-data.model';
export class FileDownloadService {
constructor(
private readonly _fileUploadControllerService: FileUploadControllerService,
+ private readonly _manualRedactionControllerService: ManualRedactionControllerService,
private readonly _redactionLogControllerService: RedactionLogControllerService
) {}
- public loadFileData(fileId: string): Observable {
+ public loadFileData(projectId: string, fileId: string): Observable {
const annotatedObs = this.loadFile('ANNOTATED', fileId);
const redactedObs = this.loadFile('REDACTED', fileId);
const reactionLogObs = this._redactionLogControllerService.getRedactionLog(fileId);
+ const manualRedactionsObs = this._manualRedactionControllerService.getManualRedaction(
+ projectId,
+ fileId
+ );
- return forkJoin([annotatedObs, redactedObs, reactionLogObs]).pipe(
+ return forkJoin([annotatedObs, redactedObs, reactionLogObs, manualRedactionsObs]).pipe(
map((data) => new FileDataModel(...data))
);
}
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
deleted file mode 100644
index 8b8d303b7..000000000
--- a/apps/red-ui/src/app/screens/file/service/filters.service.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { Injectable } from '@angular/core';
-import { AnnotationFilter } from '../../../utils/types';
-import { TypeValue } from '@redaction/red-ui-http';
-import { AnnotationWrapper } from '../model/annotation.wrapper';
-
-@Injectable({
- providedIn: 'root'
-})
-export class FiltersService {
- constructor() {}
-
- public getFilters(
- dictionaryData: { [key: string]: TypeValue },
- annotations?: AnnotationWrapper[]
- ): AnnotationFilter[] {
- const availableAnnotationTypes: Set = new Set();
- annotations?.forEach((a) => {
- availableAnnotationTypes.add(a.superType);
- availableAnnotationTypes.add(a.dictionary);
- });
- const filters: AnnotationFilter[] = [];
- for (const key of Object.keys(dictionaryData)) {
- if (availableAnnotationTypes.has(key)) {
- const typeValue = dictionaryData[key];
- const filter: AnnotationFilter = this._addOrGetGroup(
- filters,
- typeValue.hint ? 'hint' : 'redaction'
- );
- filter.filters.push({
- key: key
- });
- }
- }
-
- return filters;
- }
-
- private _addOrGetGroup(filters: AnnotationFilter[], name: string) {
- return { key: name, filters: [] };
- }
-}
diff --git a/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts b/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts
index dd2c4cb50..bbabd7500 100644
--- a/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts
+++ b/apps/red-ui/src/app/screens/file/service/manual-annotation.service.ts
@@ -16,12 +16,6 @@ import { UserService } from '../../../user/user.service';
providedIn: 'root'
})
export class ManualAnnotationService {
- private _manualAnnotationsResponse: ManualRedactions;
-
- get manualEntries(): ManualRedactionEntry[] {
- return this._manualAnnotationsResponse ? this._manualAnnotationsResponse.entriesToAdd : [];
- }
-
constructor(
private readonly _appStateService: AppStateService,
private readonly _userService: UserService,
@@ -68,7 +62,6 @@ export class ManualAnnotationService {
}
public rejectSuggestion(annotationWrapper: AnnotationWrapper) {
- console.log(annotationWrapper);
// if you're the owner, you undo, otherwise you reject
const observable =
annotationWrapper.manualRedactionOwner === this._userService.userId
@@ -83,22 +76,16 @@ export class ManualAnnotationService {
annotationWrapper.uuid
);
- return observable
- .pipe(
- tap(
- () => {
- this._notify('manual-annotation.reject-request.success');
- },
- () => {
- this._notify('manual-annotation.reject-request.error');
- }
- )
+ return observable.pipe(
+ tap(
+ () => {
+ this._notify('manual-annotation.reject-request.success');
+ },
+ () => {
+ this._notify('manual-annotation.reject-request.error');
+ }
)
- .pipe(
- mergeMap((result) => {
- return this.loadManualAnnotationsForActiveFile().pipe(map(() => result));
- })
- );
+ );
}
public removeRedaction(annotationWrapper: AnnotationWrapper) {}
@@ -140,11 +127,6 @@ export class ManualAnnotationService {
);
}
)
- )
- .pipe(
- mergeMap((result) => {
- return this.loadManualAnnotationsForActiveFile().pipe(map(() => result));
- })
);
}
@@ -165,11 +147,6 @@ export class ManualAnnotationService {
);
}
)
- )
- .pipe(
- mergeMap((result) => {
- return this.loadManualAnnotationsForActiveFile().pipe(map(() => result));
- })
);
}
@@ -196,17 +173,4 @@ export class ManualAnnotationService {
}
}
}
-
- loadManualAnnotationsForActiveFile() {
- return this._manualRedactionControllerService
- .getManualRedaction(
- this._appStateService.activeProject.project.projectId,
- this._appStateService.activeFile.fileId
- )
- .pipe(
- tap((response) => {
- this._manualAnnotationsResponse = response;
- })
- );
- }
}
diff --git a/apps/red-ui/src/app/utils/annotation-utils.ts b/apps/red-ui/src/app/utils/annotation-utils.ts
index ae675f0ad..bfbde64d6 100644
--- a/apps/red-ui/src/app/utils/annotation-utils.ts
+++ b/apps/red-ui/src/app/utils/annotation-utils.ts
@@ -15,53 +15,36 @@ export class AnnotationUtils {
});
}
- public static hasSubsections(filter: AnnotationFilter | boolean) {
- return filter instanceof Object;
+ public static hasActiveFilters(filters: AnnotationFilter[]): boolean {
+ return filters.reduce((acc, next) => acc || next.checked || next.indeterminate, false);
}
- public static checkedSubkeys(filter: AnnotationFilter | boolean) {
- return Object.keys(filter).filter((subkey) => this.isChecked(filter[subkey])).length;
- }
-
- // Only some of the sub-items are selected
- public static isIndeterminate(filter: AnnotationFilter | boolean): boolean {
- return this.hasSubsections(filter)
- ? AnnotationUtils.checkedSubkeys(filter) > 0 && !this.isChecked(filter)
- : false;
- }
-
- // All sub-items are selected
- public static isChecked(filter: AnnotationFilter | boolean): boolean {
- return this.hasSubsections(filter)
- ? AnnotationUtils.checkedSubkeys(filter) === Object.keys(filter).length
- : (filter as boolean);
- }
-
- public static hasActiveFilters(filter: AnnotationFilter[]): boolean {
- const activeFilters = Object.keys(filter).filter((key) => {
- return this.isChecked(filter[key]) || this.isIndeterminate(filter[key]);
- });
- // return activeFilters.length > 0;
- return false;
- }
-
- public static parseAnnotations(
+ public static filterAndGroupAnnotations(
annotations: AnnotationWrapper[],
filters: AnnotationFilter[]
): { [key: number]: { annotations: AnnotationWrapper[] } } {
const obj = {};
+ const hasActiveFilters = AnnotationUtils.hasActiveFilters(filters);
+
+ const flatFilters = [];
+ filters.forEach((filter) => {
+ flatFilters.push(filter);
+ flatFilters.push(...filter.filters);
+ });
for (const annotation of annotations) {
const pageNumber = annotation.pageNumber;
const type = annotation.superType;
- const dictionary = annotation.dictionary;
- if (this.hasActiveFilters(filters)) {
- if (!this.hasSubsections(filters[type]) && !filters[type]) {
- continue;
+ if (hasActiveFilters) {
+ let found = false;
+ for (const filter of flatFilters) {
+ if (filter.key === annotation.dictionary && filter.checked) {
+ found = true;
+ break;
+ }
}
-
- if (this.hasSubsections(filters[type]) && !filters[type][dictionary]) {
+ if (!found) {
continue;
}
}
diff --git a/apps/red-ui/src/app/utils/types.d.ts b/apps/red-ui/src/app/utils/types.d.ts
index 01afaabba..569d5b93d 100644
--- a/apps/red-ui/src/app/utils/types.d.ts
+++ b/apps/red-ui/src/app/utils/types.d.ts
@@ -12,5 +12,6 @@ export interface AnnotationFilter {
key: string;
checked?: boolean;
indeterminate?: boolean;
+ expanded?: boolean;
filters?: AnnotationFilter[];
}