BACKEND: fixed near_by routing bug
FRONTEND: added bulk menu
This commit is contained in:
parent
02249d2da4
commit
a2822666a6
8 changed files with 358 additions and 75 deletions
|
|
@ -14,10 +14,71 @@ const performRequest = async (requestingStore, method, url, body, expectResponse
|
||||||
params.body = JSON.stringify(body);
|
params.body = JSON.stringify(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
const request = {url: url, params: params};
|
const request = {url: url, params: params, expectResponse: expectResponse, expectedException: expectedException};
|
||||||
logger.info("Request:", request);
|
logger.info("Request:", request);
|
||||||
|
|
||||||
const response = await fetch(url, params
|
const data = await executeRequest(requestingStore, request);
|
||||||
|
|
||||||
|
logger.info("Response:", data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const performDownload = async (requestingStore, url, expectResponse = true, expectedException = null) => {
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
method: 'GET',
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = {url: url, params: params, expectResponse: expectResponse, expectedException: expectedException};
|
||||||
|
logger.info("Request:", request);
|
||||||
|
|
||||||
|
const processId = await executeRequest(null, request);
|
||||||
|
|
||||||
|
logger.info("Response:", processId);
|
||||||
|
return processId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const performUpload = async (url, file, expectResponse = true, expectedException = null) => {
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = {url: url, params: params, expectResponse: expectResponse, expectedException: expectedException};
|
||||||
|
logger.info("Request:", request);
|
||||||
|
|
||||||
|
const processId = await executeRequest(null, request);
|
||||||
|
|
||||||
|
logger.info("Response:", processId);
|
||||||
|
return processId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleErrorResponse(data, requestingStore, request) {
|
||||||
|
const errorObj = {
|
||||||
|
code: data.error.code,
|
||||||
|
title: data.error.title,
|
||||||
|
message: data.error.message,
|
||||||
|
trace: data.error.trace
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = new Error('Internal backend error');
|
||||||
|
error.errorObj = errorObj;
|
||||||
|
|
||||||
|
if (request.expectedException === null || data.error.title !== request.expectedException) {
|
||||||
|
logger.error(errorObj);
|
||||||
|
const errorStore = useErrorStore();
|
||||||
|
void errorStore.addError(errorObj, {store: requestingStore, request: request});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const executeRequest = async (requestingStore, request) => {
|
||||||
|
const response = await fetch(request.url, request.params
|
||||||
).catch(e => {
|
).catch(e => {
|
||||||
const error = {
|
const error = {
|
||||||
code: 'Network error.',
|
code: 'Network error.',
|
||||||
|
|
@ -33,7 +94,7 @@ const performRequest = async (requestingStore, method, url, body, expectResponse
|
||||||
});
|
});
|
||||||
|
|
||||||
let data = null;
|
let data = null;
|
||||||
if (expectResponse) {
|
if (request.expectResponse) {
|
||||||
data = await response.json().catch(e => {
|
data = await response.json().catch(e => {
|
||||||
const error = {
|
const error = {
|
||||||
code: 'Malformed response',
|
code: 'Malformed response',
|
||||||
|
|
@ -48,23 +109,7 @@ const performRequest = async (requestingStore, method, url, body, expectResponse
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorObj = {
|
handleErrorResponse(data, requestingStore, request);
|
||||||
code: data.error.code,
|
|
||||||
title: data.error.title,
|
|
||||||
message: data.error.message,
|
|
||||||
trace: data.error.trace
|
|
||||||
}
|
|
||||||
|
|
||||||
const error = new Error('Internal backend error');
|
|
||||||
error.errorObj = errorObj;
|
|
||||||
|
|
||||||
if (expectedException === null || data.error.title !== expectedException) {
|
|
||||||
logger.error(errorObj);
|
|
||||||
const errorStore = useErrorStore();
|
|
||||||
void errorStore.addError(errorObj, {store: requestingStore, request: request});
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
@ -82,28 +127,12 @@ const performRequest = async (requestingStore, method, url, body, expectResponse
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const errorObj = {
|
handleErrorResponse(data, requestingStore, request);
|
||||||
code: data.error.code,
|
|
||||||
title: data.error.title,
|
|
||||||
message: data.error.message,
|
|
||||||
trace: data.error.trace
|
|
||||||
}
|
|
||||||
|
|
||||||
const error = new Error('Internal backend error');
|
|
||||||
error.errorObj = errorObj;
|
|
||||||
|
|
||||||
if (expectedException === null || data.error.title !== expectedException) {
|
|
||||||
logger.error(errorObj);
|
|
||||||
const errorStore = useErrorStore();
|
|
||||||
void errorStore.addError(errorObj, {store: requestingStore, request: request});
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Response:", data);
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default performRequest;
|
export default performRequest;
|
||||||
|
export {performUpload, performDownload};
|
||||||
|
|
|
||||||
227
src/frontend/src/components/layout/config/BulkOperations.vue
Normal file
227
src/frontend/src/components/layout/config/BulkOperations.vue
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="bulk-operations-container">
|
||||||
|
|
||||||
|
<box variant="border" class="bulk-operations-box-container">
|
||||||
|
<div class="bulk-operations-sub-container">
|
||||||
|
|
||||||
|
<div class="bulk-operation-header">Export</div>
|
||||||
|
<div class="bulk-operation-caption">type</div>
|
||||||
|
<div class="bulk-operation-data">
|
||||||
|
<radio-option name="export-type" value="empty" v-model="exportType">empty template</radio-option>
|
||||||
|
<radio-option name="export-type" value="full" v-model="exportType">full data export</radio-option>
|
||||||
|
</div>
|
||||||
|
<div class="bulk-operation-caption">dataset</div>
|
||||||
|
<div class="bulk-operation-data">
|
||||||
|
<radio-option name="export-dataset" value="NODE" v-model="exportDataset">nodes</radio-option>
|
||||||
|
<radio-option name="export-dataset" value="COUNTRY_MATRIX" v-model="exportDataset">kilometer rates</radio-option>
|
||||||
|
<radio-option name="export-dataset" value="CONTAINER_RATE" v-model="exportDataset">container rates</radio-option>
|
||||||
|
<radio-option name="export-dataset" value="MATERIAL" v-model="exportDataset">materials</radio-option>
|
||||||
|
<radio-option name="export-dataset" value="PACKAGING" v-model="exportDataset">packaging</radio-option>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bulk-operation-action-footer">
|
||||||
|
<basic-button @click="downloadFile" icon="download">Export</basic-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</box>
|
||||||
|
|
||||||
|
<box variant="border" class="bulk-operations-box-container">
|
||||||
|
<div class="bulk-operations-sub-container">
|
||||||
|
|
||||||
|
<div class="bulk-operation-header">Import</div>
|
||||||
|
<div class="bulk-operation-caption">dataset</div>
|
||||||
|
<div class="bulk-operation-data">
|
||||||
|
<radio-option name="import-dataset" value="NODE" v-model="importDataset">nodes</radio-option>
|
||||||
|
<radio-option name="import-dataset" value="COUNTRY_MATRIX" v-model="importDataset">kilometer rates</radio-option>
|
||||||
|
<radio-option name="import-dataset" value="CONTAINER_RATE" v-model="importDataset">container rates</radio-option>
|
||||||
|
<radio-option name="import-dataset" value="MATERIAL" v-model="importDataset">materials</radio-option>
|
||||||
|
<radio-option name="import-dataset" value="PACKAGING" v-model="importDataset">packaging</radio-option>
|
||||||
|
</div>
|
||||||
|
<div class="bulk-operation-caption">import mode</div>
|
||||||
|
<div class="bulk-operation-data">
|
||||||
|
<radio-option name="import-type" value="APPEND" v-model="importType">append existing data</radio-option>
|
||||||
|
<radio-option name="import-type" value="FULL" v-model="importType">fully replace data</radio-option>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bulk-operation-caption">file</div>
|
||||||
|
<div class="bulk-operation-data">
|
||||||
|
<div class="file-input-container">
|
||||||
|
<label for="upload" class="file-button-label">
|
||||||
|
Choose file
|
||||||
|
</label>
|
||||||
|
<input @change="inputFile" class="file-select-button" type="file" id="upload" name="upload" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="selectedFile" class="selected-file" v-if="selectedFileName">{{ selectedFileName }}</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bulk-operation-action-footer">
|
||||||
|
<basic-button @click="uploadFile" icon="upload" :disabled="!selectedFile">Import</basic-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</box>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import Box from "@/components/UI/Box.vue";
|
||||||
|
import BasicButton from "@/components/UI/BasicButton.vue";
|
||||||
|
import RadioOption from "@/components/UI/RadioOption.vue";
|
||||||
|
import performRequest, {performUpload, performDownload} from "@/backend.js";
|
||||||
|
import {config} from "@/config.js";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "BulkOperations",
|
||||||
|
components: {RadioOption, BasicButton, Box},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
exportType: "empty",
|
||||||
|
exportDataset: "NODE",
|
||||||
|
importDataset: "NODE",
|
||||||
|
importType: "APPEND",
|
||||||
|
selectedFileName: null,
|
||||||
|
selectedFile: null,
|
||||||
|
uploading: false,
|
||||||
|
processId: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async downloadFile() {
|
||||||
|
const url = `${config.backendUrl}/bulk/upload/${this.exportDataset}/${this.exportType}/`
|
||||||
|
this.processId = await performDownload(url);
|
||||||
|
},
|
||||||
|
inputFile(event) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
this.selectedFile = file;
|
||||||
|
this.selectedFileName = file.name;
|
||||||
|
} else {
|
||||||
|
this.selectedFile = null;
|
||||||
|
this.selectedFileName = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async uploadFile() {
|
||||||
|
if (!this.selectedFile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const url = `${config.backendUrl}/bulk/upload/${this.importDataset}/${this.importType}/`
|
||||||
|
this.processId = await performUpload(url, this.selectedFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.bulk-operations-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk-operations-box-container {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk-operations-sub-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
row-gap: 3.2rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk-operation-header {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk-operation-action-footer {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
justify-self: end;
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk-operation-caption {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #6B869C;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bulk-operation-data {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.2rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* File input styling */
|
||||||
|
.file-input-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-select-button {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-button-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.2rem;
|
||||||
|
padding: 0.6rem 1.2rem;
|
||||||
|
border: 0.2rem solid transparent;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
outline: none;
|
||||||
|
user-select: none;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
|
background-color: #002F54;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-button-label:hover {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #002F54;
|
||||||
|
border-color: #002F54;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon for file upload */
|
||||||
|
.upload-icon {
|
||||||
|
width: 1.6rem;
|
||||||
|
height: 1.6rem;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Selected file display */
|
||||||
|
.selected-file {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #c3cfdf;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #002F54;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<template>
|
|
||||||
<h3>Bulk Operations</h3>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "BulkUpload"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
@ -22,6 +22,7 @@ import Properties from "@/components/layout/config/Properties.vue";
|
||||||
import Box from "@/components/UI/Box.vue";
|
import Box from "@/components/UI/Box.vue";
|
||||||
import CountryProperties from "@/components/layout/config/CountryProperties.vue";
|
import CountryProperties from "@/components/layout/config/CountryProperties.vue";
|
||||||
import StagedChanges from "@/components/layout/config/StagedChanges.vue";
|
import StagedChanges from "@/components/layout/config/StagedChanges.vue";
|
||||||
|
import BulkOperations from "@/components/layout/config/BulkOperations.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Config",
|
name: "Config",
|
||||||
|
|
@ -38,25 +39,9 @@ export default {
|
||||||
title: 'Countries',
|
title: 'Countries',
|
||||||
component: markRaw(CountryProperties),
|
component: markRaw(CountryProperties),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Nodes',
|
|
||||||
component: (null),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Kilometer rates',
|
|
||||||
component: (null),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Container rates',
|
|
||||||
component: (null),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Materials & packaging',
|
|
||||||
component: (null),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Bulk operations',
|
title: 'Bulk operations',
|
||||||
component: (null),
|
component: markRaw(BulkOperations),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="showComparableWarning && hasReport" class="destination-differ-warning">
|
||||||
|
<ph-warning size="18px"></ph-warning>
|
||||||
|
Reports may not be comparable! Calculations differ in destinations and/or their annual quantities.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="loading" class="report-spinner-container">
|
<div v-if="loading" class="report-spinner-container">
|
||||||
<div class="report-spinner">
|
<div class="report-spinner">
|
||||||
<spinner></spinner>
|
<spinner></spinner>
|
||||||
|
|
@ -54,6 +59,9 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useReportsStore),
|
...mapStores(useReportsStore),
|
||||||
|
showComparableWarning() {
|
||||||
|
return this.reportsStore.getShowComparableWarning;
|
||||||
|
},
|
||||||
hasReport() {
|
hasReport() {
|
||||||
return this.reportsStore.reports?.length > 0;
|
return this.reportsStore.reports?.length > 0;
|
||||||
},
|
},
|
||||||
|
|
@ -160,4 +168,17 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.destination-differ-warning {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
gap: 1.6rem;
|
||||||
|
background-color: #c3cfdf;
|
||||||
|
color: #002F54;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
padding: 1.6rem;
|
||||||
|
margin-bottom: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -7,10 +7,14 @@ export const useReportsStore = defineStore('reports', {
|
||||||
state() {
|
state() {
|
||||||
return {
|
return {
|
||||||
reports: [],
|
reports: [],
|
||||||
|
showComparableWarning: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
getShowComparableWarning(state) {
|
||||||
|
return state.showComparableWarning;
|
||||||
|
},
|
||||||
getChartScale(state) {
|
getChartScale(state) {
|
||||||
let max = 0;
|
let max = 0;
|
||||||
|
|
||||||
|
|
@ -25,7 +29,7 @@ export const useReportsStore = defineStore('reports', {
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
reset() {
|
reset() {
|
||||||
this.reports = [];
|
this.reports = [];
|
||||||
},
|
},
|
||||||
async fetchReports(materialId, supplierIds) {
|
async fetchReports(materialId, supplierIds) {
|
||||||
if (supplierIds == null || materialId == null) return;
|
if (supplierIds == null || materialId == null) return;
|
||||||
|
|
@ -39,10 +43,42 @@ export const useReportsStore = defineStore('reports', {
|
||||||
|
|
||||||
const url = `${config.backendUrl}/reports/view/${params.size === 0 ? '' : '?'}${params.toString()}`;
|
const url = `${config.backendUrl}/reports/view/${params.size === 0 ? '' : '?'}${params.toString()}`;
|
||||||
|
|
||||||
this.reports = await performRequest(this,'GET', url, null).catch(e => {
|
this.reports = await performRequest(this, 'GET', url, null).catch(e => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
this.showComparableWarning = false;
|
||||||
|
for (const [idx, report] of this.reports.entries()) {
|
||||||
|
for (const otherReport of this.reports.slice(idx + 1)) {
|
||||||
|
if (report.premises.length !== otherReport.premises.length) {
|
||||||
|
this.showComparableWarning = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const premise of report.premises) {
|
||||||
|
|
||||||
|
const otherPremise = otherReport.premises.find(otherPremise => otherPremise.destination.external_mapping_id === premise.destination.external_mapping_id);
|
||||||
|
|
||||||
|
if((otherPremise ?? null) == null) {
|
||||||
|
this.showComparableWarning = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(otherPremise.annual_quantity !== premise.annual_quantity) {
|
||||||
|
this.showComparableWarning = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.showComparableWarning)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ public class BulkOperationController {
|
||||||
* @param file The file to be uploaded, provided as a multipart file.
|
* @param file The file to be uploaded, provided as a multipart file.
|
||||||
* @return A ResponseEntity indicating whether the upload was processed successfully.
|
* @return A ResponseEntity indicating whether the upload was processed successfully.
|
||||||
*/
|
*/
|
||||||
@PostMapping("/upload/{type}/{processing_type}")
|
@PostMapping({"/upload/{type}/{processing_type}","/upload/{type}/{processing_type}/"})
|
||||||
public ResponseEntity<Integer> uploadFile(@PathVariable("processing_type") BulkProcessingType processingType, @PathVariable BulkFileType type, @RequestParam("file") MultipartFile file) {
|
public ResponseEntity<Integer> uploadFile(@PathVariable("processing_type") BulkProcessingType processingType, @PathVariable BulkFileType type, @RequestParam("file") MultipartFile file) {
|
||||||
return ResponseEntity.ok(bulkProcessingService.processFile(type, processingType, file));
|
return ResponseEntity.ok(bulkProcessingService.processFile(type, processingType, file));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ public class RouteRepository {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if(1 < route.size())
|
if(1 < route.size())
|
||||||
TODO throw something */
|
throw new DatabaseException("Multiple selected routes for destination with id " + id);
|
||||||
|
|
||||||
|
|
||||||
return Optional.of(route.getFirst());
|
return Optional.of(route.getFirst());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue