Query fixes: stale widget fix, multiple series colors mismatch (#3126)

- Fix for series color assignment being out of sync with the graph
(ensures added series colors match their graph representation)
- Reload widgets when returning to screen if props changed (prevents
stale widgets after filtering and scrolling)
This commit is contained in:
Matt Aitken
2026-02-25 15:50:17 +00:00
committed by GitHub
parent c05b30adfe
commit e9fb8e3b52
3 changed files with 17 additions and 5 deletions
@@ -0,0 +1,6 @@
---
area: webapp
type: fix
---
Fix metrics dashboard chart series colors going out of sync and widgets not reloading stale data when scrolled back into view
@@ -889,13 +889,15 @@ export const QueryResultsChart = memo(function QueryResultsChart({
const cfg: ChartConfig = {};
sortedSeries.forEach((s, i) => {
const statusColor = groupByIsRunStatus ? getRunStatusHexColor(s) : undefined;
const originalIndex = config.yAxisColumns.indexOf(s);
const colorIndex = originalIndex >= 0 ? originalIndex : i;
cfg[s] = {
label: s,
color: statusColor ?? config.seriesColors?.[s] ?? getSeriesColor(i),
color: statusColor ?? config.seriesColors?.[s] ?? getSeriesColor(colorIndex),
};
});
return cfg;
}, [sortedSeries, groupByIsRunStatus, config.seriesColors]);
}, [sortedSeries, groupByIsRunStatus, config.seriesColors, config.yAxisColumns]);
// Custom tooltip label formatter for better date display
const tooltipLabelFormatter = useMemo(() => {
+7 -3
View File
@@ -173,6 +173,7 @@ export function MetricWidget({
const [response, setResponse] = useState<MetricWidgetActionResponse | null>(null);
const [isLoading, setIsLoading] = useState(false);
const abortControllerRef = useRef<AbortController | null>(null);
const isDirtyRef = useRef(false);
// Track the latest props so the submit callback always uses fresh values
// without needing to be recreated (which would cause useInterval to re-register listeners).
@@ -180,8 +181,11 @@ export function MetricWidget({
propsRef.current = props;
const submit = useCallback(() => {
// Skip fetching if the widget is not visible on screen
if (!isVisibleRef.current) return;
if (!isVisibleRef.current) {
isDirtyRef.current = true;
return;
}
isDirtyRef.current = false;
// Abort any in-flight request for this widget
abortControllerRef.current?.abort();
@@ -225,7 +229,7 @@ export function MetricWidget({
// When a widget scrolls into view and has no data yet, trigger a load.
const { ref: visibilityRef, isVisibleRef } = useElementVisibility({
onVisibilityChange: (visible) => {
if (visible && !response) {
if (visible && (!response || isDirtyRef.current)) {
submit();
}
},