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}
+
+
+ Legend |
+ Current State |
+ #Nodes |
+
+ {#each refinedStateData as sd, i}
+
+ |
+ {sd.state} |
+ {sd.count} |
+
+ {/each}
+
+ {/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}
+
+
+ Legend |
+ Current Health |
+ #Nodes |
+
+ {#each refinedHealthData as hd, i}
+
+ |
+ {hd.state} |
+ {hd.count} |
+
+ {/each}
+
+ {/key}
+
+
+{/if}