Merge branch 'VM/DM-536' into 'master'

DM-536

Closes DM-536

See merge request redactmanager/red-ui!171
This commit is contained in:
Dan Percic 2023-11-07 12:39:56 +01:00
commit 407a6d67cd
9 changed files with 154 additions and 135 deletions

View File

@ -6,6 +6,18 @@
[viewModeSelection]="viewModeSelection"
>
<ng-container slot="right">
<iqser-circle-button
*allow="roles.getRss"
[attr.help-mode-key]="'editor_scm'"
[icon]="'red:extract'"
[tooltip]="
((this.entitiesService.allLength$ | async) === 0 ? 'component-download.disabled-tooltip' : 'component-download.tooltip')
| translate
"
[matMenuTriggerFor]="bulkComponentDownloadMenu"
[disabled]="(this.entitiesService.allLength$ | async) === 0"
></iqser-circle-button>
<redaction-file-download-btn
[attr.help-mode-key]="'download_dossier_in_dossier'"
[buttonId]="'download-files-btn'"
@ -49,3 +61,8 @@
<ng-template #viewModeSelection>
<redaction-view-mode-selection iqserDisableStopPropagation></redaction-view-mode-selection>
</ng-template>
<mat-menu #bulkComponentDownloadMenu="matMenu">
<button [innerHTML]="'component-download.json' | translate" (click)="downloadComponentAsJSON()" mat-menu-item></button>
<button [innerHTML]="'component-download.xml' | translate" (click)="downloadComponentAsXML()" mat-menu-item></button>
</mat-menu>

View File

