Add CalculationDumps component and API controller for dump management in Config page

This commit is contained in:
Jan 2025-12-07 20:41:27 +01:00
parent 726dfd63bd
commit f1222dc410
9 changed files with 197 additions and 35 deletions

View file

@ -66,13 +66,10 @@ export default {
<style scoped> <style scoped>
.tree-container { .tree-container {
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
overflow-y: auto; overflow-y: auto;
/* Remove any fixed height constraints */ height: 100%; /* Nimmt die volle Höhe des Parent-Containers */
min-height: fit-content; max-height: 100%; /* Verhindert Überlauf */
height: auto;
} }
.tree-container::-webkit-scrollbar { .tree-container::-webkit-scrollbar {

View file

@ -69,8 +69,6 @@ export default {
.apps-container { .apps-container {
padding: 2.4rem; padding: 2.4rem;
} }
.app-list-header { .app-list-header {

View file

@ -0,0 +1,146 @@
<template>
<div class="dump-container">
<table-view :columns="columns" :data-source="fetch" :page-size="pageSize" :page="pagination.page"
:page-count="pagination.pageCount" :total-count="pagination.totalCount" @row-click="showDump"
:mouse-over="true"></table-view>
<modal :state="showModal">
<div class="single-dump-container">
<div class="button-container">
<basic-button @click="showModal = false" :show-icon="false" variant="secondary">Close</basic-button>
</div>
<json-tree-viewer :data="dump" :all-expanded="expand"></json-tree-viewer>
</div>
</modal>
</div>
</template>
<script>
import TableView from "@/components/UI/TableView.vue";
import performRequest from "@/backend.js";
import {config} from "@/config.js";
import Modal from "@/components/UI/Modal.vue";
import JsonTreeViewer from "@/components/UI/JsonTreeViewer.vue";
import BasicButton from "@/components/UI/BasicButton.vue";
export default {
name: "CalculationDumps",
components: {BasicButton, JsonTreeViewer, Modal, TableView},
methods: {
showDump(dump) {
this.dump = dump;
this.showModal = true;
},
async fetch(query) {
const params = new URLSearchParams();
if (query?.searchTerm && query.searchTerm !== '')
params.append('filter', query.searchTerm);
if (query?.periodId)
params.append('valid', query.periodId);
if (query?.page)
params.append('page', query.page);
if (query?.pageSize)
params.append('limit', query.pageSize);
const resp = await performRequest(null, "GET", `${config.backendUrl}/dumps/dump/${params.size === 0 ? '' : '?'}${params.toString()}`, null);
this.dump = resp.data;
this.pagination = {
page: parseInt(resp.headers.get('X-Current-Page')),
pageCount: parseInt(resp.headers.get('X-Page-Count')),
totalCount: parseInt(resp.headers.get('X-Total-Count'))
};
return this.dump;
}
},
data() {
return {
showModal: false,
dump: null,
pageSize: 20,
pagination: {page: 1, pageCount: 1, totalCount: 1},
columns: [
{
key: 'id',
label: 'ID',
},
{
key: 'calculation_date',
label: 'Calculation date',
},
{
key: 'job_state',
label: 'State',
badgeResolver: (value) => {
if (value === 'VALID')
return [{text: value, variant: "primary"}];
if (value === 'EXCEPTION')
return [{text: value, variant: "exception"}]
return [{text: value, variant: "secondary"}]
}
},
{
key: 'user_id',
label: 'User ID',
},
{
key: 'premise.material.part_number',
label: 'Material',
},
{
key: 'premise.supplier.name',
label: 'Supplier',
},
{
key: 'premise.destinations',
label: 'Destinations',
formatter: (value) => {
return value.map(v => v.destination_node.name).join(', ');
}
},
],
}
}
}
</script>
<style scoped>
.button-container {
display: flex;
gap: 1rem;
}
.dump-container {
padding: 2.4rem;
}
.single-dump-container {
height: 80vh;
width: 80vw;
display: flex;
flex-direction: column;
overflow: hidden;
}
.single-dump-container > :first-child {
flex-shrink: 0; /* Button behält seine Größe */
}
.single-dump-container > :last-child {
flex: 1;
min-height: 0; /* Wichtig für Flex-Children mit overflow */
overflow-y: auto;
}
</style>

View file

@ -35,7 +35,7 @@ export default {
components: {Box, BasicButton, ToggleSwitch, JsonTreeViewer}, components: {Box, BasicButton, ToggleSwitch, JsonTreeViewer},
async created() { async created() {
const resp = await performRequest(null, "GET", `${config.backendUrl}/dev/dump/${this.$route.params.id}`, null); const resp = await performRequest(null, "GET", `${config.backendUrl}/dumps/dump/${this.$route.params.id}`, null);
this.dump = resp.data; this.dump = resp.data;
}, },

View file

@ -36,7 +36,7 @@ export default {
if(query?.pageSize) if(query?.pageSize)
params.append('limit', query.pageSize); params.append('limit', query.pageSize);
const resp = await performRequest(null, "GET", `${config.backendUrl}/dev/dump/${params.size === 0 ? '' : '?'}${params.toString()}`, null); const resp = await performRequest(null, "GET", `${config.backendUrl}/dumps/dump/${params.size === 0 ? '' : '?'}${params.toString()}`, null);
this.dump = resp.data; this.dump = resp.data;
this.pagination = { page: parseInt(resp.headers.get('X-Current-Page')), pageCount: parseInt(resp.headers.get('X-Page-Count')), totalCount: parseInt(resp.headers.get('X-Total-Count'))}; this.pagination = { page: parseInt(resp.headers.get('X-Current-Page')), pageCount: parseInt(resp.headers.get('X-Page-Count')), totalCount: parseInt(resp.headers.get('X-Total-Count'))};
@ -92,4 +92,5 @@ export default {
<style scoped> <style scoped>
</style> </style>

View file

@ -30,6 +30,7 @@ import {useActiveUserStore} from "@/store/activeuser.js";
import Apps from "@/components/layout/config/Apps.vue"; import Apps from "@/components/layout/config/Apps.vue";
import Users from "@/components/layout/config/Users.vue"; import Users from "@/components/layout/config/Users.vue";
import CalculationDumpList from "@/components/layout/dev/CalculationDumpList.vue"; import CalculationDumpList from "@/components/layout/dev/CalculationDumpList.vue";
import CalculationDumps from "@/components/layout/config/CalculationDumps.vue";
export default { export default {
name: "Config", name: "Config",
@ -59,7 +60,7 @@ export default {
}, },
calculationDump: { calculationDump: {
title: 'Calculation dump', title: 'Calculation dump',
component: markRaw(CalculationDumpList), component: markRaw(CalculationDumps),
props: {isSelected: false}, props: {isSelected: false},
}, },
materialsTab: { materialsTab: {

View file

@ -109,6 +109,7 @@ const router = createRouter({
}, },
{ {
path: '/config', path: '/config',
name: 'config',
component: Config, component: Config,
beforeEnter: async (to, from) => { beforeEnter: async (to, from) => {
const userStore = useActiveUserStore(); const userStore = useActiveUserStore();
@ -121,7 +122,7 @@ const router = createRouter({
}, },
}, },
{ {
path: '/dev/dump/:id', path: '/dumps/dump/:id',
component: CalculationDump, component: CalculationDump,
name: 'dev-calculation-dump' name: 'dev-calculation-dump'

View file

@ -0,0 +1,40 @@
package de.avatic.lcc.controller.configuration;
import de.avatic.lcc.dto.error.CalculationJobDumpDTO;
import de.avatic.lcc.repositories.error.DumpRepository;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import jakarta.validation.constraints.Min;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/dumps")
public class CalculationDumpController {
private final DumpRepository dumpRepository;
public CalculationDumpController(DumpRepository dumpRepository) {
this.dumpRepository = dumpRepository;
}
@GetMapping({"/dump/{id}", "/dump/{id}/"})
public ResponseEntity<CalculationJobDumpDTO> getDump(@PathVariable Integer id) {
return ResponseEntity.ok(dumpRepository.getDump(id));
}
@GetMapping({"/dump/", "/dump"})
public ResponseEntity<List<CalculationJobDumpDTO>> listDumps(
@RequestParam(defaultValue = "20") @Min(1) int limit,
@RequestParam(defaultValue = "1") @Min(1) int page) {
var dump = dumpRepository.listDumps(new SearchQueryPagination(page, limit));
return ResponseEntity.ok()
.header("X-Total-Count", String.valueOf(dump.getTotalElements()))
.header("X-Page-Count", String.valueOf(dump.getTotalPages()))
.header("X-Current-Page", String.valueOf(page))
.body(dump.toList());
}
}

View file

@ -1,7 +1,6 @@
package de.avatic.lcc.controller.dev; package de.avatic.lcc.controller.dev;
import de.avatic.lcc.config.filter.DevUserEmulationFilter; import de.avatic.lcc.config.filter.DevUserEmulationFilter;
import de.avatic.lcc.dto.error.CalculationJobDumpDTO;
import de.avatic.lcc.dto.users.UserDTO; import de.avatic.lcc.dto.users.UserDTO;
import de.avatic.lcc.repositories.error.DumpRepository; import de.avatic.lcc.repositories.error.DumpRepository;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination; import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
@ -21,36 +20,15 @@ import java.util.List;
@RequestMapping({"/api/dev", "/api/dev/"}) @RequestMapping({"/api/dev", "/api/dev/"})
public class DevController { public class DevController {
private final DumpRepository dumpRepository;
private final UserRepository userRepository; private final UserRepository userRepository;
private final UserTransformer userTransformer; private final UserTransformer userTransformer;
public DevController(DumpRepository dumpRepository, UserRepository userRepository, UserTransformer userTransformer) { public DevController(UserRepository userRepository, UserTransformer userTransformer) {
this.dumpRepository = dumpRepository;
this.userRepository = userRepository; this.userRepository = userRepository;
this.userTransformer = userTransformer; this.userTransformer = userTransformer;
} }
@GetMapping({"/dump/{id}", "/dump/{id}/"})
public ResponseEntity<CalculationJobDumpDTO> getDump(@PathVariable Integer id) {
return ResponseEntity.ok(dumpRepository.getDump(id));
}
@GetMapping({"/dump/", "/dump"})
public ResponseEntity<List<CalculationJobDumpDTO>> listDumps(
@RequestParam(defaultValue = "20") @Min(1) int limit,
@RequestParam(defaultValue = "1") @Min(1) int page) {
var dump = dumpRepository.listDumps(new SearchQueryPagination(page, limit));
return ResponseEntity.ok()
.header("X-Total-Count", String.valueOf(dump.getTotalElements()))
.header("X-Page-Count", String.valueOf(dump.getTotalPages()))
.header("X-Current-Page", String.valueOf(page))
.body(dump.toList());
}
@GetMapping({"/user"}) @GetMapping({"/user"})
public ResponseEntity<List<UserDTO>> listUser(@RequestParam(defaultValue = "20") @Min(1) int limit, public ResponseEntity<List<UserDTO>> listUser(@RequestParam(defaultValue = "20") @Min(1) int limit,
@RequestParam(defaultValue = "1") @Min(1) int page) { @RequestParam(defaultValue = "1") @Min(1) int page) {