Pull request #236: RED-1771

Merge in RED/ui from RED-1771 to master

* commit '483bd71c2f4998961bc9b96f2c79ee2d6eb65bdd':
  Stamp excluded pages
  Display page excluded from redaction in workload
This commit is contained in:
Adina Teudan 2021-07-13 17:55:00 +02:00
commit 3616988cf3
18 changed files with 107 additions and 53 deletions

View File

@ -70,8 +70,8 @@ export class WatermarkScreenComponent implements OnInit {
}
@debounce()
configChanged() {
this._drawWatermark();
async configChanged() {
await this._drawWatermark();
}
save() {
@ -111,17 +111,17 @@ export class WatermarkScreenComponent implements OnInit {
);
}
revert() {
async revert() {
this.configForm.setValue({ ...this._watermark });
this.configChanged();
await this.configChanged();
}
triggerChanges() {}
setValue(type: 'fontType' | 'orientation' | 'hexColor', value: any) {
async setValue(type: 'fontType' | 'orientation' | 'hexColor', value: any) {
if (!this.configForm.get(type).disabled) {
this.configForm.get(type).setValue(value);
this.configChanged();
await this.configChanged();
}
}
@ -157,9 +157,9 @@ export class WatermarkScreenComponent implements OnInit {
).then(instance => {
this._instance = instance;
instance.docViewer.on('documentLoaded', () => {
instance.docViewer.on('documentLoaded', async () => {
this.viewReady = true;
this._drawWatermark();
await this._drawWatermark();
});
this._disableElements();

View File

@ -30,6 +30,6 @@ export class DocumentInfoComponent {
}
edit() {
this._dialogService.openDialog('document-info', null, this.file);
this._dialogService.openDialog('documentInfo', null, this.file);
}
}

View File

@ -24,7 +24,7 @@ export class DossierListingActionsComponent {
) {}
openEditDossierDialog($event: MouseEvent, dossierWrapper: DossierWrapper) {
this._dialogService.openDialog('edit-dossier', $event, {
this._dialogService.openDialog('editDossier', $event, {
dossierWrapper,
afterSave: () => {
this.actionPerformed.emit();

View File

@ -27,7 +27,7 @@
>
<div>
<redaction-circle-button
(action)="closeExcludePagesView.emit()"
(action)="actionPerformed.emit('view-exclude-pages')"
icon="red:close"
tooltip="file-preview.tabs.exclude-pages.close"
tooltipPosition="before"
@ -142,13 +142,29 @@
redactionHasScrollbar
tabindex="1"
>
<ng-container *ngIf="!displayedAnnotations[activeViewerPage]">
<ng-container
*ngIf="activeViewerPage && !displayedAnnotations[activeViewerPage]"
>
<redaction-empty-state
[horizontalPadding]="24"
[verticalPadding]="40"
icon="red:document"
screen="file-preview"
></redaction-empty-state>
>
<ng-container
*ngIf="
fileData?.fileStatus?.excludedPages?.includes(activeViewerPage)
"
>
{{ 'file-preview.tabs.annotations.page-is' | translate }}
<a
(click)="actionPerformed.emit('view-exclude-pages')"
translate="file-preview.excluded-from-redaction"
>
</a
>.
</ng-container>
</redaction-empty-state>
<div class="no-annotations-buttons-container mt-32">
<redaction-icon-button
(action)="jumpToPreviousWithAnnotations()"
@ -267,8 +283,8 @@
<ng-template #annotationFilterActionTemplate let-filter="filter">
<redaction-circle-button
*ngIf="filter.key === 'skipped'"
(action)="toggleSkipped.emit($event)"
*ngIf="filter.key === 'skipped'"
[icon]="hideSkipped ? 'red:visibility-off' : 'red:visibility'"
type="dark-bg"
></redaction-circle-button>

View File

@ -50,7 +50,6 @@ export class FileWorkloadComponent {
@Output() selectPage = new EventEmitter<number>();
@Output() toggleSkipped = new EventEmitter<any>();
@Output() annotationsChanged = new EventEmitter<AnnotationWrapper>();
@Output() closeExcludePagesView = new EventEmitter();
@Output() actionPerformed = new EventEmitter<string>();
displayedPages: number[] = [];
pagesPanelActive = true;

View File

@ -9,14 +9,14 @@
type="file"
/>
<div *ngIf="utils.totalPages && utils.currentPage" class="pagination noselect">
<div *ngIf="utils?.totalPages && utils?.currentPage" class="pagination noselect">
<div (click)="utils.previousPage()">
<mat-icon class="chevron-icon" svgIcon="red:nav-prev"></mat-icon>
</div>
<div>
<input
#pageInput
(change)="utils.navigateToPageByInput(pageInput.value)"
(change)="utils.navigateToPage(pageInput.value)"
[max]="utils.totalPages"
[value]="utils.currentPage"
class="page-number-input"

View File

@ -150,8 +150,8 @@ export class PdfViewerComponent implements OnInit, OnChanges {
() => {
this.viewMode = 'COMPARE';
},
(page: number) => {
this.utils.navigateToPage(page);
() => {
this.utils.navigateToPage(1);
},
PDFNet
);

View File

@ -196,7 +196,7 @@ export class DossierListingScreenComponent
this._calculateData();
await this._router.navigate([`/main/dossiers/${addResponse.dossier.dossierId}`]);
if (addResponse.addMembers) {
this._dialogService.openDialog('edit-dossier', null, {
this._dialogService.openDialog('editDossier', null, {
dossierWrapper: addResponse.dossier,
section: 'members'
});

View File

@ -293,14 +293,14 @@ export class DossierOverviewScreenComponent
}
openEditDossierDialog($event: MouseEvent) {
this._dialogService.openDialog('edit-dossier', $event, {
this._dialogService.openDialog('editDossier', $event, {
dossierWrapper: this.activeDossier
});
}
openAssignDossierMembersDialog(): void {
this._dialogService.openDialog(
'edit-dossier',
'editDossier',
null,
{
dossierWrapper: this.activeDossier,

View File

@ -174,7 +174,6 @@
#fileWorkloadComponent
(actionPerformed)="fileActionPerformed($event)"
(annotationsChanged)="annotationsChangedByReviewAction($event)"
(closeExcludePagesView)="excludePages = false"
(deselectAnnotations)="deselectAnnotations($event)"
(selectAnnotations)="selectAnnotations($event)"
(selectPage)="selectPage($event)"

View File

@ -46,6 +46,8 @@ import {
processFilters
} from '@shared/components/filters/popup-filter/utils/filter-utils';
import { LoadingService } from '../../../../services/loading.service';
import { stampPDFPage } from '../../../../utils/page-stamper';
import { TranslateService } from '@ngx-translate/core';
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f'];
@ -96,7 +98,8 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
private readonly _statusControllerService: StatusControllerService,
private readonly _ngZone: NgZone,
private readonly _fileManagementControllerService: FileManagementControllerService,
private readonly _loadingService: LoadingService
private readonly _loadingService: LoadingService,
private readonly _translateService: TranslateService
) {
document.documentElement.addEventListener('fullscreenchange', () => {
if (!document.fullscreenElement) {
@ -361,7 +364,7 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
}
selectPage(pageNumber: number) {
this.viewerComponent.utils.navigateToPageByInput(pageNumber);
this.viewerComponent.utils.navigateToPage(pageNumber);
this._workloadComponent?.scrollAnnotationsToPage(pageNumber, 'always');
}
@ -447,8 +450,9 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
this._changeDetectorRef.detectChanges();
}
viewerReady($event: WebViewerInstance) {
async viewerReady($event: WebViewerInstance) {
this._instance = $event;
await this._stampExcludedPages();
this._cleanupAndRedrawManualAnnotations();
this._updateCanPerformActions();
this.viewReady = true;
@ -570,6 +574,30 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy, OnAttach,
window.open(`/html-debug/${this.dossierId}/${this.fileId}`, '_blank');
}
private async _stampPage(page: number) {
const document = await this._instance.docViewer.getDocument().getPDFDoc();
await stampPDFPage(
document,
this._instance.PDFNet,
this._translateService.instant('file-preview.excluded-from-redaction'),
25,
'courier',
'DIAGONAL',
33,
'#283241',
page
);
}
private async _stampExcludedPages() {
for (const page of this.fileData.fileStatus.excludedPages) {
await this._stampPage(page);
}
this._instance.docViewer.refreshAll();
this._instance.docViewer.updateView([this.activeViewerPage], this.activeViewerPage);
this._changeDetectorRef.detectChanges();
}
private _subscribeToFileUpdates(): void {
this.filesAutoUpdateTimer = timer(0, 5000)
.pipe(tap(async () => await this.appStateService.reloadActiveFile()))

View File

@ -33,7 +33,7 @@ const dialogConfig = {
// TODO: Continue refactor
type DialogType = 'confirm' | 'document-info' | 'edit-dossier';
type DialogType = 'confirm' | 'documentInfo' | 'editDossier';
type DossiersDialogConfig = {
[key in DialogType]: {
@ -48,11 +48,11 @@ export class DossiersDialogService extends DialogService<DialogType> {
confirm: {
component: ConfirmationDialogComponent
},
'document-info': {
documentInfo: {
component: DocumentInfoDialogComponent,
dialogConfig: { autoFocus: true }
},
'edit-dossier': {
editDossier: {
component: EditDossierDialogComponent,
dialogConfig: { ...this._largeConfig, autoFocus: true }
}

View File

@ -38,7 +38,7 @@ export const loadCompareDocumentWrapper = async (
instance,
fileStatus,
setCompareViewMode: () => void,
navigateToPage: (number) => void,
navigateToPage: () => void,
PDFNet
) => {
try {
@ -65,7 +65,7 @@ export const loadCompareDocumentWrapper = async (
instance.disableElements(['compareButton']);
instance.enableElements(['closeCompareButton']);
navigateToPage(1);
navigateToPage();
} catch (e) {
console.error(e);
}

View File

@ -91,28 +91,22 @@ export class PdfViewerUtils {
return this.instance?.docViewer?.getPageCount();
}
navigateToPage(pageNumber) {
const activePage = this.instance.docViewer.getCurrentPage();
if (activePage !== pageNumber) {
this.instance.docViewer.displayPageLocation(pageNumber, 0, 0);
}
}
navigateToPageByInput(pageNumber) {
this.navigateToPage(
this.paginationOffset === 2 ? pageNumber * this.paginationOffset - 1 : pageNumber
navigateToPage(pageNumber: string | number) {
const parsedNumber = typeof pageNumber === 'string' ? parseInt(pageNumber, 10) : pageNumber;
this._navigateToPage(
this.paginationOffset === 2 ? parsedNumber * this.paginationOffset - 1 : parsedNumber
);
}
previousPage() {
if (this._currentInternalPage > 1) {
this.navigateToPage(Math.max(this._currentInternalPage - this.paginationOffset, 1));
this._navigateToPage(Math.max(this._currentInternalPage - this.paginationOffset, 1));
}
}
nextPage() {
if (this._currentInternalPage < this._totalInternalPages) {
this.navigateToPage(
this._navigateToPage(
Math.min(
this._currentInternalPage + this.paginationOffset,
this._totalInternalPages
@ -178,6 +172,13 @@ export class PdfViewerUtils {
this.instance.annotManager.deselectAnnotations(ann);
}
private _navigateToPage(pageNumber) {
const activePage = this.instance.docViewer.getCurrentPage();
if (activePage !== pageNumber) {
this.instance.docViewer.displayPageLocation(pageNumber, 0, 0);
}
}
private _getAnnotationById(id: string): Annotations.Annotation {
return this.instance.annotManager.getAnnotationById(id);
}

View File

@ -7,6 +7,9 @@
class="empty-state"
>
<mat-icon [svgIcon]="icon"></mat-icon>
<div class="ng-content-wrapper heading-l">
<ng-content></ng-content>
</div>
<div [translate]="text || screen + '.' + type + '.title'" class="heading-l"></div>
<redaction-icon-button
(action)="action.emit()"

View File

@ -20,4 +20,8 @@
redaction-icon-button {
margin-top: 24px;
}
.ng-content-wrapper:not(:empty) + .heading-l {
display: none;
}
}

View File

@ -1,30 +1,32 @@
import { hexToRgb } from './functions';
import { environment } from '../../environments/environment';
import { PDFNet } from '@pdftron/webviewer';
import PDFDoc = PDFNet.PDFDoc;
export async function stampPDFPage(
document: any,
PDFNet: any,
document: PDFDoc,
PdfNet: any,
text: string,
fontSize: number,
fontType: string,
orientation: string,
orientation: 'DIAGONAL' | 'HORIZONTAL' | 'VERTICAL',
opacity: number,
color: string,
page: number
) {
await PDFNet.runWithCleanup(
await PdfNet.runWithCleanup(
async () => {
await document.lock();
const pageSet = await PDFNet.PageSet.createSinglePage(page);
const pageSet = await PdfNet.PageSet.createSinglePage(page);
await PDFNet.Stamper.deleteStamps(document, pageSet);
await PdfNet.Stamper.deleteStamps(document, pageSet);
const rgbColor = hexToRgb(color);
const stamper = await PDFNet.Stamper.create(3, fontSize, 0);
const stamper = await PdfNet.Stamper.create(3, fontSize, 0);
await stamper.setFontColor(
await PDFNet.ColorPt.init(rgbColor.r / 255, rgbColor.g / 255, rgbColor.b / 255)
await PdfNet.ColorPt.init(rgbColor.r / 255, rgbColor.g / 255, rgbColor.b / 255)
);
await stamper.setOpacity(opacity / 100);
@ -41,7 +43,7 @@ export async function stampPDFPage(
await stamper.setRotation(-45);
}
const font = await PDFNet.Font.createAndEmbed(document, convertFont(fontType));
const font = await PdfNet.Font.createAndEmbed(document, convertFont(fontType));
await stamper.setFont(font);
await stamper.setTextAlignment(0);
await stamper.stampText(document, text, pageSet);

View File

@ -923,6 +923,7 @@
"document-info": "Your Document Info lives here. This includes metadata required on each document.",
"download-original-file": "Download Original File",
"exclude-pages": "Exclude pages from redaction",
"excluded-from-redaction": "excluded from redaction",
"fullscreen": "Full Screen (F)",
"html-debug": "Open Document HTML Debug",
"last-reviewer": "Last Reviewed by:",
@ -948,7 +949,8 @@
"label": "Workload",
"select": "Select",
"select-all": "All",
"select-none": "None"
"select-none": "None",
"page-is": "This page is"
},
"document-info": {
"close": "Close Document Info",