Prevent high job counts in compare view by filter removal

This commit is contained in:
Christoph Kluge 2025-05-08 11:28:13 +02:00
parent ab616f8f79
commit c119eeb468
2 changed files with 163 additions and 154 deletions

View File

@ -99,6 +99,7 @@
</Col> </Col>
<Col lg="4" class="mb-1 mb-lg-0"> <Col lg="4" class="mb-1 mb-lg-0">
<Filters <Filters
showFilter={!showCompare}
{filterPresets} {filterPresets}
matchedJobs={showCompare? matchedCompareJobs: matchedListJobs} matchedJobs={showCompare? matchedCompareJobs: matchedListJobs}
bind:this={filterComponent} bind:this={filterComponent}
@ -136,18 +137,20 @@
</Col> </Col>
<Col lg="2" class="mb-2 mb-lg-0"> <Col lg="2" class="mb-2 mb-lg-0">
<ButtonGroup class="w-100"> <ButtonGroup class="w-100">
<Button color="primary" on:click={() => { <Button color="primary" disabled={matchedListJobs >= 500 && !(selectedJobs.length != 0)} on:click={() => {
if (selectedJobs.length != 0) filterComponent.updateFilters({dbId: selectedJobs}) if (selectedJobs.length != 0) filterComponent.updateFilters({dbId: selectedJobs})
else if (selectedJobs.length == 0) filterComponent.updateFilters({dbId: []})
showCompare = !showCompare showCompare = !showCompare
}} > }} >
{showCompare ? 'List' : 'Compare'} Jobs {selectedJobs.length != 0 ? `(${selectedJobs.length} selected)` : `(Use Filter)`} {showCompare ? 'Return to List' :
</Button> 'Compare Jobs' + (selectedJobs.length != 0 ? ` (${selectedJobs.length} selected)` : matchedListJobs >= 500 ? ` (Too Many)` : ``)}
<Button color="danger" disabled={selectedJobs.length == 0} on:click={() => {
selectedJobs = [] // Only empty array, filters handled by reactive reset
}}>
Reset
</Button> </Button>
{#if !showCompare && selectedJobs.length != 0}
<Button color="warning" on:click={() => {
selectedJobs = [] // Only empty array, filters handled by reactive reset
}}>
Clear
</Button>
{/if}
</ButtonGroup> </ButtonGroup>
</Col> </Col>
</Row> </Row>

View File

@ -44,6 +44,7 @@
export let disableClusterSelection = false; export let disableClusterSelection = false;
export let startTimeQuickSelect = false; export let startTimeQuickSelect = false;
export let matchedJobs = -2; export let matchedJobs = -2;
export let showFilter = true;
const startTimeSelectOptions = [ const startTimeSelectOptions = [
{ range: "", rangeLabel: "No Selection"}, { range: "", rangeLabel: "No Selection"},
@ -253,60 +254,63 @@
<!-- Dropdown-Button --> <!-- Dropdown-Button -->
<ButtonGroup> <ButtonGroup>
<ButtonDropdown class="cc-dropdown-on-hover mb-1" style="{(matchedJobs >= -1) ? '' : 'margin-right: 0.5rem;'}"> {#if showFilter}
<DropdownToggle outline caret color="success"> <ButtonDropdown class="cc-dropdown-on-hover mb-1" style="{(matchedJobs >= -1) ? '' : 'margin-right: 0.5rem;'}">
<Icon name="sliders" /> <DropdownToggle outline caret color="success">
Filters <Icon name="sliders" />
</DropdownToggle> Filters
<DropdownMenu> </DropdownToggle>
<DropdownItem header>Manage Filters</DropdownItem> <DropdownMenu>
{#if menuText} <DropdownItem header>Manage Filters</DropdownItem>
<DropdownItem disabled>{menuText}</DropdownItem> {#if menuText}
<DropdownItem divider /> <DropdownItem disabled>{menuText}</DropdownItem>
{/if} <DropdownItem divider />
<DropdownItem on:click={() => (isClusterOpen = true)}> {/if}
<Icon name="cpu" /> Cluster/Partition <DropdownItem on:click={() => (isClusterOpen = true)}>
</DropdownItem> <Icon name="cpu" /> Cluster/Partition
<DropdownItem on:click={() => (isJobStatesOpen = true)}> </DropdownItem>
<Icon name="gear-fill" /> Job States <DropdownItem on:click={() => (isJobStatesOpen = true)}>
</DropdownItem> <Icon name="gear-fill" /> Job States
<DropdownItem on:click={() => (isStartTimeOpen = true)}> </DropdownItem>
<Icon name="calendar-range" /> Start Time <DropdownItem on:click={() => (isStartTimeOpen = true)}>
</DropdownItem> <Icon name="calendar-range" /> Start Time
<DropdownItem on:click={() => (isDurationOpen = true)}> </DropdownItem>
<Icon name="stopwatch" /> Duration <DropdownItem on:click={() => (isDurationOpen = true)}>
</DropdownItem> <Icon name="stopwatch" /> Duration
<DropdownItem on:click={() => (isTagsOpen = true)}> </DropdownItem>
<Icon name="tags" /> Tags <DropdownItem on:click={() => (isTagsOpen = true)}>
</DropdownItem> <Icon name="tags" /> Tags
<DropdownItem on:click={() => (isResourcesOpen = true)}> </DropdownItem>
<Icon name="hdd-stack" /> Resources <DropdownItem on:click={() => (isResourcesOpen = true)}>
</DropdownItem> <Icon name="hdd-stack" /> Resources
<DropdownItem on:click={() => (isEnergyOpen = true)}> </DropdownItem>
<Icon name="lightning-charge-fill" /> Energy <DropdownItem on:click={() => (isEnergyOpen = true)}>
</DropdownItem> <Icon name="lightning-charge-fill" /> Energy
<DropdownItem on:click={() => (isStatsOpen = true)}> </DropdownItem>
<Icon name="bar-chart" on:click={() => (isStatsOpen = true)} /> Statistics <DropdownItem on:click={() => (isStatsOpen = true)}>
</DropdownItem> <Icon name="bar-chart" on:click={() => (isStatsOpen = true)} /> Statistics
{#if startTimeQuickSelect} </DropdownItem>
<DropdownItem divider /> {#if startTimeQuickSelect}
<DropdownItem disabled>Start Time Quick Selection</DropdownItem> <DropdownItem divider />
{#each startTimeSelectOptions.filter((stso) => stso.range !== "") as { rangeLabel, range }} <DropdownItem disabled>Start Time Quick Selection</DropdownItem>
<DropdownItem {#each startTimeSelectOptions.filter((stso) => stso.range !== "") as { rangeLabel, range }}
on:click={() => { <DropdownItem
filters.startTime.from = null on:click={() => {
filters.startTime.to = null filters.startTime.from = null
filters.startTime.range = range; filters.startTime.to = null
updateFilters(); filters.startTime.range = range;
}} updateFilters();
> }}
<Icon name="calendar-range" /> >
{rangeLabel} <Icon name="calendar-range" />
</DropdownItem> {rangeLabel}
{/each} </DropdownItem>
{/if} {/each}
</DropdownMenu> {/if}
</ButtonDropdown> </DropdownMenu>
</ButtonDropdown>
{/if}
{#if matchedJobs >= -1} {#if matchedJobs >= -1}
<Button class="mb-1" style="margin-right: 0.5rem;" disabled outline> <Button class="mb-1" style="margin-right: 0.5rem;" disabled outline>
{matchedJobs == -1 ? 'Loading ...' : `${matchedJobs} jobs`} {matchedJobs == -1 ? 'Loading ...' : `${matchedJobs} jobs`}
@ -314,109 +318,111 @@
{/if} {/if}
</ButtonGroup> </ButtonGroup>
<!-- SELECTED FILTER PILLS --> {#if showFilter}
{#if filters.cluster} <!-- SELECTED FILTER PILLS -->
<Info icon="cpu" on:click={() => (isClusterOpen = true)}> {#if filters.cluster}
{filters.cluster} <Info icon="cpu" on:click={() => (isClusterOpen = true)}>
{#if filters.partition} {filters.cluster}
({filters.partition}) {#if filters.partition}
{/if} ({filters.partition})
</Info> {/if}
{/if} </Info>
{/if}
{#if filters.states.length != allJobStates.length} {#if filters.states.length != allJobStates.length}
<Info icon="gear-fill" on:click={() => (isJobStatesOpen = true)}> <Info icon="gear-fill" on:click={() => (isJobStatesOpen = true)}>
{filters.states.join(", ")} {filters.states.join(", ")}
</Info> </Info>
{/if} {/if}
{#if filters.startTime.from || filters.startTime.to} {#if filters.startTime.from || filters.startTime.to}
<Info icon="calendar-range" on:click={() => (isStartTimeOpen = true)}> <Info icon="calendar-range" on:click={() => (isStartTimeOpen = true)}>
{new Date(filters.startTime.from).toLocaleString()} - {new Date( {new Date(filters.startTime.from).toLocaleString()} - {new Date(
filters.startTime.to, filters.startTime.to,
).toLocaleString()} ).toLocaleString()}
</Info> </Info>
{/if} {/if}
{#if filters.startTime.range} {#if filters.startTime.range}
<Info icon="calendar-range" on:click={() => (isStartTimeOpen = true)}> <Info icon="calendar-range" on:click={() => (isStartTimeOpen = true)}>
{startTimeSelectOptions.find((stso) => stso.range === filters.startTime.range).rangeLabel } {startTimeSelectOptions.find((stso) => stso.range === filters.startTime.range).rangeLabel }
</Info> </Info>
{/if} {/if}
{#if filters.duration.from || filters.duration.to} {#if filters.duration.from || filters.duration.to}
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}> <Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
{Math.floor(filters.duration.from / 3600)}h:{Math.floor( {Math.floor(filters.duration.from / 3600)}h:{Math.floor(
(filters.duration.from % 3600) / 60, (filters.duration.from % 3600) / 60,
)}m - )}m -
{Math.floor(filters.duration.to / 3600)}h:{Math.floor( {Math.floor(filters.duration.to / 3600)}h:{Math.floor(
(filters.duration.to % 3600) / 60, (filters.duration.to % 3600) / 60,
)}m )}m
</Info> </Info>
{/if} {/if}
{#if filters.duration.lessThan} {#if filters.duration.lessThan}
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}> <Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
Duration less than {Math.floor( Duration less than {Math.floor(
filters.duration.lessThan / 3600, filters.duration.lessThan / 3600,
)}h:{Math.floor((filters.duration.lessThan % 3600) / 60)}m )}h:{Math.floor((filters.duration.lessThan % 3600) / 60)}m
</Info> </Info>
{/if} {/if}
{#if filters.duration.moreThan} {#if filters.duration.moreThan}
<Info icon="stopwatch" on:click={() => (isDurationOpen = true)}> <Info icon="stopwatch" on:click={() => (isDurationOpen = true)}>
Duration more than {Math.floor( Duration more than {Math.floor(
filters.duration.moreThan / 3600, filters.duration.moreThan / 3600,
)}h:{Math.floor((filters.duration.moreThan % 3600) / 60)}m )}h:{Math.floor((filters.duration.moreThan % 3600) / 60)}m
</Info> </Info>
{/if} {/if}
{#if filters.tags.length != 0} {#if filters.tags.length != 0}
<Info icon="tags" on:click={() => (isTagsOpen = true)}> <Info icon="tags" on:click={() => (isTagsOpen = true)}>
{#each filters.tags as tagId} {#each filters.tags as tagId}
{#key tagId} {#key tagId}
<Tag id={tagId} clickable={false} /> <Tag id={tagId} clickable={false} />
{/key} {/key}
{/each} {/each}
</Info> </Info>
{/if} {/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} {#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)}> <Info icon="hdd-stack" on:click={() => (isResourcesOpen = true)}>
{#if isNodesModified} {#if isNodesModified}
Nodes: {filters.numNodes.from} - {filters.numNodes.to} Nodes: {filters.numNodes.from} - {filters.numNodes.to}
{/if} {/if}
{#if isNodesModified && isHwthreadsModified}, {#if isNodesModified && isHwthreadsModified},
{/if} {/if}
{#if isHwthreadsModified} {#if isHwthreadsModified}
HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to} HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to}
{/if} {/if}
{#if (isNodesModified || isHwthreadsModified) && isAccsModified}, {#if (isNodesModified || isHwthreadsModified) && isAccsModified},
{/if} {/if}
{#if isAccsModified} {#if isAccsModified}
Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to} Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to}
{/if} {/if}
</Info> </Info>
{/if} {/if}
{#if filters.node != null} {#if filters.node != null}
<Info icon="hdd-stack" on:click={() => (isResourcesOpen = true)}> <Info icon="hdd-stack" on:click={() => (isResourcesOpen = true)}>
Node{nodeMatchLabels[filters.nodeMatch]}: {filters.node} Node{nodeMatchLabels[filters.nodeMatch]}: {filters.node}
</Info> </Info>
{/if} {/if}
{#if filters.energy.from || filters.energy.to} {#if filters.energy.from || filters.energy.to}
<Info icon="lightning-charge-fill" on:click={() => (isEnergyOpen = true)}> <Info icon="lightning-charge-fill" on:click={() => (isEnergyOpen = true)}>
Total Energy: {filters.energy.from} - {filters.energy.to} Total Energy: {filters.energy.from} - {filters.energy.to}
</Info> </Info>
{/if} {/if}
{#if filters.stats.length > 0} {#if filters.stats.length > 0}
<Info icon="bar-chart" on:click={() => (isStatsOpen = true)}> <Info icon="bar-chart" on:click={() => (isStatsOpen = true)}>
{filters.stats {filters.stats
.map((stat) => `${stat.field}: ${stat.from} - ${stat.to}`) .map((stat) => `${stat.field}: ${stat.from} - ${stat.to}`)
.join(", ")} .join(", ")}
</Info> </Info>
{/if}
{/if} {/if}
<Cluster <Cluster