From 8ed5b944ad4ff0429da320b38642e8d552706444 Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Fri, 9 Jan 2026 10:38:30 +0100 Subject: fix: possible sorting errors in bar chart (#241) --- .../etl/processor/web/StatisticsRestController.kt | 39 ++++++++++-------- src/web/charts.js | 48 +++++++++++++++------- src/web/main.js | 4 +- 3 files changed, 58 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/main/kotlin/dev/dnpm/etl/processor/web/StatisticsRestController.kt b/src/main/kotlin/dev/dnpm/etl/processor/web/StatisticsRestController.kt index c99a4a3..27cc3dc 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/web/StatisticsRestController.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/web/StatisticsRestController.kt @@ -1,7 +1,8 @@ /* * This file is part of ETL-Processor * - * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken + * Copyright (c) 2023-2026 Paul-Christian Volkmer, Datenintegrationszentrum Philipps-Universität Marburg and Contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -19,6 +20,8 @@ package dev.dnpm.etl.processor.web +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonPropertyOrder import dev.dnpm.etl.processor.monitoring.RequestStatus import dev.dnpm.etl.processor.monitoring.RequestType import dev.dnpm.etl.processor.services.RequestService @@ -43,6 +46,15 @@ class StatisticsRestController( private val statisticsUpdateProducer: Sinks.Many, private val requestService: RequestService, ) { + private fun statusColor(status: RequestStatus) = + when (status) { + RequestStatus.ERROR -> "#FF0000" + RequestStatus.WARNING -> "#FF8C00" + RequestStatus.SUCCESS -> "#008000" + RequestStatus.NO_CONSENT -> "#004A9D" + else -> "#708090" + } + @GetMapping(path = ["requeststates"]) fun requestStates( @RequestParam(required = false, defaultValue = "false") delete: Boolean, @@ -56,14 +68,7 @@ class StatisticsRestController( return states .map { - val color = - when (it.status) { - RequestStatus.ERROR -> "red" - RequestStatus.WARNING -> "darkorange" - RequestStatus.SUCCESS -> "green" - else -> "slategray" - } - NameValue(it.status.toString(), it.count, color) + NameValue(it.status.toString(), it.count, statusColor(it.status)) }.sortedByDescending { it.value } } @@ -99,7 +104,9 @@ class StatisticsRestController( error = requestList[RequestStatus.ERROR] ?: 0, warning = requestList[RequestStatus.WARNING] ?: 0, success = requestList[RequestStatus.SUCCESS] ?: 0, + noConsent = requestList[RequestStatus.NO_CONSENT] ?: 0, duplication = requestList[RequestStatus.DUPLICATION] ?: 0, + blockedInitial = requestList[RequestStatus.BLOCKED_INITIAL] ?: 0, unknown = requestList[RequestStatus.UNKNOWN] ?: 0, ), ), @@ -125,14 +132,7 @@ class StatisticsRestController( } return states.map { - val color = - when (it.status) { - RequestStatus.ERROR -> "red" - RequestStatus.WARNING -> "darkorange" - RequestStatus.SUCCESS -> "green" - else -> "slategray" - } - NameValue(it.status.toString(), it.count, color) + NameValue(it.status.toString(), it.count, statusColor(it.status)) } } @@ -199,10 +199,15 @@ data class DateNameValues( val nameValues: NameValues, ) +@JsonPropertyOrder(value = ["error", "warning", "success", "no_consent", "duplication", "blocked_initial", "unknown"]) data class NameValues( val error: Int = 0, val warning: Int = 0, val success: Int = 0, + @field:JsonProperty("no_consent") + val noConsent: Int = 0, val duplication: Int = 0, + @field:JsonProperty("blocked_initial") + val blockedInitial: Int = 0, val unknown: Int = 0, ) diff --git a/src/web/charts.js b/src/web/charts.js index 4826696..866e60d 100644 --- a/src/web/charts.js +++ b/src/web/charts.js @@ -58,13 +58,13 @@ export function drawPieChart(url, elemId, title, data) { } else { fetch(url) .then(resp => resp.json()) - .then(d => { - draw(elemId, title, d); - update(elemId, d); + .then(data => { + draw(elemId, title, data); + update(elemId, data); }); } - function update(elemId, data) { + const update = (elemId, data) => { let chartDom = document.getElementById(elemId); let chart = echarts.init(chartDom, null, {renderer: 'svg'}); @@ -92,7 +92,7 @@ export function drawPieChart(url, elemId, title, data) { option && chart.setOption(option); } - function draw(elemId, title, data) { + const draw = (elemId, title, data) => { let chartDom = document.getElementById(elemId); let chart = echarts.init(chartDom, null, {renderer: 'svg'}); let option= { @@ -124,18 +124,12 @@ export function drawBarChart(url, elemId, title, data) { }); } - function update(elemId, data) { + const update = (elemId, data) => { let chartDom = document.getElementById(elemId); let chart = echarts.init(chartDom, null, {renderer: 'svg'}); let option = { series: [ - { - name: 'UNKNOWN', - type: 'bar', - stack: 'total', - data: data.map(i => i.nameValues.unknown) - }, { name: 'ERROR', type: 'bar', @@ -154,11 +148,29 @@ export function drawBarChart(url, elemId, title, data) { stack: 'total', data: data.map(i => i.nameValues.success) }, + { + name: 'NO_CONSENT', + type: 'bar', + stack: 'total', + data: data.map(i => i.nameValues.no_consent) + }, { name: 'DUPLICATION', type: 'bar', stack: 'total', data: data.map(i => i.nameValues.duplication) + }, + { + name: 'BLOCKED_INITIAL', + type: 'bar', + stack: 'total', + data: data.map(i => i.nameValues.blocked_initial) + }, + { + name: 'UNKNOWN', + type: 'bar', + stack: 'total', + data: data.map(i => i.nameValues.unknown) } ] }; @@ -166,7 +178,7 @@ export function drawBarChart(url, elemId, title, data) { option && chart.setOption(option); } - function draw(elemId, title, data) { + const draw = (elemId, title, data) => { let chartDom = document.getElementById(elemId); let chart = echarts.init(chartDom, null, {renderer: 'svg'}); let option= { @@ -185,7 +197,15 @@ export function drawBarChart(url, elemId, title, data) { tooltip: { trigger: 'item' }, - color: ['slategray', 'red', 'darkorange', 'green', 'slategray'], + color: [ + '#FF0000', + '#FF8C00', + '#008000', + '#004A9D', + '#708090', + '#708090', + '#708090' + ], animationDuration: 250, animationDurationUpdate: 250 }; diff --git a/src/web/main.js b/src/web/main.js index ca1ecc9..b72396a 100644 --- a/src/web/main.js +++ b/src/web/main.js @@ -1,4 +1,4 @@ -import * as styles from './style.css'; +import './style.css'; import 'htmx.org'; @@ -8,7 +8,7 @@ const dateTimeFormat = new Intl.DateTimeFormat('de-DE', dateTimeFormatOptions); const formatTimeElements = () => { Array.from(document.getElementsByTagName('time')).forEach((timeTag) => { let date = Date.parse(timeTag.getAttribute('datetime')); - if (! isNaN(date)) { + if (! Number.isNaN(date)) { timeTag.innerText = dateTimeFormat.format(date); } }); -- cgit v1.2.3