Pull request #208: Bugs

Merge in RED/ui from bugs to master

* commit '11dfe604511eacc13a92ea7b650df4317a030850':
  RED-1596: don't reuse component without open file permissions
  fix disable redaction for approved files
This commit is contained in:
Timo Bejan 2021-06-11 11:05:36 +02:00
commit 385ab6aafa
6 changed files with 133 additions and 164 deletions

View File

@ -2,12 +2,7 @@
<ng-container *ngTemplateOutlet="actions"></ng-container> <ng-container *ngTemplateOutlet="actions"></ng-container>
<redaction-status-bar <redaction-status-bar
*ngIf="fileStatus.isWorkable" *ngIf="fileStatus.isWorkable"
[config]="[ [config]="statusBarConfig"
{
color: fileStatus.status,
length: 1
}
]"
></redaction-status-bar> ></redaction-status-bar>
</div> </div>
@ -25,8 +20,7 @@
[type]="buttonType" [type]="buttonType"
icon="red:trash" icon="red:trash"
tooltip="dossier-overview.delete.action" tooltip="dossier-overview.delete.action"
> ></redaction-circle-button>
</redaction-circle-button>
<redaction-circle-button <redaction-circle-button
(action)="assign($event)" (action)="assign($event)"
@ -44,8 +38,7 @@
[type]="buttonType" [type]="buttonType"
icon="red:assign-me" icon="red:assign-me"
tooltip="dossier-overview.assign-me" tooltip="dossier-overview.assign-me"
> ></redaction-circle-button>
</redaction-circle-button>
<!-- download redacted file--> <!-- download redacted file-->
<redaction-file-download-btn <redaction-file-download-btn
@ -54,8 +47,7 @@
[tooltipClass]="'small'" [tooltipClass]="'small'"
[tooltipPosition]="tooltipPosition" [tooltipPosition]="tooltipPosition"
[type]="buttonType" [type]="buttonType"
> ></redaction-file-download-btn>
</redaction-file-download-btn>
<redaction-circle-button <redaction-circle-button
(action)="toggleViewDocumentInfo()" (action)="toggleViewDocumentInfo()"
@ -74,8 +66,7 @@
[type]="buttonType" [type]="buttonType"
icon="red:ready-for-approval" icon="red:ready-for-approval"
tooltip="dossier-overview.under-approval" tooltip="dossier-overview.under-approval"
> ></redaction-circle-button>
</redaction-circle-button>
<!-- Back to review --> <!-- Back to review -->
<redaction-circle-button <redaction-circle-button
@ -85,8 +76,7 @@
[type]="buttonType" [type]="buttonType"
icon="red:undo" icon="red:undo"
tooltip="dossier-overview.under-review" tooltip="dossier-overview.under-review"
> ></redaction-circle-button>
</redaction-circle-button>
<!-- Approved--> <!-- Approved-->
<redaction-circle-button <redaction-circle-button
@ -101,8 +91,7 @@
" "
[type]="buttonType" [type]="buttonType"
icon="red:approved" icon="red:approved"
> ></redaction-circle-button>
</redaction-circle-button>
<!-- Back to approval --> <!-- Back to approval -->
<redaction-circle-button <redaction-circle-button
@ -112,8 +101,7 @@
[type]="buttonType" [type]="buttonType"
icon="red:undo" icon="red:undo"
tooltip="dossier-overview.under-approval" tooltip="dossier-overview.under-approval"
> ></redaction-circle-button>
</redaction-circle-button>
<redaction-circle-button <redaction-circle-button
(action)="ocrFile($event)" (action)="ocrFile($event)"
@ -122,8 +110,7 @@
[type]="buttonType" [type]="buttonType"
icon="red:ocr" icon="red:ocr"
tooltip="dossier-overview.ocr-file" tooltip="dossier-overview.ocr-file"
> ></redaction-circle-button>
</redaction-circle-button>
<!-- reanalyse file preview --> <!-- reanalyse file preview -->
<redaction-circle-button <redaction-circle-button
@ -134,8 +121,7 @@
tooltipClass="warn small" tooltipClass="warn small"
tooltipPosition="below" tooltipPosition="below"
type="warn" type="warn"
> ></redaction-circle-button>
</redaction-circle-button>
<!-- reanalyse file listing --> <!-- reanalyse file listing -->
<redaction-circle-button <redaction-circle-button
@ -145,21 +131,19 @@
icon="red:refresh" icon="red:refresh"
tooltip="dossier-overview.reanalyse.action" tooltip="dossier-overview.reanalyse.action"
type="dark-bg" type="dark-bg"
> ></redaction-circle-button>
</redaction-circle-button>
<!-- exclude from redaction --> <!-- exclude from redaction -->
<div class="red-input-group"> <div class="red-input-group">
<mat-slide-toggle <mat-slide-toggle
(click)="toggleAnalysis($event)" (change)="toggleAnalysis()"
[checked]="!fileStatus?.isExcluded" [checked]="!fileStatus?.isExcluded"
[class.mr-24]="screen === 'dossier-overview'" [class.mr-24]="screen === 'dossier-overview'"
[disabled]="!permissionsService.canToggleAnalysis(fileStatus)" [disabled]="!permissionsService.canToggleAnalysis(fileStatus)"
[matTooltipPosition]="tooltipPosition" [matTooltipPosition]="tooltipPosition"
[matTooltip]="toggleTooltip | translate" [matTooltip]="toggleTooltip | translate"
color="primary" color="primary"
> ></mat-slide-toggle>
</mat-slide-toggle>
</div> </div>
</div> </div>
</ng-template> </ng-template>

