mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 05:19:05 +01:00
improve job list toolbar layouting, smaller layout fixes
This commit is contained in:
parent
7243dbe763
commit
37415fa261
@ -307,7 +307,7 @@
|
|||||||
<Spinner />
|
<Spinner />
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
{/if}
|
||||||
<Col xs="auto">
|
<Col xs="auto" class="mb-2 mb-lg-0">
|
||||||
{#if $initq.error}
|
{#if $initq.error}
|
||||||
<Card body color="danger">{$initq.error.message}</Card>
|
<Card body color="danger">{$initq.error.message}</Card>
|
||||||
{:else if cluster}
|
{:else if cluster}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
Button,
|
Button,
|
||||||
|
ButtonGroup,
|
||||||
Icon,
|
Icon,
|
||||||
Card,
|
Card,
|
||||||
Spinner,
|
Spinner,
|
||||||
@ -55,36 +56,41 @@
|
|||||||
onMount(() => filterComponent.updateFilters());
|
onMount(() => filterComponent.updateFilters());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Row>
|
<!-- ROW1: Status-->
|
||||||
{#if $initq.fetching}
|
{#if $initq.fetching}
|
||||||
<Col xs="auto">
|
<Row class="mb-3">
|
||||||
|
<Col>
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</Col>
|
</Col>
|
||||||
{:else if $initq.error}
|
</Row>
|
||||||
<Col xs="auto">
|
{:else if $initq.error}
|
||||||
|
<Row class="mb-3">
|
||||||
|
<Col>
|
||||||
<Card body color="danger">{$initq.error.message}</Card>
|
<Card body color="danger">{$initq.error.message}</Card>
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
</Row>
|
||||||
</Row>
|
{/if}
|
||||||
<Row>
|
|
||||||
<Col xs="auto">
|
<!-- ROW2: Tools-->
|
||||||
<Button outline color="primary" on:click={() => (isSortingOpen = true)}>
|
<Row cols={{ xs: 1, md: 2, lg: 4}} class="mb-3">
|
||||||
<Icon name="sort-up" /> Sorting
|
<Col lg="2" class="mb-2 mb-lg-0">
|
||||||
</Button>
|
<ButtonGroup class="w-100">
|
||||||
<Button
|
<Button outline color="primary" on:click={() => (isSortingOpen = true)}>
|
||||||
outline
|
<Icon name="sort-up" /> Sorting
|
||||||
color="primary"
|
</Button>
|
||||||
on:click={() => (isMetricsSelectionOpen = true)}
|
<Button
|
||||||
>
|
outline
|
||||||
<Icon name="graph-up" /> Metrics
|
color="primary"
|
||||||
</Button>
|
on:click={() => (isMetricsSelectionOpen = true)}
|
||||||
<Button disabled outline
|
>
|
||||||
>{matchedJobs == null ? "Loading..." : `${matchedJobs} jobs`}</Button
|
<Icon name="graph-up" /> Metrics
|
||||||
>
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs="auto">
|
<Col lg="4" xl="{(presetProject !== '') ? 5 : 6}" class="mb-1 mb-lg-0">
|
||||||
<Filters
|
<Filters
|
||||||
{filterPresets}
|
{filterPresets}
|
||||||
|
{matchedJobs}
|
||||||
bind:this={filterComponent}
|
bind:this={filterComponent}
|
||||||
on:update-filters={({ detail }) => {
|
on:update-filters={({ detail }) => {
|
||||||
selectedCluster = detail.filters[0]?.cluster
|
selectedCluster = detail.filters[0]?.cluster
|
||||||
@ -94,8 +100,7 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col lg="3" xl="{(presetProject !== '') ? 3 : 2}" class="mb-2 mb-lg-0">
|
||||||
<Col xs="3" style="margin-left: auto;">
|
|
||||||
<TextFilter
|
<TextFilter
|
||||||
{presetProject}
|
{presetProject}
|
||||||
bind:authlevel
|
bind:authlevel
|
||||||
@ -103,21 +108,22 @@
|
|||||||
on:set-filter={({ detail }) => filterComponent.updateFilters(detail)}
|
on:set-filter={({ detail }) => filterComponent.updateFilters(detail)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs="2">
|
<Col lg="3" xl="2" class="mb-1 mb-lg-0">
|
||||||
<Refresher on:refresh={() => {
|
<Refresher on:refresh={() => {
|
||||||
jobList.refreshJobs()
|
jobList.refreshJobs()
|
||||||
jobList.refreshAllMetrics()
|
jobList.refreshAllMetrics()
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<br />
|
|
||||||
|
<!-- ROW3: Job List-->
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<JobList
|
<JobList
|
||||||
|
bind:this={jobList}
|
||||||
bind:metrics
|
bind:metrics
|
||||||
bind:sorting
|
bind:sorting
|
||||||
bind:matchedJobs
|
bind:matchedJobs
|
||||||
bind:this={jobList}
|
|
||||||
bind:showFootprint
|
bind:showFootprint
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -104,8 +104,8 @@
|
|||||||
onMount(() => filterComponent.updateFilters());
|
onMount(() => filterComponent.updateFilters());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Row>
|
<Row cols={{ xs: 1, md: 2}}>
|
||||||
<Col xs="auto">
|
<Col xs="12" md="5" lg="4" xl="3" class="mb-2 mb-md-0">
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<Button disabled outline>
|
<Button disabled outline>
|
||||||
Search {type.toLowerCase()}s
|
Search {type.toLowerCase()}s
|
||||||
@ -119,7 +119,7 @@
|
|||||||
/>
|
/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs="auto">
|
<Col xs="12" md="7" lg="8" xl="9">
|
||||||
<Filters
|
<Filters
|
||||||
bind:this={filterComponent}
|
bind:this={filterComponent}
|
||||||
{filterPresets}
|
{filterPresets}
|
||||||
@ -135,10 +135,11 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{
|
{#if type === 'USER'}
|
||||||
USER: "Username",
|
Username
|
||||||
PROJECT: "Project Name",
|
{:else if type === 'PROJECT'}
|
||||||
}[type]}
|
Project Name
|
||||||
|
{/if}
|
||||||
<Button
|
<Button
|
||||||
color={sorting.field == "id" ? "primary" : "light"}
|
color={sorting.field == "id" ? "primary" : "light"}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
Button,
|
Button,
|
||||||
|
ButtonGroup,
|
||||||
Icon,
|
Icon,
|
||||||
Card,
|
Card,
|
||||||
Spinner,
|
Spinner,
|
||||||
@ -48,6 +49,7 @@
|
|||||||
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 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 jobList;
|
let jobList;
|
||||||
let jobFilters = [];
|
let jobFilters = [];
|
||||||
|
let matchedJobs = 0;
|
||||||
let sorting = { field: "startTime", type: "col", order: "DESC" },
|
let sorting = { field: "startTime", type: "col", order: "DESC" },
|
||||||
isSortingOpen = false;
|
isSortingOpen = false;
|
||||||
let metrics = ccconfig.plot_list_selectedMetrics,
|
let metrics = ccconfig.plot_list_selectedMetrics,
|
||||||
@ -103,41 +105,41 @@
|
|||||||
onMount(() => filterComponent.updateFilters());
|
onMount(() => filterComponent.updateFilters());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Row>
|
<!-- ROW1: Status-->
|
||||||
{#if $initq.fetching}
|
{#if $initq.fetching}
|
||||||
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</Col>
|
</Col>
|
||||||
{:else if $initq.error}
|
</Row>
|
||||||
<Col xs="auto">
|
{:else if $initq.error}
|
||||||
|
<Row>
|
||||||
|
<Col>
|
||||||
<Card body color="danger">{$initq.error.message}</Card>
|
<Card body color="danger">{$initq.error.message}</Card>
|
||||||
</Col>
|
</Col>
|
||||||
{/if}
|
</Row>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Col xs="auto">
|
<!-- ROW2: Tools-->
|
||||||
<Button outline color="primary" on:click={() => (isSortingOpen = true)}>
|
<Row cols={{ xs: 1, md: 2, lg: 4}} class="mb-3">
|
||||||
<Icon name="sort-up" /> Sorting
|
<Col lg="2" class="mb-2 mb-lg-0">
|
||||||
</Button>
|
<ButtonGroup class="w-100">
|
||||||
|
<Button outline color="primary" on:click={() => (isSortingOpen = true)}>
|
||||||
<Button
|
<Icon name="sort-up" /> Sorting
|
||||||
outline
|
</Button>
|
||||||
color="primary"
|
<Button
|
||||||
on:click={() => (isMetricsSelectionOpen = true)}
|
outline
|
||||||
>
|
color="primary"
|
||||||
<Icon name="graph-up" /> Metrics
|
on:click={() => (isMetricsSelectionOpen = true)}
|
||||||
</Button>
|
>
|
||||||
|
<Icon name="graph-up" /> Metrics
|
||||||
<Button
|
</Button>
|
||||||
outline
|
</ButtonGroup>
|
||||||
color="secondary"
|
|
||||||
on:click={() => (isHistogramSelectionOpen = true)}
|
|
||||||
>
|
|
||||||
<Icon name="bar-chart-line" /> Select Histograms
|
|
||||||
</Button>
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs="auto">
|
<Col lg="4" xl="6" class="mb-1 mb-lg-0">
|
||||||
<Filters
|
<Filters
|
||||||
{filterPresets}
|
{filterPresets}
|
||||||
|
{matchedJobs}
|
||||||
startTimeQuickSelect={true}
|
startTimeQuickSelect={true}
|
||||||
bind:this={filterComponent}
|
bind:this={filterComponent}
|
||||||
on:update-filters={({ detail }) => {
|
on:update-filters={({ detail }) => {
|
||||||
@ -149,20 +151,21 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs="auto" style="margin-left: auto;">
|
<Col lg="3" xl="2" class="mb-2 mb-lg-0">
|
||||||
<TextFilter
|
<TextFilter
|
||||||
on:set-filter={({ detail }) => filterComponent.updateFilters(detail)}
|
on:set-filter={({ detail }) => filterComponent.updateFilters(detail)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs="auto">
|
<Col lg="3" xl="2" class="mb-1 mb-lg-0">
|
||||||
<Refresher on:refresh={() => {
|
<Refresher on:refresh={() => {
|
||||||
jobList.refreshJobs()
|
jobList.refreshJobs()
|
||||||
jobList.refreshAllMetrics()
|
jobList.refreshAllMetrics()
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<br />
|
|
||||||
<Row cols={{ xs: 1, md: 3}}>
|
<!-- ROW3: Base Information-->
|
||||||
|
<Row cols={{ xs: 1, md: 3}} class="mb-2">
|
||||||
{#if $stats.error}
|
{#if $stats.error}
|
||||||
<Col>
|
<Col>
|
||||||
<Card body color="danger">{$stats.error.message}</Card>
|
<Card body color="danger">{$stats.error.message}</Card>
|
||||||
@ -210,12 +213,12 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Col>
|
</Col>
|
||||||
<Col class="text-center">
|
<Col class="px-1">
|
||||||
<div bind:clientWidth={w1}>
|
<div bind:clientWidth={w1}>
|
||||||
{#key $stats.data.jobsStatistics[0].histDuration}
|
{#key $stats.data.jobsStatistics[0].histDuration}
|
||||||
<Histogram
|
<Histogram
|
||||||
data={convert2uplot($stats.data.jobsStatistics[0].histDuration)}
|
data={convert2uplot($stats.data.jobsStatistics[0].histDuration)}
|
||||||
width={w1 - 25}
|
width={w1}
|
||||||
height={histogramHeight}
|
height={histogramHeight}
|
||||||
title="Duration Distribution"
|
title="Duration Distribution"
|
||||||
xlabel="Current Runtimes"
|
xlabel="Current Runtimes"
|
||||||
@ -226,12 +229,12 @@
|
|||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col class="text-center">
|
<Col class="px-1">
|
||||||
<div bind:clientWidth={w2}>
|
<div bind:clientWidth={w2}>
|
||||||
{#key $stats.data.jobsStatistics[0].histNumNodes}
|
{#key $stats.data.jobsStatistics[0].histNumNodes}
|
||||||
<Histogram
|
<Histogram
|
||||||
data={convert2uplot($stats.data.jobsStatistics[0].histNumNodes)}
|
data={convert2uplot($stats.data.jobsStatistics[0].histNumNodes)}
|
||||||
width={w2 - 25}
|
width={w2}
|
||||||
height={histogramHeight}
|
height={histogramHeight}
|
||||||
title="Number of Nodes Distribution"
|
title="Number of Nodes Distribution"
|
||||||
xlabel="Allocated Nodes"
|
xlabel="Allocated Nodes"
|
||||||
@ -245,7 +248,19 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{#if metricsInHistograms}
|
<!-- ROW4+5: Selectable Histograms -->
|
||||||
|
<Row cols={{ xs: 1, md: 5}}>
|
||||||
|
<Col>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
color="secondary"
|
||||||
|
on:click={() => (isHistogramSelectionOpen = true)}
|
||||||
|
>
|
||||||
|
<Icon name="bar-chart-line" /> Select Histograms
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{#if metricsInHistograms?.length > 0}
|
||||||
{#if $stats.error}
|
{#if $stats.error}
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
@ -259,6 +274,7 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{:else}
|
{:else}
|
||||||
|
<hr class="my-2"/>
|
||||||
{#key $stats.data.jobsStatistics[0].histMetrics}
|
{#key $stats.data.jobsStatistics[0].histMetrics}
|
||||||
<PlotGrid
|
<PlotGrid
|
||||||
let:item
|
let:item
|
||||||
@ -281,11 +297,24 @@
|
|||||||
</PlotGrid>
|
</PlotGrid>
|
||||||
{/key}
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<Row class="mt-2">
|
||||||
|
<Col>
|
||||||
|
<Card body>No footprint histograms selected.</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
{/if}
|
{/if}
|
||||||
<br />
|
|
||||||
<Row>
|
<!-- ROW6: JOB LIST-->
|
||||||
|
<Row class="mt-3">
|
||||||
<Col>
|
<Col>
|
||||||
<JobList bind:metrics bind:sorting bind:this={jobList} bind:showFootprint />
|
<JobList
|
||||||
|
bind:this={jobList}
|
||||||
|
bind:matchedJobs
|
||||||
|
bind:metrics
|
||||||
|
bind:sorting
|
||||||
|
bind:showFootprint
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
- `filterPresets Object?`: Optional predefined filter values [Default: {}]
|
- `filterPresets Object?`: Optional predefined filter values [Default: {}]
|
||||||
- `disableClusterSelection Bool?`: Is the selection disabled [Default: false]
|
- `disableClusterSelection Bool?`: Is the selection disabled [Default: false]
|
||||||
- `startTimeQuickSelect Bool?`: Render startTime quick selections [Default: false]
|
- `startTimeQuickSelect Bool?`: Render startTime quick selections [Default: false]
|
||||||
|
- `matchedJobs Number?`: Number of jobs matching the filter [Default: -2]
|
||||||
|
|
||||||
Events:
|
Events:
|
||||||
- `update-filters, {filters: [Object]?}`: The detail's 'filters' prop are new filter items to be applied
|
- `update-filters, {filters: [Object]?}`: The detail's 'filters' prop are new filter items to be applied
|
||||||
@ -17,11 +18,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import {
|
import {
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
DropdownItem,
|
DropdownItem,
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownToggle,
|
DropdownToggle,
|
||||||
|
Button,
|
||||||
|
ButtonGroup,
|
||||||
ButtonDropdown,
|
ButtonDropdown,
|
||||||
Icon,
|
Icon,
|
||||||
} from "@sveltestrap/sveltestrap";
|
} from "@sveltestrap/sveltestrap";
|
||||||
@ -42,6 +43,7 @@
|
|||||||
export let filterPresets = {};
|
export let filterPresets = {};
|
||||||
export let disableClusterSelection = false;
|
export let disableClusterSelection = false;
|
||||||
export let startTimeQuickSelect = false;
|
export let startTimeQuickSelect = false;
|
||||||
|
export let matchedJobs = -2;
|
||||||
|
|
||||||
let filters = {
|
let filters = {
|
||||||
projectMatch: filterPresets.projectMatch || "contains",
|
projectMatch: filterPresets.projectMatch || "contains",
|
||||||
@ -217,170 +219,174 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Row>
|
<!-- Dropdown-Button -->
|
||||||
<Col xs="auto">
|
<ButtonGroup>
|
||||||
<ButtonDropdown class="cc-dropdown-on-hover">
|
<ButtonDropdown class="cc-dropdown-on-hover mb-1" style="{(matchedJobs >= -1) ? '' : 'margin-right: 0.5rem;'}">
|
||||||
<DropdownToggle outline caret color="success">
|
<DropdownToggle outline caret color="success">
|
||||||
<Icon name="sliders" />
|
<Icon name="sliders" />
|
||||||
Filters
|
Filters
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownItem header>Manage Filters</DropdownItem>
|
<DropdownItem header>Manage Filters</DropdownItem>
|
||||||
{#if menuText}
|
{#if menuText}
|
||||||
<DropdownItem disabled>{menuText}</DropdownItem>
|
<DropdownItem disabled>{menuText}</DropdownItem>
|
||||||
<DropdownItem divider />
|
<DropdownItem divider />
|
||||||
{/if}
|
{/if}
|
||||||
<DropdownItem on:click={() => (isClusterOpen = true)}>
|
<DropdownItem on:click={() => (isClusterOpen = true)}>
|
||||||
<Icon name="cpu" /> Cluster/Partition
|
<Icon name="cpu" /> Cluster/Partition
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={() => (isJobStatesOpen = true)}>
|
<DropdownItem on:click={() => (isJobStatesOpen = true)}>
|
||||||
<Icon name="gear-fill" /> Job States
|
<Icon name="gear-fill" /> Job States
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={() => (isStartTimeOpen = true)}>
|
<DropdownItem on:click={() => (isStartTimeOpen = true)}>
|
||||||
<Icon name="calendar-range" /> Start Time
|
<Icon name="calendar-range" /> Start Time
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={() => (isDurationOpen = true)}>
|
<DropdownItem on:click={() => (isDurationOpen = true)}>
|
||||||
<Icon name="stopwatch" /> Duration
|
<Icon name="stopwatch" /> Duration
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={() => (isTagsOpen = true)}>
|
<DropdownItem on:click={() => (isTagsOpen = true)}>
|
||||||
<Icon name="tags" /> Tags
|
<Icon name="tags" /> Tags
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={() => (isResourcesOpen = true)}>
|
<DropdownItem on:click={() => (isResourcesOpen = true)}>
|
||||||
<Icon name="hdd-stack" /> Resources
|
<Icon name="hdd-stack" /> Resources
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={() => (isEnergyOpen = true)}>
|
<DropdownItem on:click={() => (isEnergyOpen = true)}>
|
||||||
<Icon name="lightning-charge-fill" /> Energy
|
<Icon name="lightning-charge-fill" /> Energy
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={() => (isStatsOpen = true)}>
|
<DropdownItem on:click={() => (isStatsOpen = true)}>
|
||||||
<Icon name="bar-chart" on:click={() => (isStatsOpen = true)} /> Statistics
|
<Icon name="bar-chart" on:click={() => (isStatsOpen = true)} /> Statistics
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
{#if startTimeQuickSelect}
|
{#if startTimeQuickSelect}
|
||||||
<DropdownItem divider />
|
<DropdownItem divider />
|
||||||
<DropdownItem disabled>Start Time Qick Selection</DropdownItem>
|
<DropdownItem disabled>Start Time Quick Selection</DropdownItem>
|
||||||
{#each [{ text: "Last 6hrs", url: "last6h", seconds: 6 * 60 * 60 }, { text: "Last 24hrs", url: "last24h", seconds: 24 * 60 * 60 }, { text: "Last 7 days", url: "last7d", seconds: 7 * 24 * 60 * 60 }, { text: "Last 30 days", url: "last30d", seconds: 30 * 24 * 60 * 60 }] as { text, url, seconds }}
|
{#each [{ text: "Last 6hrs", url: "last6h", seconds: 6 * 60 * 60 }, { text: "Last 24hrs", url: "last24h", seconds: 24 * 60 * 60 }, { text: "Last 7 days", url: "last7d", seconds: 7 * 24 * 60 * 60 }, { text: "Last 30 days", url: "last30d", seconds: 30 * 24 * 60 * 60 }] as { text, url, seconds }}
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
filters.startTime.from = new Date(
|
filters.startTime.from = new Date(
|
||||||
Date.now() - seconds * 1000,
|
Date.now() - seconds * 1000,
|
||||||
).toISOString();
|
).toISOString();
|
||||||
filters.startTime.to = new Date(Date.now()).toISOString();
|
filters.startTime.to = new Date(Date.now()).toISOString();
|
||||||
(filters.startTime.text = text), (filters.startTime.url = url);
|
(filters.startTime.text = text), (filters.startTime.url = url);
|
||||||
updateFilters();
|
updateFilters();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon name="calendar-range" />
|
<Icon name="calendar-range" />
|
||||||
{text}
|
{text}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</DropdownMenu>
|
|
||||||
</ButtonDropdown>
|
|
||||||
</Col>
|
|
||||||
<Col xs="auto">
|
|
||||||
{#if filters.cluster}
|
|
||||||
<Info icon="cpu" on:click={() => (isClusterOpen = true)}>
|
|
||||||
{filters.cluster}
|
|
||||||
{#if filters.partition}
|
|
||||||
({filters.partition})
|
|
||||||
{/if}
|
|
||||||
</Info>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if filters.states.length != allJobStates.length}
|
|
||||||
<Info icon="gear-fill" on:click={() => (isJobStatesOpen = true)}>
|
|
||||||
{filters.states.join(", ")}
|
|
||||||
</Info>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if filters.startTime.from || filters.startTime.to}
|
|
||||||
<Info icon="calendar-range" on:click={() => (isStartTimeOpen = true)}>
|
|
||||||
{#if filters.startTime.text}
|
|
||||||
{filters.startTime.text}
|
|
||||||
{:else}
|
|
||||||
{new Date(filters.startTime.from).toLocaleString()} - {new Date(
|
|
||||||
filters.startTime.to,
|
|
||||||
).toLocaleString()}
|
|
||||||
{/if}
|
|
||||||
</Info>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if filters.duration.from || filters.duration.to}
|
|
||||||
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
|
|
||||||
{Math.floor(filters.duration.from / 3600)}h:{Math.floor(
|
|
||||||
(filters.duration.from % 3600) / 60,
|
|
||||||
)}m -
|
|
||||||
{Math.floor(filters.duration.to / 3600)}h:{Math.floor(
|
|
||||||
(filters.duration.to % 3600) / 60,
|
|
||||||
)}m
|
|
||||||
</Info>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if filters.duration.lessThan}
|
|
||||||
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
|
|
||||||
Duration less than {Math.floor(
|
|
||||||
filters.duration.lessThan / 3600,
|
|
||||||
)}h:{Math.floor((filters.duration.lessThan % 3600) / 60)}m
|
|
||||||
</Info>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if filters.duration.moreThan}
|
|
||||||
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
|
|
||||||
Duration more than {Math.floor(
|
|
||||||
filters.duration.moreThan / 3600,
|
|
||||||
)}h:{Math.floor((filters.duration.moreThan % 3600) / 60)}m
|
|
||||||
</Info>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if filters.tags.length != 0}
|
|
||||||
<Info icon="tags" on:click={() => (isTagsOpen = true)}>
|
|
||||||
{#each filters.tags as tagId}
|
|
||||||
{#key tagId}
|
|
||||||
<Tag id={tagId} clickable={false} />
|
|
||||||
{/key}
|
|
||||||
{/each}
|
{/each}
|
||||||
</Info>
|
{/if}
|
||||||
{/if}
|
</DropdownMenu>
|
||||||
|
</ButtonDropdown>
|
||||||
|
{#if matchedJobs >= -1}
|
||||||
|
<Button class="mb-1" style="margin-right: 0.5rem;" disabled outline>
|
||||||
|
{matchedJobs == -1 ? 'Loading ...' : `${matchedJobs} jobs`}
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
</ButtonGroup>
|
||||||
|
|
||||||
{#if filters.numNodes.from != null || filters.numNodes.to != null || filters.numHWThreads.from != null || filters.numHWThreads.to != null || filters.numAccelerators.from != null || filters.numAccelerators.to != null}
|
<!-- SELECTED FILTER PILLS -->
|
||||||
<Info icon="hdd-stack" on:click={() => (isResourcesOpen = true)}>
|
{#if filters.cluster}
|
||||||
{#if isNodesModified}
|
<Info icon="cpu" on:click={() => (isClusterOpen = true)}>
|
||||||
Nodes: {filters.numNodes.from} - {filters.numNodes.to}
|
{filters.cluster}
|
||||||
{/if}
|
{#if filters.partition}
|
||||||
{#if isNodesModified && isHwthreadsModified},
|
({filters.partition})
|
||||||
{/if}
|
|
||||||
{#if isHwthreadsModified}
|
|
||||||
HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to}
|
|
||||||
{/if}
|
|
||||||
{#if (isNodesModified || isHwthreadsModified) && isAccsModified},
|
|
||||||
{/if}
|
|
||||||
{#if isAccsModified}
|
|
||||||
Accelerators: {filters.numAccelerators.from} - {filters
|
|
||||||
.numAccelerators.to}
|
|
||||||
{/if}
|
|
||||||
</Info>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if filters.node != null}
|
{#if filters.states.length != allJobStates.length}
|
||||||
<Info icon="hdd-stack" on:click={() => (isResourcesOpen = true)}>
|
<Info icon="gear-fill" on:click={() => (isJobStatesOpen = true)}>
|
||||||
Node: {filters.node}
|
{filters.states.join(", ")}
|
||||||
</Info>
|
</Info>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if filters.energy.from || filters.energy.to}
|
{#if filters.startTime.from || filters.startTime.to}
|
||||||
<Info icon="lightning-charge-fill" on:click={() => (isEnergyOpen = true)}>
|
<Info icon="calendar-range" on:click={() => (isStartTimeOpen = true)}>
|
||||||
Total Energy: {filters.energy.from} - {filters.energy.to}
|
{#if filters.startTime.text}
|
||||||
</Info>
|
{filters.startTime.text}
|
||||||
|
{:else}
|
||||||
|
{new Date(filters.startTime.from).toLocaleString()} - {new Date(
|
||||||
|
filters.startTime.to,
|
||||||
|
).toLocaleString()}
|
||||||
{/if}
|
{/if}
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if filters.stats.length > 0}
|
{#if filters.duration.from || filters.duration.to}
|
||||||
<Info icon="bar-chart" on:click={() => (isStatsOpen = true)}>
|
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
|
||||||
{filters.stats
|
{Math.floor(filters.duration.from / 3600)}h:{Math.floor(
|
||||||
.map((stat) => `${stat.text}: ${stat.from} - ${stat.to}`)
|
(filters.duration.from % 3600) / 60,
|
||||||
.join(", ")}
|
)}m -
|
||||||
</Info>
|
{Math.floor(filters.duration.to / 3600)}h:{Math.floor(
|
||||||
|
(filters.duration.to % 3600) / 60,
|
||||||
|
)}m
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if filters.duration.lessThan}
|
||||||
|
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
|
||||||
|
Duration less than {Math.floor(
|
||||||
|
filters.duration.lessThan / 3600,
|
||||||
|
)}h:{Math.floor((filters.duration.lessThan % 3600) / 60)}m
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if filters.duration.moreThan}
|
||||||
|
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
|
||||||
|
Duration more than {Math.floor(
|
||||||
|
filters.duration.moreThan / 3600,
|
||||||
|
)}h:{Math.floor((filters.duration.moreThan % 3600) / 60)}m
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if filters.tags.length != 0}
|
||||||
|
<Info icon="tags" on:click={() => (isTagsOpen = true)}>
|
||||||
|
{#each filters.tags as tagId}
|
||||||
|
{#key tagId}
|
||||||
|
<Tag id={tagId} clickable={false} />
|
||||||
|
{/key}
|
||||||
|
{/each}
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if filters.numNodes.from != null || filters.numNodes.to != null || filters.numHWThreads.from != null || filters.numHWThreads.to != null || filters.numAccelerators.from != null || filters.numAccelerators.to != null}
|
||||||
|
<Info icon="hdd-stack" on:click={() => (isResourcesOpen = true)}>
|
||||||
|
{#if isNodesModified}
|
||||||
|
Nodes: {filters.numNodes.from} - {filters.numNodes.to}
|
||||||
{/if}
|
{/if}
|
||||||
</Col>
|
{#if isNodesModified && isHwthreadsModified},
|
||||||
</Row>
|
{/if}
|
||||||
|
{#if isHwthreadsModified}
|
||||||
|
HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to}
|
||||||
|
{/if}
|
||||||
|
{#if (isNodesModified || isHwthreadsModified) && isAccsModified},
|
||||||
|
{/if}
|
||||||
|
{#if isAccsModified}
|
||||||
|
Accelerators: {filters.numAccelerators.from} - {filters
|
||||||
|
.numAccelerators.to}
|
||||||
|
{/if}
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if filters.node != null}
|
||||||
|
<Info icon="hdd-stack" on:click={() => (isResourcesOpen = true)}>
|
||||||
|
Node: {filters.node}
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if filters.energy.from || filters.energy.to}
|
||||||
|
<Info icon="lightning-charge-fill" on:click={() => (isEnergyOpen = true)}>
|
||||||
|
Total Energy: {filters.energy.from} - {filters.energy.to}
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if filters.stats.length > 0}
|
||||||
|
<Info icon="bar-chart" on:click={() => (isStatsOpen = true)}>
|
||||||
|
{filters.stats
|
||||||
|
.map((stat) => `${stat.text}: ${stat.from} - ${stat.to}`)
|
||||||
|
.join(", ")}
|
||||||
|
</Info>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Cluster
|
<Cluster
|
||||||
{disableClusterSelection}
|
{disableClusterSelection}
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
jobs = [...$jobsStore.data.jobs.items]
|
jobs = [...$jobsStore.data.jobs.items]
|
||||||
}
|
}
|
||||||
|
|
||||||
$: matchedJobs = $jobsStore.data != null ? $jobsStore.data.jobs.count : 0;
|
$: matchedJobs = $jobsStore.data != null ? $jobsStore.data.jobs.count : -1;
|
||||||
|
|
||||||
// Force refresh list with existing unchanged variables (== usually would not trigger reactivity)
|
// Force refresh list with existing unchanged variables (== usually would not trigger reactivity)
|
||||||
export function refreshJobs() {
|
export function refreshJobs() {
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
export let modified = false;
|
export let modified = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button outline color={modified ? "warning" : "primary"} on:click>
|
<Button class="mr-2 mb-1" outline color={modified ? "warning" : "primary"} on:click>
|
||||||
<Icon name={icon} />
|
<Icon name={icon} />
|
||||||
<slot />
|
<slot />
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -34,14 +34,15 @@
|
|||||||
<InputGroup>
|
<InputGroup>
|
||||||
<Input
|
<Input
|
||||||
type="select"
|
type="select"
|
||||||
|
title="Periodic refresh interval"
|
||||||
bind:value={refreshInterval}
|
bind:value={refreshInterval}
|
||||||
on:change={refreshIntervalChanged}
|
on:change={refreshIntervalChanged}
|
||||||
>
|
>
|
||||||
<option value={null}>No periodic refresh</option>
|
<option value={null}>No Interval</option>
|
||||||
<option value={30 * 1000}>Update every 30 seconds</option>
|
<option value={30 * 1000}>30 Seconds</option>
|
||||||
<option value={60 * 1000}>Update every minute</option>
|
<option value={60 * 1000}>60 Seconds</option>
|
||||||
<option value={2 * 60 * 1000}>Update every two minutes</option>
|
<option value={2 * 60 * 1000}>Two Minutes</option>
|
||||||
<option value={5 * 60 * 1000}>Update every 5 minutes</option>
|
<option value={5 * 60 * 1000}>5 Minutes</option>
|
||||||
</Input>
|
</Input>
|
||||||
<Button
|
<Button
|
||||||
outline
|
outline
|
||||||
|
@ -83,26 +83,28 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<select
|
<Input
|
||||||
style="max-width: 175px;"
|
type="select"
|
||||||
|
style="max-width: 120px;"
|
||||||
class="form-select"
|
class="form-select"
|
||||||
|
title="Search Mode"
|
||||||
bind:value={mode}
|
bind:value={mode}
|
||||||
on:change={modeChanged}
|
on:change={modeChanged}
|
||||||
>
|
>
|
||||||
{#if !presetProject}
|
{#if !presetProject}
|
||||||
<option value={"project"}>Search Project</option>
|
<option value={"project"}>Project</option>
|
||||||
{/if}
|
{/if}
|
||||||
{#if roles && authlevel >= roles.manager}
|
{#if roles && authlevel >= roles.manager}
|
||||||
<option value={"user"}>Search User</option>
|
<option value={"user"}>User</option>
|
||||||
{/if}
|
{/if}
|
||||||
<option value={"jobName"}>Search Jobname</option>
|
<option value={"jobName"}>Jobname</option>
|
||||||
</select>
|
</Input>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={term}
|
bind:value={term}
|
||||||
on:change={() => termChanged()}
|
on:change={() => termChanged()}
|
||||||
on:keyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)}
|
on:keyup={(event) => termChanged(event.key == "Enter" ? 0 : throttle)}
|
||||||
placeholder={presetProject ? `Filter ${mode} in ${scrambleNames ? scramble(presetProject) : presetProject} ...` : `Filter ${mode} ...`}
|
placeholder={presetProject ? `Find ${mode} in ${scrambleNames ? scramble(presetProject) : presetProject} ...` : `Find ${mode} ...`}
|
||||||
/>
|
/>
|
||||||
{#if presetProject}
|
{#if presetProject}
|
||||||
<Button title="Reset Project" on:click={resetProject}
|
<Button title="Reset Project" on:click={resetProject}
|
||||||
|
Loading…
Reference in New Issue
Block a user