Migrate metricSelection

This commit is contained in:
Christoph Kluge 2025-06-03 13:32:14 +02:00
parent 42c4926c47
commit 927e25c72c
7 changed files with 117 additions and 94 deletions

View File

@ -56,8 +56,8 @@
selectedScopes = [],
plots = {};
let availableMetrics = new Set(),
missingMetrics = [],
let totalMetrics = 0;
let missingMetrics = [],
missingHosts = [],
somethingMissing = false;
@ -294,7 +294,7 @@
{#if $initq?.data}
<Col xs="auto">
<Button outline on:click={() => (isMetricsSelectionOpen = true)} color="primary">
Select Metrics (Selected {selectedMetrics.length} of {availableMetrics.size} available)
Select Metrics (Selected {selectedMetrics.length} of {totalMetrics} available)
</Button>
</Col>
{/if}
@ -428,12 +428,16 @@
{#if $initq?.data}
<MetricSelection
bind:isOpen={isMetricsSelectionOpen}
bind:totalMetrics
presetMetrics={selectedMetrics}
cluster={$initq.data.job.cluster}
subCluster={$initq.data.job.subCluster}
configName="job_view_selectedMetrics"
bind:metrics={selectedMetrics}
bind:isOpen={isMetricsSelectionOpen}
bind:allMetrics={availableMetrics}
preInitialized
applyMetrics={(newMetrics) =>
selectedMetrics = [...newMetrics]
}
/>
{/if}

View File

@ -197,10 +197,13 @@
<Sorting bind:sorting bind:isOpen={isSortingOpen}/>
<MetricSelection
bind:cluster={selectedCluster}
configName="plot_list_selectedMetrics"
bind:metrics
bind:isOpen={isMetricsSelectionOpen}
bind:showFootprint
footprintSelect
bind:isOpen={isMetricsSelectionOpen}
bind:showFootprint
presetMetrics={metrics}
cluster={selectedCluster}
configName="plot_list_selectedMetrics"
footprintSelect
applyMetrics={(newMetrics) =>
metrics = [...newMetrics]
}
/>

View File

@ -193,12 +193,12 @@
{/if}
<MetricSelection
bind:isOpen={isMetricsSelectionOpen}
presetMetrics={selectedMetrics}
{cluster}
{subCluster}
configName="node_list_selectedMetrics"
metrics={selectedMetrics}
bind:isOpen={isMetricsSelectionOpen}
on:update-metrics={({ detail }) => {
selectedMetrics = [...detail]
}}
applyMetrics={(newMetrics) =>
selectedMetrics = [...newMetrics]
}
/>

View File

@ -366,12 +366,15 @@
<Sorting bind:sorting bind:isOpen={isSortingOpen} />
<MetricSelection
bind:cluster={selectedCluster}
configName="plot_list_selectedMetrics"
bind:metrics
bind:isOpen={isMetricsSelectionOpen}
bind:showFootprint
footprintSelect
bind:isOpen={isMetricsSelectionOpen}
bind:showFootprint
presetMetrics={metrics}
cluster={selectedCluster}
configName="plot_list_selectedMetrics"
applyMetrics={(newMetrics) =>
metrics = [...newMetrics]
}
footprintSelect
/>
<HistogramSelection

View File

@ -12,7 +12,7 @@
-->
<script>
import { getContext, createEventDispatcher } from "svelte";
import { getContext } from "svelte";
import {
Modal,
ModalBody,
@ -23,57 +23,23 @@
} from "@sveltestrap/sveltestrap";
import { gql, getContextClient, mutationStore } from "@urql/svelte";
export let metrics;
export let isOpen;
export let configName;
export let allMetrics = null;
export let cluster = null;
export let subCluster = null;
export let showFootprint = false;
export let footprintSelect = false;
const onInit = getContext("on-init")
const globalMetrics = getContext("globalMetrics")
const dispatch = createEventDispatcher();
let newMetricsOrder = [];
let unorderedMetrics = [...metrics];
let pendingShowFootprint = !!showFootprint;
onInit(() => {
if (allMetrics == null) allMetrics = new Set();
for (let metric of globalMetrics) allMetrics.add(metric.name);
});
$: {
if (allMetrics != null) {
if (!cluster) {
for (let metric of globalMetrics) allMetrics.add(metric.name);
} else {
allMetrics.clear();
for (let gm of globalMetrics) {
if (!subCluster) {
if (gm.availability.find((av) => av.cluster === cluster)) allMetrics.add(gm.name);
} else {
if (gm.availability.find((av) => av.cluster === cluster && av.subClusters.includes(subCluster))) allMetrics.add(gm.name);
}
}
}
newMetricsOrder = [...allMetrics].filter((m) => !metrics.includes(m));
newMetricsOrder.unshift(...metrics.filter((m) => allMetrics.has(m)));
unorderedMetrics = unorderedMetrics.filter((m) => allMetrics.has(m));
}
}
function printAvailability(metric, cluster) {
const avail = globalMetrics.find((gm) => gm.name === metric)?.availability
if (!cluster) {
return avail.map((av) => av.cluster).join(',')
} else {
return avail.find((av) => av.cluster === cluster).subClusters.join(',')
}
}
/* Svelte 5 Props */
let {
isOpen = $bindable(false),
showFootprint = $bindable(false),
totalMetrics = $bindable(0),
presetMetrics = [],
cluster = null,
subCluster = null,
footprintSelect = false,
preInitialized = false, // Job View is Pre-Init'd: $initialized "alone" store returns false
configName,
applyMetrics
} = $props();
/* Const Init */
const globalMetrics = getContext("globalMetrics");
const initialized = getContext("initialized");
const client = getContextClient();
const updateConfigurationMutation = ({ name, value }) => {
return mutationStore({
@ -87,7 +53,51 @@
});
};
let columnHovering = null;
/* State Init */
let pendingMetrics = $state(presetMetrics);
let pendingShowFootprint = $state(!!showFootprint);
let listedMetrics = $state([]);
let columnHovering = $state(null);
/* Derives States */
const allMetrics = $derived(loadAvailable(preInitialized || $initialized));
/* Reactive Effects */
$effect(() => {
totalMetrics = allMetrics.size;
});
$effect(() => {
listedMetrics = [...presetMetrics, ...allMetrics.difference(new Set(presetMetrics))]; // List (preset) active metrics first, then list inactives
});
/* Functions */
function loadAvailable(init) {
const availableMetrics = new Set();
if (init) {
for (let gm of globalMetrics) {
if (!cluster) {
availableMetrics.add(gm.name)
} else {
if (!subCluster) {
if (gm.availability.find((av) => av.cluster === cluster)) availableMetrics.add(gm.name);
} else {
if (gm.availability.find((av) => av.cluster === cluster && av.subClusters.includes(subCluster))) availableMetrics.add(gm.name);
}
}
}
}
return availableMetrics
}
function printAvailability(metric, cluster) {
const avail = globalMetrics.find((gm) => gm.name === metric)?.availability
if (!cluster) {
return avail.map((av) => av.cluster).join(',')
} else {
return avail.find((av) => av.cluster === cluster).subClusters.join(',')
}
}
function columnsDragStart(event, i) {
event.dataTransfer.effectAllowed = "move";
@ -99,20 +109,20 @@
event.dataTransfer.dropEffect = "move";
const start = Number.parseInt(event.dataTransfer.getData("text/plain"));
let pendingMetricsOrder = [...newMetricsOrder];
let pendingMetricsOrder = [...listedMetrics];
if (start < target) {
pendingMetricsOrder.splice(target + 1, 0, newMetricsOrder[start]);
pendingMetricsOrder.splice(target + 1, 0, listedMetrics[start]);
pendingMetricsOrder.splice(start, 1);
} else {
pendingMetricsOrder.splice(target, 0, newMetricsOrder[start]);
pendingMetricsOrder.splice(target, 0, listedMetrics[start]);
pendingMetricsOrder.splice(start + 1, 1);
}
newMetricsOrder = [...pendingMetricsOrder];
listedMetrics = [...pendingMetricsOrder];
columnHovering = null;
}
function closeAndApply() {
metrics = newMetricsOrder.filter((m) => unorderedMetrics.includes(m));
pendingMetrics = listedMetrics.filter((m) => pendingMetrics.includes(m));
isOpen = false;
let configKey;
@ -126,7 +136,7 @@
updateConfigurationMutation({
name: configKey,
value: JSON.stringify(metrics),
value: JSON.stringify(pendingMetrics),
}).subscribe((res) => {
if (res.fetching === false && res.error) {
throw res.error;
@ -148,7 +158,7 @@
});
};
dispatch('update-metrics', metrics);
applyMetrics(pendingMetrics);
}
</script>
@ -162,7 +172,7 @@
</li>
<hr />
{/if}
{#each newMetricsOrder as metric, index (metric)}
{#each listedMetrics as metric, index (metric)}
<li
class="cc-config-column list-group-item"
draggable={true}
@ -180,17 +190,17 @@
ondragenter={() => (columnHovering = index)}
class:is-active={columnHovering === index}
>
{#if unorderedMetrics.includes(metric)}
{#if pendingMetrics.includes(metric)}
<input
type="checkbox"
bind:group={unorderedMetrics}
bind:group={pendingMetrics}
value={metric}
checked
/>
{:else}
<input
type="checkbox"
bind:group={unorderedMetrics}
bind:group={pendingMetrics}
value={metric}
/>
{/if}
@ -203,8 +213,8 @@
</ListGroup>
</ModalBody>
<ModalFooter>
<Button color="primary" on:click={() => closeAndApply()}>Close & Apply</Button>
<Button color="secondary" on:click={() => (isOpen = !isOpen)}>Cancel</Button>
<Button color="primary" onclick={() => closeAndApply()}>Close & Apply</Button>
<Button color="secondary" onclick={() => (isOpen = !isOpen)}>Cancel</Button>
</ModalFooter>
</Modal>

View File

@ -33,7 +33,7 @@
let loadScopes = false;
let selectedScopes = [];
let selectedMetrics = [];
let availableMetrics = new Set(); // For Info Only, filled by MetricSelection Component
let totalMetrics = 0; // For Info Only, filled by MetricSelection Component
let isMetricSelectionOpen = false;
const client = getContextClient();
@ -99,7 +99,7 @@
<Row>
<Col class="m-2">
<Button outline on:click={() => (isMetricSelectionOpen = true)} class="px-2" color="primary" style="margin-right:0.5rem">
Select Metrics (Selected {selectedMetrics.length} of {availableMetrics.size} available)
Select Metrics (Selected {selectedMetrics.length} of {totalMetrics} available)
</Button>
{#if job.numNodes > 1}
<Button class="px-2 ml-auto" color="success" outline on:click={() => (loadScopes = !loadScopes)} disabled={loadScopes}>
@ -136,10 +136,13 @@
</TabPane>
<MetricSelection
bind:isOpen={isMetricSelectionOpen}
bind:totalMetrics
presetMetrics={selectedMetrics}
cluster={job.cluster}
subCluster={job.subCluster}
configName="job_view_nodestats_selectedMetrics"
bind:allMetrics={availableMetrics}
bind:metrics={selectedMetrics}
bind:isOpen={isMetricSelectionOpen}
applyMetrics={(newMetrics) =>
selectedMetrics = [...newMetrics]
}
/>

View File

@ -81,7 +81,7 @@
<thead>
<!-- Header Row 1: Selectors -->
<tr>
<th/>
<th></th>
{#each selectedMetrics as metric}
<!-- To Match Row-2 Header Field Count-->
<th colspan={selectedScopes[metric] == "node" ? 3 : 4}>