mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2026-03-05 07:37:30 +01:00
apply updated rangefilter logic to energy and stats
This commit is contained in:
@@ -405,6 +405,17 @@ func buildFilterPresets(query url.Values) map[string]any {
|
|||||||
if query.Get("energy") != "" {
|
if query.Get("energy") != "" {
|
||||||
parts := strings.Split(query.Get("energy"), "-")
|
parts := strings.Split(query.Get("energy"), "-")
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
|
if parts[0] == "lessthan" {
|
||||||
|
lt, lte := strconv.Atoi(parts[1])
|
||||||
|
if lte == nil {
|
||||||
|
filterPresets["energy"] = map[string]int{"from": 1, "to": lt}
|
||||||
|
}
|
||||||
|
} else if parts[0] == "morethan" {
|
||||||
|
mt, mte := strconv.Atoi(parts[1])
|
||||||
|
if mte == nil {
|
||||||
|
filterPresets["energy"] = map[string]int{"from": mt, "to": 0}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
a, e1 := strconv.Atoi(parts[0])
|
a, e1 := strconv.Atoi(parts[0])
|
||||||
b, e2 := strconv.Atoi(parts[1])
|
b, e2 := strconv.Atoi(parts[1])
|
||||||
if e1 == nil && e2 == nil {
|
if e1 == nil && e2 == nil {
|
||||||
@@ -412,11 +423,33 @@ func buildFilterPresets(query url.Values) map[string]any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if len(query["stat"]) != 0 {
|
if len(query["stat"]) != 0 {
|
||||||
statList := make([]map[string]any, 0)
|
statList := make([]map[string]any, 0)
|
||||||
for _, statEntry := range query["stat"] {
|
for _, statEntry := range query["stat"] {
|
||||||
parts := strings.Split(statEntry, "-")
|
parts := strings.Split(statEntry, "-")
|
||||||
if len(parts) == 3 { // Metric Footprint Stat Field, from - to
|
if len(parts) == 3 { // Metric Footprint Stat Field, from - to
|
||||||
|
if parts[1] == "lessthan" {
|
||||||
|
lt, lte := strconv.ParseInt(parts[2], 10, 64)
|
||||||
|
if lte == nil {
|
||||||
|
statEntry := map[string]any{
|
||||||
|
"field": parts[0],
|
||||||
|
"from": 1,
|
||||||
|
"to": lt,
|
||||||
|
}
|
||||||
|
statList = append(statList, statEntry)
|
||||||
|
}
|
||||||
|
} else if parts[1] == "morethan" {
|
||||||
|
mt, mte := strconv.ParseInt(parts[2], 10, 64)
|
||||||
|
if mte == nil {
|
||||||
|
statEntry := map[string]any{
|
||||||
|
"field": parts[0],
|
||||||
|
"from": mt,
|
||||||
|
"to": 0,
|
||||||
|
}
|
||||||
|
statList = append(statList, statEntry)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
a, e1 := strconv.ParseInt(parts[1], 10, 64)
|
a, e1 := strconv.ParseInt(parts[1], 10, 64)
|
||||||
b, e2 := strconv.ParseInt(parts[2], 10, 64)
|
b, e2 := strconv.ParseInt(parts[2], 10, 64)
|
||||||
if e1 == nil && e2 == nil {
|
if e1 == nil && e2 == nil {
|
||||||
@@ -429,6 +462,7 @@ func buildFilterPresets(query url.Values) map[string]any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
filterPresets["stats"] = statList
|
filterPresets["stats"] = statList
|
||||||
}
|
}
|
||||||
return filterPresets
|
return filterPresets
|
||||||
|
|||||||
@@ -206,7 +206,7 @@
|
|||||||
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 || filters.energy.to)
|
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 },
|
||||||
});
|
});
|
||||||
@@ -301,11 +301,20 @@
|
|||||||
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 && filters.energy.to)
|
if (filters.energy.from > 1 && filters.energy.to > 0)
|
||||||
opts.push(`energy=${filters.energy.from}-${filters.energy.to}`);
|
opts.push(`energy=${filters.energy.from}-${filters.energy.to}`);
|
||||||
if (filters.stats.length != 0)
|
else if (filters.energy.from > 1 && filters.energy.to == 0)
|
||||||
|
opts.push(`energy=morethan-${filters.energy.from}`);
|
||||||
|
else if (filters.energy.from == 1 && filters.energy.to > 0)
|
||||||
|
opts.push(`energy=lessthan-${filters.energy.to}`);
|
||||||
|
if (filters.stats.length > 0)
|
||||||
for (let stat of filters.stats) {
|
for (let stat of filters.stats) {
|
||||||
|
if (stat.from > 1 && 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)
|
||||||
|
opts.push(`stat=${stat.field}-morethan-${stat.from}`);
|
||||||
|
else if (stat.from == 1 && stat.to > 0)
|
||||||
|
opts.push(`stat=${stat.field}-lessthan-${stat.to}`);
|
||||||
}
|
}
|
||||||
// Build && Return
|
// Build && Return
|
||||||
if (opts.length == 0 && window.location.search.length <= 1) return;
|
if (opts.length == 0 && window.location.search.length <= 1) return;
|
||||||
@@ -550,18 +559,36 @@
|
|||||||
</Info>
|
</Info>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if filters.energy.from || filters.energy.to}
|
{#if filters.energy.from > 1 && 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}
|
Total Energy: {filters.energy.from} - {filters.energy.to} kWh
|
||||||
|
</Info>
|
||||||
|
{:else if filters.energy.from > 1 && filters.energy.to == 0}
|
||||||
|
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
|
||||||
|
Total Energy ≥ {filters.energy.from} kWh
|
||||||
|
</Info>
|
||||||
|
{:else if filters.energy.from == 1 && filters.energy.to > 0}
|
||||||
|
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
|
||||||
|
Total Energy ≤ {filters.energy.to} kWh
|
||||||
</Info>
|
</Info>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if filters.stats.length > 0}
|
{#if filters.stats.length > 0}
|
||||||
|
{#each filters.stats as stat}
|
||||||
|
{#if stat.from > 1 && stat.to > 0}
|
||||||
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
|
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
|
||||||
{filters.stats
|
{stat.field}: {stat.from} - {stat.to} {stat.unit}
|
||||||
.map((stat) => `${stat.field}: ${stat.from} - ${stat.to}`)
|
</Info> 
|
||||||
.join(", ")}
|
{:else if stat.from > 1 && stat.to == 0}
|
||||||
</Info>
|
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
|
||||||
|
{stat.field} ≥ {stat.from} {stat.unit}
|
||||||
|
</Info> 
|
||||||
|
{:else if stat.from == 1 && stat.to > 0}
|
||||||
|
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
|
||||||
|
{stat.field} ≤ {stat.to} {stat.unit}
|
||||||
|
</Info> 
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -15,54 +15,90 @@
|
|||||||
ModalBody,
|
ModalBody,
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
|
Tooltip,
|
||||||
|
Icon
|
||||||
} from "@sveltestrap/sveltestrap";
|
} from "@sveltestrap/sveltestrap";
|
||||||
import DoubleRangeSlider from "../select/DoubleRangeSlider.svelte";
|
import DoubleRangeSlider from "../select/DoubleRangeSlider.svelte";
|
||||||
|
|
||||||
/* Svelte 5 Props */
|
/* Svelte 5 Props */
|
||||||
let {
|
let {
|
||||||
isOpen = $bindable(false),
|
isOpen = $bindable(false),
|
||||||
presetEnergy = {
|
presetEnergy = { from: null, to: null },
|
||||||
from: null,
|
|
||||||
to: null
|
|
||||||
},
|
|
||||||
setFilter,
|
setFilter,
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
|
/* Const */
|
||||||
|
const minEnergyPreset = 1;
|
||||||
|
const maxEnergyPreset = 1000;
|
||||||
|
|
||||||
/* Derived */
|
/* Derived */
|
||||||
let energyState = $derived(presetEnergy);
|
// Pending
|
||||||
|
let pendingEnergyState = $derived({
|
||||||
|
from: presetEnergy?.from ? presetEnergy.from : minEnergyPreset,
|
||||||
|
to: !(presetEnergy.to == null || presetEnergy.to == 0) ? presetEnergy.to : maxEnergyPreset,
|
||||||
|
});
|
||||||
|
// Changable
|
||||||
|
let energyState = $derived({
|
||||||
|
from: presetEnergy?.from ? presetEnergy.from : minEnergyPreset,
|
||||||
|
to: !(presetEnergy.to == null || presetEnergy.to == 0) ? presetEnergy.to : maxEnergyPreset,
|
||||||
|
});
|
||||||
|
|
||||||
|
const energyActive = $derived(!(JSON.stringify(energyState) === JSON.stringify({ from: minEnergyPreset, to: maxEnergyPreset })));
|
||||||
|
// Block Apply if null
|
||||||
|
const disableApply = $derived(energyState.from === null || energyState.to === null);
|
||||||
|
|
||||||
|
/* Function */
|
||||||
|
function setEnergy() {
|
||||||
|
if (energyActive) {
|
||||||
|
pendingEnergyState = {
|
||||||
|
from: energyState.from,
|
||||||
|
to: (energyState.to == maxEnergyPreset) ? 0 : energyState.to
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
pendingEnergyState = { from: null, to: null};
|
||||||
|
};
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal {isOpen} toggle={() => (isOpen = !isOpen)}>
|
<Modal {isOpen} toggle={() => (isOpen = !isOpen)}>
|
||||||
<ModalHeader>Filter based on energy</ModalHeader>
|
<ModalHeader>Filter based on energy</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="mb-0"><b>Total Job Energy (kWh)</b></div>
|
<div class="mb-0">
|
||||||
|
<b>Total Job Energy (kWh)</b>
|
||||||
|
<Icon id="energy-info" style="cursor:help; padding-right: 10px;" size="sm" name="info-circle"/>
|
||||||
|
</div>
|
||||||
|
<Tooltip target={`energy-info`} placement="right">
|
||||||
|
Generalized Presets. Use input fields to change to higher values.
|
||||||
|
</Tooltip>
|
||||||
<DoubleRangeSlider
|
<DoubleRangeSlider
|
||||||
changeRange={(detail) => {
|
changeRange={(detail) => {
|
||||||
energyState.from = detail[0];
|
energyState.from = detail[0];
|
||||||
energyState.to = detail[1];
|
energyState.to = detail[1];
|
||||||
}}
|
}}
|
||||||
sliderMin={0.0}
|
sliderMin={minEnergyPreset}
|
||||||
sliderMax={1000.0}
|
sliderMax={maxEnergyPreset}
|
||||||
fromPreset={energyState?.from? energyState.from : 0.0}
|
fromPreset={energyState.from}
|
||||||
toPreset={energyState?.to? energyState.to : 1000.0}
|
toPreset={energyState.to}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
|
disabled={disableApply}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
setFilter({ energy: energyState });
|
setEnergy();
|
||||||
|
setFilter({ energy: pendingEnergyState });
|
||||||
}}>Close & Apply</Button
|
}}>Close & Apply</Button
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
color="danger"
|
color="danger"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
energyState = {from: null, to: null};
|
pendingEnergyState = {from: null, to: null};
|
||||||
setFilter({ energy: energyState });
|
setFilter({ energy: pendingEnergyState });
|
||||||
}}>Reset</Button
|
}}>Reset</Button
|
||||||
>
|
>
|
||||||
<Button onclick={() => (isOpen = false)}>Close</Button>
|
<Button onclick={() => (isOpen = false)}>Close</Button>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
} = $props();
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button class="mr-2 mb-1" outline color={modified ? "warning" : "primary"} {onclick}>
|
<Button class="mb-1" outline color={modified ? "warning" : "primary"} {onclick}>
|
||||||
<Icon name={icon} />
|
<Icon name={icon} />
|
||||||
{#if children}
|
{#if children}
|
||||||
<!-- Note: Ignore '@' Error in IDE -->
|
<!-- Note: Ignore '@' Error in IDE -->
|
||||||
|
|||||||
@@ -262,7 +262,7 @@
|
|||||||
<Icon id="numthreads-info" style="cursor:help; padding-right: 10px;" size="sm" name="info-circle"/>
|
<Icon id="numthreads-info" style="cursor:help; padding-right: 10px;" size="sm" name="info-circle"/>
|
||||||
</div>
|
</div>
|
||||||
<Tooltip target={`numthreads-info`} placement="right">
|
<Tooltip target={`numthreads-info`} placement="right">
|
||||||
Presets for a single node. Can be changed to higher values.
|
Presets for a single node. Use input fields to change to higher values.
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<DoubleRangeSlider
|
<DoubleRangeSlider
|
||||||
changeRange={(detail) => {
|
changeRange={(detail) => {
|
||||||
@@ -282,7 +282,7 @@
|
|||||||
<Icon id="numaccs-info" style="cursor:help; padding-right: 10px;" size="sm" name="info-circle"/>
|
<Icon id="numaccs-info" style="cursor:help; padding-right: 10px;" size="sm" name="info-circle"/>
|
||||||
</div>
|
</div>
|
||||||
<Tooltip target={`numaccs-info`} placement="right">
|
<Tooltip target={`numaccs-info`} placement="right">
|
||||||
Presets for a single node. Can be changed to higher values.
|
Presets for a single node. Use input fields to change to higher values.
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<DoubleRangeSlider
|
<DoubleRangeSlider
|
||||||
changeRange={(detail) => {
|
changeRange={(detail) => {
|
||||||
|
|||||||
@@ -15,13 +15,15 @@
|
|||||||
ModalBody,
|
ModalBody,
|
||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
|
Tooltip,
|
||||||
|
Icon
|
||||||
} from "@sveltestrap/sveltestrap";
|
} from "@sveltestrap/sveltestrap";
|
||||||
import DoubleRangeSlider from "../select/DoubleRangeSlider.svelte";
|
import DoubleRangeSlider from "../select/DoubleRangeSlider.svelte";
|
||||||
|
|
||||||
/* Svelte 5 Props */
|
/* Svelte 5 Props */
|
||||||
let {
|
let {
|
||||||
isOpen = $bindable(),
|
isOpen = $bindable(),
|
||||||
presetStats,
|
presetStats = [],
|
||||||
setFilter
|
setFilter
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
@@ -29,10 +31,18 @@
|
|||||||
const availableStats = $derived(getStatsItems(presetStats));
|
const availableStats = $derived(getStatsItems(presetStats));
|
||||||
|
|
||||||
/* Functions */
|
/* Functions */
|
||||||
|
function setRanges() {
|
||||||
|
for (let as of availableStats) {
|
||||||
|
if (as.enabled) {
|
||||||
|
as.to = (as.to == as.peak) ? 0 : as.to
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function resetRanges() {
|
function resetRanges() {
|
||||||
for (let as of availableStats) {
|
for (let as of availableStats) {
|
||||||
as.enabled = false
|
as.enabled = false
|
||||||
as.from = 0
|
as.from = 1
|
||||||
as.to = as.peak
|
as.to = as.peak
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -45,18 +55,24 @@
|
|||||||
<ModalBody>
|
<ModalBody>
|
||||||
{#each availableStats as aStat}
|
{#each availableStats as aStat}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="mb-0"><b>{aStat.text}</b></div>
|
<div class="mb-0">
|
||||||
|
<b>{aStat.text} ({aStat.unit})</b>
|
||||||
|
<Icon id={`${aStat.metric}-info`} style="cursor:help; padding-right: 10px;" size="sm" name="info-circle"/>
|
||||||
|
</div>
|
||||||
|
<Tooltip target={`${aStat.metric}-info`} placement="right">
|
||||||
|
Peak Threshold Preset. Use input fields to change to higher values.
|
||||||
|
</Tooltip>
|
||||||
<DoubleRangeSlider
|
<DoubleRangeSlider
|
||||||
changeRange={(detail) => {
|
changeRange={(detail) => {
|
||||||
aStat.from = detail[0];
|
aStat.from = detail[0];
|
||||||
aStat.to = detail[1];
|
aStat.to = detail[1];
|
||||||
if (aStat.from == 0 && aStat.to == aStat.peak) {
|
if (aStat.from == 1 && aStat.to == aStat.peak) {
|
||||||
aStat.enabled = false;
|
aStat.enabled = false;
|
||||||
} else {
|
} else {
|
||||||
aStat.enabled = true;
|
aStat.enabled = true;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
sliderMin={0.0}
|
sliderMin={1}
|
||||||
sliderMax={aStat.peak}
|
sliderMax={aStat.peak}
|
||||||
fromPreset={aStat.from}
|
fromPreset={aStat.from}
|
||||||
toPreset={aStat.to}
|
toPreset={aStat.to}
|
||||||
@@ -69,6 +85,7 @@
|
|||||||
color="primary"
|
color="primary"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
|
setRanges();
|
||||||
setFilter({ stats: [...availableStats.filter((as) => as.enabled)] });
|
setFilter({ stats: [...availableStats.filter((as) => as.enabled)] });
|
||||||
}}>Close & Apply</Button
|
}}>Close & Apply</Button
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -165,11 +165,11 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if inputFieldFrom != "1" && inputFieldTo != sliderMax?.toString() }
|
{#if inputFieldFrom != sliderMin?.toString() && inputFieldTo != sliderMax?.toString() }
|
||||||
<span>Selected: Range <b> {inputFieldFrom} </b> - <b> {inputFieldTo} </b></span>
|
<span>Selected: Range <b> {inputFieldFrom} </b> - <b> {inputFieldTo} </b></span>
|
||||||
{:else if inputFieldFrom != "1" && inputFieldTo == sliderMax?.toString() }
|
{:else if inputFieldFrom != sliderMin?.toString() && inputFieldTo == sliderMax?.toString() }
|
||||||
<span>Selected: More than <b> {inputFieldFrom} </b> </span>
|
<span>Selected: More than <b> {inputFieldFrom} </b> </span>
|
||||||
{:else if inputFieldFrom == "1" && inputFieldTo != sliderMax?.toString() }
|
{:else if inputFieldFrom == sliderMin?.toString() && inputFieldTo != sliderMax?.toString() }
|
||||||
<span>Selected: Less than <b> {inputFieldTo} </b></span>
|
<span>Selected: Less than <b> {inputFieldTo} </b></span>
|
||||||
{:else}
|
{:else}
|
||||||
<span><i>No Selection</i></span>
|
<span><i>No Selection</i></span>
|
||||||
|
|||||||
@@ -341,26 +341,28 @@ export function getStatsItems(presetStats = []) {
|
|||||||
if (gm?.footprint) {
|
if (gm?.footprint) {
|
||||||
const mc = getMetricConfigDeep(gm.name, null, null)
|
const mc = getMetricConfigDeep(gm.name, null, null)
|
||||||
if (mc) {
|
if (mc) {
|
||||||
const presetEntry = presetStats.find((s) => s?.field === (gm.name + '_' + gm.footprint))
|
const presetEntry = presetStats.find((s) => s.field == `${gm.name}_${gm.footprint}`)
|
||||||
if (presetEntry) {
|
if (presetEntry) {
|
||||||
return {
|
return {
|
||||||
field: gm.name + '_' + gm.footprint,
|
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,
|
||||||
to: presetEntry.to,
|
to: (presetEntry.to == 0) ? mc.peak : presetEntry.to,
|
||||||
peak: mc.peak,
|
peak: mc.peak,
|
||||||
enabled: true
|
enabled: true,
|
||||||
|
unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}`
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
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: 0,
|
from: 1,
|
||||||
to: mc.peak,
|
to: mc.peak,
|
||||||
peak: mc.peak,
|
peak: mc.peak,
|
||||||
enabled: false
|
enabled: false,
|
||||||
|
unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user