RED-3800 rss editing
This commit is contained in:
commit
4555f596bb
@ -149,9 +149,8 @@ export class ReportsScreenComponent implements OnInit {
|
||||
}
|
||||
|
||||
private async _loadReportTemplates() {
|
||||
this.availableTemplates$.next(
|
||||
await firstValueFrom(this._reportTemplateService.getAvailableReportTemplates(this.#dossierTemplateId)),
|
||||
);
|
||||
const reportTemplates = await this._reportTemplateService.getAvailableReportTemplates(this.#dossierTemplateId);
|
||||
this.availableTemplates$.next(reportTemplates);
|
||||
}
|
||||
|
||||
private async _loadPlaceholders() {
|
||||
|
||||
@ -214,18 +214,19 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnDestroy
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event.key === 'ArrowLeft') {
|
||||
if (!$event.metaKey && !$event.ctrlKey && $event.key === 'ArrowLeft') {
|
||||
this.pagesPanelActive = true;
|
||||
this._changeDetectorRef.markForCheck();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event.key === 'ArrowRight') {
|
||||
if (!$event.metaKey && !$event.ctrlKey && $event.key === 'ArrowRight') {
|
||||
this.pagesPanelActive = false;
|
||||
// if we activated annotationsPanel -
|
||||
// select first annotation from this page in case there is no
|
||||
// selected annotation on this page and not in multi select mode
|
||||
if (!this.pagesPanelActive && !this.multiSelectService.isActive) {
|
||||
this._documentViewer.clearSelection();
|
||||
this._selectFirstAnnotationOnCurrentPageIfNecessary();
|
||||
}
|
||||
this._changeDetectorRef.markForCheck();
|
||||
|
||||
@ -1,57 +1,72 @@
|
||||
<section class="dialog">
|
||||
<div translate="rss-dialog.title" class="dialog-header heading-l"></div>
|
||||
<div class="dialog-header heading-l" translate="rss-dialog.title"></div>
|
||||
|
||||
<hr />
|
||||
<div class="dialog-content">
|
||||
<div class="table output-data" *ngIf="rssData$ | async as rssEntry">
|
||||
<div *ngIf="rssData$ | async as rssEntry" class="table output-data">
|
||||
<div class="table-header">Component</div>
|
||||
<div class="table-header">Value</div>
|
||||
<div class="table-header">Transformation</div>
|
||||
<div class="table-header">Annotations</div>
|
||||
<div class="table-header">
|
||||
Annotations
|
||||
<hr />
|
||||
<div class="annotation-grid">
|
||||
<div>Type</div>
|
||||
<div>Rule</div>
|
||||
<div>Pages</div>
|
||||
<div>Reason</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngFor="let entry of rssEntry.result | keyvalue: originalOrder">
|
||||
<div class="bold">{{ entry.key }}</div>
|
||||
<div>
|
||||
<div class="value-content">
|
||||
<iqser-editable-input
|
||||
(save)="saveEdit($event, entry.value.originalKey)"
|
||||
[buttonsType]="iconButtonTypes.dark"
|
||||
[cancelTooltip]="'rss-dialog.actions.cancel-edit-name' | translate"
|
||||
[class]="'w-200'"
|
||||
[editTooltip]="'rss-dialog.actions.edit-name' | translate"
|
||||
[saveTooltip]="'rss-dialog.actions.save-name' | translate"
|
||||
[value]="entry.value.value ?? entry.value.originalValue"
|
||||
></iqser-editable-input>
|
||||
|
||||
<div class="actions">
|
||||
<iqser-editable-input
|
||||
(save)="saveEdit($event, entry)"
|
||||
[buttonsType]="iconButtonTypes.dark"
|
||||
[cancelTooltip]="'rss-dialog.actions.cancel-edit' | translate"
|
||||
[editTooltip]="'rss-dialog.actions.edit' | translate"
|
||||
[saveTooltip]="'rss-dialog.actions.save' | translate"
|
||||
[value]="entry.value.value ?? entry.value.originalValue"
|
||||
>
|
||||
<ng-container slot="editing">
|
||||
<iqser-circle-button
|
||||
(action)="undo()"
|
||||
icon="red:undo"
|
||||
[showDot]="false"
|
||||
(action)="undo(entry)"
|
||||
*ngIf="entry.value.value"
|
||||
[showDot]="true"
|
||||
[tooltip]="'rss-dialog.actions.undo' | translate"
|
||||
[type]="iconButtonTypes.dark"
|
||||
class="ml-2"
|
||||
icon="red:undo"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</iqser-editable-input>
|
||||
</div>
|
||||
<div>{{ entry.value.transformation }}</div>
|
||||
<div>{{ entry.value.scmAnnotations | json }}</div>
|
||||
<div class="annotation-grid">
|
||||
<ng-container *ngFor="let annotation of entry.value.scmAnnotations">
|
||||
<div>{{ annotation.type }}</div>
|
||||
<div>{{ annotation.ruleNumber }}</div>
|
||||
<div>{{ annotation.pages.join(',') }}</div>
|
||||
<div>{{ annotation.reason }}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button color="primary" mat-flat-button type="submit" (click)="exportJSON()">
|
||||
<button (click)="exportJSON()" color="primary" mat-flat-button type="submit">
|
||||
{{ 'rss-dialog.actions.export-json' | translate }}
|
||||
</button>
|
||||
<button color="primary" mat-flat-button type="button" (click)="exportXML()">
|
||||
<button (click)="exportXML()" color="primary" mat-flat-button type="button">
|
||||
{{ 'rss-dialog.actions.export-xml' | translate }}
|
||||
</button>
|
||||
<button color="primary" mat-flat-button type="button" (click)="exportAllInDossier()" *ngIf="userPreferences.areDevFeaturesEnabled">
|
||||
<button (click)="exportAllInDossier()" *ngIf="userPreferences.areDevFeaturesEnabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'Export All' }}
|
||||
</button>
|
||||
<div class="all-caps-label cancel" mat-dialog-close translate="rss-dialog.actions.close"></div>
|
||||
</div>
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" (action)="close()"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
|
||||
@ -47,3 +47,8 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.annotation-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 3fr 1fr 1fr 5fr;
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { BaseDialogComponent, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { RssService } from '@services/files/rss.service';
|
||||
import { IFile, IRssEntry } from '@red/domain';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { BehaviorSubject, firstValueFrom } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { FilesMapService } from '@services/files/files-map.service';
|
||||
import { UserPreferenceService } from '@users/user-preference.service';
|
||||
@ -17,12 +17,10 @@ interface RssData {
|
||||
templateUrl: './rss-dialog.component.html',
|
||||
styleUrls: ['./rss-dialog.component.scss'],
|
||||
})
|
||||
export class RssDialogComponent extends BaseDialogComponent {
|
||||
export class RssDialogComponent extends BaseDialogComponent implements OnInit {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
rssData$: Observable<IRssEntry>;
|
||||
|
||||
originalOrder = (a: KeyValue<string, any>, b: KeyValue<string, any>): number => 0;
|
||||
rssData$ = new BehaviorSubject<IRssEntry>(null);
|
||||
|
||||
constructor(
|
||||
protected readonly _dialogRef: MatDialogRef<RssDialogComponent>,
|
||||
@ -32,22 +30,14 @@ export class RssDialogComponent extends BaseDialogComponent {
|
||||
@Inject(MAT_DIALOG_DATA) readonly data: RssData,
|
||||
) {
|
||||
super(_dialogRef);
|
||||
this.rssData$ = this._rssService.getRSSData(this.data.file.dossierId, this.data.file.fileId).pipe(
|
||||
map(entry => {
|
||||
const mapped = {};
|
||||
for (const key of Object.keys(entry.result)) {
|
||||
const newKey = key.replace(new RegExp('_', 'g'), ' ');
|
||||
(<any>entry.result[key]).originalKey = key;
|
||||
mapped[newKey] = entry.result[key];
|
||||
}
|
||||
return {
|
||||
filaName: entry.filaName,
|
||||
result: mapped,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.#loadData();
|
||||
}
|
||||
|
||||
originalOrder = (a: KeyValue<string, any>, b: KeyValue<string, any>): number => 0;
|
||||
|
||||
exportJSON() {
|
||||
this._rssService.exportJSON(this.data.file.dossierId, this.data.file.fileId, this.data.file.filename).subscribe();
|
||||
}
|
||||
@ -68,14 +58,39 @@ export class RssDialogComponent extends BaseDialogComponent {
|
||||
this.exportJSON();
|
||||
}
|
||||
|
||||
undo() {
|
||||
console.log('Undo');
|
||||
async undo(entry: KeyValue<string, any>) {
|
||||
this._loadingService.start();
|
||||
await firstValueFrom(this._rssService.revertOverride(this.data.file.dossierId, this.data.file.fileId, [entry.value.originalKey]));
|
||||
await this.#loadData();
|
||||
}
|
||||
|
||||
saveEdit(event: string, originalKey: string) {
|
||||
console.log(event, originalKey);
|
||||
/**
|
||||
* https://qa2.iqser.cloud/redaction-gateway-v1/swagger-ui/index.html#/rss-controller/revertOverrides
|
||||
*/
|
||||
async saveEdit(event: string, entry: KeyValue<string, any>) {
|
||||
this._loadingService.start();
|
||||
await firstValueFrom(
|
||||
this._rssService.override(this.data.file.dossierId, this.data.file.fileId, { [entry.value.originalKey]: event }),
|
||||
);
|
||||
await this.#loadData();
|
||||
}
|
||||
|
||||
async #loadData(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
const rssData = await firstValueFrom(
|
||||
this._rssService.getRSSData(this.data.file.dossierId, this.data.file.fileId).pipe(
|
||||
map(entry => {
|
||||
const mapped = {};
|
||||
for (const key of Object.keys(entry.result)) {
|
||||
const newKey = key.replace(new RegExp('_', 'g'), ' ');
|
||||
(<any>entry.result[key]).originalKey = key;
|
||||
mapped[newKey] = entry.result[key];
|
||||
}
|
||||
return {
|
||||
filaName: entry.filaName,
|
||||
result: mapped,
|
||||
};
|
||||
}),
|
||||
),
|
||||
);
|
||||
this.rssData$.next(rssData);
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import {
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, ActivatedRouteSnapshot, NavigationExtras, Router } from '@angular/router';
|
||||
import { Core } from '@pdftron/webviewer';
|
||||
import {
|
||||
AutoUnsubscribe,
|
||||
bool,
|
||||
@ -26,7 +25,6 @@ import {
|
||||
HelpModeService,
|
||||
List,
|
||||
LoadingService,
|
||||
log,
|
||||
NestedFilter,
|
||||
OnAttach,
|
||||
OnDetach,
|
||||
@ -73,7 +71,6 @@ import { ConfigService } from '@services/config.service';
|
||||
import { ReadableRedactionsService } from '../pdf-viewer/services/readable-redactions.service';
|
||||
import { ROLES } from '@users/roles';
|
||||
import { SuggestionsService } from './services/suggestions.service';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
|
||||
const textActions = [TextPopups.ADD_DICTIONARY, TextPopups.ADD_FALSE_POSITIVE];
|
||||
|
||||
@ -92,10 +89,7 @@ export class FilePreviewScreenComponent
|
||||
fullScreen = false;
|
||||
readonly fileId = this.state.fileId;
|
||||
readonly dossierId = this.state.dossierId;
|
||||
readonly file$ = this.state.file$.pipe(
|
||||
tap(file => this._fileDataService.loadAnnotations(file)),
|
||||
log('file'),
|
||||
);
|
||||
readonly file$ = this.state.file$.pipe(tap(file => this._fileDataService.loadAnnotations(file)));
|
||||
width: number;
|
||||
@ViewChild('annotationFilterTemplate', {
|
||||
read: TemplateRef,
|
||||
@ -180,6 +174,7 @@ export class FilePreviewScreenComponent
|
||||
const earmarks$ = isEarmarksViewMode$.pipe(
|
||||
tap(() => this._loadingService.start()),
|
||||
switchMap(() => this._fileDataService.loadEarmarks()),
|
||||
switchMap(() => this._fileDataService.earmarks$),
|
||||
tap(() => this.updateViewMode().then(() => this._loadingService.stop())),
|
||||
);
|
||||
|
||||
@ -223,7 +218,7 @@ export class FilePreviewScreenComponent
|
||||
|
||||
switch (this._viewModeService.viewMode) {
|
||||
case ViewModes.STANDARD: {
|
||||
this._setAnnotationsColor(redactions, 'annotationColor');
|
||||
this._readableRedactionsService.setAnnotationsColor(redactions, 'annotationColor');
|
||||
const wrappers = await this._fileDataService.annotations;
|
||||
const ocrAnnotationIds = wrappers.filter(a => a.isOCR).map(a => a.id);
|
||||
const standardEntries = annotations
|
||||
@ -232,7 +227,7 @@ export class FilePreviewScreenComponent
|
||||
const nonStandardEntries = annotations.filter(
|
||||
a => bool(a.getCustomData('changeLogRemoved')) || this._annotationManager.isHidden(a.Id),
|
||||
);
|
||||
this._setAnnotationsOpacity(standardEntries, true);
|
||||
this._readableRedactionsService.setAnnotationsOpacity(standardEntries, true);
|
||||
this._annotationManager.show(standardEntries);
|
||||
this._annotationManager.hide(nonStandardEntries);
|
||||
break;
|
||||
@ -240,8 +235,8 @@ export class FilePreviewScreenComponent
|
||||
case ViewModes.DELTA: {
|
||||
const changeLogEntries = annotations.filter(a => bool(a.getCustomData('changeLog')));
|
||||
const nonChangeLogEntries = annotations.filter(a => !bool(a.getCustomData('changeLog')));
|
||||
this._setAnnotationsColor(redactions, 'annotationColor');
|
||||
this._setAnnotationsOpacity(changeLogEntries, true);
|
||||
this._readableRedactionsService.setAnnotationsColor(redactions, 'annotationColor');
|
||||
this._readableRedactionsService.setAnnotationsOpacity(changeLogEntries, true);
|
||||
this._annotationManager.show(changeLogEntries);
|
||||
this._annotationManager.hide(nonChangeLogEntries);
|
||||
break;
|
||||
@ -250,14 +245,8 @@ export class FilePreviewScreenComponent
|
||||
const nonRedactionEntries = annotations.filter(
|
||||
a => !bool(a.getCustomData('redaction')) || bool(a.getCustomData('changeLogRemoved')),
|
||||
);
|
||||
if (this._readableRedactionsService.active) {
|
||||
this._setAnnotationsOpacity(redactions, true);
|
||||
this._setAnnotationsColor(redactions, 'annotationColor');
|
||||
} else {
|
||||
this._setAnnotationsOpacity(redactions);
|
||||
this._setAnnotationsColor(redactions, 'redactionColor');
|
||||
}
|
||||
|
||||
this._readableRedactionsService.setPreviewAnnotationsOpacity(redactions);
|
||||
this._readableRedactionsService.setPreviewAnnotationsColor(redactions);
|
||||
this._annotationManager.show(redactions);
|
||||
this._annotationManager.hide(nonRedactionEntries);
|
||||
this._suggestionsService.hideSuggestionsInPreview(redactions);
|
||||
@ -762,20 +751,6 @@ export class FilePreviewScreenComponent
|
||||
}
|
||||
}
|
||||
|
||||
private _setAnnotationsOpacity(annotations: Annotation[], restoreToOriginal = false) {
|
||||
annotations.forEach(annotation => {
|
||||
annotation['Opacity'] = restoreToOriginal ? parseFloat(annotation.getCustomData('opacity')) : 1;
|
||||
});
|
||||
}
|
||||
|
||||
private _setAnnotationsColor(annotations: Annotation[], customData: string) {
|
||||
annotations.forEach(annotation => {
|
||||
const color = this._annotationDrawService.convertColor(annotation.getCustomData(customData));
|
||||
annotation['StrokeColor'] = color;
|
||||
annotation['FillColor'] = color;
|
||||
});
|
||||
}
|
||||
|
||||
private _navigateToDossier() {
|
||||
this._logger.info('Navigating to ', this.state.dossier.dossierName);
|
||||
return this._router.navigate([this.state.dossier.routerLink]);
|
||||
|
||||
@ -181,9 +181,10 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
async #buildRemovedRedactions(redactionLog: IRedactionLog, file: File): Promise<void> {
|
||||
const redactionLogCopy = JSON.parse(JSON.stringify(redactionLog));
|
||||
redactionLogCopy.redactionLogEntry = redactionLogCopy.redactionLogEntry.reduce((filtered, entry) => {
|
||||
const isRemoveChange = entry.manualChanges.find(c => this.#isRemoveChange(c.manualRedactionType));
|
||||
const lastChange = entry.manualChanges.at(-1);
|
||||
const isRemoveChange = this.#isRemoveChange(lastChange?.manualRedactionType);
|
||||
if (isRemoveChange) {
|
||||
entry.manualChanges = entry.manualChanges.filter(c => !this.#isRemoveChange(c.manualRedactionType));
|
||||
entry.manualChanges.pop();
|
||||
filtered.push(entry);
|
||||
}
|
||||
return filtered;
|
||||
|
||||
@ -6,6 +6,7 @@ import Annotation = Core.Annotations.Annotation;
|
||||
import { REDAnnotationManager } from '../../pdf-viewer/services/annotation-manager.service';
|
||||
import { UserPreferenceService } from '@users/user-preference.service';
|
||||
import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service';
|
||||
import { ReadableRedactionsService } from '../../pdf-viewer/services/readable-redactions.service';
|
||||
|
||||
@Injectable()
|
||||
export class SuggestionsService {
|
||||
@ -15,6 +16,7 @@ export class SuggestionsService {
|
||||
private readonly _annotationManager: REDAnnotationManager,
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
private readonly _annotationDrawService: AnnotationDrawService,
|
||||
private readonly _readableRedactionsService: ReadableRedactionsService,
|
||||
) {}
|
||||
|
||||
set removedRedactions(removedRedactions: AnnotationWrapper[]) {
|
||||
@ -39,14 +41,8 @@ export class SuggestionsService {
|
||||
|
||||
#convertRemoveSuggestionsToRedactions(suggestions: Annotation[]): void {
|
||||
const removeSuggestions = suggestions.filter(a => bool(a.getCustomData('suggestionRemove')));
|
||||
|
||||
removeSuggestions.forEach(suggestion => {
|
||||
const color = this._annotationDrawService.convertColor(suggestion.getCustomData('redactionColor'));
|
||||
suggestion['Opacity'] = 1;
|
||||
suggestion['StrokeColor'] = color;
|
||||
suggestion['FillColor'] = color;
|
||||
});
|
||||
|
||||
this._readableRedactionsService.setPreviewAnnotationsOpacity(removeSuggestions);
|
||||
this._readableRedactionsService.setPreviewAnnotationsColor(removeSuggestions);
|
||||
this._annotationManager.show(removeSuggestions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ import Quad = Core.Math.Quad;
|
||||
|
||||
const DEFAULT_TEXT_ANNOTATION_OPACITY = 1;
|
||||
const DEFAULT_REMOVED_ANNOTATION_OPACITY = 0.2;
|
||||
const FINAL_REDACTION_COLOR = '#000000';
|
||||
|
||||
@Injectable()
|
||||
export class AnnotationDrawService {
|
||||
@ -164,6 +165,7 @@ export class AnnotationDrawService {
|
||||
? this._defaultColorsService.getColor(dossierTemplateId, 'requestAddColor')
|
||||
: this._defaultColorsService.getColor(dossierTemplateId, 'previewColor');
|
||||
annotation.setCustomData('redactionColor', String(redactionColor));
|
||||
annotation.setCustomData('finalRedactionColor', FINAL_REDACTION_COLOR);
|
||||
annotation.setCustomData('annotationColor', String(annotationWrapper.color));
|
||||
|
||||
return annotation;
|
||||
|
||||
@ -80,6 +80,11 @@ export class REDDocumentViewer {
|
||||
return merge(this.#documentUnloaded$, this.#documentLoaded$).pipe(shareLast());
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
this.#document.clearSelection();
|
||||
this.#pdf.disable('textPopup');
|
||||
}
|
||||
|
||||
close() {
|
||||
this.#logger.info('[PDF] Closing document');
|
||||
this.#document.closeDocument();
|
||||
|
||||
@ -7,13 +7,15 @@ import { PdfViewer } from './pdf-viewer.service';
|
||||
import { REDAnnotationManager } from './annotation-manager.service';
|
||||
import { AnnotationDrawService } from './annotation-draw.service';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { Core } from '@pdftron/webviewer';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
|
||||
@Injectable()
|
||||
export class ReadableRedactionsService {
|
||||
readonly active$: Observable<boolean>;
|
||||
readonly #enableIcon = this._convertPath('/assets/icons/general/pdftron-action-enable-tooltips.svg');
|
||||
readonly #disableIcon = this._convertPath('/assets/icons/general/pdftron-action-disable-tooltips.svg');
|
||||
readonly #active$ = new BehaviorSubject<boolean>(false);
|
||||
readonly active$: Observable<boolean>;
|
||||
readonly #active$ = new BehaviorSubject<boolean>(true);
|
||||
|
||||
constructor(
|
||||
@Inject(BASE_HREF_FN) private readonly _convertPath: BaseHrefFn,
|
||||
@ -47,4 +49,27 @@ export class ReadableRedactionsService {
|
||||
img: this.toggleReadableRedactionsBtnIcon,
|
||||
});
|
||||
}
|
||||
|
||||
setAnnotationsOpacity(annotations: Annotation[], restoreToOriginal = false) {
|
||||
annotations.forEach(annotation => {
|
||||
annotation['Opacity'] = restoreToOriginal ? parseFloat(annotation.getCustomData('opacity')) : 0.5;
|
||||
});
|
||||
}
|
||||
|
||||
setAnnotationsColor(annotations: Annotation[], customData: string) {
|
||||
annotations.forEach(annotation => {
|
||||
const color = this._annotationDrawService.convertColor(annotation.getCustomData(customData));
|
||||
annotation['StrokeColor'] = color;
|
||||
annotation['FillColor'] = color;
|
||||
});
|
||||
}
|
||||
|
||||
setPreviewAnnotationsOpacity(annotations: Annotation[]) {
|
||||
this.setAnnotationsOpacity(annotations, !this.active);
|
||||
}
|
||||
|
||||
setPreviewAnnotationsColor(annotations: Annotation[]) {
|
||||
const color = this.active ? 'redactionColor' : 'finalRedactionColor';
|
||||
this.setAnnotationsColor(annotations, color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,7 +249,7 @@ export class ViewerHeaderService {
|
||||
header.getItems().splice(10, header.getItems().length - 14, ...enabledItems);
|
||||
});
|
||||
|
||||
this._pdf.instance.UI.updateElement('selectToolButton', {
|
||||
this._pdf.instance?.UI.updateElement('selectToolButton', {
|
||||
img: this._convertPath('/assets/icons/general/pdftron-cursor.svg'),
|
||||
});
|
||||
}
|
||||
|
||||
@ -106,8 +106,7 @@ export class EditDossierDownloadPackageComponent
|
||||
existsWatermarks: this.#existsWatermarks$,
|
||||
});
|
||||
|
||||
this.availableReportTypes =
|
||||
(await firstValueFrom(this._reportTemplateController.getAvailableReportTemplates(dossierTemplateId))) || [];
|
||||
this.availableReportTypes = (await this._reportTemplateController.getAvailableReportTemplates(dossierTemplateId)) || [];
|
||||
|
||||
this.form = this._getForm();
|
||||
if (!this.canEditDossier) {
|
||||
|
||||
@ -200,7 +200,7 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
||||
private _toTechnicalName(value: string) {
|
||||
const existingTechnicalNames = this._dictionariesMapService.get(this.dossierTemplateId).map(dict => dict.type);
|
||||
const baseTechnicalName = toSnakeCase(value.trim());
|
||||
let technicalName = baseTechnicalName;
|
||||
let technicalName = baseTechnicalName.replaceAll(/[^A-Za-z0-9_-]/g, '');
|
||||
let suffix = 1;
|
||||
while (existingTechnicalNames.includes(technicalName)) {
|
||||
technicalName = [baseTechnicalName, suffix++].join('_');
|
||||
|
||||
@ -2,8 +2,14 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { Dossier, File } from '@red/domain';
|
||||
import { FileDownloadService } from '@upload-download/services/file-download.service';
|
||||
import { CircleButtonType, CircleButtonTypes, Toaster } from '@iqser/common-ui';
|
||||
import { CircleButtonType, CircleButtonTypes, defaultDialogConfig, Toaster } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {
|
||||
DownloadDialogComponent,
|
||||
DownloadDialogData,
|
||||
DownloadDialogResult,
|
||||
} from '@shared/dialogs/download-dialog/download-dialog.component';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
@ -25,6 +31,7 @@ export class FileDownloadBtnComponent implements OnChanges {
|
||||
constructor(
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _fileDownloadService: FileDownloadService,
|
||||
private readonly _dialog: MatDialog,
|
||||
private readonly _toaster: Toaster,
|
||||
) {}
|
||||
|
||||
@ -35,9 +42,20 @@ export class FileDownloadBtnComponent implements OnChanges {
|
||||
|
||||
async downloadFiles($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
const dossierId = this.files[0].dossierId;
|
||||
const filesIds = this.files.map(f => f.id);
|
||||
await firstValueFrom(this._fileDownloadService.downloadFiles(filesIds, dossierId));
|
||||
const ref = this._dialog.open<DownloadDialogComponent, DownloadDialogData, DownloadDialogResult>(DownloadDialogComponent, {
|
||||
...defaultDialogConfig,
|
||||
data: { dossier: this.dossier, hasUnapprovedDocuments: this.files.some(file => !file.isApproved) },
|
||||
});
|
||||
const result = await firstValueFrom(ref.afterClosed());
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._fileDownloadService.downloadFiles({
|
||||
dossierId: this.dossier.id,
|
||||
fileIds: this.files.map(f => f.id),
|
||||
...result,
|
||||
});
|
||||
this._toaster.info(_('download-status.queued'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { Action, ActionTypes, File } from '@red/domain';
|
||||
import { Action, ActionTypes, Dossier, File } from '@red/domain';
|
||||
import {
|
||||
CircleButtonType,
|
||||
defaultDialogConfig,
|
||||
IqserTooltipPosition,
|
||||
OverlappingElements,
|
||||
ScrollableParentView,
|
||||
@ -13,6 +14,12 @@ import { FileDownloadService } from '@upload-download/services/file-download.ser
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { MatMenuTrigger } from '@angular/material/menu';
|
||||
import {
|
||||
DownloadDialogComponent,
|
||||
DownloadDialogData,
|
||||
DownloadDialogResult,
|
||||
} from '@shared/dialogs/download-dialog/download-dialog.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-expandable-file-actions',
|
||||
@ -39,8 +46,13 @@ export class ExpandableFileActionsComponent implements OnChanges {
|
||||
private readonly _fileDownloadService: FileDownloadService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _dialog: MatDialog,
|
||||
) {}
|
||||
|
||||
get overlappingElement() {
|
||||
return this.helpModeKey === 'document_features_in_editor' ? OverlappingElements.USER_MENU : undefined;
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.actions || changes.maxWidth || changes.minWidth) {
|
||||
let count = 0;
|
||||
@ -72,7 +84,7 @@ export class ExpandableFileActionsComponent implements OnChanges {
|
||||
// Patch download button
|
||||
const downloadBtn = this.actions.find(btn => btn.type === ActionTypes.downloadBtn);
|
||||
if (downloadBtn) {
|
||||
downloadBtn.action = ($event: MouseEvent) => this._downloadFiles($event, downloadBtn.files);
|
||||
downloadBtn.action = ($event: MouseEvent) => this._downloadFiles($event, downloadBtn.files, downloadBtn.dossier);
|
||||
downloadBtn.disabled = !this._permissionsService.canDownloadFiles(downloadBtn.files, downloadBtn.dossier);
|
||||
}
|
||||
}
|
||||
@ -83,20 +95,27 @@ export class ExpandableFileActionsComponent implements OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
private async _downloadFiles($event: MouseEvent, files: File[]) {
|
||||
$event.stopPropagation();
|
||||
const dossierId = files[0].dossierId;
|
||||
const filesIds = files.map(f => f.id);
|
||||
await firstValueFrom(this._fileDownloadService.downloadFiles(filesIds, dossierId));
|
||||
this._toaster.info(_('download-status.queued'));
|
||||
}
|
||||
|
||||
onButtonClick(button: Action, $event: MouseEvent) {
|
||||
button.action($event);
|
||||
this.matMenu.closeMenu();
|
||||
}
|
||||
|
||||
get overlappingElement() {
|
||||
return this.helpModeKey === 'document_features_in_editor' ? OverlappingElements.USER_MENU : undefined;
|
||||
private async _downloadFiles($event: MouseEvent, files: File[], dossier: Dossier) {
|
||||
$event.stopPropagation();
|
||||
const ref = this._dialog.open<DownloadDialogComponent, DownloadDialogData, DownloadDialogResult>(DownloadDialogComponent, {
|
||||
...defaultDialogConfig,
|
||||
data: { dossier, hasUnapprovedDocuments: files.some(file => !file.isApproved) },
|
||||
});
|
||||
const result = await firstValueFrom(ref.afterClosed());
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._fileDownloadService.downloadFiles({
|
||||
dossierId: dossier.id,
|
||||
fileIds: files.map(f => f.id),
|
||||
...result,
|
||||
});
|
||||
this._toaster.info(_('download-status.queued'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
flex-wrap: nowrap;
|
||||
@include common-mixins.scroll-bar();
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ export class AddDossierDialogComponent extends BaseDialogComponent implements On
|
||||
|
||||
if (dossierTemplate) {
|
||||
this.availableReportTypes =
|
||||
(await firstValueFrom(this._reportTemplateController.getAvailableReportTemplates(dossierTemplate.dossierTemplateId))) || [];
|
||||
(await this._reportTemplateController.getAvailableReportTemplates(dossierTemplate.dossierTemplateId)) || [];
|
||||
// update dropdown values
|
||||
this.form.patchValue(
|
||||
{
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
<section class="dialog">
|
||||
<form *ngIf="form" [formGroup]="form">
|
||||
<div [translate]="'download-dialog.header'" class="dialog-header heading-l"></div>
|
||||
|
||||
<div *ngIf="data.hasUnapprovedDocuments" class="inline-dialog-toast toast-warning">
|
||||
<div [translate]="'download-dialog.unapproved-files-warning'"></div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<redaction-select
|
||||
*ngIf="availableReportTypes | async as reportTypes"
|
||||
[label]="'report-type.label' | translate: { length: reportTypesLength }"
|
||||
[optionTemplate]="reportTemplateOptionTemplate"
|
||||
[options]="reportTypes"
|
||||
[valueMapper]="reportTemplateValueMapper"
|
||||
class="mb-16"
|
||||
formControlName="reportTemplateIds"
|
||||
></redaction-select>
|
||||
|
||||
<redaction-select
|
||||
[label]="'download-type.label' | translate: { length: downloadFileTypesLength }"
|
||||
[options]="downloadTypes"
|
||||
formControlName="downloadFileTypes"
|
||||
></redaction-select>
|
||||
|
||||
<div class="iqser-input-group required">
|
||||
<label translate="download-dialog.form.redaction-preview-color"></label>
|
||||
<input
|
||||
[placeholder]="'download-dialog.form.redaction-preview-color-placeholder' | translate"
|
||||
class="hex-color-input"
|
||||
formControlName="redactionPreviewColor"
|
||||
name="color"
|
||||
type="text"
|
||||
/>
|
||||
<div
|
||||
(colorPickerChange)="form.controls.redactionPreviewColor.setValue($event)"
|
||||
[colorPicker]="form.controls.redactionPreviewColor.value"
|
||||
[cpOutputFormat]="'hex'"
|
||||
[style.background]="form.controls.redactionPreviewColor.value"
|
||||
class="input-icon"
|
||||
>
|
||||
<mat-icon
|
||||
*ngIf="!form.controls.redactionPreviewColor.value || form.controls.redactionPreviewColor.value?.length === 0"
|
||||
svgIcon="red:color-picker"
|
||||
></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="form.invalid" color="primary" mat-flat-button type="submit">
|
||||
{{ 'download-dialog.actions.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<ng-template #reportTemplateOptionTemplate let-option="option">
|
||||
{{ option.fileName }} {{ option.multiFileReport ? ('reports-screen.multi-file-report' | translate) : '' }}
|
||||
</ng-template>
|
||||
@ -0,0 +1,100 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Dossier, DownloadFileType, IReportTemplate } from '@red/domain';
|
||||
import { downloadTypesForDownloadTranslations } from '@translations/download-types-translations';
|
||||
import { ReportTemplateService } from '@services/report-template.service';
|
||||
import { AbstractControl, FormBuilder } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
|
||||
import { List } from '@iqser/common-ui';
|
||||
|
||||
export interface DownloadDialogData {
|
||||
readonly dossier: Dossier;
|
||||
readonly hasUnapprovedDocuments: boolean;
|
||||
}
|
||||
|
||||
export interface DownloadDialogResult {
|
||||
downloadFileTypes: List<DownloadFileType>;
|
||||
reportTemplateIds: List;
|
||||
redactionPreviewColor: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-download-dialog',
|
||||
templateUrl: './download-dialog.component.html',
|
||||
styleUrls: ['./download-dialog.component.scss'],
|
||||
})
|
||||
export class DownloadDialogComponent {
|
||||
readonly downloadTypes: { key: DownloadFileType; label: string }[] = ['ORIGINAL', 'PREVIEW', 'DELTA_PREVIEW', 'REDACTED'].map(
|
||||
(type: DownloadFileType) => ({
|
||||
key: type,
|
||||
label: downloadTypesForDownloadTranslations[type],
|
||||
}),
|
||||
);
|
||||
readonly availableReportTypes = this._availableReportTypes;
|
||||
readonly form = this._getForm();
|
||||
|
||||
constructor(
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
private readonly _reportTemplateController: ReportTemplateService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _dialogRef: MatDialogRef<DownloadDialogComponent, DownloadDialogResult>,
|
||||
@Inject(MAT_DIALOG_DATA) readonly data: DownloadDialogData,
|
||||
) {}
|
||||
|
||||
get reportTypesLength() {
|
||||
return this.form.controls.reportTemplateIds?.value?.length || 0;
|
||||
}
|
||||
|
||||
get downloadFileTypesLength() {
|
||||
return this.form.controls.downloadFileTypes?.value?.length || 0;
|
||||
}
|
||||
|
||||
private get _availableReportTypes() {
|
||||
const dossierTemplateId = this.data.dossier.dossierTemplateId;
|
||||
const result = this._reportTemplateController.getAvailableReportTemplates(dossierTemplateId);
|
||||
return result.then(values => values ?? []);
|
||||
}
|
||||
|
||||
reportTemplateValueMapper = (reportTemplate: IReportTemplate) => reportTemplate.templateId;
|
||||
|
||||
async save() {
|
||||
const result: DownloadDialogResult = {
|
||||
reportTemplateIds: this.form.controls.reportTemplateIds.value,
|
||||
downloadFileTypes: this.form.controls.downloadFileTypes.value,
|
||||
redactionPreviewColor: this.form.controls.redactionPreviewColor.value,
|
||||
};
|
||||
|
||||
this._dialogRef.close(result);
|
||||
}
|
||||
|
||||
close() {
|
||||
this._dialogRef.close();
|
||||
}
|
||||
|
||||
private _hasReportTemplateOrDownloadType(control: AbstractControl) {
|
||||
const atLeastAReportSelected = control.get('reportTemplateIds')?.value.length > 0;
|
||||
const atLeastATypeSelected = control.get('downloadFileTypes')?.value.length > 0;
|
||||
|
||||
return atLeastATypeSelected || atLeastAReportSelected ? null : { reportTemplateIds: true, downloadFileTypes: true };
|
||||
}
|
||||
|
||||
private _getForm() {
|
||||
const previewColor = this._defaultColorsService.getColor(this.data.dossier.dossierTemplateId, 'previewColor');
|
||||
return this._formBuilder.group(
|
||||
{
|
||||
reportTemplateIds: [this.data.dossier.reportTemplateIds],
|
||||
downloadFileTypes: [this.data.dossier.downloadFileTypes],
|
||||
redactionPreviewColor: [previewColor],
|
||||
},
|
||||
{
|
||||
validators: [control => this._hasReportTemplateOrDownloadType(control), control => this._isHexColor(control)],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private _isHexColor(control: AbstractControl) {
|
||||
const color = control.get('redactionPreviewColor')?.value;
|
||||
const isHexColor = /^#[0-9A-F]{6}$/i.test(color);
|
||||
return isHexColor ? null : { redactionPreviewColor: true };
|
||||
}
|
||||
}
|
||||
@ -42,6 +42,7 @@ import { AddEditEntityComponent } from './components/add-edit-entity/add-edit-en
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { WatermarkSelectorComponent } from './components/dossier-watermark-selector/watermark-selector.component';
|
||||
import { OcrProgressBarComponent } from './components/ocr-progress-bar/ocr-progress-bar.component';
|
||||
import { DownloadDialogComponent } from './dialogs/download-dialog/download-dialog.component';
|
||||
|
||||
const buttons = [FileDownloadBtnComponent];
|
||||
|
||||
@ -76,7 +77,7 @@ const services = [SharedDialogService];
|
||||
const modules = [MatConfigModule, ScrollingModule, IconsModule, FormsModule, ReactiveFormsModule, ColorPickerModule];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components, ...utils, EditorComponent],
|
||||
declarations: [...components, ...utils, EditorComponent, DownloadDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
...modules,
|
||||
|
||||
@ -29,11 +29,9 @@ export class FileDownloadService extends EntitiesService<IDownloadStatus, Downlo
|
||||
super();
|
||||
}
|
||||
|
||||
downloadFiles(fileIds: List, dossierId: string): Observable<DownloadStatus[]> {
|
||||
return this.prepareDownload({
|
||||
fileIds,
|
||||
dossierId,
|
||||
}).pipe(switchMap(() => this.loadAll()));
|
||||
downloadFiles(request: IPrepareDownloadRequest): Promise<DownloadStatus[]> {
|
||||
const prepare = this.prepareDownload(request).pipe(switchMap(() => this.loadAll()));
|
||||
return firstValueFrom(prepare);
|
||||
}
|
||||
|
||||
loadAll(): Observable<DownloadStatus[]> {
|
||||
@ -61,7 +59,7 @@ export class FileDownloadService extends EntitiesService<IDownloadStatus, Downlo
|
||||
|
||||
@Validate()
|
||||
prepareDownload(@RequiredParam() body: IPrepareDownloadRequest): Observable<IDownloadResponse> {
|
||||
return this._post(body, `${this._defaultModelPath}/prepare`);
|
||||
return this._post(body, `${this._defaultModelPath}/prepare-option`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
|
||||
@ -40,6 +40,20 @@ export class RssService extends GenericService<void> {
|
||||
});
|
||||
}
|
||||
|
||||
@Validate()
|
||||
override(
|
||||
@RequiredParam() dossierId: string,
|
||||
@RequiredParam() fileId: string,
|
||||
@RequiredParam() componentOverrides: Record<string, string>,
|
||||
) {
|
||||
return this._post({ componentOverrides }, `rss/override/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
revertOverride(@RequiredParam() dossierId: string, @RequiredParam() fileId: string, @RequiredParam() components: string[]) {
|
||||
return this._post({ components }, `rss/override/revert/${dossierId}/${fileId}`);
|
||||
}
|
||||
|
||||
exportJSON(dossierId: string, fileId: string, name: string) {
|
||||
return this.getRSSData(dossierId, fileId).pipe(
|
||||
tap(data => {
|
||||
|
||||
@ -261,7 +261,7 @@ export class PermissionsService {
|
||||
if (files.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return this.isApprover(dossier) && files.reduce((prev, file) => prev && file.isApproved, true);
|
||||
return this.isApprover(dossier) && files.reduce((prev, file) => prev && !file.isInitialProcessing, true);
|
||||
}
|
||||
|
||||
canSoftDeleteDossier(dossier: IDossier): boolean {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { GenericService, HeadersConfiguration, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { IPlaceholdersResponse, IReportTemplate } from '@red/domain';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { firstValueFrom, Observable, of } from 'rxjs';
|
||||
import { HttpResponse } from '@angular/common/http';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
@ -34,7 +34,8 @@ export class ReportTemplateService extends GenericService<unknown> {
|
||||
|
||||
@Validate()
|
||||
getAvailableReportTemplates(@RequiredParam() dossierTemplateId: string) {
|
||||
return this.getAll<IReportTemplate[]>(`${this._defaultModelPath}/${dossierTemplateId}`);
|
||||
const request = this.getAll<IReportTemplate[]>(`${this._defaultModelPath}/${dossierTemplateId}`);
|
||||
return firstValueFrom(request);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
|
||||
@ -9,3 +9,12 @@ export const downloadTypesTranslations: { [key in DownloadFileType]: string } =
|
||||
FLATTEN: _('download-type.flatten'),
|
||||
DELTA_PREVIEW: _('download-type.delta-preview'),
|
||||
} as const;
|
||||
|
||||
export const downloadTypesForDownloadTranslations: { [key in DownloadFileType]: string } = {
|
||||
ORIGINAL: _('download-type.original'),
|
||||
PREVIEW: _('download-type.preview'),
|
||||
REDACTED: _('download-type.redacted-only'),
|
||||
ANNOTATED: _('download-type.annotated'),
|
||||
FLATTEN: _('download-type.flatten'),
|
||||
DELTA_PREVIEW: _('download-type.delta-preview'),
|
||||
} as const;
|
||||
|
||||
@ -13,7 +13,7 @@ export class RedRoleGuard extends IqserRoleGuard {
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||
const currentUser = this._userService.currentUser;
|
||||
|
||||
if (!currentUser.hasAnyRole) {
|
||||
if (!currentUser?.hasAnyRole) {
|
||||
await this._router.navigate(['/auth-error']);
|
||||
this._loadingService.stop();
|
||||
return false;
|
||||
|
||||
@ -1017,6 +1017,17 @@
|
||||
"active": "",
|
||||
"archive": ""
|
||||
},
|
||||
"download-dialog": {
|
||||
"actions": {
|
||||
"save": ""
|
||||
},
|
||||
"form": {
|
||||
"redaction-preview-color": "",
|
||||
"redaction-preview-color-placeholder": ""
|
||||
},
|
||||
"header": "",
|
||||
"unapproved-files-warning": ""
|
||||
},
|
||||
"download-includes": "Wählen Sie die Dokumente für Ihr Download-Paket aus",
|
||||
"download-status": {
|
||||
"queued": "Ihr Download wurde zur Warteschlange hinzugefügt. Hier finden Sie alle angeforderten Downloads: <a href='/main/downloads'>My Downloads<a/>."
|
||||
@ -1028,7 +1039,8 @@
|
||||
"label": "{length} Dokumenten{length, plural, one{version} other{versionen}}",
|
||||
"original": "Optimiertes PDF",
|
||||
"preview": "PDF-Vorschau",
|
||||
"redacted": "geschwärztes PDF"
|
||||
"redacted": "geschwärztes PDF",
|
||||
"redacted-only": ""
|
||||
},
|
||||
"downloads-list": {
|
||||
"actions": {
|
||||
@ -1941,9 +1953,13 @@
|
||||
},
|
||||
"rss-dialog": {
|
||||
"actions": {
|
||||
"cancel-edit": "",
|
||||
"close": "",
|
||||
"edit": "",
|
||||
"export-json": "",
|
||||
"export-xml": ""
|
||||
"export-xml": "",
|
||||
"save": "",
|
||||
"undo": ""
|
||||
},
|
||||
"title": ""
|
||||
},
|
||||
|
||||
@ -849,7 +849,7 @@
|
||||
}
|
||||
},
|
||||
"download-file": "Download",
|
||||
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be approved in order to download.",
|
||||
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be initially processed in order to download.",
|
||||
"file-listing": {
|
||||
"file-entry": {
|
||||
"file-error": "Re-processing required",
|
||||
@ -1017,6 +1017,17 @@
|
||||
"active": "Active",
|
||||
"archive": "Archived"
|
||||
},
|
||||
"download-dialog": {
|
||||
"actions": {
|
||||
"save": "Download"
|
||||
},
|
||||
"form": {
|
||||
"redaction-preview-color": "Redaction preview color",
|
||||
"redaction-preview-color-placeholder": "#000000"
|
||||
},
|
||||
"header": "Download options",
|
||||
"unapproved-files-warning": "This download contains unapproved file(s)"
|
||||
},
|
||||
"download-includes": "Choose what is included at download:",
|
||||
"download-status": {
|
||||
"queued": "Your download has been queued, you can see all your requested downloads here: <a href='/ui/main/downloads'>My Downloads<a/>."
|
||||
@ -1028,7 +1039,8 @@
|
||||
"label": "{length} document {length, plural, one{version} other{versions}}",
|
||||
"original": "Optimized PDF",
|
||||
"preview": "Preview PDF",
|
||||
"redacted": "Redacted PDF"
|
||||
"redacted": "Redacted PDF",
|
||||
"redacted-only": "Redacted PDF (approved documents only)"
|
||||
},
|
||||
"downloads-list": {
|
||||
"actions": {
|
||||
@ -1941,9 +1953,13 @@
|
||||
},
|
||||
"rss-dialog": {
|
||||
"actions": {
|
||||
"cancel-edit": "Cancel",
|
||||
"close": "Close",
|
||||
"edit": "Edit",
|
||||
"export-json": "Export JSON",
|
||||
"export-xml": "Export XML"
|
||||
"export-xml": "Export XML",
|
||||
"save": "Save",
|
||||
"undo": "Undo"
|
||||
},
|
||||
"title": "Structured Component Management"
|
||||
},
|
||||
|
||||
@ -1017,6 +1017,17 @@
|
||||
"active": "",
|
||||
"archive": ""
|
||||
},
|
||||
"download-dialog": {
|
||||
"actions": {
|
||||
"save": ""
|
||||
},
|
||||
"form": {
|
||||
"redaction-preview-color": "",
|
||||
"redaction-preview-color-placeholder": ""
|
||||
},
|
||||
"header": "",
|
||||
"unapproved-files-warning": ""
|
||||
},
|
||||
"download-includes": "Wählen Sie die Dokumente für Ihr Download-Paket aus",
|
||||
"download-status": {
|
||||
"queued": "Ihr Download wurde zur Warteschlange hinzugefügt. Hier finden Sie alle angeforderten Downloads: <a href='/main/downloads'>My Downloads<a/>."
|
||||
@ -1028,7 +1039,8 @@
|
||||
"label": "{length} Dokumenten{length, plural, one{version} other{versionen}}",
|
||||
"original": "Optimiertes PDF",
|
||||
"preview": "PDF-Vorschau",
|
||||
"redacted": "geschwärztes PDF"
|
||||
"redacted": "geschwärztes PDF",
|
||||
"redacted-only": ""
|
||||
},
|
||||
"downloads-list": {
|
||||
"actions": {
|
||||
@ -1941,9 +1953,13 @@
|
||||
},
|
||||
"rss-dialog": {
|
||||
"actions": {
|
||||
"cancel-edit": "",
|
||||
"close": "",
|
||||
"edit": "",
|
||||
"export-json": "",
|
||||
"export-xml": ""
|
||||
"export-xml": "",
|
||||
"save": "",
|
||||
"undo": ""
|
||||
},
|
||||
"title": ""
|
||||
},
|
||||
|
||||
@ -849,7 +849,7 @@
|
||||
}
|
||||
},
|
||||
"download-file": "Download",
|
||||
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be approved in order to download.",
|
||||
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be initially processed in order to download.",
|
||||
"file-listing": {
|
||||
"file-entry": {
|
||||
"file-error": "Re-processing required",
|
||||
@ -1017,6 +1017,17 @@
|
||||
"active": "Active",
|
||||
"archive": "Archived"
|
||||
},
|
||||
"download-dialog": {
|
||||
"actions": {
|
||||
"save": "Download"
|
||||
},
|
||||
"form": {
|
||||
"redaction-preview-color": "Redaction preview color",
|
||||
"redaction-preview-color-placeholder": "#000000"
|
||||
},
|
||||
"header": "Download options",
|
||||
"unapproved-files-warning": "This download contains unapproved file(s)"
|
||||
},
|
||||
"download-includes": "Choose what is included at download:",
|
||||
"download-status": {
|
||||
"queued": "Your download has been queued, you can see all your requested downloads here: <a href='/ui/main/downloads'>My Downloads<a/>."
|
||||
@ -1028,7 +1039,8 @@
|
||||
"label": "{length} document {length, plural, one{version} other{versions}}",
|
||||
"original": "Optimized PDF",
|
||||
"preview": "Preview PDF",
|
||||
"redacted": "Redacted PDF"
|
||||
"redacted": "Redacted PDF",
|
||||
"redacted-only": "Redacted PDF (redacted documents only)"
|
||||
},
|
||||
"downloads-list": {
|
||||
"actions": {
|
||||
@ -1941,9 +1953,13 @@
|
||||
},
|
||||
"rss-dialog": {
|
||||
"actions": {
|
||||
"cancel-edit": "Cancel",
|
||||
"close": "Close",
|
||||
"edit": "Edit",
|
||||
"export-json": "Export JSON",
|
||||
"export-xml": "Export XML"
|
||||
"export-xml": "Export XML",
|
||||
"save": "Save",
|
||||
"undo": "Undo"
|
||||
},
|
||||
"title": "Structured Component Management"
|
||||
},
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 5f9c754abf0fb4fcc0606d811a66c5bbb88d164a
|
||||
Subproject commit b58f1ca2fed8e8ddf2834c0fd15e48d00b6a1329
|
||||
@ -2,8 +2,12 @@
|
||||
* Object containing information on which file and report types should be included in the download.
|
||||
*/
|
||||
import { List } from '@iqser/common-ui';
|
||||
import { DownloadFileType } from '../shared';
|
||||
|
||||
export interface IPrepareDownloadRequest {
|
||||
readonly dossierId?: string;
|
||||
readonly fileIds?: List;
|
||||
readonly dossierId: string;
|
||||
readonly fileIds: List;
|
||||
readonly reportTemplateIds: List;
|
||||
readonly downloadFileTypes: List<DownloadFileType>;
|
||||
readonly redactionPreviewColor: string;
|
||||
}
|
||||
|
||||
@ -146,7 +146,11 @@ export class File extends Entity<IFile> implements IFile {
|
||||
this.isUnderApproval = this.workflowStatus === WorkflowFileStatuses.UNDER_APPROVAL;
|
||||
this.canBeApproved = !this.hasSuggestions && !this.isProcessing && !this.isError;
|
||||
this.canBeOpened = !this.isError && !this.isUnprocessed && this.numberOfAnalyses > 0;
|
||||
this.canBeOCRed = !this.excluded && !this.lastOCRTime && (this.isNew || this.isUnderReview || this.isUnderApproval);
|
||||
this.canBeOCRed =
|
||||
!this.excluded &&
|
||||
!this.lastOCRTime &&
|
||||
this.numberOfAnalyses !== 0 &&
|
||||
(this.isNew || this.isUnderReview || this.isUnderApproval);
|
||||
|
||||
this.fileAttributes =
|
||||
file.fileAttributes && file.fileAttributes.attributeIdToValue ? file.fileAttributes : { attributeIdToValue: {} };
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "redaction",
|
||||
"version": "3.813.0",
|
||||
"version": "3.828.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "redaction",
|
||||
"version": "3.813.0",
|
||||
"version": "3.828.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user