From 35c0b0be58599abc88903adafe87fe1fcf77bb1d Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Mon, 21 Jul 2025 16:03:07 +0200 Subject: [PATCH] add scheduler and health status pie charts --- internal/repository/node.go | 6 ++ web/frontend/src/status/DevelDash.svelte | 127 ++++++++++++++++++++++- 2 files changed, 130 insertions(+), 3 deletions(-) diff --git a/internal/repository/node.go b/internal/repository/node.go index 277c1c5..d7db2f4 100644 --- a/internal/repository/node.go +++ b/internal/repository/node.go @@ -321,6 +321,9 @@ func (r *NodeRepository) CountNodeStates(ctx context.Context, filters []*model.N } } + // Add Group and Order + query = query.GroupBy("state").OrderBy("count DESC") + rows, err := query.RunWith(r.stmtCache).Query() if err != nil { queryString, queryVars, _ := query.ToSql() @@ -367,6 +370,9 @@ func (r *NodeRepository) CountHealthStates(ctx context.Context, filters []*model } } + // Add Group and Order + query = query.GroupBy("state").OrderBy("count DESC") + rows, err := query.RunWith(r.stmtCache).Query() if err != nil { queryString, queryVars, _ := query.ToSql() diff --git a/web/frontend/src/status/DevelDash.svelte b/web/frontend/src/status/DevelDash.svelte index 5ac1326..f37976b 100644 --- a/web/frontend/src/status/DevelDash.svelte +++ b/web/frontend/src/status/DevelDash.svelte @@ -9,6 +9,8 @@ import { Row, Col, + Table, + Icon } from "@sveltestrap/sveltestrap"; import { queryStore, @@ -18,8 +20,9 @@ import { init, } from "../generic/utils.js"; - import Roofline from "../generic/plots/Roofline.svelte"; + //import Roofline from "../generic/plots/Roofline.svelte"; import NewBubbleRoofline from "../generic/plots/NewBubbleRoofline.svelte"; + import Pie, { colors } from "../generic/plots/Pie.svelte"; /* Svelte 5 Props */ let { @@ -34,8 +37,10 @@ let from = $state(new Date(Date.now() - 5 * 60 * 1000)); let to = $state(new Date(Date.now())); let plotWidths = $state([]); - let nodesCounts = $state({}); - let jobsJounts = $state({}); + let statesWidth = $state(0); + let healthWidth = $state(0); + // let nodesCounts = $state({}); + // let jobsJounts = $state({}); /* Derived */ // Note: nodeMetrics are requested on configured $timestep resolution @@ -183,6 +188,33 @@ }, })); + // Accumulated NodeStates for Piecharts + const nodesStateCounts = $derived(queryStore({ + client: client, + query: gql` + query ($filter: [NodeFilter!]) { + nodeStates(filter: $filter) { + state + count + } + } + `, + variables: { + filter: { cluster: { eq: cluster }} + }, + })); + + $inspect($nodesStateCounts?.data?.nodeStates) + + const refinedStateData = $derived.by(() => { + return $nodesStateCounts?.data?.nodeStates.filter((e) => ['allocated', 'reserved', 'idle', 'mixed','down', 'unknown'].includes(e.state)) + }); + + const refinedHealthData = $derived.by(() => { + return $nodesStateCounts?.data?.nodeStates.filter((e) => ['full', 'partial', 'failed'].includes(e.state)) + }); + + /* Function */ function transformJobsStatsToData(subclusterData) { /* c will contain values from 0 to 1 representing the duration */ @@ -339,3 +371,92 @@ {/each} {/if} + +
+
+ +{#if $initq.data && $nodesStateCounts.data} + + + Node State +
+ {#key refinedStateData} + Total: {refinedStateData.reduce((sum, item) => { + return sum + item.count; + }, 0)} Nodes + + sd.count, + )} + entities={refinedStateData.map( + (sd) => sd.state, + )} + /> + {/key} +
+ + + {#key refinedStateData} + + + + + + + {#each refinedStateData as sd, i} + + + + + + {/each} +
LegendCurrent State#Nodes
{sd.state}{sd.count}
+ {/key} + + + + Node Health +
+ {#key refinedHealthData} + Total: {refinedStateData.reduce((sum, item) => { + return sum + item.count; + }, 0)} Nodes + + sd.count, + )} + entities={refinedHealthData.map( + (sd) => sd.state, + )} + /> + {/key} +
+ + + {#key refinedHealthData} + + + + + + + {#each refinedHealthData as hd, i} + + + + + + {/each} +
LegendCurrent Health#Nodes
{hd.state}{hd.count}
+ {/key} + +
+{/if}