From 2cbe8e9517b4deb42484a22d10291966bdcbdf4e Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Fri, 11 Oct 2024 12:30:55 +0200 Subject: [PATCH 01/34] Split systems view into node-overview and node-list --- internal/routerConfig/routes.go | 35 +- web/frontend/src/Header.svelte | 2 +- web/frontend/src/Systems.root.svelte | 230 ++----------- web/frontend/src/header/NavbarLinks.svelte | 96 ++++-- web/frontend/src/systems.entrypoint.js | 1 + web/frontend/src/systems/NodeList.svelte | 322 ++++++++++++++++++ web/frontend/src/systems/NodeOverview.svelte | 232 +++++++++++++ .../src/systems/nodelist/NodeInfo.svelte | 152 +++++++++ .../src/systems/nodelist/NodeListRow.svelte | 207 +++++++++++ web/templates/monitoring/systems.tmpl | 1 + 10 files changed, 1032 insertions(+), 246 deletions(-) create mode 100644 web/frontend/src/systems/NodeList.svelte create mode 100644 web/frontend/src/systems/NodeOverview.svelte create mode 100644 web/frontend/src/systems/nodelist/NodeInfo.svelte create mode 100644 web/frontend/src/systems/nodelist/NodeListRow.svelte diff --git a/internal/routerConfig/routes.go b/internal/routerConfig/routes.go index 05b316d..e6cb376 100644 --- a/internal/routerConfig/routes.go +++ b/internal/routerConfig/routes.go @@ -42,10 +42,11 @@ var routes []Route = []Route{ {"/monitoring/projects/", "monitoring/list.tmpl", "Projects - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { i["listType"] = "PROJECT"; return i }}, {"/monitoring/tags/", "monitoring/taglist.tmpl", "Tags - ClusterCockpit", false, setupTaglistRoute}, {"/monitoring/user/{id}", "monitoring/user.tmpl", "User - ClusterCockpit", true, setupUserRoute}, - {"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster - ClusterCockpit", false, setupClusterRoute}, + {"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster Overview - ClusterCockpit", false, setupClusterOverviewRoute}, + {"/monitoring/systems/list/{cluster}", "monitoring/systems.tmpl", "Cluster List - ClusterCockpit", false, setupClusterListRoute}, {"/monitoring/node/{cluster}/{hostname}", "monitoring/node.tmpl", "Node - ClusterCockpit", false, setupNodeRoute}, {"/monitoring/analysis/{cluster}", "monitoring/analysis.tmpl", "Analysis - ClusterCockpit", true, setupAnalysisRoute}, - {"/monitoring/status/{cluster}", "monitoring/status.tmpl", "Status of - ClusterCockpit", false, setupClusterRoute}, + {"/monitoring/status/{cluster}", "monitoring/status.tmpl", "Status of - ClusterCockpit", false, setupClusterStatusRoute}, } func setupHomeRoute(i InfoType, r *http.Request) InfoType { @@ -96,7 +97,7 @@ func setupUserRoute(i InfoType, r *http.Request) InfoType { return i } -func setupClusterRoute(i InfoType, r *http.Request) InfoType { +func setupClusterStatusRoute(i InfoType, r *http.Request) InfoType { vars := mux.Vars(r) i["id"] = vars["cluster"] i["cluster"] = vars["cluster"] @@ -108,6 +109,34 @@ func setupClusterRoute(i InfoType, r *http.Request) InfoType { return i } +func setupClusterOverviewRoute(i InfoType, r *http.Request) InfoType { + vars := mux.Vars(r) + i["id"] = vars["cluster"] + i["cluster"] = vars["cluster"] + i["displayType"] = "OVERVIEW" + + from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to") + if from != "" || to != "" { + i["from"] = from + i["to"] = to + } + return i +} + +func setupClusterListRoute(i InfoType, r *http.Request) InfoType { + vars := mux.Vars(r) + i["id"] = vars["cluster"] + i["cluster"] = vars["cluster"] + i["displayType"] = "LIST" + + from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to") + if from != "" || to != "" { + i["from"] = from + i["to"] = to + } + return i +} + func setupNodeRoute(i InfoType, r *http.Request) InfoType { vars := mux.Vars(r) i["cluster"] = vars["cluster"] diff --git a/web/frontend/src/Header.svelte b/web/frontend/src/Header.svelte index 9b12403..9a7ae79 100644 --- a/web/frontend/src/Header.svelte +++ b/web/frontend/src/Header.svelte @@ -97,7 +97,7 @@ href: "/monitoring/systems/", icon: "hdd-rack", perCluster: true, - listOptions: false, + listOptions: true, menu: "Info", }, { diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index 488cdad..baef2d0 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -1,232 +1,44 @@ - - {#if $initq.error} - {$initq.error.message} - {:else if $initq.fetching} - - {:else} - - - - - Find Node - - - - - - - - - - - - Metric - - - - - - { - const diff = Date.now() - to; - from = new Date(from.getTime() + diff); - to = new Date(to.getTime() + diff); - }} - /> - - {/if} - -
-{#if $nodesQuery.error} - - - {$nodesQuery.error.message} - - -{:else if $nodesQuery.fetching || $initq.fetching} - - - - - +{#if displayType === 'OVERVIEW'} + +{:else if displayType === 'LIST'} + {: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} - {/if} -
+ + + + Unknown displayList type! + + + {/if} diff --git a/web/frontend/src/header/NavbarLinks.svelte b/web/frontend/src/header/NavbarLinks.svelte index c99f35d..2772eb7 100644 --- a/web/frontend/src/header/NavbarLinks.svelte +++ b/web/frontend/src/header/NavbarLinks.svelte @@ -24,39 +24,69 @@ {#each links as item} {#if item.listOptions} - - - - {item.title} - - - - All Clusters - - - {#each clusters as cluster} - - - {cluster.name} - - - - Running Jobs - - - - {/each} - - + {#if item.title === 'Nodes'} + + + + {item.title} + + + {#each clusters as cluster} + + + {cluster.name} + + + + Node Overview + + + Node List + + + + {/each} + + + {:else} + + + + {item.title} + + + + All Clusters + + + {#each clusters as cluster} + + + {cluster.name} + + + + Running Jobs + + + + {/each} + + + {/if} {:else if !item.perCluster} {item.title} + + + + +
+ + + + + {#if showFootprint} + + {/if} + {#each metrics as metric (metric)} + + {/each} + + + + {#if $jobsStore.error} + + + + {:else} + {#each jobs as job (job)} + + {:else} + + + + {/each} + {/if} + {#if $jobsStore.fetching || !$jobsStore.data} + + + + {/if} + +
+ Job Info + + Job Footprint + + {metric} + {#if $initialized} + ({getUnit(metric)}) + {/if} +
+

{$jobsStore.error.message}

+
No jobs found
+
+ +
+
+
+
+ +{#if usePaging} + { + if (detail.itemsPerPage != itemsPerPage) { + updateConfiguration(detail.itemsPerPage.toString(), detail.page); + } else { + jobs = [] + paging = { itemsPerPage: detail.itemsPerPage, page: detail.page }; + } + }} + /> +{/if} + + diff --git a/web/frontend/src/systems/NodeOverview.svelte b/web/frontend/src/systems/NodeOverview.svelte new file mode 100644 index 0000000..b5d1d0b --- /dev/null +++ b/web/frontend/src/systems/NodeOverview.svelte @@ -0,0 +1,232 @@ + + + + + + {#if $initq.error} + {$initq.error.message} + {:else if $initq.fetching} + + {:else} + + + + + Find Node + + + + + + + + + + + + Metric + + + + + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + + {/if} + +
+{#if $nodesQuery.error} + + + {$nodesQuery.error.message} + + +{: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))} + > +

+ {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} diff --git a/web/frontend/src/systems/nodelist/NodeInfo.svelte b/web/frontend/src/systems/nodelist/NodeInfo.svelte new file mode 100644 index 0000000..0aee223 --- /dev/null +++ b/web/frontend/src/systems/nodelist/NodeInfo.svelte @@ -0,0 +1,152 @@ + + + + +
+

+ {job.jobId} + ({job.cluster}) + {#if job.metaData?.jobName} +
+ {#if job.metaData?.jobName.length <= 25} +

{job.metaData.jobName}
+ {:else} +
+ {job.metaData.jobName} +
+ {/if} + {/if} + {#if job.arrayJobId} + Array Job: #{job.arrayJobId} + {/if} +

+ +

+ + + {scrambleNames ? scramble(job.user) : job.user} + + {#if job.userData && job.userData.name} + ({scrambleNames ? scramble(job.userData.name) : job.userData.name}) + {/if} + {#if job.project && job.project != "no project"} +
+ + + {scrambleNames ? scramble(job.project) : job.project} + + {/if} +

+ +

+ {#if job.numNodes == 1} + {job.resources[0].hostname} + {:else} + {job.numNodes} + {/if} + + {#if job.exclusive != 1} + (shared) + {/if} + {#if job.numAcc > 0} + , {job.numAcc} + {/if} + {#if job.numHWThreads > 0} + , {job.numHWThreads} + {/if} +
+ {job.subCluster} +

+ +

+ Start: {new Date(job.startTime).toLocaleString()} +
+ Duration: {formatDuration(job.duration)} + {job.state} + {#if job.walltime} +
+ Walltime: {formatDuration(job.walltime)} + {/if} +

+ + {#if showTagedit} +
+

+ : + {#if jobTags?.length > 0} + {#each jobTags as tag} + + {/each} + {:else} + No Tags + {/if} +

+ {:else} +

+ {#each jobTags as tag} + + {/each} +

+ {/if} +
+ + diff --git a/web/frontend/src/systems/nodelist/NodeListRow.svelte b/web/frontend/src/systems/nodelist/NodeListRow.svelte new file mode 100644 index 0000000..1832a94 --- /dev/null +++ b/web/frontend/src/systems/nodelist/NodeListRow.svelte @@ -0,0 +1,207 @@ + + + + + + + + + {#if job.monitoringStatus == 0 || job.monitoringStatus == 2} + + Not monitored or archiving failed + + {:else if $metricsQuery.fetching} + + + + {:else if $metricsQuery.error} + + + {$metricsQuery.error.message.length > 500 + ? $metricsQuery.error.message.substring(0, 499) + "..." + : $metricsQuery.error.message} + + + {:else} + {#if showFootprint} + + + + {/if} + {#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)} + + + {#if metric.disabled == false && metric.data} + { handleZoom(detail, metric.data.name) }} + height={plotHeight} + timestep={metric.data.metric.timestep} + scope={metric.data.scope} + series={metric.data.metric.series} + statisticsSeries={metric.data.metric.statisticsSeries} + metric={metric.data.name} + {cluster} + subCluster={job.subCluster} + isShared={job.exclusive != 1} + numhwthreads={job.numHWThreads} + numaccs={job.numAcc} + zoomState={zoomStates[metric.data.name] || null} + /> + {:else if metric.disabled == true && metric.data} + Metric disabled for subcluster {metric.data.name}:{job.subCluster} + {:else} + No dataset returned + {/if} + + {/each} + {/if} + diff --git a/web/templates/monitoring/systems.tmpl b/web/templates/monitoring/systems.tmpl index 27bbf64..635bf46 100644 --- a/web/templates/monitoring/systems.tmpl +++ b/web/templates/monitoring/systems.tmpl @@ -7,6 +7,7 @@ {{end}} {{define "javascript"}} From 2f6e5a7648c61bf24f2e3b5c92e5684fc8e24513 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Mon, 14 Oct 2024 11:55:59 +0200 Subject: [PATCH 02/34] Move common logic into systems view again - adds backend log if subcluster for node not configured --- internal/graph/schema.resolvers.go | 7 +- web/frontend/src/Systems.root.svelte | 245 +++++++++++++++- web/frontend/src/generic/PlotGrid.svelte | 4 +- .../src/generic/plots/MetricPlot.svelte | 2 +- web/frontend/src/generic/utils.js | 15 +- web/frontend/src/systems/NodeList.svelte | 271 ++++-------------- web/frontend/src/systems/NodeOverview.svelte | 243 +++------------- .../src/systems/nodelist/NodeInfo.svelte | 2 +- .../src/systems/nodelist/NodeListRow.svelte | 6 +- 9 files changed, 350 insertions(+), 445 deletions(-) diff --git a/internal/graph/schema.resolvers.go b/internal/graph/schema.resolvers.go index 58d664b..73090a8 100644 --- a/internal/graph/schema.resolvers.go +++ b/internal/graph/schema.resolvers.go @@ -438,7 +438,7 @@ func (r *queryResolver) NodeMetrics(ctx context.Context, cluster string, nodes [ data, err := metricDataDispatcher.LoadNodeData(cluster, metrics, nodes, scopes, from, to, ctx) if err != nil { - log.Warn("Error while loading node data") + log.Warn("error while loading node data") return nil, err } @@ -448,7 +448,10 @@ func (r *queryResolver) NodeMetrics(ctx context.Context, cluster string, nodes [ Host: hostname, Metrics: make([]*model.JobMetricWithName, 0, len(metrics)*len(scopes)), } - host.SubCluster, _ = archive.GetSubClusterByNode(cluster, hostname) + host.SubCluster, err = archive.GetSubClusterByNode(cluster, hostname) + if err != nil { + log.Warnf("error in nodeMetrics resolver: %s", err) + } for metric, scopedMetrics := range metrics { for _, scopedMetric := range scopedMetrics { diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index baef2d0..8ff25c8 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -9,36 +9,259 @@ --> -{#if displayType === 'OVERVIEW'} - -{:else if displayType === 'LIST'} - -{:else} - - - - Unknown displayList type! - - + + + {#if $initq.data} + + {#if !displayNodeOverview} + + + + Metrics + + + + {/if} + + + + + Find Node(s) + + + + + + + + + {#if displayNodeOverview} + + + + Metric + + {#each systemMetrics as metric} + + {/each} + + + + {/if} + + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + + {/if} + + +{#if displayType !== "OVERVIEW" && displayType !== "LIST"} + + + Unknown displayList type! + + +{:else if $nodesQuery.error} + + + {$nodesQuery.error.message} + + +{:else if $nodesQuery.fetching } + + + + + +{:else if $initialized && $nodesQuery?.data} + {#if displayNodeOverview} + + + + {:else} + + + + + + + + + {/if} {/if} diff --git a/web/frontend/src/generic/PlotGrid.svelte b/web/frontend/src/generic/PlotGrid.svelte index 3bbee55..a56ffef 100644 --- a/web/frontend/src/generic/PlotGrid.svelte +++ b/web/frontend/src/generic/PlotGrid.svelte @@ -22,10 +22,10 @@ function tile(items, itemsPerRow) { const rows = [] - for (let ri = 0; ri < items.length; ri += itemsPerRow) { + for (let ri = 0; ri < items?.length; ri += itemsPerRow) { const row = [] for (let ci = 0; ci < itemsPerRow; ci += 1) { - if (ri + ci < items.length) + if (ri + ci < items?.length) row.push(items[ri + ci]) else row.push({ _is_placeholder: true, ri, ci }) diff --git a/web/frontend/src/generic/plots/MetricPlot.svelte b/web/frontend/src/generic/plots/MetricPlot.svelte index 09f313c..bf3dd45 100644 --- a/web/frontend/src/generic/plots/MetricPlot.svelte +++ b/web/frontend/src/generic/plots/MetricPlot.svelte @@ -227,7 +227,7 @@ function update(u) { const { left, top } = u.cursor; - const width = u.over.querySelector(".u-legend").offsetWidth; + const width = u?.over?.querySelector(".u-legend")?.offsetWidth ? u.over.querySelector(".u-legend").offsetWidth : 0; legendEl.style.transform = "translate(" + (left - width - 15) + "px, " + (top + 15) + "px)"; } diff --git a/web/frontend/src/generic/utils.js b/web/frontend/src/generic/utils.js index 57248fc..0e06c0f 100644 --- a/web/frontend/src/generic/utils.js +++ b/web/frontend/src/generic/utils.js @@ -303,8 +303,19 @@ export function stickyHeader(datatableHeaderSelector, updatePading) { export function checkMetricDisabled(m, c, s) { // [m]etric, [c]luster, [s]ubcluster const metrics = getContext("globalMetrics"); - const result = metrics?.find((gm) => gm.name === m)?.availability?.find((av) => av.cluster === c)?.subClusters?.includes(s) - return !result + const available = metrics?.find((gm) => gm.name === m)?.availability?.find((av) => av.cluster === c)?.subClusters?.includes(s) + // Return inverse logic + return !available +} + +export function checkMetricsDisabled(ma, c, s) { // [m]etric[a]rray, [c]luster, [s]ubcluster + let result = {}; + const metrics = getContext("globalMetrics"); + ma.forEach((m) => { + // Return named inverse logic: !available + result[m] = !(metrics?.find((gm) => gm.name === m)?.availability?.find((av) => av.cluster === c)?.subClusters?.includes(s)) + }); + return result } export function getStatsItems() { diff --git a/web/frontend/src/systems/NodeList.svelte b/web/frontend/src/systems/NodeList.svelte index a5538e9..935a068 100644 --- a/web/frontend/src/systems/NodeList.svelte +++ b/web/frontend/src/systems/NodeList.svelte @@ -1,5 +1,10 @@ -
+
- {#if showFootprint} - - {/if} - {#each metrics as metric (metric)} + + {#each selectedMetrics as metric (metric)} {/each} - {#if $jobsStore.error} - - - + {#each nodes as node (node)} + {node} + {:else} - {#each jobs as job (job)} - - {:else} - - - - {/each} - {/if} - {#if $jobsStore.fetching || !$jobsStore.data} - + - {/if} + {/each}
- Job Info + Node Info - Job Footprint - - {metric} - {#if $initialized} - ({getUnit(metric)}) - {/if} + {metric} ({systemUnits[metric]})
-

{$jobsStore.error.message}

-
No jobs found
-
- -
-
No nodes found
-{#if usePaging} - { - if (detail.itemsPerPage != itemsPerPage) { - updateConfiguration(detail.itemsPerPage.toString(), detail.page); - } else { - jobs = [] - paging = { itemsPerPage: detail.itemsPerPage, page: detail.page }; - } - }} - /> -{/if} - diff --git a/web/frontend/src/systems/nodelist/NodeListRow.svelte b/web/frontend/src/systems/nodelist/NodeListRow.svelte index 3feac5c..5e9a31b 100644 --- a/web/frontend/src/systems/nodelist/NodeListRow.svelte +++ b/web/frontend/src/systems/nodelist/NodeListRow.svelte @@ -5,203 +5,52 @@ - `job Object`: The job object (GraphQL.Job) - `metrics [String]`: Currently selected metrics - `plotWidth Number`: Width of the sub-components - - `plotHeight Number?`: Height of the sub-components [Default: 275] - - `showFootprint Bool`: Display of footprint component for job - - `triggerMetricRefresh Bool?`: If changed to true from upstream, will trigger metric query --> - + - {#if job.monitoringStatus == 0 || job.monitoringStatus == 2} - - Not monitored or archiving failed - - {:else if $metricsQuery.fetching} - - - - {:else if $metricsQuery.error} - - - {$metricsQuery.error.message.length > 500 - ? $metricsQuery.error.message.substring(0, 499) + "..." - : $metricsQuery.error.message} - - - {:else} - {#if showFootprint} - - - - {/if} - {#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)} - - - {#if metric.disabled == false && metric.data} - { handleZoom(detail, metric.data.name) }} - height={plotHeight} - timestep={metric.data.metric.timestep} - scope={metric.data.scope} - series={metric.data.metric.series} - statisticsSeries={metric.data.metric.statisticsSeries} - metric={metric.data.name} - {cluster} - subCluster={job.subCluster} - isShared={job.exclusive != 1} - numhwthreads={job.numHWThreads} - numaccs={job.numAcc} - zoomState={zoomStates[metric.data.name] || null} - /> - {:else if metric.disabled == true && metric.data} - + {#if metricData} + {#if nodeData?.disabled[metricData.name]} + Metric disabled for subcluster {metric.data.name}:{job.subCluster}{metricData.name}:{nodeData.subCluster} {:else} - No dataset returned + {/if} - - {/each} - {/if} + {:else} + No dataset returned for {metricData.name} + {/if} + + {/each} From 3dfeabcec65cd1fa20a1ac5c1fe12c29e0dd8903 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Wed, 16 Oct 2024 12:41:15 +0200 Subject: [PATCH 04/34] simplify plotGrid, add cancel to metricSelect, improve metricPlot render logic --- web/frontend/src/Analysis.root.svelte | 2 - web/frontend/src/Job.root.svelte | 1 - web/frontend/src/Node.root.svelte | 1 - web/frontend/src/Status.root.svelte | 1 - web/frontend/src/Systems.root.svelte | 9 ++- web/frontend/src/User.root.svelte | 1 - web/frontend/src/generic/PlotGrid.svelte | 45 ++--------- .../src/generic/plots/MetricPlot.svelte | 44 +++++------ .../src/generic/select/MetricSelection.svelte | 1 + web/frontend/src/systems/NodeList.svelte | 4 +- web/frontend/src/systems/NodeOverview.svelte | 75 ++++++++----------- .../src/systems/nodelist/NodeInfo.svelte | 20 ++--- .../src/systems/nodelist/NodeListRow.svelte | 40 ++++------ 13 files changed, 90 insertions(+), 154 deletions(-) diff --git a/web/frontend/src/Analysis.root.svelte b/web/frontend/src/Analysis.root.svelte index d287cf3..c6dc424 100644 --- a/web/frontend/src/Analysis.root.svelte +++ b/web/frontend/src/Analysis.root.svelte @@ -519,7 +519,6 @@ ({ metric, ...binsFromFootprint( @@ -563,7 +562,6 @@ ({ m1, f1: $footprintsQuery.data.footprints.metrics.find( diff --git a/web/frontend/src/Job.root.svelte b/web/frontend/src/Job.root.svelte index bb48479..04e9cf9 100644 --- a/web/frontend/src/Job.root.svelte +++ b/web/frontend/src/Job.root.svelte @@ -351,7 +351,6 @@ {:else if $initq?.data && $jobMetrics?.data?.jobMetrics} ({ diff --git a/web/frontend/src/Status.root.svelte b/web/frontend/src/Status.root.svelte index e49d11a..65d3091 100644 --- a/web/frontend/src/Status.root.svelte +++ b/web/frontend/src/Status.root.svelte @@ -645,7 +645,6 @@ {#key $mainQuery.data.stats[0].histMetrics} diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index f2ef4ea..e1da89f 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -45,7 +45,7 @@ if (from == null || to == null) { to = new Date(Date.now()); from = new Date(to.getTime()); - from.setHours(from.getHours() - 4); + from.setHours(from.getHours() - 2); } const initialized = getContext("initialized"); @@ -61,6 +61,7 @@ // Todo: Add Idle State Filter (== No allocated Jobs) // Todo: NodeList: Mindestens Accelerator Scope ... "Show Detail" Switch? // Todo: Review performance // observed high client-side load frequency + // Is Svelte {#each} -> -> onMount() related : Cannot be skipped ... const client = getContextClient(); const nodeQuery = gql` @@ -245,13 +246,13 @@ -{:else if $initialized && $nodesQuery?.data} +{:else if filteredData?.length > 0} {#if displayNodeOverview} - + {:else} - + {/if} {/if} diff --git a/web/frontend/src/User.root.svelte b/web/frontend/src/User.root.svelte index 57f2f28..1d911ba 100644 --- a/web/frontend/src/User.root.svelte +++ b/web/frontend/src/User.root.svelte @@ -267,7 +267,6 @@ {#key $stats.data.jobsStatistics[0].histMetrics} diff --git a/web/frontend/src/generic/PlotGrid.svelte b/web/frontend/src/generic/PlotGrid.svelte index a56ffef..5152e0d 100644 --- a/web/frontend/src/generic/PlotGrid.svelte +++ b/web/frontend/src/generic/PlotGrid.svelte @@ -4,7 +4,6 @@ Properties: - `itemsPerRow Number`: Elements to render per row - `items [Any]`: List of plot components to render - - `renderFor String`: If 'job', filter disabled metrics --> -{#each rows as row} - - {#each row as item (item)} - - {#if !isPlaceholder(item)} - - {/if} - - {/each} - -{/each} + + {#each items as item} + + + + {/each} + diff --git a/web/frontend/src/generic/plots/MetricPlot.svelte b/web/frontend/src/generic/plots/MetricPlot.svelte index bf3dd45..d3af6f9 100644 --- a/web/frontend/src/generic/plots/MetricPlot.svelte +++ b/web/frontend/src/generic/plots/MetricPlot.svelte @@ -11,7 +11,7 @@ - `series [GraphQL.Series]`: The metric data object - `useStatsSeries Bool?`: If this plot uses the statistics Min/Max/Median representation; automatically set to according bool [Default: null] - `statisticsSeries [GraphQL.StatisticsSeries]?`: Min/Max/Median representation of metric data [Default: null] - - `cluster GraphQL.Cluster`: Cluster Object of the parent job + - `cluster String`: Cluster name of the parent job / data - `subCluster String`: Name of the subCluster of the parent job - `isShared Bool?`: If this job used shared resources; will adapt threshold indicators accordingly [Default: false] - `forNode Bool?`: If this plot is used for node data display; will ren[data, err := metricdata.LoadNodeData(cluster, metrics, nodes, scopes, from, to, ctx)](https://github.com/ClusterCockpit/cc-backend/blob/9fe7cdca9215220a19930779a60c8afc910276a3/internal/graph/schema.resolvers.go#L391-L392)der x-axis as negative time with $now as maximum [Default: false] @@ -117,13 +117,13 @@ export let metric; export let scope = "node"; - export let width = null; + export let width = 0; export let height = 300; export let timestep; export let series; export let useStatsSeries = null; export let statisticsSeries = null; - export let cluster; + export let cluster = ""; export let subCluster; export let isShared = false; export let forNode = false; @@ -522,17 +522,9 @@ } onMount(() => { - // Setup Wrapper - if (series[0].data.length > 0) { - if (forNode) { - plotWrapper.style.paddingTop = "0.5rem" - plotWrapper.style.paddingBottom = "0.5rem" - } - plotWrapper.style.backgroundColor = backgroundColor(); - plotWrapper.style.borderRadius = "5px"; + if (plotWrapper) { + render(width, height); } - // Init Plot - render(width, height); }); onDestroy(() => { @@ -540,22 +532,20 @@ if (uplot) uplot.destroy(); }); - // This updates it on all size changes - // Condition for reactive triggering (eg scope change) - $: if (series[0].data.length > 0) { + // This updates plot on all size changes if wrapper (== data) exists + $: if (plotWrapper) { onSizeChange(width, height); } - -
- {#if series[0].data.length > 0} -
- {:else} - Cannot render plot: No series data returned for {metric} - {/if} -
- + +{#if series[0].data.length > 0} +
+{:else} + Cannot render plot: No series data returned for {metric} +{/if} diff --git a/web/frontend/src/generic/select/MetricSelection.svelte b/web/frontend/src/generic/select/MetricSelection.svelte index b65b407..71b42b8 100644 --- a/web/frontend/src/generic/select/MetricSelection.svelte +++ b/web/frontend/src/generic/select/MetricSelection.svelte @@ -178,6 +178,7 @@ + diff --git a/web/frontend/src/systems/NodeList.svelte b/web/frontend/src/systems/NodeList.svelte index 54f7530..b8eacdf 100644 --- a/web/frontend/src/systems/NodeList.svelte +++ b/web/frontend/src/systems/NodeList.svelte @@ -36,7 +36,7 @@ {cluster} Node Info @@ -53,7 +53,7 @@ - {#each data as nodeData (nodeData)} + {#each data as nodeData (nodeData.host)} {:else} diff --git a/web/frontend/src/systems/NodeOverview.svelte b/web/frontend/src/systems/NodeOverview.svelte index 7ad711d..9e02f10 100644 --- a/web/frontend/src/systems/NodeOverview.svelte +++ b/web/frontend/src/systems/NodeOverview.svelte @@ -9,9 +9,7 @@ --> - -

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

- {#if item?.data[0]} - {#if item?.disabled[selectedMetric]} - Metric disabled for subcluster {selectedMetric}:{item.subCluster} - {:else} - c.name == cluster)} - subCluster={item.subCluster} - forNode={true} - /> - {/if} - {:else} - No dataset returned for {selectedMetric} - {/if} -
+ + + {#each data as item (item.host)} + +

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

+ {#if item?.disabled[selectedMetric]} + Metric disabled for subcluster {selectedMetric}:{item.subCluster} + {:else} + + + {/if} + + {/each} +
\ No newline at end of file diff --git a/web/frontend/src/systems/nodelist/NodeInfo.svelte b/web/frontend/src/systems/nodelist/NodeInfo.svelte index 2a40c7a..d0ea2b9 100644 --- a/web/frontend/src/systems/nodelist/NodeInfo.svelte +++ b/web/frontend/src/systems/nodelist/NodeInfo.svelte @@ -56,7 +56,7 @@ - +
@@ -106,7 +106,7 @@

{#if $nodeJobsData.data.jobs.count > 0} - + @@ -116,11 +116,11 @@ - Show List + List {:else} - + @@ -132,30 +132,30 @@ {/if}

- + - Users on Node + Show Users on Node - Show List + List

- + - Projects on Node + Show Projects on Node - Show List + List

diff --git a/web/frontend/src/systems/nodelist/NodeListRow.svelte b/web/frontend/src/systems/nodelist/NodeListRow.svelte index 5e9a31b..a510b0e 100644 --- a/web/frontend/src/systems/nodelist/NodeListRow.svelte +++ b/web/frontend/src/systems/nodelist/NodeListRow.svelte @@ -24,32 +24,24 @@ - {#each sortOrder(nodeData?.data) as metricData} + {#each sortOrder(nodeData?.data) as metricData (metricData.name)} - {#if metricData} - {#if nodeData?.disabled[metricData.name]} - Metric disabled for subcluster {metricData.name}:{nodeData.subCluster} - {:else} - - {/if} - {:else} - No dataset returned for {metricData.name}Metric disabled for subcluster {metricData.name}:{nodeData.subCluster} + {:else} + + {/if} {/each} From 85a77e05afc2b8b9de6449e4259c2ea8dce189e0 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Wed, 16 Oct 2024 12:51:10 +0200 Subject: [PATCH 05/34] edit nodeInfo string --- web/frontend/src/systems/nodelist/NodeInfo.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/frontend/src/systems/nodelist/NodeInfo.svelte b/web/frontend/src/systems/nodelist/NodeInfo.svelte index d0ea2b9..15effe2 100644 --- a/web/frontend/src/systems/nodelist/NodeInfo.svelte +++ b/web/frontend/src/systems/nodelist/NodeInfo.svelte @@ -137,9 +137,9 @@ - Show Users on Node + Show Users - + List @@ -151,7 +151,7 @@ - Show Projects on Node + Show Projects From 33d219d2acbcf0a8ea513e694781479c5a8d04f7 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Wed, 16 Oct 2024 13:05:03 +0200 Subject: [PATCH 06/34] Add subCluster to node view info field --- web/frontend/src/Node.root.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/frontend/src/Node.root.svelte b/web/frontend/src/Node.root.svelte index bbbcb0f..60ab404 100644 --- a/web/frontend/src/Node.root.svelte +++ b/web/frontend/src/Node.root.svelte @@ -141,7 +141,7 @@ Selected Node - + From 60d7984d6639a5cff1b1a0b1707cdc7ca11001de Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Wed, 16 Oct 2024 14:16:31 +0200 Subject: [PATCH 07/34] add notes --- web/frontend/src/Systems.root.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index e1da89f..39d17aa 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -58,8 +58,9 @@ let selectedMetrics = ccconfig[`node_list_selectedMetrics:${cluster}`] || [ccconfig.system_view_selectedMetric]; let isMetricsSelectionOpen = false; - // Todo: Add Idle State Filter (== No allocated Jobs) + // Todo: Add Idle State Filter (== No allocated Jobs) [Frontend?] // Todo: NodeList: Mindestens Accelerator Scope ... "Show Detail" Switch? + // Todo: Rework GQL Query: Add Paging (Scrollable), Add Nodes Filter (see jobs-onthefly-userfilter), add scopes // Todo: Review performance // observed high client-side load frequency // Is Svelte {#each} -> -> onMount() related : Cannot be skipped ... From 39b22267d6dcdf30d5b3641ecc582ce94d67e8d5 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Wed, 16 Oct 2024 16:03:31 +0200 Subject: [PATCH 08/34] Update component descriptions --- web/frontend/src/systems/NodeList.svelte | 7 ++++--- web/frontend/src/systems/nodelist/NodeInfo.svelte | 7 ++++--- web/frontend/src/systems/nodelist/NodeListRow.svelte | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/web/frontend/src/systems/NodeList.svelte b/web/frontend/src/systems/NodeList.svelte index b8eacdf..5d106b6 100644 --- a/web/frontend/src/systems/NodeList.svelte +++ b/web/frontend/src/systems/NodeList.svelte @@ -2,9 +2,10 @@ @component Cluster Per Node List component; renders current state of SELECTABLE metrics for ALL nodes Properties: - - `cluster String`: The cluster to show status information for - - `from Date?`: Custom Time Range selection 'from' [Default: null] - - `to Date?`: Custom Time Range selection 'to' [Default: null] + - `cluster String`: The nodes' cluster + - `data [Object]`: The node data array for all nodes + - `selectedMetrics [String]`: The array of selected metrics + - `selectedMetrics Object`: The object of metric units --> - - @@ -255,25 +153,13 @@ Unknown displayList type! -{:else if $nodesQuery.error} - - - {$nodesQuery.error.message} - - -{:else if $nodesQuery.fetching } - - - - - -{:else if filteredData?.length > 0} +{:else} {#if displayNodeOverview} - + {:else} - + {/if} {/if} diff --git a/web/frontend/src/generic/plots/MetricPlot.svelte b/web/frontend/src/generic/plots/MetricPlot.svelte index b70c3d7..3a0e1e4 100644 --- a/web/frontend/src/generic/plots/MetricPlot.svelte +++ b/web/frontend/src/generic/plots/MetricPlot.svelte @@ -553,7 +553,7 @@ -{#if series[0].data.length > 0} +{#if series[0]?.data && series[0].data.length > 0}
diff --git a/web/frontend/src/systems.entrypoint.js b/web/frontend/src/systems.entrypoint.js index 527e3ef..9f504cd 100644 --- a/web/frontend/src/systems.entrypoint.js +++ b/web/frontend/src/systems.entrypoint.js @@ -6,6 +6,7 @@ new Systems({ props: { displayType: displayType, cluster: infos.cluster, + subCluster: infos.subCluster, from: infos.from, to: infos.to }, diff --git a/web/frontend/src/systems/NodeList.svelte b/web/frontend/src/systems/NodeList.svelte index 5d106b6..6ef48b1 100644 --- a/web/frontend/src/systems/NodeList.svelte +++ b/web/frontend/src/systems/NodeList.svelte @@ -3,68 +3,168 @@ Properties: - `cluster String`: The nodes' cluster - - `data [Object]`: The node data array for all nodes + - `subCluster String`: The nodes' subCluster + - `ccconfig Object?`: The ClusterCockpit Config Context [Default: null] - `selectedMetrics [String]`: The array of selected metrics - - `selectedMetrics Object`: The object of metric units + - `systemUnits Object`: The object of metric units --> - -
- - - - - - {#each selectedMetrics as metric (metric)} - - {/each} - - - - {#each data as nodeData (nodeData.host)} - - {:else} +{#if $nodesQuery.error} + + + {$nodesQuery.error.message} + + +{:else if $nodesQuery.fetching } + + + + + +{:else if $initq?.data && $nodesQuery?.data} + +
+
- {cluster} Node Info - - {metric} ({systemUnits[metric]}) -
+ - + + + {#each selectedMetrics as metric (metric)} + + {/each} - {/each} - -
No nodes found + {cluster} Node Info + + {metric} ({systemUnits[metric]}) +
-
-
+ + + {#each $nodesQuery.data.nodeMetricsList.items as nodeData (nodeData.host)} + + {:else} + + No nodes found + + {/each} + + +
+ +{/if} + +{#if true} + { + paging = { itemsPerPage: detail.itemsPerPage, page: detail.page } + // if (detail.itemsPerPage != itemsPerPage) { + // updateConfiguration(detail.itemsPerPage.toString(), detail.page); + // } else { + // // nodes = [] + // paging = { itemsPerPage: detail.itemsPerPage, page: detail.page }; + // } + }} + /> +{/if}