mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-12-16 20:26:16 +01:00
add autorefresh, remove leftover query
This commit is contained in:
@@ -35,8 +35,7 @@
|
|||||||
import Pie, { colors } from "./generic/plots/Pie.svelte";
|
import Pie, { colors } from "./generic/plots/Pie.svelte";
|
||||||
import Stacked from "./generic/plots/Stacked.svelte";
|
import Stacked from "./generic/plots/Stacked.svelte";
|
||||||
import DoubleMetric from "./generic/plots/DoubleMetricPlot.svelte";
|
import DoubleMetric from "./generic/plots/DoubleMetricPlot.svelte";
|
||||||
|
import Refresher from "./generic/helper/Refresher.svelte";
|
||||||
// Todo: Refresher-Tick
|
|
||||||
|
|
||||||
/* Svelte 5 Props */
|
/* Svelte 5 Props */
|
||||||
let {
|
let {
|
||||||
@@ -206,35 +205,6 @@
|
|||||||
requestPolicy: "network-only"
|
requestPolicy: "network-only"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Note: nodeMetrics are requested on configured $timestep resolution
|
|
||||||
const nodeStatusQuery = $derived(queryStore({
|
|
||||||
client: client,
|
|
||||||
query: gql`
|
|
||||||
query (
|
|
||||||
$filter: [JobFilter!]!
|
|
||||||
$selectedHistograms: [String!]
|
|
||||||
$numDurationBins: String
|
|
||||||
) {
|
|
||||||
jobsStatistics(filter: $filter, metrics: $selectedHistograms, numDurationBins: $numDurationBins) {
|
|
||||||
histNumCores {
|
|
||||||
count
|
|
||||||
value
|
|
||||||
}
|
|
||||||
histNumAccs {
|
|
||||||
count
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
variables: {
|
|
||||||
filter: [{ state: ["running"] }, { cluster: { eq: presetCluster } }],
|
|
||||||
selectedHistograms: [], // No Metrics requested for node hardware stats - Empty Array can be used for refresh
|
|
||||||
numDurationBins: "1h", // Hardcode or selector?
|
|
||||||
},
|
|
||||||
requestPolicy: "network-only"
|
|
||||||
}));
|
|
||||||
|
|
||||||
const clusterInfo = $derived.by(() => {
|
const clusterInfo = $derived.by(() => {
|
||||||
if ($initq?.data?.clusters) {
|
if ($initq?.data?.clusters) {
|
||||||
let rawInfos = {};
|
let rawInfos = {};
|
||||||
@@ -368,28 +338,39 @@
|
|||||||
|
|
||||||
<Card style="height: 98vh;">
|
<Card style="height: 98vh;">
|
||||||
<CardBody class="align-content-center">
|
<CardBody class="align-content-center">
|
||||||
{#if $statusQuery.fetching || $statesTimed.fetching || $nodeStatusQuery.fetching}
|
<Row>
|
||||||
|
<Col>
|
||||||
|
<Refresher
|
||||||
|
hideSelector
|
||||||
|
initially={60}
|
||||||
|
onRefresh={(interval) => {
|
||||||
|
from = new Date(Date.now() - 5 * 60 * 1000);
|
||||||
|
to = new Date(Date.now());
|
||||||
|
clusterFrom = new Date(Date.now() - (8 * 60 * 60 * 1000))
|
||||||
|
|
||||||
|
if (interval) stackedFrom += Math.floor(interval / 1000);
|
||||||
|
else stackedFrom += 1 // Workaround: TimeSelection not linked, just trigger new data on manual refresh
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{#if $statusQuery.fetching || $statesTimed.fetching}
|
||||||
<Row class="justify-content-center">
|
<Row class="justify-content-center">
|
||||||
<Col xs="auto">
|
<Col xs="auto">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{:else if $statusQuery.error || $statesTimed.error || $nodeStatusQuery.error}
|
{:else if $statusQuery.error || $statesTimed.error}
|
||||||
<Row cols={{xs:1, md:2}}>
|
<Row cols={{xs:1, md:2}}>
|
||||||
{#if $statusQuery.error}
|
{#if $statusQuery.error}
|
||||||
<Col>
|
<Col>
|
||||||
<Card color="danger">Error Requesting StatusQuery: {$statusQuery.error.message}</Card>
|
<Card color="danger"><CardBody>Error Requesting Status Data: {$statusQuery.error.message}</CardBody></Card>
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $statesTimed.error}
|
{#if $statesTimed.error}
|
||||||
<Col>
|
<Col>
|
||||||
<Card color="danger">Error Requesting StatesTimed: {$statesTimed.error.message}</Card>
|
<Card color="danger"><CardBody>Error Requesting Node Scheduler States: {$statesTimed.error.message}</CardBody></Card>
|
||||||
</Col>
|
|
||||||
{/if}
|
|
||||||
{#if $nodeStatusQuery.error}
|
|
||||||
<Col>
|
|
||||||
<Card color="danger">Error Requesting NodeStatusQuery: {$nodeStatusQuery.error.message}</Card>
|
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
{/if}
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
let {
|
let {
|
||||||
initially = null,
|
initially = null,
|
||||||
presetClass = "",
|
presetClass = "",
|
||||||
|
hideSelector = false,
|
||||||
onRefresh
|
onRefresh
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
@@ -36,25 +37,27 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<InputGroup class={presetClass}>
|
{#if !hideSelector}
|
||||||
<Input
|
<InputGroup class={presetClass}>
|
||||||
type="select"
|
<Input
|
||||||
title="Periodic refresh interval"
|
type="select"
|
||||||
bind:value={refreshInterval}
|
title="Periodic refresh interval"
|
||||||
onchange={refreshIntervalChanged}
|
bind:value={refreshInterval}
|
||||||
>
|
onchange={refreshIntervalChanged}
|
||||||
<option value={null}>No Interval</option>
|
|
||||||
<option value={30 * 1000}>30 Seconds</option>
|
|
||||||
<option value={60 * 1000}>60 Seconds</option>
|
|
||||||
<option value={2 * 60 * 1000}>Two Minutes</option>
|
|
||||||
<option value={5 * 60 * 1000}>5 Minutes</option>
|
|
||||||
</Input>
|
|
||||||
<Button
|
|
||||||
outline
|
|
||||||
onclick={() => onRefresh(refreshInterval)}
|
|
||||||
disabled={refreshInterval != null}
|
|
||||||
>
|
>
|
||||||
<Icon name="arrow-clockwise" /> Refresh
|
<option value={null}>No Interval</option>
|
||||||
</Button>
|
<option value={30 * 1000}>30 Seconds</option>
|
||||||
</InputGroup>
|
<option value={60 * 1000}>60 Seconds</option>
|
||||||
|
<option value={2 * 60 * 1000}>Two Minutes</option>
|
||||||
|
<option value={5 * 60 * 1000}>5 Minutes</option>
|
||||||
|
</Input>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
onclick={() => onRefresh(refreshInterval)}
|
||||||
|
disabled={refreshInterval != null}
|
||||||
|
>
|
||||||
|
<Icon name="arrow-clockwise" /> Refresh
|
||||||
|
</Button>
|
||||||
|
</InputGroup>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
import Pie, { colors } from "../generic/plots/Pie.svelte";
|
import Pie, { colors } from "../generic/plots/Pie.svelte";
|
||||||
import Stacked from "../generic/plots/Stacked.svelte";
|
import Stacked from "../generic/plots/Stacked.svelte";
|
||||||
import DoubleMetric from "../generic/plots/DoubleMetricPlot.svelte";
|
import DoubleMetric from "../generic/plots/DoubleMetricPlot.svelte";
|
||||||
|
import Refresher from "../generic/helper/Refresher.svelte";
|
||||||
|
|
||||||
/* Svelte 5 Props */
|
/* Svelte 5 Props */
|
||||||
let {
|
let {
|
||||||
@@ -224,35 +225,6 @@
|
|||||||
requestPolicy: "network-only"
|
requestPolicy: "network-only"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Note: nodeMetrics are requested on configured $timestep resolution
|
|
||||||
const nodeStatusQuery = $derived(queryStore({
|
|
||||||
client: client,
|
|
||||||
query: gql`
|
|
||||||
query (
|
|
||||||
$filter: [JobFilter!]!
|
|
||||||
$selectedHistograms: [String!]
|
|
||||||
$numDurationBins: String
|
|
||||||
) {
|
|
||||||
jobsStatistics(filter: $filter, metrics: $selectedHistograms, numDurationBins: $numDurationBins) {
|
|
||||||
histNumCores {
|
|
||||||
count
|
|
||||||
value
|
|
||||||
}
|
|
||||||
histNumAccs {
|
|
||||||
count
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
variables: {
|
|
||||||
filter: [{ state: ["running"] }, { cluster: { eq: presetCluster } }],
|
|
||||||
selectedHistograms: [], // No Metrics requested for node hardware stats - Empty Array can be used for refresh
|
|
||||||
numDurationBins: "1h", // Hardcode or selector?
|
|
||||||
},
|
|
||||||
requestPolicy: "network-only"
|
|
||||||
}));
|
|
||||||
|
|
||||||
const clusterInfo = $derived.by(() => {
|
const clusterInfo = $derived.by(() => {
|
||||||
if ($initq?.data?.clusters) {
|
if ($initq?.data?.clusters) {
|
||||||
let rawInfos = {};
|
let rawInfos = {};
|
||||||
@@ -385,33 +357,45 @@
|
|||||||
|
|
||||||
<Card style="height: 88vh;">
|
<Card style="height: 88vh;">
|
||||||
<CardBody class="align-content-center">
|
<CardBody class="align-content-center">
|
||||||
{#if $statusQuery.fetching || $statesTimed.fetching || $topJobsQuery.fetching || $nodeStatusQuery.fetching}
|
<Row>
|
||||||
|
<Col>
|
||||||
|
<Refresher
|
||||||
|
hideSelector
|
||||||
|
initially={60}
|
||||||
|
onRefresh={(interval) => {
|
||||||
|
from = new Date(Date.now() - 5 * 60 * 1000);
|
||||||
|
to = new Date(Date.now());
|
||||||
|
clusterFrom = new Date(Date.now() - (8 * 60 * 60 * 1000))
|
||||||
|
pagingState = { page:1, itemsPerPage: 10 };
|
||||||
|
|
||||||
|
if (interval) stackedFrom += Math.floor(interval / 1000);
|
||||||
|
else stackedFrom += 1 // Workaround: TimeSelection not linked, just trigger new data on manual refresh
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{#if $statusQuery.fetching || $statesTimed.fetching || $topJobsQuery.fetching}
|
||||||
<Row class="justify-content-center">
|
<Row class="justify-content-center">
|
||||||
<Col xs="auto">
|
<Col xs="auto">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{:else if $statusQuery.error || $statesTimed.error || $topJobsQuery.error || $nodeStatusQuery.error}
|
{:else if $statusQuery.error || $statesTimed.error || $topJobsQuery.error}
|
||||||
<Row cols={{xs:1, md:2}}>
|
<Row>
|
||||||
{#if $statusQuery.error}
|
{#if $statusQuery.error}
|
||||||
<Col>
|
<Col>
|
||||||
<Card color="danger">Error Requesting StatusQuery: {$statusQuery.error.message}</Card>
|
<Card color="danger"><CardBody>Error Requesting Status Data: {$statusQuery.error.message}</CardBody></Card>
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $statesTimed.error}
|
{#if $statesTimed.error}
|
||||||
<Col>
|
<Col>
|
||||||
<Card color="danger">Error Requesting StatesTimed: {$statesTimed.error.message}</Card>
|
<Card color="danger"><CardBody>Error Requesting Node Scheduler States: {$statesTimed.error.message}</CardBody></Card>
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $topJobsQuery.error}
|
{#if $topJobsQuery.error}
|
||||||
<Col>
|
<Col>
|
||||||
<Card color="danger">Error Requesting TopJobsQuery: {$topJobsQuery.error.message}</Card>
|
<Card color="danger"><CardBody>Error Requesting Jobs By Project: {$topJobsQuery.error.message}</CardBody></Card>
|
||||||
</Col>
|
|
||||||
{/if}
|
|
||||||
{#if $nodeStatusQuery.error}
|
|
||||||
<Col>
|
|
||||||
<Card color="danger">Error Requesting NodeStatusQuery: {$nodeStatusQuery.error.message}</Card>
|
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
{/if}
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -402,7 +402,7 @@
|
|||||||
to = new Date(Date.now());
|
to = new Date(Date.now());
|
||||||
|
|
||||||
if (interval) stackedFrom += Math.floor(interval / 1000);
|
if (interval) stackedFrom += Math.floor(interval / 1000);
|
||||||
else stackedFrom += 1 // Workaround: TineSelection not linked, just trigger new data on manual refresh
|
else stackedFrom += 1 // Workaround: TimeSelection not linked, just trigger new data on manual refresh
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
Reference in New Issue
Block a user