mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 05:19:05 +01:00
Rework tag and tag edit placement, add other feedback
- admin message shown primarily if exists - comment demo summary tab
This commit is contained in:
parent
6367c1ab4d
commit
d7a8bbf40b
@ -25,7 +25,6 @@
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Button,
|
||||
Icon,
|
||||
} from "@sveltestrap/sveltestrap";
|
||||
import { getContext } from "svelte";
|
||||
import {
|
||||
@ -35,7 +34,6 @@
|
||||
transformDataForRoofline,
|
||||
} from "./generic/utils.js";
|
||||
import Metric from "./job/Metric.svelte";
|
||||
import TagManagement from "./job/TagManagement.svelte";
|
||||
import StatsTable from "./job/StatsTable.svelte";
|
||||
import JobSummary from "./job/JobSummary.svelte";
|
||||
import ConcurrentJobs from "./generic/helper/ConcurrentJobs.svelte";
|
||||
@ -54,12 +52,10 @@
|
||||
const ccconfig = getContext("cc-config")
|
||||
|
||||
let isMetricsSelectionOpen = false,
|
||||
showFootprint = !!ccconfig[`job_view_showFootprint`],
|
||||
selectedMetrics = [],
|
||||
selectedScopes = [];
|
||||
|
||||
let plots = {},
|
||||
jobTags,
|
||||
roofWidth
|
||||
|
||||
let missingMetrics = [],
|
||||
@ -240,14 +236,22 @@
|
||||
{:else if $initq.data}
|
||||
<Card class="overflow-auto" style="height: 400px;">
|
||||
<TabContent> <!-- on:tab={(e) => (status = e.detail)} -->
|
||||
<TabPane tabId="meta-info" tab="Job Info" active>
|
||||
{#if $initq.data?.job?.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>
|
||||
The following note was added by administrators:
|
||||
</Card>
|
||||
<Card body>
|
||||
{@html $initq.data.job.metaData.message}
|
||||
</Card>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{/if}
|
||||
<TabPane tabId="meta-info" tab="Job Info" active={$initq.data?.job?.metaData?.message?false:true}>
|
||||
<CardBody class="pb-2">
|
||||
<JobInfo job={$initq.data.job} {jobTags} />
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
<TabPane tabId="job-tags" tab="Job Tags">
|
||||
<CardBody>
|
||||
<TagManagement job={$initq.data.job} {username} {authlevel} {roles} bind:jobTags renderModal={false}/>
|
||||
<JobInfo job={$initq.data.job} {username} {authlevel} {roles} showTags={false} showTagedit/>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0}
|
||||
@ -260,15 +264,6 @@
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{/if}
|
||||
{#if $initq.data?.job?.metaData?.message}
|
||||
<TabPane tabId="admin-msg" tab="Admin Note">
|
||||
<CardBody>
|
||||
<p>This note was added by administrators:</p>
|
||||
<hr/>
|
||||
<p>{@html $initq.data.job.metaData.message}</p>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{/if}
|
||||
</TabContent>
|
||||
</Card>
|
||||
{:else}
|
||||
@ -276,21 +271,19 @@
|
||||
{/if}
|
||||
</Col>
|
||||
|
||||
<!-- If enabled: Column 2: Job Footprint, Polar Representation, Heuristic Summary -->
|
||||
{#if showFootprint}
|
||||
<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 && $jobMetrics?.data}
|
||||
<JobSummary job={$initq.data.job} jobMetrics={$jobMetrics.data.jobMetrics}/>
|
||||
{:else}
|
||||
<Spinner secondary />
|
||||
{/if}
|
||||
</Col>
|
||||
{/if}
|
||||
<!-- Column 2: Job Footprint, Polar Representation, Heuristic Summary -->
|
||||
<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 && $jobMetrics?.data}
|
||||
<JobSummary job={$initq.data.job} jobMetrics={$jobMetrics.data.jobMetrics}/>
|
||||
{:else}
|
||||
<Spinner secondary />
|
||||
{/if}
|
||||
</Col>
|
||||
|
||||
<!-- Column 3: Job Roofline; If footprint Enabled: full width, else half width -->
|
||||
<Col xs={12} md={showFootprint ? 12 : 6} xl={showFootprint ? 5 : 6} xxl={6}>
|
||||
<Col xs={12} md={12} xl={5} xxl={6}>
|
||||
{#if $initq.error || $jobMetrics.error}
|
||||
<Card body color="danger">
|
||||
<p>Initq Error: {$initq.error?.message}</p>
|
||||
|
@ -23,12 +23,22 @@
|
||||
if ($initialized && tag == null)
|
||||
tag = allTags.find(tag => tag.id == id)
|
||||
}
|
||||
|
||||
function getScopeColor(scope) {
|
||||
switch (scope) {
|
||||
case "admin":
|
||||
return "#19e5e6";
|
||||
case "global":
|
||||
return "#c85fc8";
|
||||
default:
|
||||
return "#ffc107";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
a {
|
||||
margin-left: 0.5rem;
|
||||
line-height: 2;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
span {
|
||||
font-size: 0.9rem;
|
||||
@ -37,13 +47,7 @@
|
||||
|
||||
<a target={clickable ? "_blank" : null} href={clickable ? `/monitoring/jobs/?tag=${id}` : null}>
|
||||
{#if tag}
|
||||
{#if tag?.scope === "global"}
|
||||
<span style="background-color:#c85fc8;" class="badge text-dark">{tag.type}: {tag.name}</span>
|
||||
{:else if tag?.scope === "admin"}
|
||||
<span style="background-color:#19e5e6;" class="badge text-dark">{tag.type}: {tag.name}</span>
|
||||
{:else}
|
||||
<span class="badge bg-warning text-dark">{tag.type}: {tag.name}</span>
|
||||
{/if}
|
||||
<span style="background-color:{getScopeColor(tag?.scope)};" class="my-1 badge text-dark">{tag.type}: {tag.name}</span>
|
||||
{:else}
|
||||
Loading...
|
||||
{/if}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
@component Job View Subcomponent; allows management of job tags by deletion or new entries
|
||||
@component Job Info Subcomponent; allows management of job tags by deletion or new entries
|
||||
|
||||
Properties:
|
||||
- `job Object`: The job object
|
||||
@ -30,8 +30,8 @@
|
||||
Alert,
|
||||
Tooltip,
|
||||
} from "@sveltestrap/sveltestrap";
|
||||
import { fuzzySearchTags } from "../generic/utils.js";
|
||||
import Tag from "../generic/helper/Tag.svelte";
|
||||
import { fuzzySearchTags } from "../utils.js";
|
||||
import Tag from "./Tag.svelte";
|
||||
|
||||
export let job;
|
||||
export let jobTags = job.tags;
|
||||
@ -178,12 +178,7 @@
|
||||
{#if renderModal}
|
||||
<Modal {isOpen} toggle={() => (isOpen = !isOpen)}>
|
||||
<ModalHeader>
|
||||
Manage Tags
|
||||
{#if pendingChange !== false}
|
||||
<Spinner size="sm" secondary />
|
||||
{:else}
|
||||
<Icon name="tags" />
|
||||
{/if}
|
||||
Manage Tags <Icon name="tags"/>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<InputGroup class="mb-3">
|
||||
@ -317,8 +312,8 @@
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
|
||||
<Button outline on:click={() => (isOpen = true)}>
|
||||
Manage Tags <Icon name="tags" />
|
||||
<Button outline on:click={() => (isOpen = true)} size="sm" color="primary">
|
||||
Manage {jobTags?.length ? jobTags.length : ''} Tags
|
||||
</Button>
|
||||
|
||||
{:else}
|
@ -10,9 +10,14 @@
|
||||
import { Badge, Icon } from "@sveltestrap/sveltestrap";
|
||||
import { scrambleNames, scramble } from "../utils.js";
|
||||
import Tag from "../helper/Tag.svelte";
|
||||
import TagManagement from "../helper/TagManagement.svelte";
|
||||
|
||||
export let job;
|
||||
export let jobTags = job.tags;
|
||||
export let showTagedit = false;
|
||||
export let username = null;
|
||||
export let authlevel= null;
|
||||
export let roles = null;
|
||||
|
||||
function formatDuration(duration) {
|
||||
const hours = Math.floor(duration / 3600);
|
||||
@ -36,7 +41,7 @@
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
<p class="mb-2">
|
||||
<span class="fw-bold"
|
||||
><a href="/monitoring/job/{job.id}" target="_blank">{job.jobId}</a>
|
||||
({job.cluster})</span
|
||||
@ -63,7 +68,7 @@
|
||||
{/if}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<p class="mb-2">
|
||||
<Icon name="person-fill" />
|
||||
<a class="fst-italic" href="/monitoring/user/{job.user}" target="_blank">
|
||||
{scrambleNames ? scramble(job.user) : job.user}
|
||||
@ -84,7 +89,7 @@
|
||||
{/if}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<p class="mb-2">
|
||||
{#if job.numNodes == 1}
|
||||
{job.resources[0].hostname}
|
||||
{:else}
|
||||
@ -104,7 +109,7 @@
|
||||
{job.subCluster}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<p class="mb-2">
|
||||
Start: <span class="fw-bold"
|
||||
>{new Date(job.startTime).toLocaleString()}</span
|
||||
>
|
||||
@ -117,11 +122,25 @@
|
||||
{/if}
|
||||
</p>
|
||||
|
||||
<p class="mb-2">
|
||||
{#each jobTags as tag}
|
||||
<Tag {tag} />
|
||||
{/each}
|
||||
</p>
|
||||
{#if showTagedit}
|
||||
<hr class="mt-0 mb-2"/>
|
||||
<p class="mb-1">
|
||||
<TagManagement bind:jobTags {job} {username} {authlevel} {roles} renderModal/> :
|
||||
{#if jobTags?.length > 0}
|
||||
{#each jobTags as tag}
|
||||
<Tag {tag}/>
|
||||
{/each}
|
||||
{:else}
|
||||
<span style="font-size: 0.9rem; background-color: lightgray;" class="my-1 badge text-dark">No Tags</span>
|
||||
{/if}
|
||||
</p>
|
||||
{:else}
|
||||
<p class="mb-1">
|
||||
{#each jobTags as tag}
|
||||
<Tag {tag} />
|
||||
{/each}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
@ -68,6 +68,7 @@
|
||||
export let height = "400px";
|
||||
|
||||
const ccconfig = getContext("cc-config")
|
||||
const showFootprint = !!ccconfig[`job_view_showFootprint`];
|
||||
|
||||
const footprintData = job?.footprint?.map((jf) => {
|
||||
const fmc = getContext("getMetricConfig")(job.cluster, job.subCluster, jf.name);
|
||||
@ -165,101 +166,142 @@
|
||||
}
|
||||
}
|
||||
|
||||
function writeSummary(fpd) {
|
||||
// Hardcoded! Needs to be retrieved from globalMetrics
|
||||
const performanceMetrics = ['flops_any', 'mem_bw'];
|
||||
const utilizationMetrics = ['cpu_load', 'acc_utilization'];
|
||||
const energyMetrics = ['cpu_power'];
|
||||
/*
|
||||
function writeSummary(fpd) {
|
||||
// Hardcoded! Needs to be retrieved from globalMetrics
|
||||
const performanceMetrics = ['flops_any', 'mem_bw'];
|
||||
const utilizationMetrics = ['cpu_load', 'acc_utilization'];
|
||||
const energyMetrics = ['cpu_power'];
|
||||
|
||||
let performanceScore = 0;
|
||||
let utilizationScore = 0;
|
||||
let energyScore = 0;
|
||||
let performanceScore = 0;
|
||||
let utilizationScore = 0;
|
||||
let energyScore = 0;
|
||||
|
||||
let performanceMetricsCounted = 0;
|
||||
let utilizationMetricsCounted = 0;
|
||||
let energyMetricsCounted = 0;
|
||||
let performanceMetricsCounted = 0;
|
||||
let utilizationMetricsCounted = 0;
|
||||
let energyMetricsCounted = 0;
|
||||
|
||||
fpd.forEach(metric => {
|
||||
console.log('Metric, Impact', metric.name, metric.impact)
|
||||
if (performanceMetrics.includes(metric.name)) {
|
||||
performanceScore += metric.impact
|
||||
performanceMetricsCounted += 1
|
||||
} else if (utilizationMetrics.includes(metric.name)) {
|
||||
utilizationScore += metric.impact
|
||||
utilizationMetricsCounted += 1
|
||||
} else if (energyMetrics.includes(metric.name)) {
|
||||
energyScore += metric.impact
|
||||
energyMetricsCounted += 1
|
||||
fpd.forEach(metric => {
|
||||
console.log('Metric, Impact', metric.name, metric.impact)
|
||||
if (performanceMetrics.includes(metric.name)) {
|
||||
performanceScore += metric.impact
|
||||
performanceMetricsCounted += 1
|
||||
} else if (utilizationMetrics.includes(metric.name)) {
|
||||
utilizationScore += metric.impact
|
||||
utilizationMetricsCounted += 1
|
||||
} else if (energyMetrics.includes(metric.name)) {
|
||||
energyScore += metric.impact
|
||||
energyMetricsCounted += 1
|
||||
}
|
||||
});
|
||||
|
||||
performanceScore = (performanceMetricsCounted == 0) ? performanceScore : (performanceScore / performanceMetricsCounted);
|
||||
utilizationScore = (utilizationMetricsCounted == 0) ? utilizationScore : (utilizationScore / utilizationMetricsCounted);
|
||||
energyScore = (energyMetricsCounted == 0) ? energyScore : (energyScore / energyMetricsCounted);
|
||||
|
||||
let res = [];
|
||||
|
||||
console.log('Perf', performanceScore, performanceMetricsCounted)
|
||||
console.log('Util', utilizationScore, utilizationMetricsCounted)
|
||||
console.log('Energy', energyScore, energyMetricsCounted)
|
||||
|
||||
if (performanceScore == 1) {
|
||||
res.push('<b>Performance:</b> Your job performs well.')
|
||||
} else if (performanceScore != 0) {
|
||||
res.push('<b>Performance:</b> Your job performs suboptimal.')
|
||||
}
|
||||
});
|
||||
|
||||
performanceScore = (performanceMetricsCounted == 0) ? performanceScore : (performanceScore / performanceMetricsCounted);
|
||||
utilizationScore = (utilizationMetricsCounted == 0) ? utilizationScore : (utilizationScore / utilizationMetricsCounted);
|
||||
energyScore = (energyMetricsCounted == 0) ? energyScore : (energyScore / energyMetricsCounted);
|
||||
if (utilizationScore == 1) {
|
||||
res.push('<b>Utilization:</b> Your job utilizes resources well.')
|
||||
} else if (utilizationScore != 0) {
|
||||
res.push('<b>Utilization:</b> Your job utilizes resources suboptimal.')
|
||||
}
|
||||
|
||||
let res = [];
|
||||
if (energyScore == 1) {
|
||||
res.push('<b>Energy:</b> Your job has good energy values.')
|
||||
} else if (energyScore != 0) {
|
||||
res.push('<b>Energy:</b> Your job consumes more energy than necessary.')
|
||||
}
|
||||
|
||||
console.log('Perf', performanceScore, performanceMetricsCounted)
|
||||
console.log('Util', utilizationScore, utilizationMetricsCounted)
|
||||
console.log('Energy', energyScore, energyMetricsCounted)
|
||||
return res;
|
||||
};
|
||||
|
||||
if (performanceScore == 1) {
|
||||
res.push('<b>Performance:</b> Your job performs well.')
|
||||
} else if (performanceScore != 0) {
|
||||
res.push('<b>Performance:</b> Your job performs suboptimal.')
|
||||
}
|
||||
|
||||
if (utilizationScore == 1) {
|
||||
res.push('<b>Utilization:</b> Your job utilizes resources well.')
|
||||
} else if (utilizationScore != 0) {
|
||||
res.push('<b>Utilization:</b> Your job utilizes resources suboptimal.')
|
||||
}
|
||||
|
||||
if (energyScore == 1) {
|
||||
res.push('<b>Energy:</b> Your job has good energy values.')
|
||||
} else if (energyScore != 0) {
|
||||
res.push('<b>Energy:</b> Your job consumes more energy than necessary.')
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
$: summaryMessages = writeSummary(footprintData)
|
||||
$: summaryMessages = writeSummary(footprintData)
|
||||
*/
|
||||
</script>
|
||||
|
||||
<Card class="overflow-auto" style="width: {width}; height: {height}">
|
||||
<TabContent> <!-- on:tab={(e) => (status = e.detail)} -->
|
||||
<TabPane tabId="foot" tab="Footprint" active>
|
||||
<CardBody>
|
||||
{#each footprintData as fpd, index}
|
||||
{#if fpd.impact !== 4}
|
||||
<div class="mb-1 d-flex justify-content-between">
|
||||
<div> <b>{fpd.name} ({fpd.stat})</b></div>
|
||||
<div
|
||||
class="cursor-help d-inline-flex"
|
||||
id={`footprint-${job.jobId}-${index}`}
|
||||
>
|
||||
<div class="mx-1">
|
||||
{#if fpd.impact === 3 || fpd.impact === -1}
|
||||
<Icon name="exclamation-triangle-fill" class="text-danger" />
|
||||
{:else if fpd.impact === 2}
|
||||
<Icon name="exclamation-triangle" class="text-warning" />
|
||||
{/if}
|
||||
{#if fpd.impact === 3}
|
||||
<Icon name="emoji-frown" class="text-danger" />
|
||||
{:else if fpd.impact === 2}
|
||||
<Icon name="emoji-neutral" class="text-warning" />
|
||||
{:else if fpd.impact === 1}
|
||||
<Icon name="emoji-smile" class="text-success" />
|
||||
{:else if fpd.impact === 0}
|
||||
<Icon name="emoji-laughing" class="text-info" />
|
||||
{:else if fpd.impact === -1}
|
||||
<Icon name="emoji-dizzy" class="text-danger" />
|
||||
{/if}
|
||||
{#if showFootprint}
|
||||
<TabPane tabId="foot" tab="Footprint" active>
|
||||
<CardBody>
|
||||
{#each footprintData as fpd, index}
|
||||
{#if fpd.impact !== 4}
|
||||
<div class="mb-1 d-flex justify-content-between">
|
||||
<div> <b>{fpd.name} ({fpd.stat})</b></div>
|
||||
<div
|
||||
class="cursor-help d-inline-flex"
|
||||
id={`footprint-${job.jobId}-${index}`}
|
||||
>
|
||||
<div class="mx-1">
|
||||
{#if fpd.impact === 3 || fpd.impact === -1}
|
||||
<Icon name="exclamation-triangle-fill" class="text-danger" />
|
||||
{:else if fpd.impact === 2}
|
||||
<Icon name="exclamation-triangle" class="text-warning" />
|
||||
{/if}
|
||||
{#if fpd.impact === 3}
|
||||
<Icon name="emoji-frown" class="text-danger" />
|
||||
{:else if fpd.impact === 2}
|
||||
<Icon name="emoji-neutral" class="text-warning" />
|
||||
{:else if fpd.impact === 1}
|
||||
<Icon name="emoji-smile" class="text-success" />
|
||||
{:else if fpd.impact === 0}
|
||||
<Icon name="emoji-laughing" class="text-info" />
|
||||
{:else if fpd.impact === -1}
|
||||
<Icon name="emoji-dizzy" class="text-danger" />
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
{fpd.value} / {fpd.peak}
|
||||
{fpd.unit}
|
||||
</div>
|
||||
</div>
|
||||
<Tooltip
|
||||
target={`footprint-${job.jobId}-${index}`}
|
||||
placement="right"
|
||||
>{fpd.message}</Tooltip
|
||||
>
|
||||
</div>
|
||||
<Row cols={12} class="{(footprintData.length == (index + 1)) ? 'mb-0' : 'mb-2'}">
|
||||
{#if fpd.dir}
|
||||
<Col xs="1">
|
||||
<Icon name="caret-left-fill" />
|
||||
</Col>
|
||||
{/if}
|
||||
<Col xs="11" class="align-content-center">
|
||||
<Progress value={fpd.value} max={fpd.peak} color={fpd.color} />
|
||||
</Col>
|
||||
{#if !fpd.dir}
|
||||
<Col xs="1">
|
||||
<Icon name="caret-right-fill" />
|
||||
</Col>
|
||||
{/if}
|
||||
</Row>
|
||||
{:else}
|
||||
<div class="mb-1 d-flex justify-content-between">
|
||||
<div>
|
||||
{fpd.value} / {fpd.peak}
|
||||
{fpd.unit}
|
||||
<b>{fpd.name} ({fpd.stat})</b>
|
||||
</div>
|
||||
<div
|
||||
class="cursor-help d-inline-flex"
|
||||
id={`footprint-${job.jobId}-${index}`}
|
||||
>
|
||||
<div class="mx-1">
|
||||
<Icon name="info-circle"/>
|
||||
</div>
|
||||
<div>
|
||||
{fpd.value}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tooltip
|
||||
@ -267,49 +309,12 @@
|
||||
placement="right"
|
||||
>{fpd.message}</Tooltip
|
||||
>
|
||||
</div>
|
||||
<Row cols={12} class="{(footprintData.length == (index + 1)) ? 'mb-0' : 'mb-2'}">
|
||||
{#if fpd.dir}
|
||||
<Col xs="1">
|
||||
<Icon name="caret-left-fill" />
|
||||
</Col>
|
||||
{/if}
|
||||
<Col xs="11" class="align-content-center">
|
||||
<Progress value={fpd.value} max={fpd.peak} color={fpd.color} />
|
||||
</Col>
|
||||
{#if !fpd.dir}
|
||||
<Col xs="1">
|
||||
<Icon name="caret-right-fill" />
|
||||
</Col>
|
||||
{/if}
|
||||
</Row>
|
||||
{:else}
|
||||
<div class="mb-1 d-flex justify-content-between">
|
||||
<div>
|
||||
<b>{fpd.name} ({fpd.stat})</b>
|
||||
</div>
|
||||
<div
|
||||
class="cursor-help d-inline-flex"
|
||||
id={`footprint-${job.jobId}-${index}`}
|
||||
>
|
||||
<div class="mx-1">
|
||||
<Icon name="info-circle"/>
|
||||
</div>
|
||||
<div>
|
||||
{fpd.value}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tooltip
|
||||
target={`footprint-${job.jobId}-${index}`}
|
||||
placement="right"
|
||||
>{fpd.message}</Tooltip
|
||||
>
|
||||
{/if}
|
||||
{/each}
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
<TabPane tabId="polar" tab="Polar">
|
||||
{/if}
|
||||
{/each}
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
{/if}
|
||||
<TabPane tabId="polar" tab="Polar" active={!showFootprint}>
|
||||
<CardBody>
|
||||
<Polar
|
||||
{footprintData}
|
||||
@ -317,19 +322,21 @@
|
||||
/>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
<TabPane tabId="summary" tab="Summary">
|
||||
<CardBody>
|
||||
<p>Based on footprint data, this job performs as follows:</p>
|
||||
<hr/>
|
||||
<ul>
|
||||
{#each summaryMessages as sm}
|
||||
<li>
|
||||
{@html sm}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
<!--
|
||||
<TabPane tabId="summary" tab="Summary">
|
||||
<CardBody>
|
||||
<p>Based on footprint data, this job performs as follows:</p>
|
||||
<hr/>
|
||||
<ul>
|
||||
{#each summaryMessages as sm}
|
||||
<li>
|
||||
{@html sm}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
-->
|
||||
</TabContent>
|
||||
</Card>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user