From 7243dbe763879f11fa9901010e2c95156306ad4d Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Wed, 2 Oct 2024 17:48:46 +0200 Subject: [PATCH] replace plotTable with new bootstrap plotGrid component - helps with narrow window sizes - plotTable kept for now --- web/frontend/src/Analysis.root.svelte | 12 +- web/frontend/src/Job.root.svelte | 79 +++++----- web/frontend/src/Node.root.svelte | 6 +- web/frontend/src/Status.root.svelte | 48 +++--- web/frontend/src/Systems.root.svelte | 138 +++++++++--------- web/frontend/src/User.root.svelte | 125 ++++++++-------- web/frontend/src/analysis.entrypoint.js | 3 +- web/frontend/src/generic/PlotGrid.svelte | 60 ++++++++ .../src/generic/plots/MetricPlot.svelte | 6 +- web/frontend/src/generic/plots/Scatter.svelte | 28 ++-- web/frontend/src/generic/utils.js | 22 +-- web/frontend/src/job/Metric.svelte | 2 +- 12 files changed, 305 insertions(+), 224 deletions(-) create mode 100644 web/frontend/src/generic/PlotGrid.svelte diff --git a/web/frontend/src/Analysis.root.svelte b/web/frontend/src/Analysis.root.svelte index b210dcb..0aa7ca5 100644 --- a/web/frontend/src/Analysis.root.svelte +++ b/web/frontend/src/Analysis.root.svelte @@ -28,7 +28,7 @@ } from "./generic/utils.js"; import PlotSelection from "./analysis/PlotSelection.svelte"; import Filters from "./generic/Filters.svelte"; - import PlotTable from "./generic/PlotTable.svelte"; + import PlotGrid from "./generic/PlotGrid.svelte"; import Histogram from "./generic/plots/Histogram.svelte"; import Pie, { colors } from "./generic/plots/Pie.svelte"; import ScatterPlot from "./generic/plots/Scatter.svelte"; @@ -70,6 +70,8 @@ ...new Set([...metricsInHistograms, ...metricsInScatterplots.flat()]), ]; + $: console.log(">>> CLUSTER", cluster) + const sortOptions = [ { key: "totalWalltime", label: "Walltime" }, { key: "totalNodeHours", label: "Node Hours" }, @@ -523,7 +525,7 @@ - - +
@@ -569,7 +571,7 @@ - - + {/if} diff --git a/web/frontend/src/Job.root.svelte b/web/frontend/src/Job.root.svelte index 2827248..ca1ce9e 100644 --- a/web/frontend/src/Job.root.svelte +++ b/web/frontend/src/Job.root.svelte @@ -38,7 +38,7 @@ import JobSummary from "./job/JobSummary.svelte"; import EnergySummary from "./job/EnergySummary.svelte"; import ConcurrentJobs from "./generic/helper/ConcurrentJobs.svelte"; - import PlotTable from "./generic/PlotTable.svelte"; + import PlotGrid from "./generic/PlotGrid.svelte"; import Roofline from "./generic/plots/Roofline.svelte"; import JobInfo from "./generic/joblist/JobInfo.svelte"; import MetricSelection from "./generic/select/MetricSelection.svelte"; @@ -330,50 +330,55 @@ {/if} -
- - - {#if $jobMetrics.error} +
+ + {#if $jobMetrics.error} + + {#if $initq.data.job.monitoringStatus == 0 || $initq.data.job.monitoringStatus == 2} Not monitored or archiving failed
{/if} {$jobMetrics.error.message} - {:else if $jobMetrics.fetching} + +
+ {:else if $jobMetrics.fetching} + + - {:else if $initq?.data && $jobMetrics?.data?.jobMetrics} - + + {:else if $initq?.data && $jobMetrics?.data?.jobMetrics} + + {#if item.data} + statsTable.moreLoaded(detail)} + job={$initq.data.job} + metricName={item.metric} + metricUnit={$initq.data.globalMetrics.find((gm) => gm.name == item.metric)?.unit} + nativeScope={$initq.data.globalMetrics.find((gm) => gm.name == item.metric)?.scope} + rawData={item.data.map((x) => x.metric)} + scopes={item.data.map((x) => x.scope)} + {width} + isShared={$initq.data.job.exclusive != 1} + /> + {:else} + No dataset returned for {item.metric} - {#if item.data} - statsTable.moreLoaded(detail)} - job={$initq.data.job} - metricName={item.metric} - metricUnit={$initq.data.globalMetrics.find((gm) => gm.name == item.metric)?.unit} - nativeScope={$initq.data.globalMetrics.find((gm) => gm.name == item.metric)?.scope} - rawData={item.data.map((x) => x.metric)} - scopes={item.data.map((x) => x.scope)} - {width} - isShared={$initq.data.job.exclusive != 1} - /> - {:else} - No dataset returned for {item.metric} - {/if} - {/if} - -
+ + {/if} diff --git a/web/frontend/src/Node.root.svelte b/web/frontend/src/Node.root.svelte index 7dba330..700b1de 100644 --- a/web/frontend/src/Node.root.svelte +++ b/web/frontend/src/Node.root.svelte @@ -29,7 +29,7 @@ init, checkMetricDisabled, } from "./generic/utils.js"; - import PlotTable from "./generic/PlotTable.svelte"; + import PlotGrid from "./generic/PlotGrid.svelte"; import MetricPlot from "./generic/plots/MetricPlot.svelte"; import TimeSelection from "./generic/select/TimeSelection.svelte"; import Refresher from "./generic/helper/Refresher.svelte"; @@ -187,7 +187,7 @@ {:else if $nodeMetricsData.fetching || $initq.fetching} {:else} - No dataset returned for {item.name} {/if} - + {/if} diff --git a/web/frontend/src/Status.root.svelte b/web/frontend/src/Status.root.svelte index f995150..47a7918 100644 --- a/web/frontend/src/Status.root.svelte +++ b/web/frontend/src/Status.root.svelte @@ -32,7 +32,7 @@ transformPerNodeDataForRoofline, } from "./generic/utils.js"; import { scaleNumbers } from "./generic/units.js"; - import PlotTable from "./generic/PlotTable.svelte"; + import PlotGrid from "./generic/PlotGrid.svelte"; import Roofline from "./generic/plots/Roofline.svelte"; import Pie, { colors } from "./generic/plots/Pie.svelte"; import Histogram from "./generic/plots/Histogram.svelte"; @@ -651,31 +651,27 @@
{#if metricsInHistograms} - - - {#key $mainQuery.data.stats[0].histMetrics} - - - - {/key} - - + {#key $mainQuery.data.stats[0].histMetrics} + + + + {/key} {/if} {/if} diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index 8894fd9..ecd9a5b 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -28,7 +28,7 @@ init, checkMetricDisabled, } from "./generic/utils.js"; - import PlotTable from "./generic/PlotTable.svelte"; + import PlotGrid from "./generic/PlotGrid.svelte"; import MetricPlot from "./generic/plots/MetricPlot.svelte"; import TimeSelection from "./generic/select/TimeSelection.svelte"; import Refresher from "./generic/helper/Refresher.svelte"; @@ -160,73 +160,77 @@ {/if}
- - - {#if $nodesQuery.error} +{#if $nodesQuery.error} + + {$nodesQuery.error.message} - {:else if $nodesQuery.fetching || $initq.fetching} + + +{:else if $nodesQuery.fetching || $initq.fetching} + + - {:else} - - h.host.includes(hostnameFilter) && - h.metrics.some( - (m) => m.name == selectedMetric && m.scope == "node", - ), - ) - .map((h) => ({ - host: h.host, - subCluster: h.subCluster, - data: h.metrics.find( - (m) => m.name == selectedMetric && m.scope == "node", - ), - disabled: checkMetricDisabled( - selectedMetric, - cluster, - h.subCluster, - ), - })) - .sort((a, b) => a.host.localeCompare(b.host))} + + +{:else} + + h.host.includes(hostnameFilter) && + h.metrics.some( + (m) => m.name == selectedMetric && m.scope == "node", + ), + ) + .map((h) => ({ + host: h.host, + subCluster: h.subCluster, + data: h.metrics.find( + (m) => m.name == selectedMetric && m.scope == "node", + ), + disabled: checkMetricDisabled( + selectedMetric, + cluster, + h.subCluster, + ), + })) + .sort((a, b) => a.host.localeCompare(b.host))} + > +

+ {item.host} ({item.subCluster}) +

+ {#if item.disabled === false && item.data} + c.name == cluster)} + subCluster={item.subCluster} + forNode={true} + /> + {:else if item.disabled === true && item.data} + Metric disabled for subcluster {selectedMetric}:{item.subCluster} + {:else} + No dataset returned for {selectedMetric} -

- {item.host} ({item.subCluster}) -

- {#if item.disabled === false && item.data} - c.name == cluster)} - subCluster={item.subCluster} - forNode={true} - /> - {:else if item.disabled === true && item.data} - Metric disabled for subcluster {selectedMetric}:{item.subCluster} - {:else} - No dataset returned for {selectedMetric} - {/if} - {/if} - -
+ +{/if} diff --git a/web/frontend/src/User.root.svelte b/web/frontend/src/User.root.svelte index 61d5420..a2347df 100644 --- a/web/frontend/src/User.root.svelte +++ b/web/frontend/src/User.root.svelte @@ -30,7 +30,7 @@ } from "./generic/utils.js"; import JobList from "./generic/JobList.svelte"; import Filters from "./generic/Filters.svelte"; - import PlotTable from "./generic/PlotTable.svelte"; + import PlotGrid from "./generic/PlotGrid.svelte"; import Histogram from "./generic/plots/Histogram.svelte"; import MetricSelection from "./generic/select/MetricSelection.svelte"; import HistogramSelection from "./generic/select/HistogramSelection.svelte"; @@ -162,7 +162,7 @@
- + {#if $stats.error} {$stats.error.message} @@ -172,7 +172,7 @@ {:else} - + @@ -210,72 +210,77 @@
-
- {#key $stats.data.jobsStatistics[0].histDuration} - - {/key} -
-
- {#key $stats.data.jobsStatistics[0].histNumNodes} - - {/key} -
+ +
+ {#key $stats.data.jobsStatistics[0].histDuration} + + {/key} +
+ + +
+ {#key $stats.data.jobsStatistics[0].histNumNodes} + + {/key} +
+ {/if}
+ {#if metricsInHistograms} - - {#if $stats.error} + {#if $stats.error} + {$stats.error.message} - {:else if !$stats.data} + + {:else if !$stats.data} + - {:else} - - {#key $stats.data.jobsStatistics[0].histMetrics} - - - - {/key} - - {/if} - + + {:else} + {#key $stats.data.jobsStatistics[0].histMetrics} + + + + {/key} + {/if} {/if}
diff --git a/web/frontend/src/analysis.entrypoint.js b/web/frontend/src/analysis.entrypoint.js index d889144..07c63f5 100644 --- a/web/frontend/src/analysis.entrypoint.js +++ b/web/frontend/src/analysis.entrypoint.js @@ -6,7 +6,8 @@ filterPresets.cluster = cluster new Analysis({ target: document.getElementById('svelte-app'), props: { - filterPresets: filterPresets + filterPresets: filterPresets, + cluster: cluster }, context: new Map([ ['cc-config', clusterCockpitConfig] diff --git a/web/frontend/src/generic/PlotGrid.svelte b/web/frontend/src/generic/PlotGrid.svelte new file mode 100644 index 0000000..1c6c822 --- /dev/null +++ b/web/frontend/src/generic/PlotGrid.svelte @@ -0,0 +1,60 @@ + + + + +{#each rows as row} + + {#each row as item (item)} + +
+ {#if !isPlaceholder(item)} + + {/if} +
+ + {/each} +
+{/each} + diff --git a/web/frontend/src/generic/plots/MetricPlot.svelte b/web/frontend/src/generic/plots/MetricPlot.svelte index 7950b04..7386710 100644 --- a/web/frontend/src/generic/plots/MetricPlot.svelte +++ b/web/frontend/src/generic/plots/MetricPlot.svelte @@ -549,6 +549,10 @@ onMount(() => { if (series[0].data.length > 0) { + if (forNode) { + plotWrapper.style.paddingTop = "0.5rem" + plotWrapper.style.paddingBottom = "0.5rem" + } plotWrapper.style.backgroundColor = backgroundColor(); render(); } @@ -562,7 +566,7 @@ {#if series[0].data.length > 0} -
+
{:else} Cannot render plot: No series data returned for {metric} Math.max(maxX, x), minX); - let maxY = Y.reduce((maxY, y) => Math.max(maxY, y), minY); + let maxX = X ? X.reduce((maxX, x) => Math.max(maxX, x), minX) : 1.0; + let maxY = Y ? Y.reduce((maxY, y) => Math.max(maxY, y), minY) : 1.0; const w = width - paddingLeft - paddingRight; const h = height - paddingTop - paddingBottom; @@ -68,24 +68,26 @@ // Draw Data let size = 3 - if (S) { + if (S && X && Y) { let max = S.reduce((max, s, i) => (X[i] == null || Y[i] == null || Number.isNaN(X[i]) || Number.isNaN(Y[i])) ? max : Math.max(max, s), 0) size = (w / 15) / max } ctx.fillStyle = color; - for (let i = 0; i < X.length; i++) { - let x = X[i], y = Y[i]; - if (x == null || y == null || Number.isNaN(x) || Number.isNaN(y)) - continue; + if (X?.length > 0) { + for (let i = 0; i < X.length; i++) { + let x = X[i], y = Y[i]; + if (x == null || y == null || Number.isNaN(x) || Number.isNaN(y)) + continue; - const s = S ? S[i] * size : size; - const px = getCanvasX(x); - const py = getCanvasY(y); + const s = S ? S[i] * size : size; + const px = getCanvasX(x); + const py = getCanvasY(y); - ctx.beginPath(); - ctx.arc(px, py, s, 0, Math.PI * 2, false); - ctx.fill(); + ctx.beginPath(); + ctx.arc(px, py, s, 0, Math.PI * 2, false); + ctx.fill(); + } } // Axes diff --git a/web/frontend/src/generic/utils.js b/web/frontend/src/generic/utils.js index 8a818ab..57248fc 100644 --- a/web/frontend/src/generic/utils.js +++ b/web/frontend/src/generic/utils.js @@ -397,16 +397,18 @@ function getMetricConfigDeep(metric, cluster, subCluster) { export function convert2uplot(canvasData) { // Prep: Uplot Data Structure let uplotData = [[],[]] // [X, Y1, Y2, ...] - // Iterate - canvasData.forEach( cd => { - if (Object.keys(cd).length == 4) { // MetricHisto Datafromat - uplotData[0].push(cd?.max ? cd.max : 0) - uplotData[1].push(cd.count) - } else { // Default - uplotData[0].push(cd.value) - uplotData[1].push(cd.count) - } - }) + // Iterate if exists + if (canvasData) { + canvasData.forEach( cd => { + if (Object.keys(cd).length == 4) { // MetricHisto Datafromat + uplotData[0].push(cd?.max ? cd.max : 0) + uplotData[1].push(cd.count) + } else { // Default + uplotData[0].push(cd.value) + uplotData[1].push(cd.count) + } + }) + } return uplotData } diff --git a/web/frontend/src/job/Metric.svelte b/web/frontend/src/job/Metric.svelte index 4b4c8d0..ab1616a 100644 --- a/web/frontend/src/job/Metric.svelte +++ b/web/frontend/src/job/Metric.svelte @@ -171,7 +171,7 @@ ); - + {metricName} ({unit})