@ -14,6 +14,7 @@ import { Roles } from '@users/roles';
import { SortingService } from '@iqser/common-ui/lib/sorting';
import { List, some } from '@iqser/common-ui/lib/utils';
import { TenantsService } from '@iqser/common-ui/lib/tenants';
import { ComponentLogService } from '@services/files/component-log.service';
@Component({
selector: 'redaction-dossier-overview-screen-header [dossier] [upload]',
@ -41,6 +42,7 @@ export class DossierOverviewScreenHeaderComponent implements OnInit {
private readonly _reanalysisService: ReanalysisService,
private readonly _loadingService: LoadingService,
private readonly _primaryFileAttributeService: PrimaryFileAttributeService,
private readonly _componentLogService: ComponentLogService,
) {
const someNotProcessed$ = this.entitiesService.all$.pipe(some(file => !file.lastProcessed));
this.downloadBtnDisabled$ = combineLatest([this.listingService.areSomeSelected$, someNotProcessed$]).pipe(
@ -92,4 +94,12 @@ export class DossierOverviewScreenHeaderComponent implements OnInit {
];
saveAsCSV(fileName, entities, fileFields, mapper);
}
downloadComponentAsJSON() {
return firstValueFrom(this._componentLogService.exportJSON(this.dossier.dossierTemplateId, this.dossier.dossierId));
}
async downloadComponentAsXML() {
return firstValueFrom(this._componentLogService.exportXML(this.dossier.dossierTemplateId, this.dossier.dossierId));
}
}

View File

@ -64,35 +64,21 @@ export class StructuredComponentManagementDialogComponent extends BaseDialogComp
exportJSON() {
return firstValueFrom(
this._componentLogService.exportJSON(
this.data.file.dossierTemplateId,
this.data.file.dossierId,
this.data.file.fileId,
this.data.file.filename,
),
this._componentLogService.exportJSON(this.data.file.dossierTemplateId, this.data.file.dossierId, this.data.file),
);
}
exportXML() {
return firstValueFrom(
this._componentLogService.exportXML(
this.data.file.dossierTemplateId,
this.data.file.dossierId,
this.data.file.fileId,
this.data.file.filename,
),
this._componentLogService.exportXML(this.data.file.dossierTemplateId, this.data.file.dossierId, this.data.file),
);
}
async exportAllInDossier() {
const allFilesInDossier = this._filesMapService.get(this.data.file.dossierId);
for (const file of allFilesInDossier) {
await firstValueFrom(
this._componentLogService.exportJSON(this.data.file.dossierTemplateId, file.dossierId, file.fileId, file.filename),
);
await firstValueFrom(
this._componentLogService.exportXML(this.data.file.dossierTemplateId, file.dossierId, file.fileId, file.filename),
);
await firstValueFrom(this._componentLogService.exportJSON(this.data.file.dossierTemplateId, file.dossierId, file));
await firstValueFrom(this._componentLogService.exportXML(this.data.file.dossierTemplateId, file.dossierId, file));
}
}

View File

@ -4,7 +4,7 @@ import { catchError, map, tap } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { HttpHeaders } from '@angular/common/http';
import { saveAs } from 'file-saver';
import { ComponentDetails, ComponentLogEntry, IComponentLogData, IComponentLogEntry } from '@red/domain';
import { ComponentDetails, ComponentLogEntry, IComponentLogData, IComponentLogEntry, IFile } from '@red/domain';
import { mapEach } from '@common-ui/utils';
@Injectable({ providedIn: 'root' })
@ -25,6 +25,15 @@ export class ComponentLogService extends GenericService<void> {
);
}
#bulkComponentLogRequest(dossierTemplateId: string, dossierId: string, includeDetails = false): Observable<IComponentLogData> {
return this._http.get<IComponentLogData>(
`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/bulk/get-components`,
{
params: { includeDetails },
},
);
}
getComponentLogData(dossierTemplateId: string, dossierId: string, fileId: string): Observable<ComponentLogEntry[]> {
return this.#componentLogRequest(dossierTemplateId, dossierId, fileId).pipe(
map(data => data.componentDetails),
@ -42,29 +51,34 @@ export class ComponentLogService extends GenericService<void> {
return this._post({ components }, `componentLog/override/revert/${dossierId}/${fileId}`);
}
exportJSON(dossierTemplateId: string, dossierId: string, fileId: string, name: string): Observable<IComponentLogData> {
return this.#componentLogRequest(dossierTemplateId, dossierId, fileId, false).pipe(
exportJSON(dossierTemplateId: string, dossierId: string, file?: IFile): Observable<IComponentLogData> {
const request$ = file?.fileId
? this.#componentLogRequest(dossierTemplateId, dossierId, file?.fileId, false)
: this.#bulkComponentLogRequest(dossierTemplateId, dossierId);
return request$.pipe(
tap(data => {
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
saveAs(blob, name + '.component_log.json');
saveAs(blob, (file?.filename ? `${file.filename}}.` : '') + 'component_log.json');
}),
);
}
exportXML(dossierTemplateId, dossierId: string, fileId: string, name: string): Observable<string> {
return this.#getComponentLogDataAsXML(dossierTemplateId, dossierId, fileId).pipe(
exportXML(dossierTemplateId, dossierId: string, file?: IFile): Observable<string> {
return this.#getComponentLogDataAsXML(dossierTemplateId, dossierId, file).pipe(
tap(data => {
const blob = new Blob([data], { type: 'application/xml' });
saveAs(blob, name + '.component_log.xml');
saveAs(blob, (file?.filename ? `${file.filename}}.` : '') + 'component_log.xml');
}),
);
}
#getComponentLogDataAsXML(dossierTemplateId: string, dossierId: string, fileId: string) {
#getComponentLogDataAsXML(dossierTemplateId: string, dossierId: string, file?: IFile) {
let headers = new HttpHeaders();
headers = headers.set('accept', 'application/xml');
return this._http.get(`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/${fileId}/components`, {
const pathSuffix = file?.fileId ? `${file.fileId}/components` : 'bulk/get-components';
return this._http.get(`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/${pathSuffix}`, {
headers: headers,
responseType: 'text',
observe: 'body',

View File

@ -254,9 +254,6 @@
"user-management": "User Management",
"watermarks": "Watermarks"
},
"annotation": {
"pending": "(Pending Analysis)"
},
"annotation-actions": {
"accept-recommendation": {
"label": "Empfehlung annehmen"
@ -315,14 +312,14 @@
"error": "Rekategorisierung des Bildes gescheitert: {error}",
"success": "Bild wurde einer neuen Kategorie zugeordnet."
},
"remove": {
"error": "Fehler beim Entfernen der Schwärzung: {error}",
"success": "Schwärzung entfernt!"
},
"remove-hint": {
"error": "Failed to remove hint: {error}",
"success": "Hint removed!"
},
"remove": {
"error": "Fehler beim Entfernen der Schwärzung: {error}",
"success": "Schwärzung entfernt!"
},
"undo": {
"error": "Die Aktion konnte nicht rückgängig gemacht werden. Fehler: {error}",
"success": "erfolgreich Rückgängig gemacht"
@ -335,15 +332,15 @@
"remove-highlights": {
"label": "Remove Selected Earmarks"
},
"resize": {
"label": "Größe ändern"
},
"resize-accept": {
"label": "Größe speichern"
},
"resize-cancel": {
"label": "Größenänderung abbrechen"
},
"resize": {
"label": "Größe ändern"
},
"see-references": {
"label": "See References"
},
@ -374,6 +371,9 @@
"skipped": "Übersprungen",
"text-highlight": "Earmark"
},
"annotation": {
"pending": "(Pending Analysis)"
},
"archived-dossiers-listing": {
"no-data": {
"title": "No archived dossiers."
@ -493,6 +493,12 @@
"title": "Aktion bestätigen"
}
},
"component-download": {
"disabled-tooltip": "",
"json": "",
"tooltip": "",
"xml": ""
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
@ -573,18 +579,14 @@
"warning": "Achtung: Diese Aktion kann nicht rückgängig gemacht werden!"
},
"confirmation-dialog": {
"approve-file": {
"question": "Dieses Dokument enthält ungesehene Änderungen. Möchten Sie es trotzdem genehmigen?",
"title": "Warnung!"
},
"approve-file-without-analysis": {
"confirmationText": "Approve without analysis",
"denyText": "Cancel",
"question": "Analysis required to detect new redactions.",
"title": "Warning!"
},
"approve-multiple-files": {
"question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen. Möchten Sie sie trotzdem genehmigen?",
"approve-file": {
"question": "Dieses Dokument enthält ungesehene Änderungen. Möchten Sie es trotzdem genehmigen?",
"title": "Warnung!"
},
"approve-multiple-files-without-analysis": {
@ -593,6 +595,10 @@
"question": "Analysis required to detect new redactions for at least one file.",
"title": "Warning"
},
"approve-multiple-files": {
"question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen. Möchten Sie sie trotzdem genehmigen?",
"title": "Warnung!"
},
"assign-file-to-me": {
"question": {
"multiple": "Dieses Dokument wird gerade von einer anderen Person geprüft. Möchten Sie Reviewer werden und sich selbst dem Dokument zuweisen?",
@ -938,13 +944,13 @@
"recent": "Neu ({hours} h)",
"unassigned": "Niemandem zugewiesen"
},
"reanalyse": {
"action": "Datei analysieren"
},
"reanalyse-dossier": {
"error": "Die Dateien konnten nicht für eine Reanalyse eingeplant werden. Bitte versuchen Sie es erneut.",
"success": "Dateien für Reanalyse vorgesehen."
},
"reanalyse": {
"action": "Datei analysieren"
},
"start-auto-analysis": "Enable auto-analysis",
"stop-auto-analysis": "Stop auto-analysis",
"table-col-names": {
@ -1013,14 +1019,6 @@
"total-documents": "Anzahl der Dokumente",
"total-people": "<strong>{count}</strong> {count, plural, one{User} other {Users}}"
},
"dossier-templates": {
"label": "Dossier-Vorlagen",
"status": {
"active": "Active",
"inactive": "Inactive",
"incomplete": "Incomplete"
}
},
"dossier-templates-listing": {
"action": {
"clone": "Clone Template",
@ -1056,6 +1054,14 @@
"title": "{length} {length, plural, one{Dossier-Vorlage} other{Dossier-Vorlagen}}"
}
},
"dossier-templates": {
"label": "Dossier-Vorlagen",
"status": {
"active": "Active",
"inactive": "Inactive",
"incomplete": "Incomplete"
}
},
"dossier-watermark-selector": {
"heading": "Watermarks on documents",
"no-watermark": "There is no watermark defined for the dossier template.<br>Contact your app admin to define one.",
@ -1239,15 +1245,6 @@
"title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}"
}
},
"entity": {
"info": {
"actions": {
"revert": "Revert",
"save": "Save Changes"
},
"heading": "Edit Entity"
}
},
"entity-rules-screen": {
"error": {
"generic": "Something went wrong... Entity rules update failed!"
@ -1261,19 +1258,28 @@
"title": "Entity Rule Editor",
"warning-text": "Warning: experimental feature!"
},
"entity": {
"info": {
"actions": {
"revert": "Revert",
"save": "Save Changes"
},
"heading": "Edit Entity"
}
},
"error": {
"deleted-entity": {
"dossier": {
"action": "Zurück zur Übersicht",
"label": "Dieses Dossier wurde gelöscht!"
},
"file": {
"action": "Zurück zum Dossier",
"label": "Diese Datei wurde gelöscht!"
},
"file-dossier": {
"action": "Zurück zur Übersicht",
"label": "Das Dossier dieser Datei wurde gelöscht!"
},
"file": {
"action": "Zurück zum Dossier",
"label": "Diese Datei wurde gelöscht!"
}
},
"file-preview": {
@ -1291,12 +1297,6 @@
},
"exact-date": "{day} {month} {year} um {hour}:{minute} Uhr",
"file": "Datei",
"file-attribute": {
"update": {
"error": "Failed to update file attribute value!",
"success": "File attribute value has been updated successfully!"
}
},
"file-attribute-encoding-types": {
"ascii": "ASCII",
"iso": "ISO-8859-1",
@ -1307,6 +1307,12 @@
"number": "Nummer",
"text": "Freier Text"
},
"file-attribute": {
"update": {
"error": "Failed to update file attribute value!",
"success": "File attribute value has been updated successfully!"
}
},
"file-attributes-configurations": {
"cancel": "Cancel",
"form": {
@ -1520,15 +1526,6 @@
"csv": "File attributes were imported successfully from uploaded CSV file."
}
},
"filter": {
"analysis": "Analyse erforderlich",
"comment": "Kommentare",
"hint": "Nut Hinweise",
"image": "Bilder",
"none": "Keine Anmerkungen",
"redaction": "Geschwärzt",
"updated": "Aktualisiert"
},
"filter-menu": {
"filter-options": "Filteroptionen",
"filter-types": "Filter",
@ -1538,6 +1535,15 @@
"unseen-pages": "Nur Anmerkungen auf unsichtbaren Seiten",
"with-comments": "Nur Anmerkungen mit Kommentaren"
},
"filter": {
"analysis": "Analyse erforderlich",
"comment": "Kommentare",
"hint": "Nut Hinweise",
"image": "Bilder",
"none": "Keine Anmerkungen",
"redaction": "Geschwärzt",
"updated": "Aktualisiert"
},
"filters": {
"assigned-people": "Beauftragt",
"documents-status": "Documents State",
@ -1716,14 +1722,6 @@
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
"copyright-claim-title": "Copyright",
"custom-app-title": "Name der Anwendung",
"email": {
"body": {
"analyzed": "Im aktuellen Lizenzzeitraum insgesamt analysierte Seiten: {pages}.",
"licensed": "Lizenzierte Seiten: {pages}."
},
"title": "Lizenzbericht {licenseCustomer}"
},
"email-report": "E-Mail-Bericht",
"end-user-license-text": "Die Nutzung dieses Produkts unterliegt den Bedingungen der Endbenutzer-Lizenzvereinbarung für den RedactManager, sofern darin nichts anderweitig festgelegt.",
"end-user-license-title": "Endbenutzer-Lizenzvereinbarung",
"licensing-details": {
@ -1816,13 +1814,6 @@
"user-promoted-to-approver": "<b>{user}</b> wurde im Dossier <b>{dossierHref, select, null{{dossierName}} other{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b> zum Genehmiger ernannt!",
"user-removed-as-dossier-member": "<b>{user}</b> wurde als Mitglied von: <b>{dossierHref, select, null{{dossierName}} other{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b> entfernt!"
},
"notifications": {
"button-text": "Notifications",
"deleted-dossier": "Deleted Dossier",
"label": "Benachrichtigungen",
"mark-all-as-read": "Alle als gelesen markieren",
"mark-as": "Mark as {type, select, read{read} unread{unread} other{}}"
},
"notifications-screen": {
"category": {
"email-notifications": "E-Mail Benachrichtigungen",
@ -1836,6 +1827,7 @@
"dossier": "Dossierbezogene Benachrichtigungen",
"other": "Andere Benachrichtigungen"
},
"options-title": "Wählen Sie aus, in welcher Kategorie Sie benachrichtigt werden möchten",
"options": {
"ASSIGN_APPROVER": "Wenn ich einem Dokument als Genehmiger zugewiesen bin",
"ASSIGN_REVIEWER": "Wenn ich einem Dokument als Überprüfer zugewiesen bin",
@ -1853,7 +1845,6 @@
"USER_PROMOTED_TO_APPROVER": "Wenn ich Genehmiger in einem Dossier werde",
"USER_REMOVED_AS_DOSSIER_MEMBER": "Wenn ich die Dossier-Mitgliedschaft verliere"
},
"options-title": "Wählen Sie aus, in welcher Kategorie Sie benachrichtigt werden möchten",
"schedule": {
"daily": "Tägliche Zusammenfassung",
"instant": "Sofortig",
@ -1861,6 +1852,13 @@
},
"title": "Benachrichtigungseinstellungen"
},
"notifications": {
"button-text": "Notifications",
"deleted-dossier": "Deleted Dossier",
"label": "Benachrichtigungen",
"mark-all-as-read": "Alle als gelesen markieren",
"mark-as": "Mark as {type, select, read{read} unread{unread} other{}}"
},
"ocr": {
"confirmation-dialog": {
"cancel": "Cancel",
@ -1952,16 +1950,16 @@
"warnings-subtitle": "Do not show again options",
"warnings-title": "Prompts and Dialogs Settings"
},
"processing": {
"basic": "Processing",
"ocr": "OCR"
},
"processing-status": {
"ocr": "OCR",
"pending": "Pending",
"processed": "Processed",
"processing": "Processing"
},
"processing": {
"basic": "Processing",
"ocr": "OCR"
},
"readonly": "Lesemodus",
"readonly-archived": "Read only (archived)",
"redact-text": {
@ -2191,12 +2189,6 @@
"red-user-admin": "Benutzer-Admin",
"regular": "Regulär"
},
"search": {
"active-dossiers": "ganze Plattform",
"all-dossiers": "all documents",
"placeholder": "Nach Dokumenten oder Dokumenteninhalt suchen",
"this-dossier": "in diesem Dossier"
},
"search-screen": {
"cols": {
"assignee": "Bevollmächtigter",
@ -2220,6 +2212,12 @@
"no-match": "Keine Dokumente entsprechen Ihren aktuellen Filtern.",
"table-header": "{length} {length, plural, one{Suchergebnis} other{Suchergebnisse}}"
},
"search": {
"active-dossiers": "ganze Plattform",
"all-dossiers": "all documents",
"placeholder": "Nach Dokumenten oder Dokumenteninhalt suchen",
"this-dossier": "in diesem Dossier"
},
"seconds": "seconds",
"size": "Size",
"smtp-auth-config": {
@ -2470,4 +2468,4 @@
}
},
"yesterday": "Gestern"
}
}

View File

@ -493,6 +493,12 @@
"title": "Confirm Action"
}
},
"component-download": {
"disabled-tooltip": "",
"json": "",
"tooltip": "",
"xml": ""
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
@ -1716,14 +1722,6 @@
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
"copyright-claim-title": "Copyright Claim",
"custom-app-title": "Custom Application Title",
"email-report": "Email Report",
"email": {
"body": {
"analyzed": "Total Analyzed Pages in current license period: {pages}.",
"licensed": "Licensed Pages: {pages}."
},
"title": "License Report {licenseCustomer}"
},
"end-user-license-text": "The use of this product is subject to the terms of the RedactManager End User License Agreement, unless otherwise specified therein.",
"end-user-license-title": "End User License Agreement",
"licensing-details": {
@ -2470,4 +2468,4 @@
}
},
"yesterday": "Yesterday"
}
}

View File

@ -493,6 +493,12 @@
"title": "Aktion bestätigen"
}
},
"component-download": {
"disabled-tooltip": "",
"json": "",
"tooltip": "",
"xml": ""
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
@ -1716,14 +1722,6 @@
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon AG (powered by IQSER)",
"copyright-claim-title": "Copyright",
"custom-app-title": "Name der Anwendung",
"email-report": "E-Mail-Bericht",
"email": {
"body": {
"analyzed": "Im aktuellen Lizenzzeitraum insgesamt analysierte Seiten: {pages}.",
"licensed": "Lizenzierte Seiten: {pages}."
},
"title": "Lizenzbericht {licenseCustomer}"
},
"end-user-license-text": "Die Nutzung dieses Produkts unterliegt den Bedingungen der Endbenutzer-Lizenzvereinbarung für den RedactManager, sofern darin nichts anderweitig festgelegt.",
"end-user-license-title": "Endbenutzer-Lizenzvereinbarung",
"licensing-details": {

View File

@ -493,6 +493,12 @@
"title": "Confirm Action"
}
},
"component-download": {
"disabled-tooltip": "You need to upload at least one file to be able to export the components as JSON or XML",
"json": "Download as JSON",
"tooltip": "Component Download",
"xml": "Download as XML"
},
"component-log-dialog": {
"actions": {
"cancel-edit": "Cancel",
@ -1716,14 +1722,6 @@
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
"copyright-claim-title": "Copyright Claim",
"custom-app-title": "Custom Application Title",
"email-report": "Email Report",
"email": {
"body": {
"analyzed": "Total Analyzed Pages in current license period: {pages}.",
"licensed": "Licensed Pages: {pages}."
},
"title": "License Report {licenseCustomer}"
},
"end-user-license-text": "The use of this product is subject to the terms of the DocuMine End User License Agreement, unless otherwise specified therein.",
"end-user-license-title": "End User License Agreement",
"licensing-details": {

@ -1 +1 @@
Subproject commit 99b2c83d61c82b058ecb664cae81463077e0aa02
Subproject commit 052bf3a5d76fa5bb1697a01a532af553c96922b1