use observable file instead of fileData

This commit is contained in:
Dan Percic 2021-11-16 00:08:47 +02:00
parent b50fd15f7f
commit 86f6b4a3be
4 changed files with 86 additions and 74 deletions

View File

@ -26,8 +26,8 @@
</div>
<div class="right-content">
<div *ngIf="isReadOnly" [class.justify-center]="!isProcessing" class="read-only d-flex">
<div *ngIf="isProcessing" class="flex-align-items-center">
<div *ngIf="isReadOnly" [class.justify-center]="!file.isProcessing" class="read-only d-flex">
<div *ngIf="file.isProcessing" class="flex-align-items-center">
<span [translate]="'file-status.processing'" class="read-only-text"></span>
<mat-progress-bar [mode]="'indeterminate'" class="w-100"></mat-progress-bar>
</div>
@ -87,15 +87,15 @@
*ngFor="let pageNumber of displayedPages"
[activeSelection]="pageHasSelection(pageNumber)"
[active]="pageNumber === activeViewerPage"
[file]="fileData?.file"
[file]="file"
[number]="pageNumber"
[showDottedIcon]="hasOnlyManualRedactionsAndNotExcluded(pageNumber)"
[viewedPages]="fileData?.viewedPages"
[viewedPages]="viewedPages"
></redaction-page-indicator>
</div>
<div
(click)="scrollQuickNavLast()"
[class.disabled]="activeViewerPage === fileData?.file?.numberOfPages"
[class.disabled]="activeViewerPage === file?.numberOfPages"
[matTooltip]="'file-preview.quick-nav.jump-last' | translate"
class="jump"
matTooltipPosition="above"
@ -195,7 +195,7 @@
<redaction-page-exclusion
(actionPerformed)="actionPerformed.emit($event)"
*ngIf="excludePages"
[file]="fileData.file"
[file]="file"
></redaction-page-exclusion>
</div>
</div>

View File

