mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2026-02-11 21:41:46 +01:00
complete review of context initialization and access, streamlining
This commit is contained in:
@@ -68,12 +68,8 @@
|
||||
energyFootprint { hardware, metric, value }
|
||||
}
|
||||
`);
|
||||
const client = getContextClient();
|
||||
const ccconfig = getContext("cc-config");
|
||||
const showRoofline = !!ccconfig[`jobView_showRoofline`];
|
||||
const showStatsTable = !!ccconfig[`jobView_showStatTable`];
|
||||
|
||||
/* Note: Actual metric data queried in <Metric> Component, only require base infos here -> reduce backend load by requesting just stats */
|
||||
const client = getContextClient();
|
||||
const query = gql`
|
||||
query ($dbid: ID!, $selectedMetrics: [String!]!, $selectedScopes: [MetricScope!]!) {
|
||||
scopedJobStats(id: $dbid, metrics: $selectedMetrics, scopes: $selectedScopes) {
|
||||
@@ -89,25 +85,68 @@
|
||||
/* State Init */
|
||||
let plots = $state({});
|
||||
let isMetricsSelectionOpen = $state(false);
|
||||
let selectedMetrics = $state([]);
|
||||
let selectedScopes = $state([]);
|
||||
let totalMetrics = $state(0);
|
||||
|
||||
/* Derived */
|
||||
const showSummary = $derived((!!ccconfig[`jobView_showFootprint`] || !!ccconfig[`jobView_showPolarPlot`]))
|
||||
/* Derived Init Return */
|
||||
const thisJob = $derived($initq?.data ? $initq.data.job : null);
|
||||
|
||||
/* Derived Settings */
|
||||
const globalMetrics = $derived(thisJob ? getContext("globalMetrics") : null);
|
||||
const clusterInfo = $derived(thisJob ? getContext("clusters") : null);
|
||||
const ccconfig = $derived(thisJob ? getContext("cc-config") : null);
|
||||
const showRoofline = $derived(ccconfig ? !!ccconfig[`jobView_showRoofline`] : false);
|
||||
const showStatsTable = $derived(ccconfig ? !!ccconfig[`jobView_showStatTable`] : false);
|
||||
const showSummary = $derived(ccconfig ? (!!ccconfig[`jobView_showFootprint`] || !!ccconfig[`jobView_showPolarPlot`]) : false)
|
||||
|
||||
/* Derived Var Preprocessing*/
|
||||
let selectedMetrics = $derived.by(() => {
|
||||
if(thisJob && ccconfig) {
|
||||
if (thisJob.cluster) {
|
||||
if (thisJob.subCluster) {
|
||||
return ccconfig[`metricConfig_jobViewPlotMetrics:${thisJob.cluster}:${thisJob.subCluster}`] ||
|
||||
ccconfig[`metricConfig_jobViewPlotMetrics:${thisJob.cluster}`] ||
|
||||
ccconfig.metricConfig_jobViewPlotMetrics
|
||||
}
|
||||
return ccconfig[`metricConfig_jobViewPlotMetrics:${thisJob.cluster}`] ||
|
||||
ccconfig.metricConfig_jobViewPlotMetrics
|
||||
}
|
||||
return ccconfig.metricConfig_jobViewPlotMetrics
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
let selectedScopes = $derived.by(() => {
|
||||
const pendingScopes = ["node"]
|
||||
if (thisJob) {
|
||||
const accScopeDefault = [...selectedMetrics].some(function (m) {
|
||||
const thisCluster = clusterInfo.find((c) => c.name == thisJob.cluster);
|
||||
const subCluster = thisCluster.subClusters.find((sc) => sc.name == thisJob.subCluster);
|
||||
return subCluster.metricConfig.find((smc) => smc.name == m)?.scope === "accelerator";
|
||||
});
|
||||
|
||||
|
||||
if (accScopeDefault) pendingScopes.push("accelerator")
|
||||
if (thisJob.numNodes === 1) {
|
||||
pendingScopes.push("socket")
|
||||
pendingScopes.push("core")
|
||||
}
|
||||
}
|
||||
return[...new Set(pendingScopes)];
|
||||
});
|
||||
|
||||
/* Derived Query and Postprocessing*/
|
||||
const jobMetrics = $derived(queryStore({
|
||||
client: client,
|
||||
query: query,
|
||||
variables: { dbid, selectedMetrics, selectedScopes },
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
const missingMetrics = $derived.by(() => {
|
||||
if ($initq?.data && $jobMetrics?.data) {
|
||||
let job = $initq.data.job;
|
||||
if (thisJob && $jobMetrics?.data) {
|
||||
let metrics = $jobMetrics.data.scopedJobStats;
|
||||
let metricNames = $initq.data.globalMetrics.reduce((names, gm) => {
|
||||
if (gm.availability.find((av) => av.cluster === job.cluster)) {
|
||||
let metricNames = globalMetrics.reduce((names, gm) => {
|
||||
if (gm.availability.find((av) => av.cluster === thisJob.cluster)) {
|
||||
names.push(gm.name);
|
||||
}
|
||||
return names;
|
||||
@@ -118,9 +157,10 @@
|
||||
!metrics.some((jm) => jm.name == metric) &&
|
||||
selectedMetrics.includes(metric) &&
|
||||
!checkMetricDisabled(
|
||||
globalMetrics,
|
||||
metric,
|
||||
$initq.data.job.cluster,
|
||||
$initq.data.job.subCluster,
|
||||
thisJob.cluster,
|
||||
thisJob.subCluster,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@@ -129,17 +169,16 @@
|
||||
});
|
||||
|
||||
const missingHosts = $derived.by(() => {
|
||||
if ($initq?.data && $jobMetrics?.data) {
|
||||
let job = $initq.data.job;
|
||||
if (thisJob && $jobMetrics?.data) {
|
||||
let metrics = $jobMetrics.data.scopedJobStats;
|
||||
let metricNames = $initq.data.globalMetrics.reduce((names, gm) => {
|
||||
if (gm.availability.find((av) => av.cluster === job.cluster)) {
|
||||
let metricNames = globalMetrics.reduce((names, gm) => {
|
||||
if (gm.availability.find((av) => av.cluster === thisJob.cluster)) {
|
||||
names.push(gm.name);
|
||||
}
|
||||
return names;
|
||||
}, []);
|
||||
|
||||
return job.resources
|
||||
return thisJob.resources
|
||||
.map(({ hostname }) => ({
|
||||
hostname: hostname,
|
||||
metrics: metricNames.filter(
|
||||
@@ -165,51 +204,19 @@
|
||||
? "Loading..."
|
||||
: $initq?.error
|
||||
? "Error"
|
||||
: `Job ${$initq.data.job.jobId} - ClusterCockpit`;
|
||||
});
|
||||
|
||||
/* On Init */
|
||||
getContext("on-init")(() => {
|
||||
let job = $initq.data.job;
|
||||
if (!job) return;
|
||||
const pendingMetrics = (
|
||||
ccconfig[`metricConfig_jobViewPlotMetrics:${job.cluster}:${job.subCluster}`] ||
|
||||
ccconfig[`metricConfig_jobViewPlotMetrics:${job.cluster}`]
|
||||
) ||
|
||||
$initq.data.globalMetrics.reduce((names, gm) => {
|
||||
if (gm.availability.find((av) => av.cluster === job.cluster && av.subClusters.includes(job.subCluster))) {
|
||||
names.push(gm.name);
|
||||
}
|
||||
return names;
|
||||
}, [])
|
||||
|
||||
// Select default Scopes to load: Check before if any metric has accelerator scope by default
|
||||
const accScopeDefault = [...pendingMetrics].some(function (m) {
|
||||
const cluster = $initq.data.clusters.find((c) => c.name == job.cluster);
|
||||
const subCluster = cluster.subClusters.find((sc) => sc.name == job.subCluster);
|
||||
return subCluster.metricConfig.find((smc) => smc.name == m)?.scope === "accelerator";
|
||||
});
|
||||
|
||||
const pendingScopes = ["node"]
|
||||
if (accScopeDefault) pendingScopes.push("accelerator")
|
||||
if (job.numNodes === 1) {
|
||||
pendingScopes.push("socket")
|
||||
pendingScopes.push("core")
|
||||
}
|
||||
|
||||
selectedMetrics = [...new Set(pendingMetrics)];
|
||||
selectedScopes = [...new Set(pendingScopes)];
|
||||
: `Job ${thisJob.jobId} - ClusterCockpit`;
|
||||
});
|
||||
|
||||
/* Functions */
|
||||
const orderAndMap = (grouped, selectedMetrics) =>
|
||||
selectedMetrics.map((metric) => ({
|
||||
const orderAndMap = (grouped, inputMetrics) =>
|
||||
inputMetrics.map((metric) => ({
|
||||
metric: metric,
|
||||
data: grouped.find((group) => group[0].name == metric),
|
||||
disabled: checkMetricDisabled(
|
||||
globalMetrics,
|
||||
metric,
|
||||
$initq.data.job.cluster,
|
||||
$initq.data.job.subCluster,
|
||||
thisJob.cluster,
|
||||
thisJob.subCluster,
|
||||
),
|
||||
}));
|
||||
</script>
|
||||
@@ -219,34 +226,34 @@
|
||||
<Col xs={12} md={6} xl={3} class="mb-3 mb-xxl-0">
|
||||
{#if $initq.error}
|
||||
<Card body color="danger">{$initq.error.message}</Card>
|
||||
{:else if $initq?.data}
|
||||
{:else if thisJob}
|
||||
<Card class="overflow-auto" style="height: auto;">
|
||||
<TabContent> <!-- on:tab={(e) => (status = e.detail)} -->
|
||||
{#if $initq.data?.job?.metaData?.message}
|
||||
{#if thisJob?.metaData?.message}
|
||||
<TabPane tabId="admin-msg" tab="Admin Note" active>
|
||||
<CardBody>
|
||||
<Card body class="mb-2" color="warning">
|
||||
<h5>Job {$initq.data?.job?.jobId} ({$initq.data?.job?.cluster})</h5>
|
||||
<h5>Job {thisJob?.jobId} ({thisJob?.cluster})</h5>
|
||||
The following note was added by administrators:
|
||||
</Card>
|
||||
<Card body>
|
||||
{@html $initq.data.job.metaData.message}
|
||||
{@html thisJob.metaData.message}
|
||||
</Card>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{/if}
|
||||
<TabPane tabId="meta-info" tab="Job Info" active={$initq.data?.job?.metaData?.message?false:true}>
|
||||
<TabPane tabId="meta-info" tab="Job Info" active={thisJob?.metaData?.message?false:true}>
|
||||
<CardBody class="pb-2">
|
||||
<JobInfo job={$initq.data.job} {username} {authlevel} {roles} showTagEdit/>
|
||||
<JobInfo job={thisJob} {username} {authlevel} {roles} showTagEdit/>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0}
|
||||
{#if thisJob.concurrentJobs != null && thisJob.concurrentJobs.items.length != 0}
|
||||
<TabPane tabId="shared-jobs">
|
||||
<span slot="tab">
|
||||
{$initq.data.job.concurrentJobs.items.length} Concurrent Jobs
|
||||
{thisJob.concurrentJobs.items.length} Concurrent Jobs
|
||||
</span>
|
||||
<CardBody>
|
||||
<ConcurrentJobs cJobs={$initq.data.job.concurrentJobs} showLinks={(authlevel > roles.manager)}/>
|
||||
<ConcurrentJobs cJobs={thisJob.concurrentJobs} showLinks={(authlevel > roles.manager)}/>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{/if}
|
||||
@@ -261,9 +268,9 @@
|
||||
<Col xs={12} md={6} xl={4} xxl={3} class="mb-3 mb-xxl-0">
|
||||
{#if $initq.error}
|
||||
<Card body color="danger">{$initq.error.message}</Card>
|
||||
{:else if $initq?.data}
|
||||
{:else if thisJob}
|
||||
{#if showSummary}
|
||||
<JobSummary job={$initq.data.job}/>
|
||||
<JobSummary job={thisJob}/>
|
||||
{/if}
|
||||
{:else}
|
||||
<Spinner secondary />
|
||||
@@ -274,9 +281,9 @@
|
||||
<Col xs={12} md={12} xl={5} xxl={6}>
|
||||
{#if $initq.error}
|
||||
<Card body color="danger">{$initq.error.message}</Card>
|
||||
{:else if $initq?.data}
|
||||
{:else if thisJob}
|
||||
{#if showRoofline}
|
||||
<JobRoofline job={$initq.data.job} clusters={$initq.data.clusters}/>
|
||||
<JobRoofline job={thisJob} {clusterInfo}/>
|
||||
{/if}
|
||||
{:else}
|
||||
<Spinner secondary />
|
||||
@@ -285,10 +292,10 @@
|
||||
</Row>
|
||||
|
||||
<!-- Row 2: Energy Information if available -->
|
||||
{#if $initq?.data && $initq.data.job.energyFootprint.length != 0}
|
||||
{#if thisJob && thisJob?.energyFootprint?.length != 0}
|
||||
<Row class="mb-3">
|
||||
<Col>
|
||||
<EnergySummary jobId={$initq.data.job.jobId} jobEnergy={$initq.data.job.energy} jobEnergyFootprint={$initq.data.job.energyFootprint}/>
|
||||
<EnergySummary jobId={thisJob.jobId} jobEnergy={thisJob.energy} jobEnergyFootprint={thisJob.energyFootprint}/>
|
||||
</Col>
|
||||
</Row>
|
||||
{/if}
|
||||
@@ -297,7 +304,7 @@
|
||||
<Card class="mb-3">
|
||||
<CardBody>
|
||||
<Row class="mb-2">
|
||||
{#if $initq?.data}
|
||||
{#if thisJob}
|
||||
<Col xs="auto">
|
||||
<Button outline onclick={() => (isMetricsSelectionOpen = true)} color="primary">
|
||||
Select Metrics (Selected {selectedMetrics.length} of {totalMetrics} available)
|
||||
@@ -310,7 +317,7 @@
|
||||
{#if $jobMetrics.error}
|
||||
<Row class="mt-2">
|
||||
<Col>
|
||||
{#if $initq?.data && ($initq.data.job?.monitoringStatus == 0 || $initq.data.job?.monitoringStatus == 2)}
|
||||
{#if thisJob && (thisJob?.monitoringStatus == 0 || thisJob?.monitoringStatus == 2)}
|
||||
<Card body color="warning">Not monitored or archiving failed</Card>
|
||||
<br />
|
||||
{/if}
|
||||
@@ -323,18 +330,18 @@
|
||||
<Spinner secondary />
|
||||
</Col>
|
||||
</Row>
|
||||
{:else if $initq?.data && $jobMetrics?.data?.scopedJobStats}
|
||||
{:else if thisJob && $jobMetrics?.data?.scopedJobStats}
|
||||
<!-- Note: Ignore '#snippet' Error in IDE -->
|
||||
{#snippet gridContent(item)}
|
||||
{#if item.data}
|
||||
<Metric
|
||||
bind:this={plots[item.metric]}
|
||||
job={$initq.data.job}
|
||||
job={thisJob}
|
||||
metricName={item.metric}
|
||||
metricUnit={$initq.data.globalMetrics.find((gm) => gm.name == item.metric)?.unit}
|
||||
nativeScope={$initq.data.globalMetrics.find((gm) => gm.name == item.metric)?.scope}
|
||||
metricUnit={globalMetrics.find((gm) => gm.name == item.metric)?.unit}
|
||||
nativeScope={globalMetrics.find((gm) => gm.name == item.metric)?.scope}
|
||||
presetScopes={item.data.map((x) => x.scope)}
|
||||
isShared={$initq.data.job.shared != "none"}
|
||||
isShared={thisJob.shared != "none"}
|
||||
/>
|
||||
{:else if item.disabled == true}
|
||||
<Card color="info">
|
||||
@@ -342,7 +349,7 @@
|
||||
<b>Disabled Metric</b>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<p>Metric <b>{item.metric}</b> is disabled for cluster <b>{$initq.data.job.cluster}:{$initq.data.job.subCluster}</b>.</p>
|
||||
<p>Metric <b>{item.metric}</b> is disabled for cluster <b>{thisJob.cluster}:{thisJob.subCluster}</b>.</p>
|
||||
<p class="mb-1">To remove this card, open metric selection and press "Close and Apply".</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
@@ -353,7 +360,7 @@
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<p>No dataset(s) returned for <b>{item.metric}</b>.</p>
|
||||
<p class="mb-1">Metric was not found in metric store for cluster <b>{$initq.data.job.cluster}</b>.</p>
|
||||
<p class="mb-1">Metric was not found in metric store for cluster <b>{thisJob.cluster}</b>.</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
{/if}
|
||||
@@ -374,7 +381,7 @@
|
||||
<!-- Metadata && Statistcics Table -->
|
||||
<Row class="mb-3">
|
||||
<Col>
|
||||
{#if $initq?.data}
|
||||
{#if thisJob}
|
||||
<Card>
|
||||
<TabContent>
|
||||
{#if somethingMissing}
|
||||
@@ -409,12 +416,12 @@
|
||||
{/if}
|
||||
{#if showStatsTable}
|
||||
<!-- Includes <TabPane> Statistics Table with Independent GQL Query -->
|
||||
<StatsTab job={$initq.data.job} clusters={$initq.data.clusters} tabActive={!somethingMissing}/>
|
||||
<StatsTab job={thisJob} {clusterInfo} {globalMetrics} {ccconfig} tabActive={!somethingMissing}/>
|
||||
{/if}
|
||||
<TabPane tabId="job-script" tab="Job Script">
|
||||
<div class="pre-wrapper">
|
||||
{#if $initq.data.job.metaData?.jobScript}
|
||||
<pre><code>{$initq.data.job.metaData?.jobScript}</code></pre>
|
||||
{#if thisJob.metaData?.jobScript}
|
||||
<pre><code>{thisJob.metaData?.jobScript}</code></pre>
|
||||
{:else}
|
||||
<Card body color="warning">No job script available</Card>
|
||||
{/if}
|
||||
@@ -422,8 +429,8 @@
|
||||
</TabPane>
|
||||
<TabPane tabId="slurm-info" tab="Slurm Info">
|
||||
<div class="pre-wrapper">
|
||||
{#if $initq.data.job.metaData?.slurmInfo}
|
||||
<pre><code>{$initq.data.job.metaData?.slurmInfo}</code></pre>
|
||||
{#if thisJob.metaData?.slurmInfo}
|
||||
<pre><code>{thisJob.metaData?.slurmInfo}</code></pre>
|
||||
{:else}
|
||||
<Card body color="warning"
|
||||
>No additional slurm information available</Card
|
||||
@@ -437,15 +444,15 @@
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{#if $initq?.data}
|
||||
{#if thisJob}
|
||||
<MetricSelection
|
||||
bind:isOpen={isMetricsSelectionOpen}
|
||||
bind:totalMetrics
|
||||
presetMetrics={selectedMetrics}
|
||||
cluster={$initq.data.job.cluster}
|
||||
subCluster={$initq.data.job.subCluster}
|
||||
cluster={thisJob.cluster}
|
||||
subCluster={thisJob.subCluster}
|
||||
configName="metricConfig_jobViewPlotMetrics"
|
||||
preInitialized
|
||||
{globalMetrics}
|
||||
applyMetrics={(newMetrics) =>
|
||||
selectedMetrics = [...newMetrics]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user