improve handling and layout if missing data in dashboard

This commit is contained in:
Christoph Kluge
2025-12-16 15:43:57 +01:00
parent 102109388b
commit 11e94124cc
4 changed files with 92 additions and 78 deletions

View File

@@ -509,44 +509,52 @@
</Col> </Col>
<Col> <!-- Pie Last States --> <Col> <!-- Pie Last States -->
<Row> <Row>
<Col class="px-3 mt-2 mt-lg-0"> {#if refinedStateData.length > 0}
<div bind:clientWidth={colWidthStates}> <Col class="px-3 mt-2 mt-lg-0">
<div bind:clientWidth={colWidthStates}>
{#key refinedStateData}
<Pie
canvasId="hpcpie-slurm"
size={colWidthStates * 0.66}
sliceLabel="Nodes"
quantities={refinedStateData.map(
(sd) => sd.count,
)}
entities={refinedStateData.map(
(sd) => sd.state,
)}
fixColors={refinedStateData.map(
(sd) => colors['nodeStates'][sd.state],
)}
/>
{/key}
</div>
</Col>
<Col class="px-4 py-2">
{#key refinedStateData} {#key refinedStateData}
<Pie <Table>
canvasId="hpcpie-slurm" <tr class="mb-2">
size={colWidthStates * 0.66} <th></th>
sliceLabel="Nodes" <th class="h4">State</th>
quantities={refinedStateData.map( <th class="h4">Count</th>
(sd) => sd.count,
)}
entities={refinedStateData.map(
(sd) => sd.state,
)}
fixColors={refinedStateData.map(
(sd) => colors['nodeStates'][sd.state],
)}
/>
{/key}
</div>
</Col>
<Col class="px-4 py-2">
{#key refinedStateData}
<Table>
<tr class="mb-2">
<th></th>
<th class="h4">State</th>
<th class="h4">Count</th>
</tr>
{#each refinedStateData as sd, i}
<tr>
<td><Icon name="circle-fill" style="color: {colors['nodeStates'][sd.state]}; font-size: 30px;"/></td>
<td class="h5">{sd.state.charAt(0).toUpperCase() + sd.state.slice(1)}</td>
<td class="h5">{sd.count}</td>
</tr> </tr>
{/each} {#each refinedStateData as sd, i}
</Table> <tr>
{/key} <td><Icon name="circle-fill" style="color: {colors['nodeStates'][sd.state]}; font-size: 30px;"/></td>
</Col> <td class="h5">{sd.state.charAt(0).toUpperCase() + sd.state.slice(1)}</td>
<td class="h5">{sd.count}</td>
</tr>
{/each}
</Table>
{/key}
</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

@@ -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,45 +487,51 @@
</Col> </Col>
<Col> <!-- Pie Jobs --> <Col> <!-- Pie Jobs -->
<Row cols={{xs:1, md:2}}> {#if topJobsQuery?.data?.jobsStatistics?.length > 0}
<Col class="p-2"> <Row cols={{xs:1, md:2}}>
<div bind:clientWidth={colWidthJobs}> <Col class="p-2">
<h4 class="text-center"> <div bind:clientWidth={colWidthJobs}>
Top Projects: Jobs <h4 class="text-center">
</h4> Top Projects: Jobs
<Pie </h4>
{useCbColors} <Pie
canvasId="hpcpie-jobs-projects" {useCbColors}
size={colWidthJobs * 0.75} canvasId="hpcpie-jobs-projects"
sliceLabel={'Jobs'} size={colWidthJobs * 0.75}
quantities={$topJobsQuery.data.jobsStatistics.map( sliceLabel={'Jobs'}
(tp) => tp['totalJobs'], quantities={$topJobsQuery.data.jobsStatistics.map(
)} (tp) => tp['totalJobs'],
entities={$topJobsQuery.data.jobsStatistics.map((tp) => scrambleNames ? scramble(tp.id) : tp.id)} )}
/> entities={$topJobsQuery.data.jobsStatistics.map((tp) => scrambleNames ? scramble(tp.id) : tp.id)}
</div> />
</Col> </div>
<Col class="p-2"> </Col>
<Table> <Col class="p-2">
<tr class="mb-2"> <Table>
<th></th> <tr class="mb-2">
<th style="padding-left: 0.5rem;">Project</th> <th></th>
<th>Jobs</th> <th style="padding-left: 0.5rem;">Project</th>
</tr> <th>Jobs</th>
{#each $topJobsQuery.data.jobsStatistics as tp, i}
<tr>
<td><Icon name="circle-fill" style="color: {legendColors(i)};" /></td>
<td>
<a target="_blank" href="/monitoring/jobs/?cluster={presetCluster}&state=running&project={tp.id}&projectMatch=eq"
>{scrambleNames ? scramble(tp.id) : tp.id}
</a>
</td>
<td>{tp['totalJobs']}</td>
</tr> </tr>
{/each} {#each $topJobsQuery.data.jobsStatistics as tp, i}
</Table> <tr>
</Col> <td><Icon name="circle-fill" style="color: {legendColors(i)};" /></td>
</Row> <td>
<a target="_blank" href="/monitoring/jobs/?cluster={presetCluster}&state=running&project={tp.id}&projectMatch=eq"
>{scrambleNames ? scramble(tp.id) : tp.id}
</a>
</td>
<td>{tp['totalJobs']}</td>
</tr>
{/each}
</Table>
</Col>
</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 -->