@ -1,14 +1,25 @@
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, HostListener, Input, Output, TemplateRef, ViewChild } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
HostListener,
Input,
Output,
TemplateRef,
ViewChild,
} from '@angular/core';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { AnnotationProcessingService } from '../../services/annotation-processing.service';
import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
import scrollIntoView from 'scroll-into-view-if-needed';
import { CircleButtonTypes, Debounce, FilterService, IconButtonTypes, INestedFilter, IqserEventTarget } from '@iqser/common-ui';
import { FileDataModel } from '@models/file/file-data.model';
import { PermissionsService } from '@services/permissions.service';
import { WebViewerInstance } from '@pdftron/webviewer';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { File, IViewedPage } from '@red/domain';
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
@ -17,6 +28,7 @@ const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
selector: 'redaction-file-workload',
templateUrl: './file-workload.component.html',
styleUrls: ['./file-workload.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FileWorkloadComponent {
readonly iconButtonTypes = IconButtonTypes;
@ -27,7 +39,8 @@ export class FileWorkloadComponent {
@Input() activeViewerPage: number;
@Input() shouldDeselectAnnotationsOnPageChange: boolean;
@Input() dialogRef: MatDialogRef<unknown>;
@Input() fileData: FileDataModel;
@Input() viewedPages: IViewedPage[];
@Input() file: File;
@Input() hideSkipped: boolean;
@Input() excludePages: boolean;
@Input() annotationActionsTemplate: TemplateRef<unknown>;
@ -78,20 +91,16 @@ export class FileWorkloadComponent {
}
}
get isProcessing(): boolean {
return this.fileData?.file?.isProcessing;
}
get activeAnnotations(): AnnotationWrapper[] | undefined {
return this.displayedAnnotations.get(this.activeViewerPage);
}
get isReadOnly(): boolean {
return !this._permissionsService.canPerformAnnotationActions(this.fileData?.file);
return !this._permissionsService.canPerformAnnotationActions(this.file);
}
get currentPageIsExcluded(): boolean {
return this.fileData?.file?.excludedPages?.includes(this.activeViewerPage);
return this.file?.excludedPages?.includes(this.activeViewerPage);
}
private get _firstSelectedAnnotation() {
@ -120,7 +129,7 @@ export class FileWorkloadComponent {
hasOnlyManualRedactionsAndNotExcluded(pageNumber: number): boolean {
const hasOnlyManualRedactions = this.displayedAnnotations.get(pageNumber).every(annotation => annotation.manual);
return hasOnlyManualRedactions && this.fileData.file.excludedPages.includes(pageNumber);
return hasOnlyManualRedactions && this.file.excludedPages.includes(pageNumber);
}
pageHasSelection(page: number) {
@ -171,7 +180,7 @@ export class FileWorkloadComponent {
this._navigatePages($event);
}
this._changeDetectorRef.detectChanges();
this._changeDetectorRef.markForCheck();
}
scrollAnnotations(): void {
@ -212,7 +221,7 @@ export class FileWorkloadComponent {
}
scrollQuickNavLast(): void {
this.selectPage.emit(this.fileData.file.numberOfPages);
this.selectPage.emit(this.file.numberOfPages);
}
pageSelectedByClick($event: number): void {

View File

@ -19,9 +19,9 @@
{{ 'file-preview.delta' | translate }}
</div>
<div
(click)="canSwitchToRedactedView && switchView('REDACTED')"
(click)="canSwitchToRedactedView(file) && switchView('REDACTED')"
[class.active]="viewMode === 'REDACTED'"
[class.disabled]="!canSwitchToRedactedView"
[class.disabled]="!canSwitchToRedactedView(file)"
[matTooltip]="'file-preview.redacted-tooltip' | translate"
class="red-tab"
>
@ -32,11 +32,11 @@
<div *ngIf="dossier$ | async as dossier" class="flex-1 actions-container">
<ng-container *ngIf="!file.excluded">
<ng-container *ngIf="!file.isProcessing">
<iqser-status-bar [configs]="statusBarConfig" [small]="true"></iqser-status-bar>
<iqser-status-bar [configs]="statusBarConfig(file)" [small]="true"></iqser-status-bar>
<div class="all-caps-label mr-16 ml-8">
{{ translations[file.workflowStatus] | translate }}
<span *ngIf="isUnderReviewOrApproval">{{ 'by' | translate }}:</span>
<span *ngIf="isUnderReviewOrApproval(file)">{{ 'by' | translate }}:</span>
</div>
</ng-container>
@ -48,7 +48,7 @@
></redaction-initials-avatar>
<div
(click)="editingReviewer = true"
*ngIf="!editingReviewer && canAssignReviewer(dossier)"
*ngIf="!editingReviewer && canAssignReviewer(file, dossier)"
class="assign-reviewer pointer"
translate="file-preview.assign-reviewer"
></div>
@ -56,9 +56,9 @@
<redaction-assign-user-dropdown
(cancel)="editingReviewer = false"
(save)="assignReviewer($event)"
(save)="assignReviewer(file, $event)"
*ngIf="editingReviewer"
[options]="singleUsersSelectOptions(dossier)"
[options]="usersOptions(file, dossier)"
[value]="file.currentReviewer"
></redaction-assign-user-dropdown>
@ -66,13 +66,13 @@
<iqser-circle-button
(action)="editingReviewer = true"
*ngIf="(permissionsService.canAssignUser(file) || permissionsService.canUnassignUser(file)) && !!file.currentReviewer"
[tooltip]="assignTooltip"
[tooltip]="assignTooltip(file)"
icon="iqser:edit"
tooltipPosition="below"
></iqser-circle-button>
<iqser-circle-button
(action)="assignToMe()"
(action)="assignToMe(file)"
*ngIf="permissionsService.canAssignToSelf(file)"
[tooltip]="'file-preview.assign-me' | translate"
icon="red:assign-me"
@ -106,7 +106,7 @@
<!-- Dev Mode Features-->
<iqser-circle-button
(action)="downloadOriginalFile()"
(action)="downloadOriginalFile(file)"
*ngIf="userPreferenceService.areDevFeaturesEnabled"
[tooltip]="'file-preview.download-original-file' | translate"
[type]="circleButtonTypes.primary"
@ -178,9 +178,10 @@
[annotations]="annotations"
[dialogRef]="dialogRef"
[excludePages]="excludePages"
[fileData]="fileData"
[file]="file"
[hideSkipped]="hideSkipped"
[selectedAnnotations]="selectedAnnotations"
[viewedPages]="fileData?.viewedPages"
[viewer]="activeViewer"
></redaction-file-workload>
</div>

View File

@ -86,7 +86,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
readonly dossier$: Observable<Dossier>;
readonly file$: Observable<File>;
readonly fileId: string;
file: File;
private _instance: WebViewerInstance;
private _lastPage: string;
private _reloadFileOnReanalysis = false;
@ -126,7 +125,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this.dossierId = _activatedRoute.snapshot.paramMap.get('dossierId');
this.dossier$ = this._dossiersService.getEntityChanged$(this.dossierId);
this.fileId = _activatedRoute.snapshot.paramMap.get('fileId');
this.file = _filesMapService.get(this.dossierId, this.fileId);
this.file$ = _filesMapService.watch$(this.dossierId, this.fileId);
document.documentElement.addEventListener('fullscreenchange', () => {
if (!document.fullscreenElement) {
@ -135,12 +133,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
});
}
get assignTooltip(): string {
return this.file.isUnderApproval
? this._translateService.instant('dossier-overview.assign-approver')
: this.assignOrChangeReviewerTooltip;
}
get annotations(): AnnotationWrapper[] {
return this.annotationData ? this.annotationData.visibleAnnotations : [];
}
@ -161,10 +153,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
: (currentPage + 1) / 2;
}
get canSwitchToRedactedView(): boolean {
return this.fileData && !this.fileData.file.analysisRequired && !this.fileData.file.excluded;
}
get canSwitchToDeltaView(): boolean {
return this.fileData?.hasChangeLog;
}
@ -177,18 +165,28 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
return !!this._workloadComponent?.multiSelectActive;
}
get assignOrChangeReviewerTooltip(): string {
return this.file.currentReviewer
assignTooltip(file: File): string {
return file.isUnderApproval
? this._translateService.instant('dossier-overview.assign-approver')
: this.assignOrChangeReviewerTooltip(file);
}
canSwitchToRedactedView(file: File): boolean {
return this.fileData && !file.analysisRequired && !file.excluded;
}
assignOrChangeReviewerTooltip(file: File): string {
return file.currentReviewer
? this._translateService.instant('file-preview.change-reviewer')
: this._translateService.instant('file-preview.assign-reviewer');
}
get statusBarConfig(): [{ length: number; color: WorkflowFileStatus }] {
return [{ length: 1, color: this.file.workflowStatus }];
statusBarConfig(file: File): [{ length: number; color: WorkflowFileStatus }] {
return [{ length: 1, color: file.workflowStatus }];
}
get isUnderReviewOrApproval(): boolean {
return this.file.isUnderReview || this.file.isUnderApproval;
isUnderReviewOrApproval(file: File): boolean {
return file.isUnderReview || file.isUnderApproval;
}
canAssign(file: File): boolean {
@ -200,13 +198,13 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
);
}
singleUsersSelectOptions(dossier: Dossier): List {
const unassignUser = this.permissionsService.canUnassignUser(this.file) ? [undefined] : [];
return this.file?.isUnderApproval ? [...dossier.approverIds, ...unassignUser] : [...dossier.memberIds, ...unassignUser];
usersOptions(file: File, dossier: Dossier): List {
const unassignUser = this.permissionsService.canUnassignUser(file) ? [undefined] : [];
return file.isUnderApproval ? [...dossier.approverIds, ...unassignUser] : [...dossier.memberIds, ...unassignUser];
}
canAssignReviewer(dossier: Dossier): boolean {
return !this.file.currentReviewer && this.permissionsService.canAssignUser(this.file) && dossier.hasReviewers;
canAssignReviewer(file: File, dossier: Dossier): boolean {
return !file.currentReviewer && this.permissionsService.canAssignUser(file) && dossier.hasReviewers;
}
updateViewMode(): void {
@ -250,7 +248,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
async ngOnAttach(previousRoute: ActivatedRouteSnapshot): Promise<boolean> {
if (!this.file.canBeOpened) {
const file = this._filesMapService.get(this.dossierId, this.fileId);
if (!file.canBeOpened) {
return this._router.navigate([this.dossiersService.find(this.dossierId)?.routerLink]);
}
@ -264,7 +263,8 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._updateCanPerformActions();
this._subscribeToFileUpdates();
if (this.fileData?.file?.analysisRequired) {
const file = this._filesMapService.get(this.dossierId, this.fileId);
if (file?.analysisRequired) {
this.fileActions.reanalyseFile();
}
}
@ -358,7 +358,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
response.manualRedactionEntryWrapper.rectId,
);
this._instance.Core.annotationManager.deleteAnnotation(annotation);
this.fileData.file = await this.appStateService.reloadFile(this.dossierId, this.fileId);
await this.appStateService.reloadFile(this.dossierId, this.fileId);
const distinctPages = entryWrapper.manualRedactionEntry.positions
.map(p => p.page)
.filter((item, pos, self) => self.indexOf(item) === pos);
@ -497,18 +497,18 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
}
async assignToMe() {
await this._fileActionService.assignToMe([this.fileData.file], async () => {
async assignToMe(file: File) {
await this._fileActionService.assignToMe([file], async () => {
await this.appStateService.reloadFile(this.dossierId, this.fileId);
this._updateCanPerformActions();
});
}
async assignReviewer(user: User | string) {
async assignReviewer(file: File, user: User | string) {
const reviewerId = typeof user === 'string' ? user : user?.id;
const reviewerName = this.userService.getNameForId(reviewerId);
const { dossierId, fileId, filename } = this.fileData.file;
const { dossierId, fileId, filename } = file;
await this._filesService.setReviewerFor([fileId], dossierId, reviewerId).toPromise();
this._toaster.info(_('assignment.reviewer'), { params: { reviewerName, filename } });
@ -529,11 +529,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this._scrollViews();
}
async downloadOriginalFile() {
async downloadOriginalFile(file: File) {
const data = await this._fileManagementService
.downloadOriginalFile(this.fileData.file.dossierId, this.fileId, 'response', true, this.fileData.file.cacheIdentifier)
.downloadOriginalFile(this.dossierId, this.fileId, 'response', true, file.cacheIdentifier)
.toPromise();
download(data, this.fileData.file.filename);
download(data, file.filename);
}
toggleSkipped($event) {
@ -555,14 +555,15 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
});
}
private async _doStampExcludedPages(excludedPages: number[]) {
private async _doStampExcludedPages() {
const pdfNet = this._instance.Core.PDFNet;
const document = await this._instance.Core.documentViewer.getDocument().getPDFDoc();
const allPages = [...Array(this.fileData.file.numberOfPages).keys()].map(page => page + 1);
const file = this._filesMapService.get(this.dossierId, this.fileId);
const allPages = [...Array(file.numberOfPages).keys()].map(page => page + 1);
await clearStamps(document, pdfNet, allPages);
if (excludedPages && excludedPages.length > 0) {
this.viewerComponent.utils.excludedPages = excludedPages;
if (file.excludedPages && file.excludedPages.length > 0) {
this.viewerComponent.utils.excludedPages = file.excludedPages;
await stampPDFPage(
document,
pdfNet,
@ -572,13 +573,13 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
'DIAGONAL',
33,
'#283241',
excludedPages,
file.excludedPages,
);
}
}
private async _stampExcludedPages() {
await this._doStampExcludedPages(this.fileData.file.excludedPages);
await this._doStampExcludedPages();
this._instance.Core.documentViewer.refreshAll();
this._instance.Core.documentViewer.updateView([this.activeViewerPage], this.activeViewerPage);
this._changeDetectorRef.markForCheck();
@ -600,20 +601,21 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
private _updateCanPerformActions() {
const file = this._filesMapService.get(this.dossierId, this.fileId);
this.canPerformAnnotationActions =
this.permissionsService.canPerformAnnotationActions(this.file) &&
this.permissionsService.canPerformAnnotationActions(file) &&
this.viewMode === 'STANDARD' &&
!this.viewerComponent?.utils.isCompareMode;
}
private async _loadFileData(performUpdate = false): Promise<void> {
const fileData = await this._fileDownloadService.loadDataFor(this.file).toPromise();
const file = this._filesMapService.get(this.dossierId, this.fileId);
const fileData = await this._fileDownloadService.loadDataFor(file).toPromise();
if (!fileData.file?.isPending && !fileData.file?.isError) {
if (!file?.isPending && !file?.isError) {
if (performUpdate) {
this.fileData.redactionLog = fileData.redactionLog;
this.fileData.viewedPages = fileData.viewedPages;
this.fileData.file = fileData.file;
this.rebuildFilters(true);
} else {
this.fileData = fileData;
@ -623,7 +625,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
return;
}
if (fileData.file.isError) {
if (file.isError) {
await this._router.navigate([this.dossiersService.find(this.dossierId).routerLink]);
}
}
@ -647,7 +649,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
const currentPageAnnotations = this.annotations.filter(a => a.pageNumber === page);
const currentPageAnnotationIds = currentPageAnnotations.map(a => a.id);
this.fileData.file = await this.appStateService.reloadFile(this.dossierId, this.fileId);
await this.appStateService.reloadFile(this.dossierId, this.fileId);
this.fileData.redactionLog = await this._fileDownloadService.loadRedactionLogFor(this.dossierId, this.fileId).toPromise();
this.rebuildFilters();