cc-backend/web/frontend/src/Jobs.root.svelte

191 lines
5.5 KiB
Svelte

<!--
@component Main job list component
Properties:
- `filterPresets Object?`: Optional predefined filter values [Default: {}]
- `authlevel Number`: The current users authentication level
- `roles [Number]`: Enum containing available roles
-->
<script>
import { onMount, getContext } from "svelte";
import {
Row,
Col,
Button,
ButtonGroup,
Icon,
Card,
Spinner,
} from "@sveltestrap/sveltestrap";
import { init } from "./generic/utils.js";
import Filters from "./generic/Filters.svelte";
import JobList from "./generic/JobList.svelte";
import JobCompare from "./generic/JobCompare.svelte";
import TextFilter from "./generic/helper/TextFilter.svelte";
import Refresher from "./generic/helper/Refresher.svelte";
import Sorting from "./generic/select/SortSelection.svelte";
import MetricSelection from "./generic/select/MetricSelection.svelte";
const { query: initq } = init();
const ccconfig = getContext("cc-config");
export let filterPresets = {};
export let authlevel;
export let roles;
let filterComponent; // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the
let filterBuffer = [];
let selectedJobs = [];
let jobList,
jobCompare,
matchedListJobs,
matchedCompareJobs = null;
let sorting = { field: "startTime", type: "col", order: "DESC" },
isSortingOpen = false,
isMetricsSelectionOpen = false;
let metrics = filterPresets.cluster
? ccconfig[`plot_list_selectedMetrics:${filterPresets.cluster}`] ||
ccconfig.plot_list_selectedMetrics
: ccconfig.plot_list_selectedMetrics;
let showFootprint = filterPresets.cluster
? !!ccconfig[`plot_list_showFootprint:${filterPresets.cluster}`]
: !!ccconfig.plot_list_showFootprint;
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null;
let presetProject = filterPresets?.project ? filterPresets.project : ""
let showCompare = false;
// The filterPresets are handled by the Filters component,
// so we need to wait for it to be ready before we can start a query.
// This is also why JobList component starts out with a paused query.
onMount(() => filterComponent.updateFilters());
$: if (filterComponent && selectedJobs.length == 0) {
filterComponent.updateFilters({dbId: []})
}
</script>
<!-- ROW1: Status-->
{#if $initq.fetching}
<Row class="mb-3">
<Col>
<Spinner />
</Col>
</Row>
{:else if $initq.error}
<Row class="mb-3">
<Col>
<Card body color="danger">{$initq.error.message}</Card>
</Col>
</Row>
{/if}
<!-- ROW2: Tools-->
<Row cols={{ xs: 1, md: 2, lg: 5}} class="mb-3">
<Col lg="2" class="mb-2 mb-lg-0">
<ButtonGroup class="w-100">
<Button outline color="primary" on:click={() => (isSortingOpen = true)} disabled={showCompare}>
<Icon name="sort-up" /> Sorting
</Button>
<Button
outline
color="primary"
on:click={() => (isMetricsSelectionOpen = true)}
>
<Icon name="graph-up" /> Metrics
</Button>
</ButtonGroup>
</Col>
<Col lg="4" class="mb-1 mb-lg-0">
<Filters
showFilter={!showCompare}
{filterPresets}
matchedJobs={showCompare? matchedCompareJobs: matchedListJobs}
bind:this={filterComponent}
on:update-filters={({ detail }) => {
selectedCluster = detail.filters[0]?.cluster
? detail.filters[0].cluster.eq
: null;
filterBuffer = [...detail.filters]
if (showCompare) {
jobCompare.queryJobs(detail.filters);
} else {
jobList.queryJobs(detail.filters);
}
}}
/>
</Col>
<Col lg="2" class="mb-2 mb-lg-0">
{#if !showCompare}
<TextFilter
{presetProject}
bind:authlevel
bind:roles
on:set-filter={({ detail }) => filterComponent.updateFilters(detail)}
/>
{/if}
</Col>
<Col lg="2" class="mb-1 mb-lg-0">
{#if !showCompare}
<Refresher on:refresh={() => {
jobList.refreshJobs()
jobList.refreshAllMetrics()
}} />
{/if}
</Col>
<Col lg="2" class="mb-2 mb-lg-0">
<ButtonGroup class="w-100">
<Button color="primary" disabled={matchedListJobs >= 500 && !(selectedJobs.length != 0)} on:click={() => {
if (selectedJobs.length != 0) filterComponent.updateFilters({dbId: selectedJobs}, true)
showCompare = !showCompare
}} >
{showCompare ? 'Return to List' :
'Compare Jobs' + (selectedJobs.length != 0 ? ` (${selectedJobs.length} selected)` : matchedListJobs >= 500 ? ` (Too Many)` : ``)}
</Button>
{#if !showCompare && selectedJobs.length != 0}
<Button color="warning" on:click={() => {
selectedJobs = [] // Only empty array, filters handled by reactive reset
}}>
Clear
</Button>
{/if}
</ButtonGroup>
</Col>
</Row>
<!-- ROW3: Job List / Job Compare-->
<Row>
<Col>
{#if !showCompare}
<JobList
bind:this={jobList}
bind:metrics
bind:sorting
bind:matchedListJobs
bind:showFootprint
bind:selectedJobs
{filterBuffer}
/>
{:else}
<JobCompare
bind:this={jobCompare}
bind:metrics
bind:matchedCompareJobs
{filterBuffer}
/>
{/if}
</Col>
</Row>
<Sorting bind:sorting bind:isOpen={isSortingOpen}/>
<MetricSelection
bind:cluster={selectedCluster}
configName="plot_list_selectedMetrics"
bind:metrics
bind:isOpen={isMetricsSelectionOpen}
bind:showFootprint
footprintSelect
/>