RED-3797 - Improve import redaction dialog

This commit is contained in:
Valentin Mihai 2022-10-22 17:19:14 +03:00
parent d2de11a465
commit 1897264bca
10 changed files with 123 additions and 28 deletions

View File

@ -8,6 +8,7 @@ import { ExcludedPagesService } from '../../services/excluded-pages.service';
import { combineLatest, firstValueFrom, Observable } from 'rxjs';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { map, pluck } from 'rxjs/operators';
import { extractPageRanges } from '@utils/page-ranges-mapper';
@Component({
selector: 'redaction-page-exclusion',
@ -52,21 +53,9 @@ export class PageExclusionComponent {
async excludePagesRange(inputValue: string): Promise<void> {
this._loadingService.start();
const value = inputValue.replace(/[^0-9-,]/g, '');
const file = this._state.file;
try {
const pageRanges = value.split(',').map(range => {
const splitted = range.split('-');
const startPage = parseInt(splitted[0], 10);
const endPage = splitted.length > 1 ? parseInt(splitted[1], 10) : startPage;
if (!startPage || !endPage || startPage > file.numberOfPages || endPage > file.numberOfPages) {
throw new Error();
}
return {
startPage,
endPage,
};
});
const pageRanges = extractPageRanges(inputValue, file);
const excludePages$ = this._reanalysisService.excludePages({ pageRanges }, file.dossierId, file);
await firstValueFrom(excludePages$);
this._inputComponent.reset();

View File

@ -4,10 +4,25 @@
<div class="dialog-content">
<div translate="import-redactions-dialog.details" class="mb-24"></div>
<iqser-upload-file (fileChanged)="fileChanged($event)"></iqser-upload-file>
<div class="only-for-pages">
<mat-checkbox color="primary" [checked]="onlyForSpecificPages" (change)="onlyForSpecificPages = $event.checked">
{{ 'import-redactions-dialog.import-only-for-pages' | translate }}
</mat-checkbox>
<div class="iqser-input-group">
<input
[placeholder]="'import-redactions-dialog.range.placeholder' | translate"
type="text"
[(ngModel)]="rangesValue"
[disabled]="!onlyForSpecificPages"
/>
<label [translate]="'import-redactions-dialog.range.label'"></label>
</div>
</div>
</div>
<div class="dialog-actions">
<button color="primary" mat-flat-button type="submit" (click)="save()" [disabled]="!fileToImport">
<button color="primary" mat-flat-button type="submit" (click)="save()" [disabled]="disabled">
{{ 'import-redactions-dialog.actions.import' | translate }}
</button>
<div class="all-caps-label cancel" mat-dialog-close translate="import-redactions-dialog.actions.cancel"></div>

View File

@ -1,7 +1,4 @@
.only-for-pages {
margin-top: 16px;
margin-left: 21px;
min-height: 34px;
display: flex;
flex-direction: row;
align-items: center;
@ -10,4 +7,11 @@
width: fit-content;
margin-right: 16px;
}
.iqser-input-group {
width: 260px !important;
max-width: 260px !important;
margin-top: 25px;
gap: 10px;
}
}

View File

@ -5,6 +5,8 @@ import { firstValueFrom } from 'rxjs';
import { RedactionImportService } from '@services/files/redaction-import.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { HttpStatusCode } from '@angular/common/http';
import { extractPageRanges } from '@utils/page-ranges-mapper';
import { File } from '@red/domain';
interface ImportData {
dossierId: string;
@ -18,8 +20,10 @@ interface ImportData {
export class ImportRedactionsDialogComponent extends BaseDialogComponent {
@ViewChild('attachFileInput', { static: true }) attachFileInput: ElementRef;
fileToImport: File | null;
fileToImport: Blob | null;
numberOfPages = 0;
onlyForSpecificPages = false;
rangesValue = '';
constructor(
protected readonly _dialogRef: MatDialogRef<ImportRedactionsDialogComponent>,
@ -29,16 +33,60 @@ export class ImportRedactionsDialogComponent extends BaseDialogComponent {
super(_dialogRef);
}
fileChanged(file: File | null) {
fileChanged(file: Blob | null) {
this.fileToImport = file;
if (!this.fileToImport) {
this.onlyForSpecificPages = false;
this.rangesValue = '';
return;
}
this.#extractNumberOfPages(this.fileToImport);
}
#extractNumberOfPages(file: Blob) {
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onloadend = () => {
this.numberOfPages = (reader.result as any).match(/\/Type[\s]*\/Page[^s]/g).length;
};
}
get #pagesToImport(): Set<number> {
const pageRanges = extractPageRanges(this.rangesValue, { numberOfPages: this.numberOfPages } as File);
const pagesToImport = new Set<number>();
pageRanges.forEach(r => {
for (let i = r.startPage; i <= r.endPage; i++) {
pagesToImport.add(i);
}
});
return pagesToImport;
}
get disabled(): boolean {
if (!this.fileToImport) {
return true;
}
if (this.onlyForSpecificPages) {
try {
extractPageRanges(this.rangesValue, { numberOfPages: this.numberOfPages } as File);
} catch (e) {
return true;
}
}
return false;
}
async save(): Promise<void> {
this._loadingService.start();
const import$ = this._redactionImportService.importRedactions(this.data.dossierId, this.data.fileId, this.fileToImport);
const pagesToImport = this.onlyForSpecificPages ? this.#pagesToImport : null;
const import$ = this._redactionImportService.importRedactions(
this.data.dossierId,
this.data.fileId,
this.fileToImport,
pagesToImport,
);
const result: any = await firstValueFrom(import$).catch(error =>
this._toaster.error(_('import-redactions-dialog.http.error'), { error }),
);

View File

@ -309,8 +309,7 @@ export class FileActionsComponent implements OnChanges {
}
private _openImportRedactionsDialog($event: MouseEvent) {
$event.stopPropagation();
this._dialogService.openDialog('importRedactions', null, { dossierId: this.file.dossierId, fileId: this.file.fileId });
this._dialogService.openDialog('importRedactions', $event, { dossierId: this.file.dossierId, fileId: this.file.fileId });
}
private _openDeleteFileDialog($event: MouseEvent) {

View File

@ -6,13 +6,17 @@ export class RedactionImportService extends GenericService<void> {
protected readonly _defaultModelPath = 'import-redactions';
@Validate()
importRedactions(@RequiredParam() dossierId: string, @RequiredParam() fileId: string, file?: Blob) {
importRedactions(@RequiredParam() dossierId: string, @RequiredParam() fileId: string, file: Blob, pagesToImport: Set<number> | null) {
const formParams = new FormData();
if (file !== undefined) {
formParams.append('file', file);
}
if (pagesToImport) {
formParams.append('pageInclusionRequest', Array.from(pagesToImport).toString());
}
const headers = HeadersConfiguration.getHeaders({ contentType: false }).append('ngsw-bypass', 'true');
return this._http.post<void>(`/${this._defaultModelPath}/${dossierId}/${fileId}`, formParams, {

View File

@ -0,0 +1,22 @@
import { File } from '@red/domain';
interface PageRange {
startPage: number;
endPage: number;
}
export function extractPageRanges(inputValue: string, file: File): PageRange[] {
const value = inputValue.replace(/[^0-9-,]/g, '');
return value.split(',').map(range => {
const splitted = range.split('-');
const startPage = parseInt(splitted[0], 10);
const endPage = splitted.length > 1 ? parseInt(splitted[1], 10) : startPage;
if (!startPage || !endPage || startPage > file.numberOfPages || endPage > file.numberOfPages) {
throw new Error();
}
return {
startPage,
endPage,
};
});
}

View File

@ -1557,8 +1557,12 @@
"error": "",
"success": ""
},
"title": "",
"upload-area-text": ""
"import-only-for-pages": "",
"range": {
"label": "",
"placeholder": ""
},
"title": ""
},
"initials-avatar": {
"unassigned": "Unbekannt",
@ -2053,6 +2057,9 @@
"question": "Wählen Sie, wie Sie fortfahren möchten:",
"title": "Das Wörterbuch hat bereits Einträge!"
},
"upload-file": {
"upload-area-text": ""
},
"upload-status": {
"dialog": {
"actions": {

View File

@ -1557,8 +1557,12 @@
"error": "Failed to import redactions! {error}",
"success": "Redactions have been imported!"
},
"title": "Import document with redactions",
"upload-area-text": "Click or drag & drop anywhere on this area..."
"import-only-for-pages": "Import only for pages",
"range": {
"label": "Minus(-) for range and comma(,) for enumeration.",
"placeholder": "e.g. 1-20,22,32"
},
"title": "Import document with redactions"
},
"initials-avatar": {
"unassigned": "Unassigned",
@ -2053,6 +2057,9 @@
"question": "Choose how you want to proceed:",
"title": "The dictionary already has entries!"
},
"upload-file": {
"upload-area-text": "Click or drag & drop anywhere on this area..."
},
"upload-status": {
"dialog": {
"actions": {

@ -1 +1 @@
Subproject commit 401e6a047f6af09e9b737e80df6f86fd18f009d3
Subproject commit 76289b16e002506c80f83697f33ae3118b30ff1a