review doubleranged filters, fix and improve valeu selection

This commit is contained in:
Christoph Kluge
2026-03-24 15:00:41 +01:00
parent 93a9d732a4
commit bd7125a52e
8 changed files with 120 additions and 147 deletions

View File

@@ -280,11 +280,11 @@ func BuildWhereClause(filter *model.JobFilter, query sq.SelectBuilder) sq.Select
// buildIntCondition creates clauses for integer range filters, using BETWEEN only if required. // buildIntCondition creates clauses for integer range filters, using BETWEEN only if required.
func buildIntCondition(field string, cond *config.IntRange, query sq.SelectBuilder) sq.SelectBuilder { func buildIntCondition(field string, cond *config.IntRange, query sq.SelectBuilder) sq.SelectBuilder {
if cond.From != 1 && cond.To != 0 { if cond.From > 0 && cond.To > 0 {
return query.Where(field+" BETWEEN ? AND ?", cond.From, cond.To) return query.Where(field+" BETWEEN ? AND ?", cond.From, cond.To)
} else if cond.From != 1 && cond.To == 0 { } else if cond.From > 0 && cond.To == 0 {
return query.Where(field+" >= ?", cond.From) return query.Where(field+" >= ?", cond.From)
} else if cond.From == 1 && cond.To != 0 { } else if cond.From == 0 && cond.To > 0 {
return query.Where(field+" <= ?", cond.To) return query.Where(field+" <= ?", cond.To)
} else { } else {
return query return query
@@ -293,11 +293,11 @@ func buildIntCondition(field string, cond *config.IntRange, query sq.SelectBuild
// buildFloatCondition creates a clauses for float range filters, using BETWEEN only if required. // buildFloatCondition creates a clauses for float range filters, using BETWEEN only if required.
func buildFloatCondition(field string, cond *model.FloatRange, query sq.SelectBuilder) sq.SelectBuilder { func buildFloatCondition(field string, cond *model.FloatRange, query sq.SelectBuilder) sq.SelectBuilder {
if cond.From != 1.0 && cond.To != 0.0 { if cond.From > 0.0 && cond.To > 0.0 {
return query.Where(field+" BETWEEN ? AND ?", cond.From, cond.To) return query.Where(field+" BETWEEN ? AND ?", cond.From, cond.To)
} else if cond.From != 1.0 && cond.To == 0.0 { } else if cond.From > 0.0 && cond.To == 0.0 {
return query.Where(field+" >= ?", cond.From) return query.Where(field+" >= ?", cond.From)
} else if cond.From == 1.0 && cond.To != 0.0 { } else if cond.From == 0.0 && cond.To > 0.0 {
return query.Where(field+" <= ?", cond.To) return query.Where(field+" <= ?", cond.To)
} else { } else {
return query return query
@@ -339,11 +339,11 @@ func buildTimeCondition(field string, cond *config.TimeRange, query sq.SelectBui
// buildFloatJSONCondition creates a filter on a numeric field within the footprint JSON column, using BETWEEN only if required. // buildFloatJSONCondition creates a filter on a numeric field within the footprint JSON column, using BETWEEN only if required.
func buildFloatJSONCondition(jsonField string, cond *model.FloatRange, query sq.SelectBuilder) sq.SelectBuilder { func buildFloatJSONCondition(jsonField string, cond *model.FloatRange, query sq.SelectBuilder) sq.SelectBuilder {
query = query.Where("JSON_VALID(footprint)") query = query.Where("JSON_VALID(footprint)")
if cond.From != 1.0 && cond.To != 0.0 { if cond.From > 0.0 && cond.To > 0.0 {
return query.Where("JSON_EXTRACT(footprint, \"$."+jsonField+"\") BETWEEN ? AND ?", cond.From, cond.To) return query.Where("JSON_EXTRACT(footprint, \"$."+jsonField+"\") BETWEEN ? AND ?", cond.From, cond.To)
} else if cond.From != 1.0 && cond.To == 0.0 { } else if cond.From > 0.0 && cond.To == 0.0 {
return query.Where("JSON_EXTRACT(footprint, \"$."+jsonField+"\") >= ?", cond.From) return query.Where("JSON_EXTRACT(footprint, \"$."+jsonField+"\") >= ?", cond.From)
} else if cond.From == 1.0 && cond.To != 0.0 { } else if cond.From == 0.0 && cond.To > 0.0 {
return query.Where("JSON_EXTRACT(footprint, \"$."+jsonField+"\") <= ?", cond.To) return query.Where("JSON_EXTRACT(footprint, \"$."+jsonField+"\") <= ?", cond.To)
} else { } else {
return query return query

View File

@@ -308,7 +308,7 @@ func buildFilterPresets(query url.Values) map[string]any {
if parts[0] == "lessthan" { if parts[0] == "lessthan" {
lt, lte := strconv.Atoi(parts[1]) lt, lte := strconv.Atoi(parts[1])
if lte == nil { if lte == nil {
filterPresets["numNodes"] = map[string]int{"from": 1, "to": lt} filterPresets["numNodes"] = map[string]int{"from": 0, "to": lt}
} }
} else if parts[0] == "morethan" { } else if parts[0] == "morethan" {
mt, mte := strconv.Atoi(parts[1]) mt, mte := strconv.Atoi(parts[1])
@@ -330,7 +330,7 @@ func buildFilterPresets(query url.Values) map[string]any {
if parts[0] == "lessthan" { if parts[0] == "lessthan" {
lt, lte := strconv.Atoi(parts[1]) lt, lte := strconv.Atoi(parts[1])
if lte == nil { if lte == nil {
filterPresets["numHWThreads"] = map[string]int{"from": 1, "to": lt} filterPresets["numHWThreads"] = map[string]int{"from": 0, "to": lt}
} }
} else if parts[0] == "morethan" { } else if parts[0] == "morethan" {
mt, mte := strconv.Atoi(parts[1]) mt, mte := strconv.Atoi(parts[1])
@@ -352,7 +352,7 @@ func buildFilterPresets(query url.Values) map[string]any {
if parts[0] == "lessthan" { if parts[0] == "lessthan" {
lt, lte := strconv.Atoi(parts[1]) lt, lte := strconv.Atoi(parts[1])
if lte == nil { if lte == nil {
filterPresets["numAccelerators"] = map[string]int{"from": 1, "to": lt} filterPresets["numAccelerators"] = map[string]int{"from": 0, "to": lt}
} }
} else if parts[0] == "morethan" { } else if parts[0] == "morethan" {
mt, mte := strconv.Atoi(parts[1]) mt, mte := strconv.Atoi(parts[1])
@@ -408,7 +408,7 @@ func buildFilterPresets(query url.Values) map[string]any {
if parts[0] == "lessthan" { if parts[0] == "lessthan" {
lt, lte := strconv.Atoi(parts[1]) lt, lte := strconv.Atoi(parts[1])
if lte == nil { if lte == nil {
filterPresets["energy"] = map[string]int{"from": 1, "to": lt} filterPresets["energy"] = map[string]int{"from": 0, "to": lt}
} }
} else if parts[0] == "morethan" { } else if parts[0] == "morethan" {
mt, mte := strconv.Atoi(parts[1]) mt, mte := strconv.Atoi(parts[1])
@@ -434,7 +434,7 @@ func buildFilterPresets(query url.Values) map[string]any {
if lte == nil { if lte == nil {
statEntry := map[string]any{ statEntry := map[string]any{
"field": parts[0], "field": parts[0],
"from": 1, "from": 0,
"to": lt, "to": lt,
} }
statList = append(statList, statEntry) statList = append(statList, statEntry)

View File

@@ -166,12 +166,12 @@
items.push({ project: { [filters.projectMatch]: filters.project } }); items.push({ project: { [filters.projectMatch]: filters.project } });
if (filters.user) if (filters.user)
items.push({ user: { [filters.userMatch]: filters.user } }); items.push({ user: { [filters.userMatch]: filters.user } });
if (filters.numNodes.from != null || filters.numNodes.to != null) { if (filters.numNodes.from != null && filters.numNodes.to != null) {
items.push({ items.push({
numNodes: { from: filters.numNodes.from, to: filters.numNodes.to }, numNodes: { from: filters.numNodes.from, to: filters.numNodes.to },
}); });
} }
if (filters.numAccelerators.from != null || filters.numAccelerators.to != null) { if (filters.numAccelerators.from != null && filters.numAccelerators.to != null) {
items.push({ items.push({
numAccelerators: { numAccelerators: {
from: filters.numAccelerators.from, from: filters.numAccelerators.from,
@@ -179,7 +179,7 @@
}, },
}); });
} }
if (filters.numHWThreads.from != null || filters.numHWThreads.to != null) { if (filters.numHWThreads.from != null && filters.numHWThreads.to != null) {
items.push({ items.push({
numHWThreads: { numHWThreads: {
from: filters.numHWThreads.from, from: filters.numHWThreads.from,
@@ -206,14 +206,21 @@
items.push({ duration: { to: filters.duration.lessThan, from: 0 } }); items.push({ duration: { to: filters.duration.lessThan, from: 0 } });
if (filters.duration.moreThan) if (filters.duration.moreThan)
items.push({ duration: { to: 0, from: filters.duration.moreThan } }); items.push({ duration: { to: 0, from: filters.duration.moreThan } });
if (filters.energy.from != null || filters.energy.to != null) if (filters.energy.from != null && filters.energy.to != null)
items.push({ items.push({
energy: { from: filters.energy.from, to: filters.energy.to }, energy: { from: filters.energy.from, to: filters.energy.to },
}); });
if (filters.jobId) if (filters.jobId)
items.push({ jobId: { [filters.jobIdMatch]: filters.jobId } }); items.push({ jobId: { [filters.jobIdMatch]: filters.jobId } });
if (filters.stats.length != 0) if (filters.stats.length != 0) {
items.push({ metricStats: filters.stats.map((st) => { return { metricName: st.field, range: { from: st.from, to: st.to }} }) }); const metricStats = [];
filters.stats.forEach((st) => {
if (st.from != null && st.to != null)
metricStats.push({ metricName: st.field, range: { from: st.from, to: st.to }});
});
if (metricStats.length != 0)
items.push({metricStats})
};
if (filters.node) items.push({ node: { [filters.nodeMatch]: filters.node } }); if (filters.node) items.push({ node: { [filters.nodeMatch]: filters.node } });
if (filters.jobName) items.push({ jobName: { contains: filters.jobName } }); if (filters.jobName) items.push({ jobName: { contains: filters.jobName } });
if (filters.schedule) items.push({ schedule: filters.schedule }); if (filters.schedule) items.push({ schedule: filters.schedule });
@@ -280,40 +287,40 @@
opts.push(`duration=morethan-${filters.duration.moreThan}`); opts.push(`duration=morethan-${filters.duration.moreThan}`);
if (filters.tags.length != 0) if (filters.tags.length != 0)
for (let tag of filters.tags) opts.push(`tag=${tag}`); for (let tag of filters.tags) opts.push(`tag=${tag}`);
if (filters.numNodes.from > 1 && filters.numNodes.to > 0) if (filters.numNodes.from > 0 && filters.numNodes.to > 0)
opts.push(`numNodes=${filters.numNodes.from}-${filters.numNodes.to}`); opts.push(`numNodes=${filters.numNodes.from}-${filters.numNodes.to}`);
else if (filters.numNodes.from > 1 && filters.numNodes.to == 0) else if (filters.numNodes.from > 0 && filters.numNodes.to == 0)
opts.push(`numNodes=morethan-${filters.numNodes.from}`); opts.push(`numNodes=morethan-${filters.numNodes.from}`);
else if (filters.numNodes.from == 1 && filters.numNodes.to > 0) else if (filters.numNodes.from == 0 && filters.numNodes.to > 0)
opts.push(`numNodes=lessthan-${filters.numNodes.to}`); opts.push(`numNodes=lessthan-${filters.numNodes.to}`);
if (filters.numHWThreads.from > 1 && filters.numHWThreads.to > 0) if (filters.numHWThreads.from > 0 && filters.numHWThreads.to > 0)
opts.push(`numHWThreads=${filters.numHWThreads.from}-${filters.numHWThreads.to}`); opts.push(`numHWThreads=${filters.numHWThreads.from}-${filters.numHWThreads.to}`);
else if (filters.numHWThreads.from > 1 && filters.numHWThreads.to == 0) else if (filters.numHWThreads.from > 0 && filters.numHWThreads.to == 0)
opts.push(`numHWThreads=morethan-${filters.numHWThreads.from}`); opts.push(`numHWThreads=morethan-${filters.numHWThreads.from}`);
else if (filters.numHWThreads.from == 1 && filters.numHWThreads.to > 0) else if (filters.numHWThreads.from == 0 && filters.numHWThreads.to > 0)
opts.push(`numHWThreads=lessthan-${filters.numHWThreads.to}`); opts.push(`numHWThreads=lessthan-${filters.numHWThreads.to}`);
if (filters.numAccelerators.from && filters.numAccelerators.to) if (filters.numAccelerators.from > 0 && filters.numAccelerators.to > 0)
opts.push(`numAccelerators=${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) else if (filters.numAccelerators.from > 0 && filters.numAccelerators.to == 0)
opts.push(`numAccelerators=morethan-${filters.numAccelerators.from}`); opts.push(`numAccelerators=morethan-${filters.numAccelerators.from}`);
else if (filters.numAccelerators.from == 1 && filters.numAccelerators.to > 0) else if (filters.numAccelerators.from == 0 && filters.numAccelerators.to > 0)
opts.push(`numAccelerators=lessthan-${filters.numAccelerators.to}`); opts.push(`numAccelerators=lessthan-${filters.numAccelerators.to}`);
if (filters.node) opts.push(`node=${filters.node}`); if (filters.node) opts.push(`node=${filters.node}`);
if (filters.node && filters.nodeMatch != "eq") // "eq" is default-case if (filters.node && filters.nodeMatch != "eq") // "eq" is default-case
opts.push(`nodeMatch=${filters.nodeMatch}`); opts.push(`nodeMatch=${filters.nodeMatch}`);
if (filters.energy.from > 1 && filters.energy.to > 0) if (filters.energy.from > 0 && filters.energy.to > 0)
opts.push(`energy=${filters.energy.from}-${filters.energy.to}`); opts.push(`energy=${filters.energy.from}-${filters.energy.to}`);
else if (filters.energy.from > 1 && filters.energy.to == 0) else if (filters.energy.from > 0 && filters.energy.to == 0)
opts.push(`energy=morethan-${filters.energy.from}`); opts.push(`energy=morethan-${filters.energy.from}`);
else if (filters.energy.from == 1 && filters.energy.to > 0) else if (filters.energy.from == 0 && filters.energy.to > 0)
opts.push(`energy=lessthan-${filters.energy.to}`); opts.push(`energy=lessthan-${filters.energy.to}`);
if (filters.stats.length > 0) if (filters.stats.length > 0)
for (let stat of filters.stats) { for (let stat of filters.stats) {
if (stat.from > 1 && stat.to > 0) if (stat.from > 0 && stat.to > 0)
opts.push(`stat=${stat.field}-${stat.from}-${stat.to}`); opts.push(`stat=${stat.field}-${stat.from}-${stat.to}`);
else if (stat.from > 1 && stat.to == 0) else if (stat.from > 0 && stat.to == 0)
opts.push(`stat=${stat.field}-morethan-${stat.from}`); opts.push(`stat=${stat.field}-morethan-${stat.from}`);
else if (stat.from == 1 && stat.to > 0) else if (stat.from == 0 && stat.to > 0)
opts.push(`stat=${stat.field}-lessthan-${stat.to}`); opts.push(`stat=${stat.field}-lessthan-${stat.to}`);
} }
// Build && Return // Build && Return
@@ -511,43 +518,43 @@
</Info> </Info>
{/if} {/if}
{#if filters.numNodes.from > 1 && filters.numNodes.to > 0} {#if filters.numNodes.from > 0 && filters.numNodes.to > 0}
<Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}> <Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}>
Nodes: {filters.numNodes.from} - {filters.numNodes.to} Nodes: {filters.numNodes.from} - {filters.numNodes.to}
</Info> </Info>
{:else if filters.numNodes.from > 1 && filters.numNodes.to == 0} {:else if filters.numNodes.from > 0 && filters.numNodes.to == 0}
<Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}> <Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}>
&nbsp;&ge;&nbsp;{filters.numNodes.from} Node(s) &nbsp;&ge;&nbsp;{filters.numNodes.from} Node(s)
</Info> </Info>
{:else if filters.numNodes.from == 1 && filters.numNodes.to > 0} {:else if filters.numNodes.from == 0 && filters.numNodes.to > 0}
<Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}> <Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}>
&nbsp;&le;&nbsp;{filters.numNodes.to} Node(s) &nbsp;&le;&nbsp;{filters.numNodes.to} Node(s)
</Info> </Info>
{/if} {/if}
{#if filters.numHWThreads.from > 1 && filters.numHWThreads.to > 0} {#if filters.numHWThreads.from > 0 && filters.numHWThreads.to > 0}
<Info icon="cpu" onclick={() => (isResourcesOpen = true)}> <Info icon="cpu" onclick={() => (isResourcesOpen = true)}>
HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to} HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to}
</Info> </Info>
{:else if filters.numHWThreads.from > 1 && filters.numHWThreads.to == 0} {:else if filters.numHWThreads.from > 0 && filters.numHWThreads.to == 0}
<Info icon="cpu" onclick={() => (isResourcesOpen = true)}> <Info icon="cpu" onclick={() => (isResourcesOpen = true)}>
&nbsp;&ge;&nbsp;{filters.numHWThreads.from} HWThread(s) &nbsp;&ge;&nbsp;{filters.numHWThreads.from} HWThread(s)
</Info> </Info>
{:else if filters.numHWThreads.from == 1 && filters.numHWThreads.to > 0} {:else if filters.numHWThreads.from == 0 && filters.numHWThreads.to > 0}
<Info icon="cpu" onclick={() => (isResourcesOpen = true)}> <Info icon="cpu" onclick={() => (isResourcesOpen = true)}>
&nbsp;&le;&nbsp;{filters.numHWThreads.to} HWThread(s) &nbsp;&le;&nbsp;{filters.numHWThreads.to} HWThread(s)
</Info> </Info>
{/if} {/if}
{#if filters.numAccelerators.from > 1 && filters.numAccelerators.to > 0} {#if filters.numAccelerators.from > 0 && filters.numAccelerators.to > 0}
<Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}> <Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}>
Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to} Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to}
</Info> </Info>
{:else if filters.numAccelerators.from > 1 && filters.numAccelerators.to == 0} {:else if filters.numAccelerators.from > 0 && filters.numAccelerators.to == 0}
<Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}> <Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}>
&nbsp;&ge;&nbsp;{filters.numAccelerators.from} Acc(s) &nbsp;&ge;&nbsp;{filters.numAccelerators.from} Acc(s)
</Info> </Info>
{:else if filters.numAccelerators.from == 1 && filters.numAccelerators.to > 0} {:else if filters.numAccelerators.from == 0 && filters.numAccelerators.to > 0}
<Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}> <Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}>
&nbsp;&le;&nbsp;{filters.numAccelerators.to} Acc(s) &nbsp;&le;&nbsp;{filters.numAccelerators.to} Acc(s)
</Info> </Info>
@@ -559,15 +566,15 @@
</Info> </Info>
{/if} {/if}
{#if filters.energy.from > 1 && filters.energy.to > 0} {#if filters.energy.from > 0 && filters.energy.to > 0}
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}> <Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
Total Energy: {filters.energy.from} - {filters.energy.to} kWh Total Energy: {filters.energy.from} - {filters.energy.to} kWh
</Info> </Info>
{:else if filters.energy.from > 1 && filters.energy.to == 0} {:else if filters.energy.from > 0 && filters.energy.to == 0}
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}> <Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
Total Energy &ge;&nbsp;{filters.energy.from} kWh Total Energy &ge;&nbsp;{filters.energy.from} kWh
</Info> </Info>
{:else if filters.energy.from == 1 && filters.energy.to > 0} {:else if filters.energy.from == 0 && filters.energy.to > 0}
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}> <Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
Total Energy &le;&nbsp;{filters.energy.to} kWh Total Energy &le;&nbsp;{filters.energy.to} kWh
</Info> </Info>
@@ -575,15 +582,15 @@
{#if filters.stats.length > 0} {#if filters.stats.length > 0}
{#each filters.stats as stat} {#each filters.stats as stat}
{#if stat.from > 1 && stat.to > 0} {#if stat.from > 0 && stat.to > 0}
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}> <Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
{stat.field}: {stat.from} - {stat.to} {stat.unit} {stat.field}: {stat.from} - {stat.to} {stat.unit}
</Info>&thinsp; </Info>&thinsp;
{:else if stat.from > 1 && stat.to == 0} {:else if stat.from > 0 && stat.to == 0}
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}> <Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
{stat.field} &ge;&nbsp;{stat.from} {stat.unit} {stat.field} &ge;&nbsp;{stat.from} {stat.unit}
</Info>&thinsp; </Info>&thinsp;
{:else if stat.from == 1 && stat.to > 0} {:else if stat.from == 0 && stat.to > 0}
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}> <Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
{stat.field} &le;&nbsp;{stat.to} {stat.unit} {stat.field} &le;&nbsp;{stat.to} {stat.unit}
</Info>&thinsp; </Info>&thinsp;

View File

@@ -28,31 +28,29 @@
} = $props(); } = $props();
/* Const */ /* Const */
const minEnergyPreset = 1; const minEnergyPreset = 0;
const maxEnergyPreset = 100; const maxEnergyPreset = 100;
/* Derived */ /* Derived */
// Pending // Pending
let pendingEnergyState = $derived({ let pendingEnergyState = $derived({
from: presetEnergy?.from ? presetEnergy.from : minEnergyPreset, from: presetEnergy?.from || minEnergyPreset,
to: !(presetEnergy.to == null || presetEnergy.to == 0) ? presetEnergy.to : maxEnergyPreset, to: (presetEnergy.to == 0) ? null : presetEnergy.to,
}); });
// Changable // Changable
let energyState = $derived({ let energyState = $derived({
from: presetEnergy?.from ? presetEnergy.from : minEnergyPreset, from: presetEnergy?.from || minEnergyPreset,
to: !(presetEnergy.to == null || presetEnergy.to == 0) ? presetEnergy.to : maxEnergyPreset, to: (presetEnergy.to == 0) ? null : presetEnergy.to,
}); });
const energyActive = $derived(!(JSON.stringify(energyState) === JSON.stringify({ from: minEnergyPreset, to: maxEnergyPreset }))); const energyActive = $derived(!(JSON.stringify(energyState) === JSON.stringify({ from: minEnergyPreset, to: null })));
// Block Apply if null
const disableApply = $derived(energyState.from === null || energyState.to === null);
/* Function */ /* Function */
function setEnergy() { function setEnergy() {
if (energyActive) { if (energyActive) {
pendingEnergyState = { pendingEnergyState = {
from: energyState.from, from: (!energyState?.from) ? 0 : energyState.from,
to: (energyState.to == maxEnergyPreset) ? 0 : energyState.to to: (energyState.to === null) ? 0 : energyState.to
}; };
} else { } else {
pendingEnergyState = { from: null, to: null}; pendingEnergyState = { from: null, to: null};
@@ -86,7 +84,6 @@
<ModalFooter> <ModalFooter>
<Button <Button
color="primary" color="primary"
disabled={disableApply}
onclick={() => { onclick={() => {
isOpen = false; isOpen = false;
setEnergy(); setEnergy();

View File

@@ -98,44 +98,38 @@
// Pending // Pending
let pendingNumNodes = $derived({ let pendingNumNodes = $derived({
from: presetNumNodes.from, from: presetNumNodes.from,
to: (presetNumNodes.to == 0) ? maxNumNodes : presetNumNodes.to to: (presetNumNodes.to == 0) ? null : presetNumNodes.to
}); });
let pendingNumHWThreads = $derived({ let pendingNumHWThreads = $derived({
from: presetNumHWThreads.from, from: presetNumHWThreads.from,
to: (presetNumHWThreads.to == 0) ? maxNumHWThreads : presetNumHWThreads.to to: (presetNumHWThreads.to == 0) ? null : presetNumHWThreads.to
}); });
let pendingNumAccelerators = $derived({ let pendingNumAccelerators = $derived({
from: presetNumAccelerators.from, from: presetNumAccelerators.from,
to: (presetNumAccelerators.to == 0) ? maxNumAccelerators : presetNumAccelerators.to to: (presetNumAccelerators.to == 0) ? null : presetNumAccelerators.to
}); });
let pendingNamedNode = $derived(presetNamedNode); let pendingNamedNode = $derived(presetNamedNode);
let pendingNodeMatch = $derived(presetNodeMatch); let pendingNodeMatch = $derived(presetNodeMatch);
// Changable States // Changable States
let nodesState = $derived({ let nodesState = $derived({
from: presetNumNodes.from, from: presetNumNodes?.from || 0,
to: (presetNumNodes.to == 0) ? maxNumNodes : presetNumNodes.to to: (presetNumNodes.to == 0) ? null : presetNumNodes.to
}); });
let threadState = $derived({ let threadState = $derived({
from: presetNumHWThreads.from, from: presetNumHWThreads?.from || 0,
to: (presetNumHWThreads.to == 0) ? maxNumHWThreads : presetNumHWThreads.to to: (presetNumHWThreads.to == 0) ? null : presetNumHWThreads.to
}); });
let accState = $derived({ let accState = $derived({
from: presetNumAccelerators.from, from: presetNumAccelerators?.from || 0,
to: (presetNumAccelerators.to == 0) ? maxNumAccelerators : presetNumAccelerators.to to: (presetNumAccelerators.to == 0) ? null : presetNumAccelerators.to
}); });
const initialized = $derived(getContext("initialized") || false); const initialized = $derived(getContext("initialized") || false);
const clusterInfos = $derived($initialized ? getContext("clusters") : null); const clusterInfos = $derived($initialized ? getContext("clusters") : null);
// Is Selection Active // Is Selection Active
const nodesActive = $derived(!(JSON.stringify(nodesState) === JSON.stringify({ from: 1, to: maxNumNodes }))); const nodesActive = $derived(!(JSON.stringify(nodesState) === JSON.stringify({ from: 0, to: null })));
const threadActive = $derived(!(JSON.stringify(threadState) === JSON.stringify({ from: 1, to: maxNumHWThreads }))); const threadActive = $derived(!(JSON.stringify(threadState) === JSON.stringify({ from: 0, to: null })));
const accActive = $derived(!(JSON.stringify(accState) === JSON.stringify({ from: 1, to: maxNumAccelerators }))); const accActive = $derived(!(JSON.stringify(accState) === JSON.stringify({ from: 0, to: null })));
// Block Apply if null
const disableApply = $derived(
nodesState.from === null || nodesState.to === null ||
threadState.from === null || threadState.to === null ||
accState.from === null || accState.to === null
);
/* Reactive Effects | Svelte 5 onMount */ /* Reactive Effects | Svelte 5 onMount */
$effect(() => { $effect(() => {
@@ -153,58 +147,28 @@
} }
}); });
$effect(() => {
if (
$initialized &&
pendingNumNodes.from == null &&
pendingNumNodes.to == null
) {
nodesState = { from: 1, to: maxNumNodes };
}
});
$effect(() => {
if (
$initialized &&
pendingNumHWThreads.from == null &&
pendingNumHWThreads.to == null
) {
threadState = { from: 1, to: maxNumHWThreads };
}
});
$effect(() => {
if (
$initialized &&
pendingNumAccelerators.from == null &&
pendingNumAccelerators.to == null
) {
accState = { from: 1, to: maxNumAccelerators };
}
});
/* Functions */ /* Functions */
function setResources() { function setResources() {
if (nodesActive) { if (nodesActive) {
pendingNumNodes = { pendingNumNodes = {
from: nodesState.from, from: (!nodesState?.from) ? 0 : nodesState.from,
to: (nodesState.to == maxNumNodes) ? 0 : nodesState.to to: (nodesState.to === null) ? 0 : nodesState.to
}; };
} else { } else {
pendingNumNodes = { from: null, to: null}; pendingNumNodes = { from: null, to: null};
}; };
if (threadActive) { if (threadActive) {
pendingNumHWThreads = { pendingNumHWThreads = {
from: threadState.from, from: (!threadState?.from) ? 0 : threadState.from,
to: (threadState.to == maxNumHWThreads) ? 0 : threadState.to to: (threadState.to === null) ? 0 : threadState.to
}; };
} else { } else {
pendingNumHWThreads = { from: null, to: null}; pendingNumHWThreads = { from: null, to: null};
}; };
if (accActive) { if (accActive) {
pendingNumAccelerators = { pendingNumAccelerators = {
from: accState.from, from: (!accState?.from) ? 0 : accState.from,
to: (accState.to == maxNumAccelerators) ? 0 : accState.to to: (accState.to === null) ? 0 : accState.to
}; };
} else { } else {
pendingNumAccelerators = { from: null, to: null}; pendingNumAccelerators = { from: null, to: null};
@@ -249,7 +213,7 @@
nodesState.from = detail[0]; nodesState.from = detail[0];
nodesState.to = detail[1]; nodesState.to = detail[1];
}} }}
sliderMin={1} sliderMin={0}
sliderMax={maxNumNodes} sliderMax={maxNumNodes}
fromPreset={nodesState.from} fromPreset={nodesState.from}
toPreset={nodesState.to} toPreset={nodesState.to}
@@ -269,7 +233,7 @@
threadState.from = detail[0]; threadState.from = detail[0];
threadState.to = detail[1]; threadState.to = detail[1];
}} }}
sliderMin={1} sliderMin={0}
sliderMax={maxNumHWThreads} sliderMax={maxNumHWThreads}
fromPreset={threadState.from} fromPreset={threadState.from}
toPreset={threadState.to} toPreset={threadState.to}
@@ -289,7 +253,7 @@
accState.from = detail[0]; accState.from = detail[0];
accState.to = detail[1]; accState.to = detail[1];
}} }}
sliderMin={1} sliderMin={0}
sliderMax={maxNumAccelerators} sliderMax={maxNumAccelerators}
fromPreset={accState.from} fromPreset={accState.from}
toPreset={accState.to} toPreset={accState.to}
@@ -300,7 +264,6 @@
<ModalFooter> <ModalFooter>
<Button <Button
color="primary" color="primary"
disabled={disableApply}
onclick={() => { onclick={() => {
isOpen = false; isOpen = false;
setResources(); setResources();

View File

@@ -34,7 +34,8 @@
function setRanges() { function setRanges() {
for (let as of availableStats) { for (let as of availableStats) {
if (as.enabled) { if (as.enabled) {
as.to = (as.to == as.peak) ? 0 : as.to as.from = (!as?.from) ? 0 : as.from,
as.to = (as.to == null) ? 0 : as.to
} }
}; };
} }
@@ -42,8 +43,8 @@
function resetRanges() { function resetRanges() {
for (let as of availableStats) { for (let as of availableStats) {
as.enabled = false as.enabled = false
as.from = 1 as.from = null
as.to = as.peak as.to = null
}; };
} }
</script> </script>
@@ -66,13 +67,13 @@
changeRange={(detail) => { changeRange={(detail) => {
aStat.from = detail[0]; aStat.from = detail[0];
aStat.to = detail[1]; aStat.to = detail[1];
if (aStat.from == 1 && aStat.to == aStat.peak) { if (aStat.from == 0 && aStat.to === null) {
aStat.enabled = false; aStat.enabled = false;
} else { } else {
aStat.enabled = true; aStat.enabled = true;
} }
}} }}
sliderMin={1} sliderMin={0}
sliderMax={aStat.peak} sliderMax={aStat.peak}
fromPreset={aStat.from} fromPreset={aStat.from}
toPreset={aStat.to} toPreset={aStat.to}

View File

@@ -21,7 +21,7 @@
let { let {
sliderMin, sliderMin,
sliderMax, sliderMax,
fromPreset = 1, fromPreset = 0,
toPreset = 100, toPreset = 100,
changeRange changeRange
} = $props(); } = $props();
@@ -33,9 +33,9 @@
/* Derived */ /* Derived */
let pendingValues = $derived([fromPreset, toPreset]); let pendingValues = $derived([fromPreset, toPreset]);
let sliderFrom = $derived(Math.max(((fromPreset == null ? sliderMin : fromPreset) - sliderMin) / (sliderMax - sliderMin), 0.)); 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 sliderTo = $derived(Math.min(((toPreset == null ? sliderMax : toPreset) - sliderMin) / (sliderMax - sliderMin), 1.));
let inputFieldFrom = $derived(fromPreset ? fromPreset.toString() : null); let inputFieldFrom = $derived(fromPreset != null ? fromPreset.toString() : null);
let inputFieldTo = $derived(toPreset ? toPreset.toString() : null); let inputFieldTo = $derived(toPreset != null ? toPreset.toString() : null);
/* Var Init */ /* Var Init */
let timeoutId = null; let timeoutId = null;
@@ -79,17 +79,22 @@
evt.preventDefault() evt.preventDefault()
evt.stopPropagation() evt.stopPropagation()
const newV = Number.parseInt(evt.target.value); const newV = Number.parseInt(evt.target.value);
const newP = clamp((newV - sliderMin) / (sliderMax - sliderMin), 0., 1.) const newP = clamp((newV - sliderMin) / (sliderMax - sliderMin), 0., 1., target)
updateStates(newV, newP, target); updateStates(newV, newP, target);
} }
function clamp(x, testMin, testMax) { function clamp(x, testMin, testMax, target) {
return x < testMin if (isNaN(x)) {
? testMin if (target == 'from') return testMin
: (x > testMax else if (target == 'to') return testMax
? testMax } else {
: x return x < testMin
); ? testMin
: (x > testMax
? testMax
: x
);
}
} }
function draggable(node) { function draggable(node) {
@@ -159,23 +164,23 @@
<div class="double-range-container"> <div class="double-range-container">
<div class="header"> <div class="header">
<input class="form-control" type="text" placeholder="from..." value={inputFieldFrom} <input class="form-control" type="text" placeholder={`${sliderMin} ...`} value={inputFieldFrom}
oninput={(e) => { oninput={(e) => {
inputChanged(e, 'from'); inputChanged(e, 'from');
}} }}
/> />
{#if inputFieldFrom != sliderMin?.toString() && inputFieldTo != sliderMax?.toString() } {#if (inputFieldFrom && inputFieldFrom != sliderMin?.toString()) && inputFieldTo != null }
<span>Selected: Range <b> {inputFieldFrom} </b> - <b> {inputFieldTo} </b></span> <span>Selected: Range <b> {inputFieldFrom} </b> - <b> {inputFieldTo} </b></span>
{:else if inputFieldFrom != sliderMin?.toString() && inputFieldTo == sliderMax?.toString() } {:else if (inputFieldFrom && inputFieldFrom != sliderMin?.toString()) && inputFieldTo == null }
<span>Selected: More than <b> {inputFieldFrom} </b> </span> <span>Selected: More Than Equal <b> {inputFieldFrom} </b> </span>
{:else if inputFieldFrom == sliderMin?.toString() && inputFieldTo != sliderMax?.toString() } {:else if (!inputFieldFrom || inputFieldFrom == sliderMin?.toString()) && inputFieldTo != null }
<span>Selected: Less than <b> {inputFieldTo} </b></span> <span>Selected: Less Than Equal <b> {inputFieldTo} </b></span>
{:else} {:else}
<span><i>No Selection</i></span> <span><i>No Selection</i></span>
{/if} {/if}
<input class="form-control" type="text" placeholder="to..." value={inputFieldTo} <input class="form-control" type="text" placeholder={`... ${sliderMax} ...`} value={inputFieldTo}
oninput={(e) => { oninput={(e) => {
inputChanged(e, 'to'); inputChanged(e, 'to');
}} }}

View File

@@ -347,8 +347,8 @@ export function getStatsItems(presetStats = []) {
field: presetEntry.field, field: presetEntry.field,
text: `${gm.name} (${gm.footprint})`, text: `${gm.name} (${gm.footprint})`,
metric: gm.name, metric: gm.name,
from: presetEntry.from, from: presetEntry?.from || 0,
to: (presetEntry.to == 0) ? mc.peak : presetEntry.to, to: (presetEntry.to == 0) ? null : presetEntry.to,
peak: mc.peak, peak: mc.peak,
enabled: true, enabled: true,
unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}` unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}`
@@ -358,8 +358,8 @@ export function getStatsItems(presetStats = []) {
field: `${gm.name}_${gm.footprint}`, field: `${gm.name}_${gm.footprint}`,
text: `${gm.name} (${gm.footprint})`, text: `${gm.name} (${gm.footprint})`,
metric: gm.name, metric: gm.name,
from: 1, from: 0,
to: mc.peak, to: null,
peak: mc.peak, peak: mc.peak,
enabled: false, enabled: false,
unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}` unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}`