diff --git a/internal/graph/schema.resolvers.go b/internal/graph/schema.resolvers.go
index 9c877d1..20ad7cc 100644
--- a/internal/graph/schema.resolvers.go
+++ b/internal/graph/schema.resolvers.go
@@ -423,8 +423,8 @@ func (r *queryResolver) RooflineHeatmap(ctx context.Context, filter []*model.Job
// NodeMetrics is the resolver for the nodeMetrics field.
func (r *queryResolver) NodeMetrics(ctx context.Context, cluster string, nodes []string, scopes []schema.MetricScope, metrics []string, from time.Time, to time.Time) ([]*model.NodeMetrics, error) {
user := repository.GetUserFromContext(ctx)
- if user != nil && !user.HasRole(schema.RoleAdmin) {
- return nil, errors.New("you need to be an administrator for this query")
+ if user != nil && !user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport}) {
+ return nil, errors.New("you need to be administrator or support staff for this query")
}
if metrics == nil {
@@ -479,8 +479,8 @@ func (r *queryResolver) NodeMetricsList(ctx context.Context, cluster string, sub
}
user := repository.GetUserFromContext(ctx)
- if user != nil && !user.HasRole(schema.RoleAdmin) {
- return nil, errors.New("you need to be an administrator for this query")
+ if user != nil && !user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport}) {
+ return nil, errors.New("you need to be administrator or support staff for this query")
}
if metrics == nil {
diff --git a/internal/metricDataDispatcher/dataLoader.go b/internal/metricDataDispatcher/dataLoader.go
index 4642ffd..939a0fb 100644
--- a/internal/metricDataDispatcher/dataLoader.go
+++ b/internal/metricDataDispatcher/dataLoader.go
@@ -287,11 +287,11 @@ func LoadNodeListData(
}
// NOTE: New StatsSeries will always be calculated as 'min/median/max'
- const maxSeriesSize int = 15
+ const maxSeriesSize int = 8
for _, jd := range data {
for _, scopes := range jd {
for _, jm := range scopes {
- if jm.StatisticsSeries != nil || len(jm.Series) <= maxSeriesSize {
+ if jm.StatisticsSeries != nil || len(jm.Series) < maxSeriesSize {
continue
}
jm.AddStatisticsSeries()
diff --git a/web/frontend/src/Header.svelte b/web/frontend/src/Header.svelte
index 573a057..cf3e058 100644
--- a/web/frontend/src/Header.svelte
+++ b/web/frontend/src/Header.svelte
@@ -94,7 +94,7 @@
},
{
title: "Nodes",
- requiredRole: roles.admin,
+ requiredRole: roles.support,
href: "/monitoring/systems/",
icon: "hdd-rack",
perCluster: true,
@@ -102,19 +102,19 @@
menu: "Info",
},
{
- title: "Status",
- requiredRole: roles.admin,
- href: "/monitoring/status/",
- icon: "clipboard-data",
+ title: "Analysis",
+ requiredRole: roles.support,
+ href: "/monitoring/analysis/",
+ icon: "graph-up",
perCluster: true,
listOptions: false,
menu: "Info",
},
{
- title: "Analysis",
- requiredRole: roles.support,
- href: "/monitoring/analysis/",
- icon: "graph-up",
+ title: "Status",
+ requiredRole: roles.admin,
+ href: "/monitoring/status/",
+ icon: "clipboard-data",
perCluster: true,
listOptions: false,
menu: "Info",
diff --git a/web/frontend/src/generic/plots/MetricPlot.svelte b/web/frontend/src/generic/plots/MetricPlot.svelte
index f2bff02..3d143bd 100644
--- a/web/frontend/src/generic/plots/MetricPlot.svelte
+++ b/web/frontend/src/generic/plots/MetricPlot.svelte
@@ -9,7 +9,7 @@
- `height Number?`: The plot height [Default: 300]
- `timestep Number`: The timestep used for X-axis rendering
- `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]
+ - `useStatsSeries Bool?`: If this plot uses the statistics Min/Max/Median representation; automatically set to according bool [Default: false]
- `statisticsSeries [GraphQL.StatisticsSeries]?`: Min/Max/Median representation of metric data [Default: null]
- `cluster String`: Cluster name of the parent job / data
- `subCluster String`: Name of the subCluster of the parent job
@@ -128,7 +128,7 @@
export let height = 300;
export let timestep;
export let series;
- export let useStatsSeries = null;
+ export let useStatsSeries = false;
export let statisticsSeries = null;
export let cluster = "";
export let subCluster;
@@ -139,10 +139,9 @@
export let zoomState = null;
export let thresholdState = null;
- if (useStatsSeries == null) useStatsSeries = statisticsSeries != null;
- if (useStatsSeries == false && series == null) useStatsSeries = true;
+ if (!useStatsSeries && statisticsSeries != null) useStatsSeries = true;
- const usesMeanStatsSeries = (useStatsSeries?.mean && statisticsSeries.mean.length != 0)
+ const usesMeanStatsSeries = (statisticsSeries?.mean && statisticsSeries.mean.length != 0)
const dispatch = createEventDispatcher();
const subClusterTopology = getContext("getHardwareTopology")(cluster, subCluster);
const metricConfig = getContext("getMetricConfig")(cluster, subCluster, metric);
@@ -205,11 +204,10 @@
// conditional hide series color markers:
if (
- useStatsSeries === true || // Min/Max/Median Self-Explanatory
+ useStatsSeries || // Min/Max/Median Self-Explanatory
dataSize === 1 || // Only one Y-Dataseries
- dataSize > 6
+ dataSize > 8 // More than 8 Y-Dataseries
) {
- // More than 6 Y-Dataseries
const idents = legendEl.querySelectorAll(".u-marker");
for (let i = 0; i < idents.length; i++)
idents[i].style.display = "none";
@@ -240,7 +238,7 @@
"translate(" + (left - width - 15) + "px, " + (top + 15) + "px)";
}
- if (dataSize <= 12 || useStatsSeries === true) {
+ if (dataSize <= 12 || useStatsSeries) {
return {
hooks: {
init: init,
@@ -432,13 +430,13 @@
u.ctx.save();
u.ctx.textAlign = "start"; // 'end'
u.ctx.fillStyle = "black";
- u.ctx.fillText(textl, u.bbox.left + 10, u.bbox.top + 10);
+ u.ctx.fillText(textl, u.bbox.left + 10, u.bbox.top + (forNode ? 0 : 10));
u.ctx.textAlign = "end";
u.ctx.fillStyle = "black";
u.ctx.fillText(
textr,
u.bbox.left + u.bbox.width - 10,
- u.bbox.top + 10,
+ u.bbox.top + (forNode ? 0 : 10),
);
// u.ctx.fillText(text, u.bbox.left + u.bbox.width - 10, u.bbox.top + u.bbox.height - 10) // Recipe for bottom right
@@ -496,10 +494,12 @@
},
legend: {
// Display legend until max 12 Y-dataseries
- show: series.length <= 12 || useStatsSeries === true ? true : false,
- live: series.length <= 12 || useStatsSeries === true ? true : false,
+ show: series.length <= 12 || useStatsSeries,
+ live: series.length <= 12 || useStatsSeries,
},
- cursor: { drag: { x: true, y: true } },
+ cursor: {
+ drag: { x: true, y: true },
+ }
};
// RENDER HANDLING
diff --git a/web/frontend/src/systems/nodelist/NodeInfo.svelte b/web/frontend/src/systems/nodelist/NodeInfo.svelte
index 825bca7..057ef9f 100644
--- a/web/frontend/src/systems/nodelist/NodeInfo.svelte
+++ b/web/frontend/src/systems/nodelist/NodeInfo.svelte
@@ -45,6 +45,11 @@
$paging: PageRequest!
) {
jobs(filter: $filter, order: $sorting, page: $paging) {
+ items {
+ user
+ project
+ exclusive
+ }
count
}
}
@@ -61,6 +66,13 @@
variables: { paging, sorting, filter },
});
+ let userList;
+ let projectList;
+ $: if ($nodeJobsData?.data) {
+ userList = Array.from(new Set($nodeJobsData.data.jobs.items.map((j) => j.user))).sort((a, b) => a.localeCompare(b));
+ projectList = Array.from(new Set($nodeJobsData.data.jobs.items.map((j) => j.project))).sort((a, b) => a.localeCompare(b));
+ }
+
- {#if healthWarn}
-
- {#if $nodeJobsData.data.jobs.count > 0}
-
-
-
-
+
+