Merge branch 'dev' of github.com:ClusterCockpit/cc-backend into dev

This commit is contained in:
2025-12-17 05:46:10 +01:00
8 changed files with 137 additions and 84 deletions

View File

@@ -7,6 +7,7 @@
- `isApi Bool!`: Is currently logged in user api authority - `isApi Bool!`: Is currently logged in user api authority
- `username String!`: Empty string if auth. is disabled, otherwise the username as string - `username String!`: Empty string if auth. is disabled, otherwise the username as string
- `ncontent String!`: The currently displayed message on the homescreen - `ncontent String!`: The currently displayed message on the homescreen
- `clusters [String]`: The available clusternames
--> -->
<script> <script>
@@ -22,6 +23,7 @@
isApi, isApi,
username, username,
ncontent, ncontent,
clusters
} = $props(); } = $props();
</script> </script>
@@ -30,7 +32,7 @@
<CardHeader> <CardHeader>
<CardTitle class="mb-1">Admin Options</CardTitle> <CardTitle class="mb-1">Admin Options</CardTitle>
</CardHeader> </CardHeader>
<AdminSettings {ncontent}/> <AdminSettings {ncontent} {clusters}/>
</Card> </Card>
{/if} {/if}

View File

@@ -30,6 +30,7 @@
Table, Table,
Progress, Progress,
Icon, Icon,
Button
} from "@sveltestrap/sveltestrap"; } from "@sveltestrap/sveltestrap";
import Roofline from "./generic/plots/Roofline.svelte"; import Roofline from "./generic/plots/Roofline.svelte";
import Pie, { colors } from "./generic/plots/Pie.svelte"; import Pie, { colors } from "./generic/plots/Pie.svelte";
@@ -353,6 +354,11 @@
}} }}
/> />
</Col> </Col>
<Col class="d-flex justify-content-end">
<Button outline class="mb-1" size="sm" color="light" href="/">
<Icon name="x"/>
</Button>
</Col>
</Row> </Row>
{#if $statusQuery.fetching || $statesTimed.fetching} {#if $statusQuery.fetching || $statesTimed.fetching}
<Row class="justify-content-center"> <Row class="justify-content-center">
@@ -503,6 +509,7 @@
</Col> </Col>
<Col> <!-- Pie Last States --> <Col> <!-- Pie Last States -->
<Row> <Row>
{#if refinedStateData.length > 0}
<Col class="px-3 mt-2 mt-lg-0"> <Col class="px-3 mt-2 mt-lg-0">
<div bind:clientWidth={colWidthStates}> <div bind:clientWidth={colWidthStates}>
{#key refinedStateData} {#key refinedStateData}
@@ -541,6 +548,13 @@
</Table> </Table>
{/key} {/key}
</Col> </Col>
{:else}
<Col>
<Card body color="warning" class="mx-4 my-2"
>Cannot render state status: No state data returned for <code>Pie Chart</code></Card
>
</Col>
{/if}
</Row> </Row>
</Col> </Col>

View File

@@ -10,6 +10,7 @@ mount(Config, {
isApi: isApi, isApi: isApi,
username: username, username: username,
ncontent: ncontent, ncontent: ncontent,
clusters: hClusters.map((c) => c.name) // Defined in Header Template
}, },
context: new Map([ context: new Map([
['cc-config', clusterCockpitConfig], ['cc-config', clusterCockpitConfig],

View File

@@ -3,6 +3,7 @@
Properties: Properties:
- `ncontent String`: The homepage notice content - `ncontent String`: The homepage notice content
- `clusters [String]`: The available clusternames
--> -->
<script> <script>
@@ -17,7 +18,8 @@
/* Svelte 5 Props */ /* Svelte 5 Props */
let { let {
ncontent ncontent,
clusters
} = $props(); } = $props();
/* Const Init*/ /* Const Init*/
@@ -66,6 +68,6 @@
<Col> <Col>
<EditProject reloadUser={() => getUserList()} /> <EditProject reloadUser={() => getUserList()} />
</Col> </Col>
<Options config={ccconfig}/> <Options config={ccconfig} {clusters}/>
<NoticeEdit {ncontent}/> <NoticeEdit {ncontent}/>
</Row> </Row>

View File

@@ -1,10 +1,18 @@
<!-- <!--
@component Admin option select card @component Admin option select card
Properties:
- `clusters [String]`: The available clusternames
--> -->
<script> <script>
import { getContext, onMount } from "svelte"; import { getContext, onMount } from "svelte";
import { Col, Card, CardBody, CardTitle } from "@sveltestrap/sveltestrap"; import { Row, Col, Card, CardBody, CardTitle, Button, Icon } from "@sveltestrap/sveltestrap";
/* Svelte 5 Props */
let {
clusters,
} = $props();
/*Const Init */ /*Const Init */
const resampleConfig = getContext("resampling"); const resampleConfig = getContext("resampling");
@@ -44,6 +52,26 @@
</Card> </Card>
</Col> </Col>
{#if clusters?.length > 0}
<Col>
<Card class="h-100">
<CardBody>
<CardTitle class="mb-3">Public Dashboard Links</CardTitle>
<Row>
{#each clusters as cluster}
<Col>
<Button color="info" class="mb-2 mb-xl-0" href={`/monitoring/dashboard/${cluster}`} target="_blank">
<Icon name="clipboard-pulse" class="mr-2"/>
{cluster.charAt(0).toUpperCase() + cluster.slice(1)} Public Dashboard
</Button>
</Col>
{/each}
</Row>
</CardBody>
</Card>
</Col>
{/if}
{#if resampleConfig} {#if resampleConfig}
<Col> <Col>
<Card class="h-100"> <Card class="h-100">

View File

@@ -997,5 +997,5 @@
{#if roofData != null} {#if roofData != null}
<div bind:this={plotWrapper} class="p-2"></div> <div bind:this={plotWrapper} class="p-2"></div>
{:else} {:else}
<Card class="mx-4" body color="warning">Cannot render roofline: No data!</Card> <Card class="mx-4 my-2" body color="warning">Cannot render roofline: No data!</Card>
{/if} {/if}

View File

@@ -101,10 +101,10 @@
}; };
// Data Prep For uPlot // Data Prep For uPlot
const sortedData = data.sort((a, b) => a.state.localeCompare(b.state)); const sortedData = data?.sort((a, b) => a.state.localeCompare(b.state)) || [];
const collectLabel = sortedData.map(d => d.state); const collectLabel = sortedData.map(d => d.state);
// Align Data to Timesteps, Introduces 'undefied' as placeholder, reiterate and set those to 0 // Align Data to Timesteps, Introduces 'undefied' as placeholder, reiterate and set those to 0
const collectData = uPlot.join(sortedData.map(d => [d.times, d.counts])).map(d => d.map(i => i ? i : 0)); const collectData = (sortedData.length > 0) ? uPlot.join(sortedData.map(d => [d.times, d.counts])).map(d => d.map(i => i ? i : 0)) : [];
// STACKED CHART FUNCTIONS // // STACKED CHART FUNCTIONS //
function stack(data, omit) { function stack(data, omit) {
@@ -344,7 +344,7 @@
</script> </script>
<!-- Define $width Wrapper and NoData Card --> <!-- Define $width Wrapper and NoData Card -->
{#if data && collectData[0].length > 0} {#if data && collectData.length > 0}
<div bind:this={plotWrapper} bind:clientWidth={width} <div bind:this={plotWrapper} bind:clientWidth={width}
style="background-color: rgba(255, 255, 255, 1.0);" class="rounded" style="background-color: rgba(255, 255, 255, 1.0);" class="rounded"
></div> ></div>

View File

@@ -487,6 +487,7 @@
</Col> </Col>
<Col> <!-- Pie Jobs --> <Col> <!-- Pie Jobs -->
{#if topJobsQuery?.data?.jobsStatistics?.length > 0}
<Row cols={{xs:1, md:2}}> <Row cols={{xs:1, md:2}}>
<Col class="p-2"> <Col class="p-2">
<div bind:clientWidth={colWidthJobs}> <div bind:clientWidth={colWidthJobs}>
@@ -526,6 +527,11 @@
</Table> </Table>
</Col> </Col>
</Row> </Row>
{:else}
<Card body color="warning" class="mx-4 my-2"
>Cannot render job status: No state data returned for <code>Pie Chart</code></Card
>
{/if}
</Col> </Col>
<Col> <!-- Job Roofline --> <Col> <!-- Job Roofline -->