migrate system view, node list and node overview

This commit is contained in:
Christoph Kluge
2025-06-12 16:23:31 +02:00
parent a0190f8f40
commit f471214ef7
4 changed files with 290 additions and 257 deletions

View File

@@ -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);
}
};
</script>
<!-- ROW1: Tools-->
@@ -108,7 +110,7 @@
<Button
outline
color="primary"
on:click={() => (isMetricsSelectionOpen = true)}
onclick={() => (isMetricsSelectionOpen = true)}
>
{selectedMetrics.length} selected
</Button>
@@ -139,6 +141,7 @@
placeholder="Filter hostname ..."
type="text"
bind:value={pendingHostnameFilter}
oninput={updateHostnameFilter}
/>
</InputGroup>
</Col>
@@ -153,26 +156,28 @@
<InputGroupText><Icon name="graph-up" /></InputGroupText>
<InputGroupText>Metric</InputGroupText>
<Input type="select" bind:value={selectedMetric}>
{#each systemMetrics as metric}
{#each systemMetrics as metric (metric.name)}
<option value={metric.name}
>{metric.name} {systemUnits[metric.name] ? "("+systemUnits[metric.name]+")" : ""}</option
>{metric.name} {presetSystemUnits[metric.name] ? "("+presetSystemUnits[metric.name]+")" : ""}</option
>
{:else}
<option disabled>No available options</option>
{/each}
</Input>
</InputGroup>
</Col>
{/if}
<!-- Refresh Col-->
<Col class="mt-2 mt-lg-0">
<Refresher
onRefresh={() => {
const diff = Date.now() - to;
from = new Date(from.getTime() + diff);
to = new Date(to.getTime() + diff);
}}
/>
</Col>
{/if}
<!-- Refresh Col-->
<Col class="mt-2 mt-lg-0">
<Refresher
onRefresh={() => {
const diff = Date.now() - to;
from = new Date(from.getTime() + diff);
to = new Date(to.getTime() + diff);
}}
/>
</Col>
</Row>
<!-- ROW2: Content-->
@@ -185,20 +190,22 @@
{:else}
{#if displayNodeOverview}
<!-- ROW2-1: Node Overview (Grid Included)-->
<NodeOverview {cluster} {subCluster} {ccconfig} {selectedMetrics} {from} {to} {hostnameFilter}/>
<NodeOverview {cluster} {ccconfig} {selectedMetric} {from} {to} {hostnameFilter}/>
{:else}
<!-- ROW2-2: Node List (Grid Included)-->
<NodeList {cluster} {subCluster} {ccconfig} {selectedMetrics} {selectedResolution} {hostnameFilter} {from} {to} {systemUnits}/>
<NodeList {cluster} {subCluster} {ccconfig} {selectedMetrics} {selectedResolution} {hostnameFilter} {from} {to} {presetSystemUnits}/>
{/if}
{/if}
<MetricSelection
bind:isOpen={isMetricsSelectionOpen}
presetMetrics={selectedMetrics}
{cluster}
{subCluster}
configName="node_list_selectedMetrics"
applyMetrics={(newMetrics) =>
selectedMetrics = [...newMetrics]
}
/>
{#if !displayNodeOverview}
<MetricSelection
bind:isOpen={isMetricsSelectionOpen}
presetMetrics={selectedMetrics}
{cluster}
{subCluster}
configName="node_list_selectedMetrics"
applyMetrics={(newMetrics) =>
selectedMetrics = [...newMetrics]
}
/>
{/if}