RED-3797 - Improve import redaction dialog
This commit is contained in:
parent
d2de11a465
commit
1897264bca
@ -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();
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 }),
|
||||
);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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, {
|
||||
|
||||
22
apps/red-ui/src/app/utils/page-ranges-mapper.ts
Normal file
22
apps/red-ui/src/app/utils/page-ranges-mapper.ts
Normal 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,
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -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": {
|
||||
|
||||
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user