diff --git a/src/frontend/src/backend.js b/src/frontend/src/backend.js
index 5f77966..f1d1007 100644
--- a/src/frontend/src/backend.js
+++ b/src/frontend/src/backend.js
@@ -29,13 +29,24 @@ const performDownload = async (url, expectResponse = true, expectedException = n
method: 'GET',
};
- const request = {url: url, params: params, expectResponse: expectResponse, expectedException: expectedException};
+ const request = {url: url, params: params, expectResponse: expectResponse, expectedException: expectedException, type: 'blob'};
logger.info("Request:", request);
- const processId = await executeRequest(null, request);
+ const blob = await executeRequest(null, request);
- logger.info("Response:", processId);
- return processId;
+
+ const downloadUrl = window.URL.createObjectURL(blob);
+
+ // Create temporary link element and trigger download
+ const link = document.createElement('a');
+ link.href = downloadUrl;
+ link.download = `export.xlsx`; // or get filename from response headers
+ document.body.appendChild(link);
+ link.click();
+
+ // Clean up
+ document.body.removeChild(link);
+ window.URL.revokeObjectURL(downloadUrl);
}
const performUpload = async (url, file, expectResponse = true, expectedException = null) => {
@@ -95,7 +106,14 @@ const executeRequest = async (requestingStore, request) => {
let data = null;
if (request.expectResponse) {
- data = await response.json().catch(e => {
+ try {
+ if (request.type === 'blob' && response.ok) {
+ data = await response.blob();
+ } else {
+ data = await response.json();
+ }
+
+ } catch (e) {
const error = {
code: 'Malformed response',
message: "Malformed server response. Please contact support.",
@@ -106,7 +124,7 @@ const executeRequest = async (requestingStore, request) => {
const errorStore = useErrorStore();
void errorStore.addError(error, {store: requestingStore, request: request});
throw e;
- });
+ }
if (!response.ok) {
handleErrorResponse(data, requestingStore, request);
diff --git a/src/frontend/src/components/layout/config/BulkOperations.vue b/src/frontend/src/components/layout/config/BulkOperations.vue
index 5fa2fc8..d274548 100644
--- a/src/frontend/src/components/layout/config/BulkOperations.vue
+++ b/src/frontend/src/components/layout/config/BulkOperations.vue
@@ -8,8 +8,8 @@
type
- empty template
- full data export
+ empty template
+ full data export
dataset
@@ -83,7 +83,7 @@ export default {
components: {RadioOption, BasicButton, Box},
data() {
return {
- exportType: "empty",
+ exportType: "templates",
exportDataset: "NODE",
importDataset: "NODE",
importType: "APPEND",
@@ -95,8 +95,8 @@ export default {
},
methods: {
async downloadFile() {
- const url = `${config.backendUrl}/bulk/upload/${this.exportDataset}/${this.exportType}/`
+ const url = `${config.backendUrl}/bulk/${this.exportType}/${this.exportDataset}/`
this.processId = await performDownload(url);
},
inputFile(event) {
diff --git a/src/main/java/de/avatic/lcc/controller/bulk/BulkOperationController.java b/src/main/java/de/avatic/lcc/controller/bulk/BulkOperationController.java
index 3073d32..60b7bc5 100644
--- a/src/main/java/de/avatic/lcc/controller/bulk/BulkOperationController.java
+++ b/src/main/java/de/avatic/lcc/controller/bulk/BulkOperationController.java
@@ -41,7 +41,7 @@ public class BulkOperationController {
* @param id The unique identifier of the operation (processing_id) to check its status.
* @return A ResponseEntity with the bulk processing status payload.
*/
- @GetMapping("/status/{processing_id}")
+ @GetMapping({"/status/{processing_id}","/status/{processing_id}/"})
public ResponseEntity getUploadStatus(@PathVariable("processing_id") Integer id) {
return ResponseEntity.ok(bulkProcessingService.getStatus(id));
}
@@ -68,7 +68,7 @@ public class BulkOperationController {
* specifying it as a downloadable file.
* @throws IllegalArgumentException if the file type is invalid.
*/
- @GetMapping("/templates/{type}")
+ @GetMapping({"/templates/{type}","/templates/{type}/"})
public ResponseEntity generateTemplate(@PathVariable BulkFileType type) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=lcc_template_" + type.name().toLowerCase() + ".xlsx");
@@ -88,7 +88,7 @@ public class BulkOperationController {
* The file is served as an Excel document, with proper headers for download.
* @throws IllegalArgumentException if the provided file type is not supported.
*/
- @GetMapping("/download/{type}")
+ @GetMapping({"/download/{type}", "/download/{type}/"})
public ResponseEntity downloadFile(@PathVariable BulkFileType type) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=lcc_export_" + type.name().toLowerCase() + ".xlsx");
@@ -109,7 +109,7 @@ public class BulkOperationController {
* The file is served as an Excel document, with appropriate headers for download.
* @throws IllegalArgumentException if the file type or validity period ID is invalid.
*/
- @GetMapping("/download/{type}/{validity_period_id}")
+ @GetMapping({"/download/{type}/{validity_period_id}","/download/{type}/{validity_period_id}/"})
public ResponseEntity downloadFile(@PathVariable BulkFileType type, @PathVariable("validity_period_id") Integer validityPeriodId) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=lcc_export_" + type.name().toLowerCase() + ".xlsx");