From f471214ef7d087682b377ebf18a39df0bcc84ef8 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Thu, 12 Jun 2025 16:23:31 +0200 Subject: [PATCH] migrate system view, node list and node overview --- web/frontend/src/Systems.root.svelte | 167 ++++++++-------- web/frontend/src/systems.entrypoint.js | 4 +- web/frontend/src/systems/NodeList.svelte | 193 +++++++++++-------- web/frontend/src/systems/NodeOverview.svelte | 183 +++++++++--------- 4 files changed, 290 insertions(+), 257 deletions(-) diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index 83abdaa..9c12aed 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -28,72 +28,74 @@ import TimeSelection from "./generic/select/TimeSelection.svelte"; import Refresher from "./generic/helper/Refresher.svelte"; - export let displayType; - export let cluster = null; - export let subCluster = null; - export let from = null; - export let to = null; - - const { query: initq } = init(); - - console.assert( - displayType == "OVERVIEW" || displayType == "LIST", - "Invalid nodes displayType provided!", - ); - - if (from == null || to == null) { - to = new Date(Date.now()); - from = new Date(to.getTime()); - from.setHours(from.getHours() - 12); - } - - const initialized = getContext("initialized"); - const ccconfig = getContext("cc-config"); - const globalMetrics = getContext("globalMetrics"); - const displayNodeOverview = (displayType === 'OVERVIEW') - - const resampleConfig = getContext("resampling") || null; - const resampleResolutions = resampleConfig ? [...resampleConfig.resolutions] : []; - const resampleDefault = resampleConfig ? Math.max(...resampleConfig.resolutions) : 0; - let selectedResolution = resampleConfig ? resampleDefault : 0; - - let hostnameFilter = ""; - let pendingHostnameFilter = ""; - let selectedMetric = ccconfig.system_view_selectedMetric || ""; - let selectedMetrics = ( - ccconfig[`node_list_selectedMetrics:${cluster}:${subCluster}`] || - ccconfig[`node_list_selectedMetrics:${cluster}`] - ) || [ccconfig.system_view_selectedMetric]; - let isMetricsSelectionOpen = false; - /* Note 1: "Sorting" as use-case ignored for now, probably default to alphanumerical on hostnames of cluster (handled in frontend at the moment) Note 2: Add Idle State Filter (== No allocated Jobs) [Frontend?] : Cannot be handled by CCMS, requires secondary job query and refiltering of visible nodes */ - let systemMetrics = []; - let systemUnits = {}; + /* Scelte 5 Props */ + let { + displayType, + cluster = null, + subCluster = null, + fromPreset = null, + toPreset = null, + } = $props(); - function loadMetrics(isInitialized) { - if (!isInitialized) return - systemMetrics = [...globalMetrics.filter((gm) => gm?.availability.find((av) => av.cluster == cluster))] - for (let sm of systemMetrics) { - systemUnits[sm.name] = (sm?.unit?.prefix ? sm.unit.prefix : "") + (sm?.unit?.base ? sm.unit.base : "") - } - if (!selectedMetric) selectedMetric = systemMetrics[0].name - } + /* Const Init */ + const { query: initq } = init(); + const displayNodeOverview = (displayType === 'OVERVIEW'); + const ccconfig = getContext("cc-config"); + const initialized = getContext("initialized"); + const globalMetrics = getContext("globalMetrics"); + const resampleConfig = getContext("resampling") || null; - $: loadMetrics($initialized) + const resampleResolutions = resampleConfig ? [...resampleConfig.resolutions] : []; + const resampleDefault = resampleConfig ? Math.max(...resampleConfig.resolutions) : 0; + const nowDate = new Date(Date.now()); - $: if (displayNodeOverview) { - selectedMetrics = [selectedMetric] - } + /* State Init */ + let to = $state(toPreset || new Date(Date.now())); + let from = $state(fromPreset || new Date(nowDate.setHours(nowDate.getHours() - 12))); + let selectedResolution = $state(resampleConfig ? resampleDefault : 0); + let hostnameFilter = $state(""); + let pendingHostnameFilter = $state(""); + let isMetricsSelectionOpen = $state(false); + let selectedMetric = $state(ccconfig.system_view_selectedMetric || ""); + let selectedMetrics = $state(( + ccconfig[`node_list_selectedMetrics:${cluster}:${subCluster}`] || + ccconfig[`node_list_selectedMetrics:${cluster}`] + ) || [ccconfig.system_view_selectedMetric]); - $: { // Wait after input for some time to prevent too many requests - setTimeout(function () { + /* Derived States */ + const systemMetrics = $derived($initialized ? [...globalMetrics.filter((gm) => gm?.availability.find((av) => av.cluster == cluster))] : []); + const presetSystemUnits = $derived(loadUnits(systemMetrics)); + + /* Effects */ + $effect(() => { + // OnMount: Ping Var, without this, OVERVIEW metric select is empty (reason tbd) + systemMetrics + }); + + /* Functions */ + function loadUnits(systemMetrics) { + let pendingUnits = {}; + if (systemMetrics.length > 0) { + for (let sm of systemMetrics) { + pendingUnits[sm.name] = (sm?.unit?.prefix ? sm.unit.prefix : "") + (sm?.unit?.base ? sm.unit.base : "") + }; + }; + return {...pendingUnits}; + }; + + // Wait after input for some time to prevent too many requests + let timeoutId = null; + function updateHostnameFilter() { + if (timeoutId != null) clearTimeout(timeoutId); + timeoutId = setTimeout(function () { hostnameFilter = pendingHostnameFilter; }, 500); - } + }; @@ -108,7 +110,7 @@ @@ -139,6 +141,7 @@ placeholder="Filter hostname ..." type="text" bind:value={pendingHostnameFilter} + oninput={updateHostnameFilter} /> @@ -153,26 +156,28 @@ Metric - {#each systemMetrics as metric} + {#each systemMetrics as metric (metric.name)} {metric.name} {presetSystemUnits[metric.name] ? "("+presetSystemUnits[metric.name]+")" : ""} + {:else} + {/each} {/if} - - - { - const diff = Date.now() - to; - from = new Date(from.getTime() + diff); - to = new Date(to.getTime() + diff); - }} - /> - {/if} + + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + @@ -185,20 +190,22 @@ {:else} {#if displayNodeOverview} - + {:else} - + {/if} {/if} - - selectedMetrics = [...newMetrics] - } -/> +{#if !displayNodeOverview} + + selectedMetrics = [...newMetrics] + } + /> +{/if} diff --git a/web/frontend/src/systems.entrypoint.js b/web/frontend/src/systems.entrypoint.js index 2976b7d..8d5fd41 100644 --- a/web/frontend/src/systems.entrypoint.js +++ b/web/frontend/src/systems.entrypoint.js @@ -8,8 +8,8 @@ mount(Systems, { displayType: displayType, cluster: infos.cluster, subCluster: infos.subCluster, - from: infos.from, - to: infos.to + fromPreset: infos.from, + toPreset: infos.to }, context: new Map([ ['cc-config', clusterCockpitConfig], diff --git a/web/frontend/src/systems/NodeList.svelte b/web/frontend/src/systems/NodeList.svelte index c8a5e51..bcdd293 100644 --- a/web/frontend/src/systems/NodeList.svelte +++ b/web/frontend/src/systems/NodeList.svelte @@ -10,38 +10,28 @@ --> @@ -192,7 +216,7 @@ scope="col" style="padding-top: {headerPaddingTop}px" > - {metric} ({systemUnits[metric]}) + {metric} ({presetSystemUnits[metric]}) {/each} @@ -212,7 +236,7 @@ No nodes found {/each} - {/if} + {/if} {#if $nodesQuery.fetching || !$nodesQuery.data} @@ -244,10 +268,11 @@ totalItems={matchedNodes} on:update-paging={({ detail }) => { if (detail.itemsPerPage != itemsPerPage) { - updateConfiguration(detail.itemsPerPage.toString(), detail.page); + updateConfiguration(detail.itemsPerPage, detail.page); } else { - nodes = [] - paging = { itemsPerPage: detail.itemsPerPage, page: detail.page }; + nodes = []; + itemsPerPage = detail.itemsPerPage; + page = detail.page; } }} /> diff --git a/web/frontend/src/systems/NodeOverview.svelte b/web/frontend/src/systems/NodeOverview.svelte index 68ccd78..2e7ae3c 100644 --- a/web/frontend/src/systems/NodeOverview.svelte +++ b/web/frontend/src/systems/NodeOverview.svelte @@ -10,101 +10,99 @@ @@ -132,22 +130,25 @@ >{item.host} ({item.subCluster}) - {#if item?.disabled[selectedMetric]} + {#if item?.disabled} Metric disabled for subcluster {selectedMetric}:{item.subCluster} {:else} - - + + + {#key item.data[0].metric.series[0].data.length} + + {/key} {/if} {/each}