diff --git a/internal/routerConfig/routes.go b/internal/routerConfig/routes.go
index b6137ddb..218384e0 100644
--- a/internal/routerConfig/routes.go
+++ b/internal/routerConfig/routes.go
@@ -305,30 +305,66 @@ func buildFilterPresets(query url.Values) map[string]any {
if query.Get("numNodes") != "" {
parts := strings.Split(query.Get("numNodes"), "-")
if len(parts) == 2 {
- a, e1 := strconv.Atoi(parts[0])
- b, e2 := strconv.Atoi(parts[1])
- if e1 == nil && e2 == nil {
- filterPresets["numNodes"] = map[string]int{"from": a, "to": b}
+ if parts[0] == "lessthan" {
+ lt, lte := strconv.Atoi(parts[1])
+ if lte == nil {
+ filterPresets["numNodes"] = map[string]int{"from": 1, "to": lt}
+ }
+ } else if parts[0] == "morethan" {
+ mt, mte := strconv.Atoi(parts[1])
+ if mte == nil {
+ filterPresets["numNodes"] = map[string]int{"from": mt, "to": 0}
+ }
+ } else {
+ a, e1 := strconv.Atoi(parts[0])
+ b, e2 := strconv.Atoi(parts[1])
+ if e1 == nil && e2 == nil {
+ filterPresets["numNodes"] = map[string]int{"from": a, "to": b}
+ }
}
}
}
if query.Get("numHWThreads") != "" {
parts := strings.Split(query.Get("numHWThreads"), "-")
if len(parts) == 2 {
- a, e1 := strconv.Atoi(parts[0])
- b, e2 := strconv.Atoi(parts[1])
- if e1 == nil && e2 == nil {
- filterPresets["numHWThreads"] = map[string]int{"from": a, "to": b}
+ if parts[0] == "lessthan" {
+ lt, lte := strconv.Atoi(parts[1])
+ if lte == nil {
+ filterPresets["numHWThreads"] = map[string]int{"from": 1, "to": lt}
+ }
+ } else if parts[0] == "morethan" {
+ mt, mte := strconv.Atoi(parts[1])
+ if mte == nil {
+ filterPresets["numHWThreads"] = map[string]int{"from": mt, "to": 0}
+ }
+ } else {
+ a, e1 := strconv.Atoi(parts[0])
+ b, e2 := strconv.Atoi(parts[1])
+ if e1 == nil && e2 == nil {
+ filterPresets["numHWThreads"] = map[string]int{"from": a, "to": b}
+ }
}
}
}
if query.Get("numAccelerators") != "" {
parts := strings.Split(query.Get("numAccelerators"), "-")
if len(parts) == 2 {
- a, e1 := strconv.Atoi(parts[0])
- b, e2 := strconv.Atoi(parts[1])
- if e1 == nil && e2 == nil {
- filterPresets["numAccelerators"] = map[string]int{"from": a, "to": b}
+ if parts[0] == "lessthan" {
+ lt, lte := strconv.Atoi(parts[1])
+ if lte == nil {
+ filterPresets["numAccelerators"] = map[string]int{"from": 1, "to": lt}
+ }
+ } else if parts[0] == "morethan" {
+ mt, mte := strconv.Atoi(parts[1])
+ if mte == nil {
+ filterPresets["numAccelerators"] = map[string]int{"from": mt, "to": 0}
+ }
+ } else {
+ a, e1 := strconv.Atoi(parts[0])
+ b, e2 := strconv.Atoi(parts[1])
+ if e1 == nil && e2 == nil {
+ filterPresets["numAccelerators"] = map[string]int{"from": a, "to": b}
+ }
}
}
}
diff --git a/web/frontend/src/generic/Filters.svelte b/web/frontend/src/generic/Filters.svelte
index 4031d0a5..162082c0 100644
--- a/web/frontend/src/generic/Filters.svelte
+++ b/web/frontend/src/generic/Filters.svelte
@@ -280,12 +280,24 @@
opts.push(`duration=morethan-${filters.duration.moreThan}`);
if (filters.tags.length != 0)
for (let tag of filters.tags) opts.push(`tag=${tag}`);
- if (filters.numNodes.from && filters.numNodes.to)
+ if (filters.numNodes.from > 1 && filters.numNodes.to > 0)
opts.push(`numNodes=${filters.numNodes.from}-${filters.numNodes.to}`);
- if (filters.numHWThreads.from && filters.numHWThreads.to)
+ else if (filters.numNodes.from > 1 && filters.numNodes.to == 0)
+ opts.push(`numNodes=morethan-${filters.numNodes.from}`);
+ else if (filters.numNodes.from == 1 && filters.numNodes.to > 0)
+ opts.push(`numNodes=lessthan-${filters.numNodes.to}`);
+ if (filters.numHWThreads.from > 1 && filters.numHWThreads.to > 0)
opts.push(`numHWThreads=${filters.numHWThreads.from}-${filters.numHWThreads.to}`);
+ else if (filters.numHWThreads.from > 1 && filters.numHWThreads.to == 0)
+ opts.push(`numHWThreads=morethan-${filters.numHWThreads.from}`);
+ else if (filters.numHWThreads.from == 1 && filters.numHWThreads.to > 0)
+ opts.push(`numHWThreads=lessthan-${filters.numHWThreads.to}`);
if (filters.numAccelerators.from && filters.numAccelerators.to)
opts.push(`numAccelerators=${filters.numAccelerators.from}-${filters.numAccelerators.to}`);
+ else if (filters.numAccelerators.from > 1 && filters.numAccelerators.to == 0)
+ opts.push(`numAccelerators=morethan-${filters.numAccelerators.from}`);
+ else if (filters.numAccelerators.from == 1 && filters.numAccelerators.to > 0)
+ opts.push(`numAccelerators=lessthan-${filters.numAccelerators.to}`);
if (filters.node) opts.push(`node=${filters.node}`);
if (filters.node && filters.nodeMatch != "eq") // "eq" is default-case
opts.push(`nodeMatch=${filters.nodeMatch}`);
@@ -490,21 +502,45 @@
{/if}
- {#if filters.numNodes.from != null || filters.numNodes.to != null}
+ {#if filters.numNodes.from > 1 && filters.numNodes.to > 0}
(isResourcesOpen = true)}>
- Nodes: {filters.numNodes.from} - {filters.numNodes.to}
+ Nodes: {filters.numNodes.from} - {filters.numNodes.to}
+
+ {:else if filters.numNodes.from > 1 && filters.numNodes.to == 0}
+ (isResourcesOpen = true)}>
+ ≥ {filters.numNodes.from} Node(s)
+
+ {:else if filters.numNodes.from == 1 && filters.numNodes.to > 0}
+ (isResourcesOpen = true)}>
+ ≤ {filters.numNodes.to} Node(s)
{/if}
- {#if filters.numHWThreads.from != null || filters.numHWThreads.to != null}
+ {#if filters.numHWThreads.from > 1 && filters.numHWThreads.to > 0}
(isResourcesOpen = true)}>
- HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to}
+ HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to}
+
+ {:else if filters.numHWThreads.from > 1 && filters.numHWThreads.to == 0}
+ (isResourcesOpen = true)}>
+ ≥ {filters.numHWThreads.from} HWThread(s)
+
+ {:else if filters.numHWThreads.from == 1 && filters.numHWThreads.to > 0}
+ (isResourcesOpen = true)}>
+ ≤ {filters.numHWThreads.to} HWThread(s)
{/if}
- {#if filters.numAccelerators.from != null || filters.numAccelerators.to != null}
+ {#if filters.numAccelerators.from > 1 && filters.numAccelerators.to > 0}
(isResourcesOpen = true)}>
- Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to}
+ Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to}
+
+ {:else if filters.numAccelerators.from > 1 && filters.numAccelerators.to == 0}
+ (isResourcesOpen = true)}>
+ ≥ {filters.numAccelerators.from} Acc(s)
+
+ {:else if filters.numAccelerators.from == 1 && filters.numAccelerators.to > 0}
+ (isResourcesOpen = true)}>
+ ≤ {filters.numAccelerators.to} Acc(s)
{/if}
diff --git a/web/frontend/src/generic/filters/Resources.svelte b/web/frontend/src/generic/filters/Resources.svelte
index d8cdbc65..be55bcc3 100644
--- a/web/frontend/src/generic/filters/Resources.svelte
+++ b/web/frontend/src/generic/filters/Resources.svelte
@@ -20,7 +20,9 @@
ModalBody,
ModalHeader,
ModalFooter,
- Input
+ Input,
+ Tooltip,
+ Icon
} from "@sveltestrap/sveltestrap";
import DoubleRangeSlider from "../select/DoubleRangeSlider.svelte";
@@ -42,6 +44,19 @@
contains: "Contains",
}
+ const findMaxNumNodes = (infos) =>
+ infos.reduce(
+ (max, cluster) =>
+ Math.max(
+ max,
+ cluster.subClusters.reduce(
+ (max, sc) => Math.max(max, sc.numberOfNodes || 0),
+ 0,
+ ),
+ ),
+ 0,
+ );
+
const findMaxNumAccels = (infos) =>
infos.reduce(
(max, cluster) =>
@@ -75,29 +90,46 @@
/* State Init*/
// Counts
- let minNumNodes = $state(1);
- let maxNumNodes = $state(128);
- let maxNumHWThreads = $state(0);
- let maxNumAccelerators = $state(0);
+ let maxNumNodes = $state(1);
+ let maxNumHWThreads = $state(1);
+ let maxNumAccelerators = $state(1);
/* Derived States */
// Pending
- let pendingNumNodes = $derived(presetNumNodes);
- let pendingNumHWThreads = $derived(presetNumHWThreads);
- let pendingNumAccelerators = $derived(presetNumAccelerators);
+ let pendingNumNodes = $derived({
+ from: presetNumNodes.from,
+ to: (presetNumNodes.to == 0) ? maxNumNodes : presetNumNodes.to
+ });
+ let pendingNumHWThreads = $derived({
+ from: presetNumHWThreads.from,
+ to: (presetNumHWThreads.to == 0) ? maxNumHWThreads : presetNumHWThreads.to
+ });
+ let pendingNumAccelerators = $derived({
+ from: presetNumAccelerators.from,
+ to: (presetNumAccelerators.to == 0) ? maxNumAccelerators : presetNumAccelerators.to
+ });
let pendingNamedNode = $derived(presetNamedNode);
let pendingNodeMatch = $derived(presetNodeMatch);
// Changable States
- let nodesState = $derived(presetNumNodes);
- let threadState = $derived(presetNumHWThreads);
- let accState = $derived(presetNumAccelerators);
+ let nodesState = $derived({
+ from: presetNumNodes.from,
+ to: (presetNumNodes.to == 0) ? maxNumNodes : presetNumNodes.to
+ });
+ let threadState = $derived({
+ from: presetNumHWThreads.from,
+ to: (presetNumHWThreads.to == 0) ? maxNumHWThreads : presetNumHWThreads.to
+ });
+ let accState = $derived({
+ from: presetNumAccelerators.from,
+ to: (presetNumAccelerators.to == 0) ? maxNumAccelerators : presetNumAccelerators.to
+ });
const initialized = $derived(getContext("initialized") || false);
const clusterInfos = $derived($initialized ? getContext("clusters") : null);
// Is Selection Active
const nodesActive = $derived(!(JSON.stringify(nodesState) === JSON.stringify({ from: 1, to: maxNumNodes })));
const threadActive = $derived(!(JSON.stringify(threadState) === JSON.stringify({ from: 1, to: maxNumHWThreads })));
- const accActive = $derived(!(JSON.stringify(accState) === JSON.stringify({ from: 0, to: maxNumAccelerators })));
+ const accActive = $derived(!(JSON.stringify(accState) === JSON.stringify({ from: 1, to: maxNumAccelerators })));
// Block Apply if null
const disableApply = $derived(
nodesState.from === null || nodesState.to === null ||
@@ -110,11 +142,13 @@
if ($initialized) {
if (activeCluster != null) {
const { subClusters } = clusterInfos.find((c) => c.name == activeCluster);
- maxNumAccelerators = findMaxNumAccels([{ subClusters }]);
+ maxNumNodes = findMaxNumNodes([{ subClusters }]);
maxNumHWThreads = findMaxNumHWThreadsPerNode([{ subClusters }]);
+ maxNumAccelerators = findMaxNumAccels([{ subClusters }]);
} else if (clusterInfos.length > 0) {
- maxNumAccelerators = findMaxNumAccels(clusterInfos);
+ maxNumNodes = findMaxNumNodes(clusterInfos);
maxNumHWThreads = findMaxNumHWThreadsPerNode(clusterInfos);
+ maxNumAccelerators = findMaxNumAccels(clusterInfos);
}
}
});
@@ -145,26 +179,35 @@
pendingNumAccelerators.from == null &&
pendingNumAccelerators.to == null
) {
- accState = { from: 0, to: maxNumAccelerators };
+ accState = { from: 1, to: maxNumAccelerators };
}
});
/* Functions */
function setResources() {
if (nodesActive) {
- pendingNumNodes = {...nodesState};
+ pendingNumNodes = {
+ from: nodesState.from,
+ to: (nodesState.to == maxNumNodes) ? 0 : nodesState.to
+ };
} else {
- pendingNumNodes = { from: null, to: null };
+ pendingNumNodes = { from: null, to: null};
};
if (threadActive) {
- pendingNumHWThreads = {...threadState};
+ pendingNumHWThreads = {
+ from: threadState.from,
+ to: (threadState.to == maxNumHWThreads) ? 0 : threadState.to
+ };
} else {
- pendingNumHWThreads = { from: null, to: null };
+ pendingNumHWThreads = { from: null, to: null};
};
if (accActive) {
- pendingNumAccelerators = {...accState};
+ pendingNumAccelerators = {
+ from: accState.from,
+ to: (accState.to == maxNumAccelerators) ? 0 : accState.to
+ };
} else {
- pendingNumAccelerators = { from: null, to: null };
+ pendingNumAccelerators = { from: null, to: null};
};
};
@@ -195,13 +238,18 @@
-
Number of Nodes
+
Number of Nodes
+
+
+
+ Preset maximum is for whole cluster.
+
{
nodesState.from = detail[0];
nodesState.to = detail[1];
}}
- sliderMin={minNumNodes}
+ sliderMin={1}
sliderMax={maxNumNodes}
fromPreset={nodesState.from}
toPreset={nodesState.to}
@@ -209,7 +257,13 @@
-
Number of HWThreads (Use for Single-Node Jobs)
+
+ Number of HWThreads
+
+
+
+ Presets for a single node. Can be changed to higher values.
+
{
threadState.from = detail[0];
@@ -223,13 +277,19 @@
{#if maxNumAccelerators != null && maxNumAccelerators > 1}
-
Number of Accelerators
+
+ Number of Accelerators
+
+
+
+ Presets for a single node. Can be changed to higher values.
+
{
accState.from = detail[0];
accState.to = detail[1];
}}
- sliderMin={0}
+ sliderMin={1}
sliderMax={maxNumAccelerators}
fromPreset={accState.from}
toPreset={accState.to}
diff --git a/web/frontend/src/generic/select/DoubleRangeSlider.svelte b/web/frontend/src/generic/select/DoubleRangeSlider.svelte
index 12ca7449..c655087f 100644
--- a/web/frontend/src/generic/select/DoubleRangeSlider.svelte
+++ b/web/frontend/src/generic/select/DoubleRangeSlider.svelte
@@ -34,8 +34,8 @@
let pendingValues = $derived([fromPreset, toPreset]);
let sliderFrom = $derived(Math.max(((fromPreset == null ? sliderMin : fromPreset) - sliderMin) / (sliderMax - sliderMin), 0.));
let sliderTo = $derived(Math.min(((toPreset == null ? sliderMin : toPreset) - sliderMin) / (sliderMax - sliderMin), 1.));
- let inputFieldFrom = $derived(fromPreset.toString());
- let inputFieldTo = $derived(toPreset.toString());
+ let inputFieldFrom = $derived(fromPreset ? fromPreset.toString() : null);
+ let inputFieldTo = $derived(toPreset ? toPreset.toString() : null);
/* Var Init */
let timeoutId = null;
@@ -160,12 +160,26 @@