diff --git a/apps/red-ui/src/app/components/buttons/icon-button/icon-button.component.html b/apps/red-ui/src/app/components/buttons/icon-button/icon-button.component.html
index 5f7c9657f..1cb7087e1 100644
--- a/apps/red-ui/src/app/components/buttons/icon-button/icon-button.component.html
+++ b/apps/red-ui/src/app/components/buttons/icon-button/icon-button.component.html
@@ -5,6 +5,7 @@
(click)="action.emit($event)"
[class.show-bg]="type === 'show-bg'"
[disabled]="disabled"
+ type="button"
>
diff --git a/apps/red-ui/src/app/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts b/apps/red-ui/src/app/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts
index ea85626a8..0cb553200 100644
--- a/apps/red-ui/src/app/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts
+++ b/apps/red-ui/src/app/dialogs/assign-owner-dialog/assign-owner-dialog.component.ts
@@ -105,7 +105,7 @@ export class AssignOwnerDialogComponent {
}
}
} catch (error) {
- this._notificationService.showToastNotification('Failed: ' + error.error.message, null, NotificationType.ERROR);
+ this._notificationService.showToastNotification('Failed: ' + error.error ? error.error.message : error, null, NotificationType.ERROR);
}
this.dialogRef.close();
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 9f9fd6847..8901854c4 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
@@ -163,6 +163,7 @@
[canPerformActions]="canPerformAnnotationActions"
[fileData]="displayData"
[fileStatus]="appStateService.activeFile"
+ [shouldDeselectAnnotationsOnPageChange]="shouldDeselectAnnotationsOnPageChange"
[annotations]="annotations"
>
@@ -241,7 +242,10 @@
{{ annotation.typeLabel | translate }}
- : {{ annotation.dictionary | humanize: false }}
+ {{ annotation.descriptor | translate }}: {{ annotation.dictionary | humanize: false }}
: {{ annotation.content }}
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 02d47ec80..7ea2c7174 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
@@ -44,6 +44,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
public fullScreen = false;
public editingReviewer = false;
public reviewerForm: FormGroup;
+ public shouldDeselectAnnotationsOnPageChange = true;
@ViewChild(PdfViewerComponent) private _viewerComponent: PdfViewerComponent;
@ViewChild('annotationsElement') private _annotationsElement: ElementRef;
@@ -193,6 +194,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
handleAnnotationSelected(annotationId: string) {
this.selectedAnnotation = this.annotations.find((a) => a.id === annotationId);
this.scrollToSelectedAnnotation();
+ console.log('selected: ', annotationId);
this._changeDetectorRef.detectChanges();
}
@@ -328,9 +330,11 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
// Displayed page doesn't have annotations
if ($event.key === 'ArrowDown') {
const nextPage = this._nextPageWithAnnotations();
+ this.shouldDeselectAnnotationsOnPageChange = false;
this.selectAnnotation(this.displayedAnnotations[nextPage].annotations[0]);
} else {
const prevPage = this._prevPageWithAnnotations();
+ this.shouldDeselectAnnotationsOnPageChange = false;
const prevPageAnnotations = this.displayedAnnotations[prevPage].annotations;
this.selectAnnotation(prevPageAnnotations[prevPageAnnotations.length - 1]);
}
@@ -348,6 +352,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
} else if (pageIdx + 1 < this.displayedPages.length) {
// If not last page
const nextPageAnnotations = this.displayedAnnotations[this.displayedPages[pageIdx + 1]].annotations;
+ this.shouldDeselectAnnotationsOnPageChange = false;
this.selectAnnotation(nextPageAnnotations[0]);
}
} else {
@@ -357,6 +362,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
} else if (pageIdx) {
// If not first page
const prevPageAnnotations = this.displayedAnnotations[this.displayedPages[pageIdx - 1]].annotations;
+ this.shouldDeselectAnnotationsOnPageChange = false;
this.selectAnnotation(prevPageAnnotations[prevPageAnnotations.length - 1]);
}
}
@@ -419,9 +425,12 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
return idx >= 0 ? this.displayedPages[idx] : null;
}
- viewerPageChanged($event: number) {
- this._scrollViews();
- this._changeDetectorRef.detectChanges();
+ viewerPageChanged($event: any) {
+ if (typeof $event === 'number') {
+ this._scrollViews();
+ this.shouldDeselectAnnotationsOnPageChange = true;
+ this._changeDetectorRef.detectChanges();
+ }
}
viewerReady($event: WebViewerInstance) {
diff --git a/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts b/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts
index 7acf2749d..7cb9ce388 100644
--- a/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts
+++ b/apps/red-ui/src/app/screens/file/model/annotation.wrapper.ts
@@ -36,6 +36,16 @@ export class AnnotationWrapper {
textAfter?: string;
textBefore?: string;
+ get isDictionaryBased() {
+ return (this.isHint || this.isRedacted) && !this.isManual;
+ }
+
+ get descriptor() {
+ // TODO clarify: RED-894
+ // return this.isDictionaryBased ? 'dictionary' : 'type';
+ return 'dictionary';
+ }
+
get hasTextAfter() {
return this.textAfter && this.textAfter.trim().length > 0;
}
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 a4f0b9bd3..65292487b 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
@@ -37,6 +37,7 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
@Input() fileStatus: FileStatusWrapper;
@Input() canPerformActions = false;
@Input() annotations: AnnotationWrapper[];
+ @Input() shouldDeselectAnnotationsOnPageChange = true;
@Output() fileReady = new EventEmitter();
@Output() annotationSelected = new EventEmitter
();
@@ -107,7 +108,11 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
}
});
- instance.docViewer.on('pageComplete', (p) => {
+ instance.docViewer.on('pageNumberUpdated', (p) => {
+ console.log(this.shouldDeselectAnnotationsOnPageChange);
+ if (this.shouldDeselectAnnotationsOnPageChange) {
+ this.instance.annotManager.deselectAllAnnotations();
+ }
this._ngZone.run(() => this.pageChanged.emit(p));
});
@@ -257,19 +262,18 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
}
});
- // Temporary removed false positive action
- // this.instance.textPopup.add({
- // type: 'actionButton',
- // dataElement: 'add-false-positive',
- // img: '/assets/icons/general/pdftron-action-false-positive.svg',
- // title: this._translateService.instant(this._manualAnnotationService.getTitle('FALSE_POSITIVE')),
- // onClick: () => {
- // const selectedQuads = this.instance.docViewer.getSelectedTextQuads();
- // const text = this.instance.docViewer.getSelectedText();
- // const mre = this._getManualRedactionEntry(selectedQuads, text);
- // this.manualAnnotationRequested.emit(new ManualRedactionEntryWrapper(this.instance.docViewer.getSelectedTextQuads(), mre, 'FALSE_POSITIVE'));
- // }
- // });
+ this.instance.textPopup.add({
+ type: 'actionButton',
+ dataElement: 'add-false-positive',
+ img: '/assets/icons/general/pdftron-action-false-positive.svg',
+ title: this._translateService.instant(this._manualAnnotationService.getTitle('FALSE_POSITIVE')),
+ onClick: () => {
+ const selectedQuads = this.instance.docViewer.getSelectedTextQuads();
+ const text = this.instance.docViewer.getSelectedText();
+ const mre = this._getManualRedactionEntry(selectedQuads, text);
+ this.manualAnnotationRequested.emit(new ManualRedactionEntryWrapper(this.instance.docViewer.getSelectedTextQuads(), mre, 'FALSE_POSITIVE'));
+ }
+ });
this.instance.textPopup.add({
type: 'actionButton',
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 efcb4c2c7..360ca57b6 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
@@ -186,7 +186,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
@HostListener('drop', ['$event'])
onDrop(event: DragEvent) {
- handleFileDrop(event, this._uploadFiles.bind(this));
+ handleFileDrop(event, this.appStateService.activeProjectId, this._uploadFiles.bind(this));
}
@HostListener('dragover', ['$event'])
@@ -196,7 +196,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
}
uploadFiles(files: File[] | FileList) {
- this._uploadFiles(convertFiles(files));
+ this._uploadFiles(convertFiles(files, this.appStateService.activeProjectId));
}
private _uploadFiles(files: FileUploadModel[]) {
@@ -206,6 +206,10 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
}
private _computeAllFilters() {
+ if (!this.appStateService.activeProject) {
+ return;
+ }
+
const allDistinctFileStatusWrapper = new Set();
const allDistinctPeople = new Set();
const allDistinctAddedDates = new Set();
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 a11731266..32a4d7696 100644
--- a/apps/red-ui/src/app/state/app-state.service.ts
+++ b/apps/red-ui/src/app/state/app-state.service.ts
@@ -345,11 +345,11 @@ export class AppStateService {
this._appState.projects.push(foundProject);
}
this._appState.projects = [...this._appState.projects];
- return foundProject.project;
+ return foundProject;
} catch (error) {
this._notificationService.showToastNotification(
this._translateService.instant(
- error.status === 409 ? 'projects.add-edit-dialog.errors.project-already-exists' : 'projects.add-edit-dialog.errors.generic'
+ error.status === 409 ? 'project-listing.add-edit-dialog.errors.project-already-exists' : 'project-listing.add-edit-dialog.errors.generic'
),
null,
NotificationType.ERROR
diff --git a/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts b/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts
index d424e5de1..193f8558a 100644
--- a/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts
+++ b/apps/red-ui/src/app/upload/file-drop/file-drop.component.ts
@@ -4,6 +4,7 @@ import { FileUploadModel } from '../model/file-upload.model';
import { OverlayRef } from '@angular/cdk/overlay';
import { UploadStatusOverlayService } from '../upload-status-dialog/service/upload-status-overlay.service';
import { handleFileDrop } from '../../utils/file-drop-utils';
+import { AppStateService } from '../../state/app-state.service';
@Component({
selector: 'redaction-file-drop',
@@ -14,6 +15,7 @@ export class FileDropComponent implements OnInit {
constructor(
private readonly _dialogRef: OverlayRef,
private readonly _fileUploadService: FileUploadService,
+ private readonly _appStateService: AppStateService,
private readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _uploadStatusOverlayService: UploadStatusOverlayService
) {}
@@ -33,7 +35,7 @@ export class FileDropComponent implements OnInit {
@HostListener('drop', ['$event'])
onDrop(event: DragEvent) {
- handleFileDrop(event, this.uploadFiles.bind(this));
+ handleFileDrop(event, this._appStateService.activeProjectId, this.uploadFiles.bind(this));
}
@HostListener('dragover', ['$event'])
diff --git a/apps/red-ui/src/app/upload/file-upload.service.ts b/apps/red-ui/src/app/upload/file-upload.service.ts
index e94ead8d4..d02960f80 100644
--- a/apps/red-ui/src/app/upload/file-upload.service.ts
+++ b/apps/red-ui/src/app/upload/file-upload.service.ts
@@ -77,12 +77,7 @@ export class FileUploadService {
private _createSubscription(uploadFile: FileUploadModel) {
this.activeUploads++;
- const obs = this._fileManagementControllerService.uploadFileForm(
- uploadFile.file,
- this._appStateService.activeProject.project.projectId,
- 'events',
- true
- );
+ const obs = this._fileManagementControllerService.uploadFileForm(uploadFile.file, uploadFile.projectId, 'events', true);
const subscription = obs.subscribe(
async (event) => {
if (event.type === HttpEventType.UploadProgress) {
diff --git a/apps/red-ui/src/app/upload/model/file-upload.model.ts b/apps/red-ui/src/app/upload/model/file-upload.model.ts
index 7ff1519c9..750f92b02 100644
--- a/apps/red-ui/src/app/upload/model/file-upload.model.ts
+++ b/apps/red-ui/src/app/upload/model/file-upload.model.ts
@@ -6,4 +6,5 @@ export interface FileUploadModel {
retryCount: number;
size: number;
sizeError: any;
+ projectId?: string;
}
diff --git a/apps/red-ui/src/app/utils/file-drop-utils.ts b/apps/red-ui/src/app/utils/file-drop-utils.ts
index 937fc245d..83395e26e 100644
--- a/apps/red-ui/src/app/utils/file-drop-utils.ts
+++ b/apps/red-ui/src/app/utils/file-drop-utils.ts
@@ -1,6 +1,6 @@
import { FileUploadModel } from '../upload/model/file-upload.model';
-export function handleFileDrop(event: DragEvent, uploadFiles: (files: FileUploadModel[]) => void) {
+export function handleFileDrop(event: DragEvent, projectId: string, uploadFiles: (files: FileUploadModel[]) => void) {
event.preventDefault();
event.stopPropagation();
const { dataTransfer } = event;
@@ -16,16 +16,16 @@ export function handleFileDrop(event: DragEvent, uploadFiles: (files: FileUpload
} else {
files = dataTransfer.files;
dataTransfer.clearData();
- uploadFiles(convertFiles(files));
+ uploadFiles(convertFiles(files, projectId));
}
- const convertedFiles = convertFiles(files);
+ const convertedFiles = convertFiles(files, projectId);
if (convertedFiles.length > 0) {
uploadFiles(convertedFiles);
}
}
-export function convertFiles(files: FileList | File[]): FileUploadModel[] {
+export function convertFiles(files: FileList | File[], projectId: string): FileUploadModel[] {
let uploadFiles: FileUploadModel[] = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
@@ -34,6 +34,7 @@ export function convertFiles(files: FileList | File[]): FileUploadModel[] {
progress: 0,
completed: false,
error: null,
+ projectId: projectId,
sizeError: false,
retryCount: 0,
size: file.size
diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json
index dd85a8b34..4c5e73292 100644
--- a/apps/red-ui/src/assets/i18n/en.json
+++ b/apps/red-ui/src/assets/i18n/en.json
@@ -422,6 +422,7 @@
"comment": "Comment",
"suggestion": "Suggestion for redaction",
"dictionary": "Dictionary",
+ "type": "Type",
"content": "Reason",
"page": "Page",
"annotation": "Annotation",
diff --git a/apps/red-ui/src/assets/styles/red-editor.scss b/apps/red-ui/src/assets/styles/red-editor.scss
index bc9583aa6..f17edf52a 100644
--- a/apps/red-ui/src/assets/styles/red-editor.scss
+++ b/apps/red-ui/src/assets/styles/red-editor.scss
@@ -15,7 +15,7 @@
.search-marker {
position: absolute;
- background: rgba($yellow-1, 0.3);
+ background: rgba($blue-5, 0.3);
z-index: 40;
}
diff --git a/apps/red-ui/src/assets/styles/red-variables.scss b/apps/red-ui/src/assets/styles/red-variables.scss
index d21f0c0d2..0a64ed393 100644
--- a/apps/red-ui/src/assets/styles/red-variables.scss
+++ b/apps/red-ui/src/assets/styles/red-variables.scss
@@ -13,6 +13,7 @@ $blue-1: #4875f7;
$blue-2: #48c9f7;
$blue-3: #5b97db;
$blue-4: #374c81;
+$blue-5: #c5d3eb;
$red-1: #dd4d50;
$red-2: #f16164;
$yellow-1: #ffb83b;