View File

@ -25,6 +25,10 @@ export class FileActionsComponent implements OnInit {
private readonly _fileActionService: FileActionService private readonly _fileActionService: FileActionService
) {} ) {}
get statusBarConfig() {
return [{ color: this.fileStatus.status, length: 1 }];
}
get tooltipPosition() { get tooltipPosition() {
return this.screen === 'file-preview' ? 'below' : 'above'; return this.screen === 'file-preview' ? 'below' : 'above';
} }
@ -63,26 +67,14 @@ export class FileActionsComponent implements OnInit {
return this.permissionsService.canOcrFile(this.fileStatus); return this.permissionsService.canOcrFile(this.fileStatus);
} }
// Under review
get canSetToUnderReview() { get canSetToUnderReview() {
return this.permissionsService.canSetUnderReview(this.fileStatus); return this.permissionsService.canSetUnderReview(this.fileStatus);
} }
// Under approval
get canSetToUnderApproval() { get canSetToUnderApproval() {
return this.permissionsService.canSetUnderApproval(this.fileStatus); return this.permissionsService.canSetUnderApproval(this.fileStatus);
} }
// Approve
get isReadyForApproval() {
return this.permissionsService.isReadyForApproval(this.fileStatus);
}
get canApprove() {
return this.permissionsService.canApprove(this.fileStatus);
}
// Undo approval
get canUndoApproval() { get canUndoApproval() {
return this.permissionsService.canUndoApproval(this.fileStatus); return this.permissionsService.canUndoApproval(this.fileStatus);
} }
@ -94,17 +86,18 @@ export class FileActionsComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
if (!this.fileStatus) { if (this.fileStatus) {
this.fileStatus = this.appStateService.activeFile;
this.screen = 'file-preview';
this.appStateService.fileChanged.subscribe((fileStatus: FileStatusWrapper) => {
if (fileStatus.fileId === this.fileStatus?.fileId) {
this.fileStatus = this.appStateService.activeFile;
}
});
} else {
this.screen = 'dossier-overview'; this.screen = 'dossier-overview';
return;
} }
this.fileStatus = this.appStateService.activeFile;
this.screen = 'file-preview';
this.appStateService.fileChanged.subscribe(fileStatus => {
if (fileStatus.fileId === this.fileStatus?.fileId) {
this.fileStatus = this.appStateService.activeFile;
}
});
} }
toggleViewDocumentInfo() { toggleViewDocumentInfo() {
@ -116,9 +109,7 @@ export class FileActionsComponent implements OnInit {
$event, $event,
this.fileStatus.dossierId, this.fileStatus.dossierId,
[this.fileStatus.fileId], [this.fileStatus.fileId],
() => { () => this.actionPerformed.emit('delete')
this.actionPerformed.emit('delete');
}
); );
} }
@ -191,8 +182,7 @@ export class FileActionsComponent implements OnInit {
}); });
} }
async toggleAnalysis($event: MouseEvent) { async toggleAnalysis() {
$event.stopPropagation();
await this._fileActionService.toggleAnalysis(this.fileStatus).toPromise(); await this._fileActionService.toggleAnalysis(this.fileStatus).toPromise();
await this.appStateService.getFiles(); await this.appStateService.getFiles();
this.actionPerformed.emit( this.actionPerformed.emit(

View File

@ -78,8 +78,8 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
} }
} }
ngAfterViewInit(): void { async ngAfterViewInit(): Promise<void> {
this._loadViewer(); await this._loadViewer();
} }
deselectAllAnnotations() { deselectAllAnnotations() {
@ -135,99 +135,98 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnChanges {
return this.instance.annotManager.getAnnotationById(id); return this.instance.annotManager.getAnnotationById(id);
} }
private _loadViewer() { private async _loadViewer() {
WebViewer( this.instance = await WebViewer(
{ {
licenseKey: environment.licenseKey ? atob(environment.licenseKey) : null, licenseKey: environment.licenseKey ? atob(environment.licenseKey) : null,
path: this._convertPath('/assets/wv-resources'), path: this._convertPath('/assets/wv-resources'),
css: this._convertPath('/assets/pdftron/stylesheet.css') css: this._convertPath('/assets/pdftron/stylesheet.css')
}, },
this.viewer.nativeElement this.viewer.nativeElement
).then(instance => { );
this.instance = instance;
this._setSelectionMode();
this._disableElements();
this._disableHotkeys();
this._configureTextPopup();
instance.annotManager.on('annotationSelected', (annotations, action) => { this._setSelectionMode();
this.annotationSelected.emit( this._disableElements();
instance.annotManager.getSelectedAnnotations().map(ann => ann.Id) this._disableHotkeys();
this._configureTextPopup();
this.instance.annotManager.on('annotationSelected', (annotations, action) => {
this.annotationSelected.emit(
this.instance.annotManager.getSelectedAnnotations().map(ann => ann.Id)
);
if (action === 'deselected') {
this._toggleRectangleAnnotationAction(true);
} else {
this._configureAnnotationSpecificActions(annotations);
this._toggleRectangleAnnotationAction(
annotations.length === 1 && annotations[0].ReadOnly
); );
if (action === 'deselected') { }
this._toggleRectangleAnnotationAction(true); });
} else {
this._configureAnnotationSpecificActions(annotations);
this._toggleRectangleAnnotationAction(
annotations.length === 1 && annotations[0].ReadOnly
);
}
});
instance.annotManager.on('annotationChanged', annotations => { this.instance.annotManager.on('annotationChanged', annotations => {
// when a rectangle is drawn, // when a rectangle is drawn,
// it returns one annotation with tool name 'AnnotationCreateRectangle; // it returns one annotation with tool name 'AnnotationCreateRectangle;
// this will auto select rectangle after drawing // this will auto select rectangle after drawing
if ( if (
annotations.length === 1 && annotations.length === 1 &&
annotations[0].ToolName === 'AnnotationCreateRectangle' annotations[0].ToolName === 'AnnotationCreateRectangle'
) { ) {
instance.annotManager.selectAnnotations(annotations); this.instance.annotManager.selectAnnotations(annotations);
} }
}); });
instance.docViewer.on('pageNumberUpdated', pageNumber => { this.instance.docViewer.on('pageNumberUpdated', pageNumber => {
if (this.shouldDeselectAnnotationsOnPageChange) { if (this.shouldDeselectAnnotationsOnPageChange) {
this.deselectAllAnnotations(); this.deselectAllAnnotations();
} }
this._ngZone.run(() => this.pageChanged.emit(pageNumber)); this._ngZone.run(() => this.pageChanged.emit(pageNumber));
}); });
instance.docViewer.on('documentLoaded', this._documentLoaded); this.instance.docViewer.on('documentLoaded', this._documentLoaded);
instance.docViewer.on('keyUp', $event => { this.instance.docViewer.on('keyUp', $event => {
// arrows and full-screen // arrows and full-screen
if ($event.target?.tagName?.toLowerCase() !== 'input') { if ($event.target?.tagName?.toLowerCase() !== 'input') {
if ($event.key.startsWith('Arrow') || $event.key === 'f') { if ($event.key.startsWith('Arrow') || $event.key === 'f') {
this._ngZone.run(() => { this._ngZone.run(() => {
this.keyUp.emit($event); this.keyUp.emit($event);
}); });
$event.preventDefault();
$event.stopPropagation();
}
}
if (this._allowedKeyboardShortcuts.indexOf($event.key) < 0) {
$event.preventDefault(); $event.preventDefault();
$event.stopPropagation(); $event.stopPropagation();
} }
}); }
instance.docViewer.on('textSelected', (quads, selectedText) => { if (this._allowedKeyboardShortcuts.indexOf($event.key) < 0) {
this._selectedText = selectedText; $event.preventDefault();
if (selectedText.length > 2 && this.canPerformActions) { $event.stopPropagation();
this.instance.enableElements(['add-dictionary', 'add-false-positive']); }
} else {
this.instance.disableElements(['add-dictionary', 'add-false-positive']);
}
});
instance.iframeWindow.addEventListener('visibilityChanged', (event: any) => {
if (event.detail.element === 'searchPanel') {
const inputElement = instance.iframeWindow.document.getElementById(
'SearchPanel__input'
) as HTMLInputElement;
setTimeout(() => {
inputElement.value = '';
}, 0);
if (!event.detail.isVisible) {
instance.docViewer.clearSearchResults();
}
}
});
this._loadDocument();
}); });
this.instance.docViewer.on('textSelected', (quads, selectedText) => {
this._selectedText = selectedText;
if (selectedText.length > 2 && this.canPerformActions) {
this.instance.enableElements(['add-dictionary', 'add-false-positive']);
} else {
this.instance.disableElements(['add-dictionary', 'add-false-positive']);
}
});
this.instance.iframeWindow.addEventListener('visibilityChanged', (event: any) => {
if (event.detail.element === 'searchPanel') {
const inputElement = this.instance.iframeWindow.document.getElementById(
'SearchPanel__input'
) as HTMLInputElement;
setTimeout(() => {
inputElement.value = '';
}, 0);
if (!event.detail.isVisible) {
this.instance.docViewer.clearSearchResults();
}
}
});
this._loadDocument();
} }
private _setSelectionMode(): void { private _setSelectionMode(): void {

View File

@ -242,8 +242,7 @@
(closeDocumentInfoView)="viewDocumentInfo = false" (closeDocumentInfoView)="viewDocumentInfo = false"
*ngIf="viewReady && viewDocumentInfo" *ngIf="viewReady && viewDocumentInfo"
[file]="fileData.fileStatus.fileStatus" [file]="fileData.fileStatus.fileStatus"
> ></redaction-document-info>
</redaction-document-info>
<redaction-file-workload <redaction-file-workload
#fileWorkloadComponent #fileWorkloadComponent

View File

@ -222,6 +222,11 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
} }
async ngOnAttach(previousRoute: ActivatedRouteSnapshot) { async ngOnAttach(previousRoute: ActivatedRouteSnapshot) {
if (!this.permissionsService.canOpenFile(this.appStateService.activeFile)) {
await this._router.navigate(['/main/dossiers/' + this.dossierId]);
return;
}
await this.ngOnInit(); await this.ngOnInit();
this._lastPage = previousRoute.queryParams.page; this._lastPage = previousRoute.queryParams.page;
} }
@ -325,7 +330,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
selectPage(pageNumber: number) { selectPage(pageNumber: number) {
this._viewerComponent.navigateToPage(pageNumber); this._viewerComponent.navigateToPage(pageNumber);
this._workloadComponent.scrollAnnotationsToPage(pageNumber, 'always'); this._workloadComponent?.scrollAnnotationsToPage(pageNumber, 'always');
} }
openManualAnnotationDialog($event: ManualRedactionEntryWrapper) { openManualAnnotationDialog($event: ManualRedactionEntryWrapper) {
@ -393,7 +398,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
viewerPageChanged($event: any) { viewerPageChanged($event: any) {
if (typeof $event === 'number') { if (typeof $event === 'number') {
this._scrollViews(); this._scrollViews();
if (!this._workloadComponent.multiSelectActive) { if (!this._workloadComponent?.multiSelectActive) {
this.shouldDeselectAnnotationsOnPageChange = true; this.shouldDeselectAnnotationsOnPageChange = true;
} }
@ -583,9 +588,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
} }
} else { } else {
if (fileDataModel.fileStatus.isError) { if (fileDataModel.fileStatus.isError) {
this._router.navigate([ this._router.navigate(['/main/dossiers/' + this.dossierId]);
'/main/dossiers/' + this.appStateService.activeDossierId
]);
} else { } else {
this.loadingMessage = 'file-preview.reanalyse-file'; this.loadingMessage = 'file-preview.reanalyse-file';
} }
@ -597,8 +600,8 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
@debounce() @debounce()
private _scrollViews() { private _scrollViews() {
this._workloadComponent.scrollQuickNavigation(); this._workloadComponent?.scrollQuickNavigation();
this._workloadComponent.scrollAnnotations(); this._workloadComponent?.scrollAnnotations();
} }
/* Get the documentElement (<html>) to display the page in fullscreen */ /* Get the documentElement (<html>) to display the page in fullscreen */

View File

@ -31,33 +31,27 @@ export class PdfViewerDataService {
} }
loadActiveFileData(): Observable<FileDataModel> { loadActiveFileData(): Observable<FileDataModel> {
const fileObs = this.downloadOriginalFile(this._appStateService.activeFile); const dossierId = this._appStateService.activeDossierId;
const reactionLogObs = this._redactionLogControllerService const fileId = this._appStateService.activeFileId;
.getRedactionLog(
this._appStateService.activeDossierId, const file$ = this.downloadOriginalFile(this._appStateService.activeFile);
this._appStateService.activeFileId const reactionLog$ = this._redactionLogControllerService
) .getRedactionLog(dossierId, fileId)
.pipe(catchError(() => of({}))); .pipe(catchError(() => of({})));
const redactionChangeLogObs = this._redactionLogControllerService const redactionChangeLog$ = this._redactionLogControllerService
.getRedactionChangeLog( .getRedactionChangeLog(dossierId, fileId)
this._appStateService.activeDossierId,
this._appStateService.activeFileId
)
.pipe(catchError(() => of({}))); .pipe(catchError(() => of({})));
const manualRedactionsObs = this._manualRedactionControllerService const manualRedactions$ = this._manualRedactionControllerService
.getManualRedaction( .getManualRedaction(dossierId, fileId)
this._appStateService.activeDossierId,
this._appStateService.activeFileId
)
.pipe(catchError(() => of({}))); .pipe(catchError(() => of({})));
const viewedPagesObs = this.getViewedPagesForActiveFile(); const viewedPages$ = this.getViewedPagesForActiveFile();
return forkJoin([ return forkJoin([
fileObs, file$,
reactionLogObs, reactionLog$,
redactionChangeLogObs, redactionChangeLog$,
manualRedactionsObs, manualRedactions$,
viewedPagesObs viewedPages$
]).pipe(map(data => new FileDataModel(this._appStateService.activeFile, ...data))); ]).pipe(map(data => new FileDataModel(this._appStateService.activeFile, ...data)));
} }