mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-07-01 11:13:50 +02:00
Migrate jobList and jobListRow
This commit is contained in:
parent
c8fe81cd80
commit
c4c422da57
@ -562,6 +562,7 @@
|
|||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
|
<!-- Note: Ignore '#snippet' Error in IDE -->
|
||||||
{#snippet histoGridContent(item)}
|
{#snippet histoGridContent(item)}
|
||||||
<Histogram
|
<Histogram
|
||||||
data={convert2uplot(item.bins)}
|
data={convert2uplot(item.bins)}
|
||||||
|
@ -315,7 +315,7 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{:else if $initq?.data && $jobMetrics?.data?.scopedJobStats}
|
{:else if $initq?.data && $jobMetrics?.data?.scopedJobStats}
|
||||||
<!-- Note: Ignore 'Expected If ...' Error in IDE -->
|
<!-- Note: Ignore '#snippet' Error in IDE -->
|
||||||
{#snippet gridContent(item)}
|
{#snippet gridContent(item)}
|
||||||
{#if item.data}
|
{#if item.data}
|
||||||
<Metric
|
<Metric
|
||||||
|
@ -178,18 +178,18 @@
|
|||||||
{#if !showCompare}
|
{#if !showCompare}
|
||||||
<JobList
|
<JobList
|
||||||
bind:this={jobList}
|
bind:this={jobList}
|
||||||
bind:metrics
|
|
||||||
bind:sorting
|
|
||||||
bind:matchedListJobs
|
bind:matchedListJobs
|
||||||
bind:showFootprint
|
|
||||||
bind:selectedJobs
|
bind:selectedJobs
|
||||||
|
{metrics}
|
||||||
|
{sorting}
|
||||||
|
{showFootprint}
|
||||||
{filterBuffer}
|
{filterBuffer}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<JobCompare
|
<JobCompare
|
||||||
bind:this={jobCompare}
|
bind:this={jobCompare}
|
||||||
bind:metrics
|
|
||||||
bind:matchedCompareJobs
|
bind:matchedCompareJobs
|
||||||
|
{metrics}
|
||||||
{filterBuffer}
|
{filterBuffer}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
@ -201,7 +201,8 @@
|
|||||||
presetSorting={sorting}
|
presetSorting={sorting}
|
||||||
applySorting={(newSort) =>
|
applySorting={(newSort) =>
|
||||||
sorting = {...newSort}
|
sorting = {...newSort}
|
||||||
}/>
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<MetricSelection
|
<MetricSelection
|
||||||
bind:isOpen={isMetricsSelectionOpen}
|
bind:isOpen={isMetricsSelectionOpen}
|
||||||
|
@ -204,6 +204,7 @@
|
|||||||
{:else if $nodeMetricsData.fetching || $initq.fetching}
|
{:else if $nodeMetricsData.fetching || $initq.fetching}
|
||||||
<Spinner />
|
<Spinner />
|
||||||
{:else}
|
{:else}
|
||||||
|
<!-- Note: Ignore '#snippet' Error in IDE -->
|
||||||
{#snippet gridContent(item)}
|
{#snippet gridContent(item)}
|
||||||
<h4 style="text-align: center; padding-top:15px;">
|
<h4 style="text-align: center; padding-top:15px;">
|
||||||
{item.name}
|
{item.name}
|
||||||
|
@ -676,6 +676,7 @@
|
|||||||
<!-- Selectable Stats as Histograms : Average Values of Running Jobs -->
|
<!-- Selectable Stats as Histograms : Average Values of Running Jobs -->
|
||||||
|
|
||||||
{#if selectedHistograms}
|
{#if selectedHistograms}
|
||||||
|
<!-- Note: Ignore '#snippet' Error in IDE -->
|
||||||
{#snippet gridContent(item)}
|
{#snippet gridContent(item)}
|
||||||
<Histogram
|
<Histogram
|
||||||
data={convert2uplot(item.data)}
|
data={convert2uplot(item.data)}
|
||||||
|
@ -335,6 +335,7 @@
|
|||||||
</Row>
|
</Row>
|
||||||
{:else}
|
{:else}
|
||||||
<hr class="my-2"/>
|
<hr class="my-2"/>
|
||||||
|
<!-- Note: Ignore '#snippet' Error in IDE -->
|
||||||
{#snippet gridContent(item)}
|
{#snippet gridContent(item)}
|
||||||
<Histogram
|
<Histogram
|
||||||
data={convert2uplot(item.data)}
|
data={convert2uplot(item.data)}
|
||||||
@ -369,9 +370,9 @@
|
|||||||
<JobList
|
<JobList
|
||||||
bind:this={jobList}
|
bind:this={jobList}
|
||||||
bind:matchedListJobs
|
bind:matchedListJobs
|
||||||
bind:metrics
|
{metrics}
|
||||||
bind:sorting
|
{sorting}
|
||||||
bind:showFootprint
|
{showFootprint}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -390,10 +391,10 @@
|
|||||||
presetMetrics={metrics}
|
presetMetrics={metrics}
|
||||||
cluster={selectedCluster}
|
cluster={selectedCluster}
|
||||||
configName="plot_list_selectedMetrics"
|
configName="plot_list_selectedMetrics"
|
||||||
|
footprintSelect
|
||||||
applyMetrics={(newMetrics) =>
|
applyMetrics={(newMetrics) =>
|
||||||
metrics = [...newMetrics]
|
metrics = [...newMetrics]
|
||||||
}
|
}
|
||||||
footprintSelect
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<HistogramSelection
|
<HistogramSelection
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
/* Svelte 5 Props */
|
/* Svelte 5 Props */
|
||||||
let {
|
let {
|
||||||
matchedCompareJobs = $bindable(0),
|
matchedCompareJobs = $bindable(0),
|
||||||
metrics = $bindable(ccconfig?.plot_list_selectedMetrics),
|
metrics = ccconfig?.plot_list_selectedMetrics,
|
||||||
filterBuffer = [],
|
filterBuffer = [],
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
|
@ -26,35 +26,22 @@
|
|||||||
import Pagination from "./joblist/Pagination.svelte";
|
import Pagination from "./joblist/Pagination.svelte";
|
||||||
import JobListRow from "./joblist/JobListRow.svelte";
|
import JobListRow from "./joblist/JobListRow.svelte";
|
||||||
|
|
||||||
const ccconfig = getContext("cc-config"),
|
/* Svelte 5 Props */
|
||||||
initialized = getContext("initialized"),
|
let {
|
||||||
globalMetrics = getContext("globalMetrics");
|
matchedListJobs = $bindable(0),
|
||||||
|
selectedJobs = $bindable([]),
|
||||||
const equalsCheck = (a, b) => {
|
metrics = getContext("cc-config").plot_list_selectedMetrics,
|
||||||
return JSON.stringify(a) === JSON.stringify(b);
|
sorting = { field: "startTime", type: "col", order: "DESC" },
|
||||||
}
|
showFootprint = false,
|
||||||
|
filterBuffer = [],
|
||||||
export let sorting = { field: "startTime", type: "col", order: "DESC" };
|
} = $props();
|
||||||
export let matchedListJobs = 0;
|
|
||||||
export let metrics = ccconfig.plot_list_selectedMetrics;
|
|
||||||
export let showFootprint;
|
|
||||||
export let filterBuffer = [];
|
|
||||||
export let selectedJobs = [];
|
|
||||||
|
|
||||||
let usePaging = ccconfig.job_list_usePaging
|
|
||||||
let itemsPerPage = usePaging ? ccconfig.plot_list_jobsPerPage : 10;
|
|
||||||
let page = 1;
|
|
||||||
let paging = { itemsPerPage, page };
|
|
||||||
let filter = [...filterBuffer];
|
|
||||||
let lastFilter = [];
|
|
||||||
let lastSorting = null;
|
|
||||||
let triggerMetricRefresh = false;
|
|
||||||
|
|
||||||
function getUnit(m) {
|
|
||||||
const rawUnit = globalMetrics.find((gm) => gm.name === m)?.unit
|
|
||||||
return (rawUnit?.prefix ? rawUnit.prefix : "") + (rawUnit?.base ? rawUnit.base : "")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Const Init */
|
||||||
|
const ccconfig = getContext("cc-config");
|
||||||
|
const initialized = getContext("initialized");
|
||||||
|
const globalMetrics = getContext("globalMetrics");
|
||||||
|
const usePaging = ccconfig?.job_list_usePaging || false;
|
||||||
|
const jobInfoColumnWidth = 250;
|
||||||
const client = getContextClient();
|
const client = getContextClient();
|
||||||
const query = gql`
|
const query = gql`
|
||||||
query (
|
query (
|
||||||
@ -107,50 +94,102 @@
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
$: jobsStore = queryStore({
|
/* Var Init */
|
||||||
client: client,
|
let lastFilter = [];
|
||||||
query: query,
|
let lastSorting = null;
|
||||||
variables: { paging, sorting, filter },
|
|
||||||
|
/* State Init */
|
||||||
|
let headerPaddingTop = $state(0);
|
||||||
|
let jobs = $state([]);
|
||||||
|
let filter = $state([...filterBuffer]);
|
||||||
|
let page = $state(1);
|
||||||
|
let itemsPerPage = $state(usePaging ? (ccconfig?.plot_list_jobsPerPag || 10) : 10);
|
||||||
|
let triggerMetricRefresh = $state(false);
|
||||||
|
let tableWidth = $state(0);
|
||||||
|
|
||||||
|
/* Derived */
|
||||||
|
let paging = $derived({ itemsPerPage, page });
|
||||||
|
const plotWidth = $derived.by(() => {
|
||||||
|
return Math.floor(
|
||||||
|
(tableWidth - jobInfoColumnWidth) / (metrics.length + (showFootprint ? 1 : 0)) - 10,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
let jobsStore = $derived(queryStore({
|
||||||
|
client: client,
|
||||||
|
query: query,
|
||||||
|
variables: { paging, sorting, filter },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Effects */
|
||||||
|
$effect(() => {
|
||||||
|
if ($jobsStore?.data) {
|
||||||
|
matchedListJobs = $jobsStore.data.jobs.count;
|
||||||
|
} else {
|
||||||
|
matchedListJobs = -1
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let jobs = [];
|
$effect(() => {
|
||||||
$: if ($initialized && $jobsStore.data) {
|
if (!usePaging) {
|
||||||
if (usePaging) {
|
window.addEventListener('scroll', () => {
|
||||||
jobs = [...$jobsStore.data.jobs.items]
|
let {
|
||||||
} else { // Prevents jump to table head in continiuous mode, only if no change in sort or filter
|
scrollTop,
|
||||||
if (equalsCheck(filter, lastFilter) && equalsCheck(sorting, lastSorting)) {
|
scrollHeight,
|
||||||
// console.log('Both Equal: Continuous Addition ... Set None')
|
clientHeight
|
||||||
jobs = jobs.concat([...$jobsStore.data.jobs.items])
|
} = document.documentElement;
|
||||||
} else if (equalsCheck(filter, lastFilter)) {
|
|
||||||
// console.log('Filter Equal: Continuous Reset ... Set lastSorting')
|
// Add 100 px offset to trigger load earlier
|
||||||
lastSorting = { ...sorting }
|
if (scrollTop + clientHeight >= scrollHeight - 100 && $jobsStore?.data?.jobs?.hasNextPage) {
|
||||||
jobs = [...$jobsStore.data.jobs.items]
|
page += 1
|
||||||
} else if (equalsCheck(sorting, lastSorting)) {
|
};
|
||||||
// console.log('Sorting Equal: Continuous Reset ... Set lastFilter')
|
});
|
||||||
lastFilter = [ ...filter ]
|
};
|
||||||
jobs = [...$jobsStore.data.jobs.items]
|
});
|
||||||
} else {
|
|
||||||
// console.log('None Equal: Continuous Reset ... Set lastBoth')
|
$effect(() => {
|
||||||
lastSorting = { ...sorting }
|
// Triggers (Except Paging)
|
||||||
lastFilter = [ ...filter ]
|
sorting
|
||||||
jobs = [...$jobsStore.data.jobs.items]
|
filter
|
||||||
}
|
// Continous Scroll: Reset jobs and paging if parameters change: Existing entries will not match new selections
|
||||||
|
if (!usePaging) {
|
||||||
|
jobs = [];
|
||||||
|
page = 1;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
$: if (!usePaging && (sorting || filter)) {
|
$effect(() => {
|
||||||
// Continous Scroll: Reset list and paging if parameters change: Existing entries will not match new selections
|
if ($initialized && $jobsStore?.data) {
|
||||||
jobs = [];
|
if (usePaging) {
|
||||||
paging = { itemsPerPage: 10, page: 1 };
|
jobs = [...$jobsStore.data.jobs.items]
|
||||||
}
|
} else { // Prevents jump to table head in continiuous mode, only if no change in sort or filter
|
||||||
|
if (equalsCheck(filter, lastFilter) && equalsCheck(sorting, lastSorting)) {
|
||||||
$: matchedListJobs = $jobsStore.data != null ? $jobsStore.data.jobs.count : -1;
|
// console.log('Both Equal: Continuous Addition ... Set None')
|
||||||
|
jobs = jobs.concat([...$jobsStore.data.jobs.items])
|
||||||
|
} else if (equalsCheck(filter, lastFilter)) {
|
||||||
|
// console.log('Filter Equal: Continuous Reset ... Set lastSorting')
|
||||||
|
lastSorting = { ...sorting }
|
||||||
|
jobs = [...$jobsStore.data.jobs.items]
|
||||||
|
} else if (equalsCheck(sorting, lastSorting)) {
|
||||||
|
// console.log('Sorting Equal: Continuous Reset ... Set lastFilter')
|
||||||
|
lastFilter = [ ...filter ]
|
||||||
|
jobs = [...$jobsStore.data.jobs.items]
|
||||||
|
} else {
|
||||||
|
// console.log('None Equal: Continuous Reset ... Set lastBoth')
|
||||||
|
lastSorting = { ...sorting }
|
||||||
|
lastFilter = [ ...filter ]
|
||||||
|
jobs = [...$jobsStore.data.jobs.items]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Functions */
|
||||||
// Force refresh list with existing unchanged variables (== usually would not trigger reactivity)
|
// Force refresh list with existing unchanged variables (== usually would not trigger reactivity)
|
||||||
export function refreshJobs() {
|
export function refreshJobs() {
|
||||||
if (!usePaging) {
|
if (!usePaging) {
|
||||||
jobs = []; // Empty Joblist before refresh, prevents infinite buildup
|
jobs = []; // Empty Joblist before refresh, prevents infinite buildup
|
||||||
paging = { itemsPerPage: 10, page: 1 };
|
page = 1;
|
||||||
}
|
}
|
||||||
jobsStore = queryStore({
|
jobsStore = queryStore({
|
||||||
client: client,
|
client: client,
|
||||||
@ -178,8 +217,26 @@
|
|||||||
filter = filters;
|
filter = filters;
|
||||||
}
|
}
|
||||||
page = 1;
|
page = 1;
|
||||||
paging = paging = { page, itemsPerPage };
|
};
|
||||||
}
|
|
||||||
|
function updateConfiguration(value, newPage) {
|
||||||
|
updateConfigurationMutation({
|
||||||
|
name: "plot_list_jobsPerPage",
|
||||||
|
value: value,
|
||||||
|
}).subscribe((res) => {
|
||||||
|
if (res.fetching === false && !res.error) {
|
||||||
|
jobs = [] // Empty List
|
||||||
|
paging = { itemsPerPage: value, page: newPage }; // Trigger reload of jobList
|
||||||
|
} else if (res.fetching === false && res.error) {
|
||||||
|
throw res.error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function getUnit(m) {
|
||||||
|
const rawUnit = globalMetrics.find((gm) => gm.name === m)?.unit
|
||||||
|
return (rawUnit?.prefix ? rawUnit.prefix : "") + (rawUnit?.base ? rawUnit.base : "")
|
||||||
|
};
|
||||||
|
|
||||||
const updateConfigurationMutation = ({ name, value }) => {
|
const updateConfigurationMutation = ({ name, value }) => {
|
||||||
return mutationStore({
|
return mutationStore({
|
||||||
@ -193,52 +250,11 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateConfiguration(value, page) {
|
const equalsCheck = (a, b) => {
|
||||||
updateConfigurationMutation({
|
return JSON.stringify(a) === JSON.stringify(b);
|
||||||
name: "plot_list_jobsPerPage",
|
|
||||||
value: value,
|
|
||||||
}).subscribe((res) => {
|
|
||||||
if (res.fetching === false && !res.error) {
|
|
||||||
jobs = [] // Empty List
|
|
||||||
paging = { itemsPerPage: value, page: page }; // Trigger reload of jobList
|
|
||||||
} else if (res.fetching === false && res.error) {
|
|
||||||
throw res.error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!usePaging) {
|
/* Init Header */
|
||||||
window.addEventListener('scroll', () => {
|
|
||||||
let {
|
|
||||||
scrollTop,
|
|
||||||
scrollHeight,
|
|
||||||
clientHeight
|
|
||||||
} = document.documentElement;
|
|
||||||
|
|
||||||
// Add 100 px offset to trigger load earlier
|
|
||||||
if (scrollTop + clientHeight >= scrollHeight - 100 && $jobsStore.data != null && $jobsStore.data.jobs.hasNextPage) {
|
|
||||||
let pendingPaging = { ...paging }
|
|
||||||
pendingPaging.page += 1
|
|
||||||
paging = pendingPaging
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
let plotWidth = null;
|
|
||||||
let tableWidth = null;
|
|
||||||
let jobInfoColumnWidth = 250;
|
|
||||||
|
|
||||||
$: if (showFootprint) {
|
|
||||||
plotWidth = Math.floor(
|
|
||||||
(tableWidth - jobInfoColumnWidth) / (metrics.length + 1) - 10,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
plotWidth = Math.floor(
|
|
||||||
(tableWidth - jobInfoColumnWidth) / metrics.length - 10,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let headerPaddingTop = 0;
|
|
||||||
stickyHeader(
|
stickyHeader(
|
||||||
".cc-table-wrapper > table.table >thead > tr > th.position-sticky:nth-child(1)",
|
".cc-table-wrapper > table.table >thead > tr > th.position-sticky:nth-child(1)",
|
||||||
(x) => (headerPaddingTop = x),
|
(x) => (headerPaddingTop = x),
|
||||||
@ -292,8 +308,8 @@
|
|||||||
{:else}
|
{:else}
|
||||||
{#each jobs as job (job.id)}
|
{#each jobs as job (job.id)}
|
||||||
<JobListRow bind:triggerMetricRefresh {job} {metrics} {plotWidth} {showFootprint} previousSelect={selectedJobs.includes(job.id)}
|
<JobListRow bind:triggerMetricRefresh {job} {metrics} {plotWidth} {showFootprint} previousSelect={selectedJobs.includes(job.id)}
|
||||||
on:select-job={({detail}) => selectedJobs = [...selectedJobs, detail]}
|
selectJob={(detail) => selectedJobs = [...selectedJobs, detail]}
|
||||||
on:unselect-job={({detail}) => selectedJobs = selectedJobs.filter(item => item !== detail)}
|
unselectJob={(detail) => selectedJobs = selectedJobs.filter(item => item !== detail)}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
username = null,
|
username = null,
|
||||||
authlevel= null,
|
authlevel= null,
|
||||||
roles = null,
|
roles = null,
|
||||||
isSelected = null,
|
isSelected = $bindable(),
|
||||||
showSelect = false,
|
showSelect = false,
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
@ -89,10 +89,8 @@
|
|||||||
}}>
|
}}>
|
||||||
{#if isSelected}
|
{#if isSelected}
|
||||||
<Icon name="check-square"/>
|
<Icon name="check-square"/>
|
||||||
{:else if isSelected == false}
|
{:else }
|
||||||
<Icon name="square"/>
|
<Icon name="plus-square-dotted"/>
|
||||||
{:else}
|
|
||||||
<Icon name="plus-square-dotted" />
|
|
||||||
{/if}
|
{/if}
|
||||||
</Button>
|
</Button>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
@ -12,39 +12,37 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { queryStore, gql, getContextClient } from "@urql/svelte";
|
import { queryStore, gql, getContextClient } from "@urql/svelte";
|
||||||
import { getContext, createEventDispatcher } from "svelte";
|
import { getContext } from "svelte";
|
||||||
import { Card, Spinner } from "@sveltestrap/sveltestrap";
|
import { Card, Spinner } from "@sveltestrap/sveltestrap";
|
||||||
import { maxScope, checkMetricDisabled } from "../utils.js";
|
import { maxScope, checkMetricDisabled } from "../utils.js";
|
||||||
import JobInfo from "./JobInfo.svelte";
|
import JobInfo from "./JobInfo.svelte";
|
||||||
import MetricPlot from "../plots/MetricPlot.svelte";
|
import MetricPlot from "../plots/MetricPlot.svelte";
|
||||||
import JobFootprint from "../helper/JobFootprint.svelte";
|
import JobFootprint from "../helper/JobFootprint.svelte";
|
||||||
|
|
||||||
export let job;
|
/* Svelte 5 Props */
|
||||||
export let metrics;
|
let {
|
||||||
export let plotWidth;
|
triggerMetricRefresh = $bindable(false),
|
||||||
export let plotHeight = 275;
|
job,
|
||||||
export let showFootprint;
|
metrics,
|
||||||
export let triggerMetricRefresh = false;
|
plotWidth,
|
||||||
export let previousSelect = false;
|
plotHeight = 275,
|
||||||
|
showFootprint,
|
||||||
|
previousSelect = false,
|
||||||
|
selectJob,
|
||||||
|
unselectJob
|
||||||
|
} = $props();
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
/* Const Init */
|
||||||
const resampleConfig = getContext("resampling") || null;
|
const client = getContextClient();
|
||||||
const resampleDefault = resampleConfig ? Math.max(...resampleConfig.resolutions) : 0;
|
const jobId = job.id;
|
||||||
|
const cluster = getContext("clusters").find((c) => c.name == job.cluster);
|
||||||
let { id } = job;
|
const scopes = (job.numNodes == 1)
|
||||||
let scopes = job.numNodes == 1
|
? (job.numAcc >= 1)
|
||||||
? job.numAcc >= 1
|
|
||||||
? ["core", "accelerator"]
|
? ["core", "accelerator"]
|
||||||
: ["core"]
|
: ["core"]
|
||||||
: ["node"];
|
: ["node"];
|
||||||
let selectedResolution = resampleDefault;
|
const resampleConfig = getContext("resampling") || null;
|
||||||
let zoomStates = {};
|
const resampleDefault = resampleConfig ? Math.max(...resampleConfig.resolutions) : 0;
|
||||||
let thresholdStates = {};
|
|
||||||
|
|
||||||
$: isSelected = previousSelect || null;
|
|
||||||
|
|
||||||
const cluster = getContext("clusters").find((c) => c.name == job.cluster);
|
|
||||||
const client = getContextClient();
|
|
||||||
const query = gql`
|
const query = gql`
|
||||||
query ($id: ID!, $metrics: [String!]!, $scopes: [MetricScope!]!, $selectedResolution: Int) {
|
query ($id: ID!, $metrics: [String!]!, $scopes: [MetricScope!]!, $selectedResolution: Int) {
|
||||||
jobMetrics(id: $id, metrics: $metrics, scopes: $scopes, resolution: $selectedResolution) {
|
jobMetrics(id: $id, metrics: $metrics, scopes: $scopes, resolution: $selectedResolution) {
|
||||||
@ -77,52 +75,59 @@
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function handleZoom(detail, metric) {
|
/* State Init */
|
||||||
if ( // States have to differ, causes deathloop if just set
|
let selectedResolution = $state(resampleDefault);
|
||||||
(zoomStates[metric]?.x?.min !== detail?.lastZoomState?.x?.min) &&
|
let zoomStates = $state({});
|
||||||
(zoomStates[metric]?.y?.max !== detail?.lastZoomState?.y?.max)
|
let thresholdStates = $state({});
|
||||||
) {
|
|
||||||
zoomStates[metric] = {...detail.lastZoomState}
|
/* Derived */
|
||||||
|
let isSelected = $derived(previousSelect);
|
||||||
|
let metricsQuery = $derived(queryStore({
|
||||||
|
client: client,
|
||||||
|
query: query,
|
||||||
|
variables: { id: jobId, metrics, scopes, selectedResolution },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Effects */
|
||||||
|
$effect(() => {
|
||||||
|
if (job.state === 'running' && triggerMetricRefresh === true) {
|
||||||
|
refreshMetrics();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if ( // States have to differ, causes deathloop if just set
|
$effect(() => {
|
||||||
detail?.lastThreshold &&
|
if (isSelected == true && previousSelect == false) {
|
||||||
thresholdStates[metric] !== detail.lastThreshold
|
selectJob(jobId)
|
||||||
) { // Handle to correctly reset on summed metric scope change
|
} else if (isSelected == false && previousSelect == true) {
|
||||||
thresholdStates[metric] = detail.lastThreshold;
|
unselectJob(jobId)
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (detail?.newRes) { // Triggers GQL
|
/* Functions */
|
||||||
selectedResolution = detail.newRes
|
function handleZoom(detail, metric) {
|
||||||
|
// Buffer last zoom state to allow seamless zoom on rerender
|
||||||
|
// console.log('Update zoomState for/with:', metric, {...detail.lastZoomState})
|
||||||
|
zoomStates[metric] = detail?.lastZoomState ? {...detail.lastZoomState} : null;
|
||||||
|
// Handle to correctly reset on summed metric scope change
|
||||||
|
// console.log('Update thresholdState for/with:', metric, detail.lastThreshold)
|
||||||
|
thresholdStates[metric] = detail?.lastThreshold ? detail.lastThreshold : null;
|
||||||
|
// Triggers GQL
|
||||||
|
if (detail?.newRes) {
|
||||||
|
// console.log('Update selectedResolution for/with:', metric, detail.newRes)
|
||||||
|
selectedResolution = detail.newRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: metricsQuery = queryStore({
|
|
||||||
client: client,
|
|
||||||
query: query,
|
|
||||||
variables: { id, metrics, scopes, selectedResolution },
|
|
||||||
});
|
|
||||||
|
|
||||||
function refreshMetrics() {
|
function refreshMetrics() {
|
||||||
metricsQuery = queryStore({
|
metricsQuery = queryStore({
|
||||||
client: client,
|
client: client,
|
||||||
query: query,
|
query: query,
|
||||||
variables: { id, metrics, scopes, selectedResolution },
|
variables: { id: jobId, metrics, scopes, selectedResolution },
|
||||||
// requestPolicy: 'network-only' // use default cache-first for refresh
|
// requestPolicy: 'network-only' // use default cache-first for refresh
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (job.state === 'running' && triggerMetricRefresh === true) {
|
|
||||||
refreshMetrics();
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if (isSelected == true && previousSelect == false) {
|
|
||||||
dispatch("select-job", job.id)
|
|
||||||
} else if (isSelected == false && previousSelect == true) {
|
|
||||||
dispatch("unselect-job", job.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper
|
|
||||||
const selectScope = (jobMetrics) =>
|
const selectScope = (jobMetrics) =>
|
||||||
jobMetrics.reduce(
|
jobMetrics.reduce(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
@ -157,7 +162,6 @@
|
|||||||
return jobMetric;
|
return jobMetric;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -196,7 +200,7 @@
|
|||||||
<!-- Subluster Metricconfig remove keyword for jobtables (joblist main, user joblist, project joblist) to be used here as toplevel case-->
|
<!-- Subluster Metricconfig remove keyword for jobtables (joblist main, user joblist, project joblist) to be used here as toplevel case-->
|
||||||
{#if metric.disabled == false && metric.data}
|
{#if metric.disabled == false && metric.data}
|
||||||
<MetricPlot
|
<MetricPlot
|
||||||
on:zoom={({detail}) => { handleZoom(detail, metric.data.name) }}
|
on:zoom={({detail}) => handleZoom(detail, metric.data.name)}
|
||||||
height={plotHeight}
|
height={plotHeight}
|
||||||
timestep={metric.data.metric.timestep}
|
timestep={metric.data.metric.timestep}
|
||||||
scope={metric.data.scope}
|
scope={metric.data.scope}
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
/* State Init */
|
/* State Init */
|
||||||
let requestedScopes = $state(presetScopes);
|
let requestedScopes = $state(presetScopes);
|
||||||
let selectedResolution = $state(resampleConfig ? resampleDefault : 0);
|
let selectedResolution = $state(resampleDefault);
|
||||||
|
|
||||||
let selectedHost = $state(null);
|
let selectedHost = $state(null);
|
||||||
let zoomState = $state(null);
|
let zoomState = $state(null);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user