mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-26 08:02:31 +00:00
RunsPage redesign v0
This commit is contained in:
@@ -260,6 +260,6 @@
|
||||
} as any)
|
||||
</script>
|
||||
|
||||
<div class="relative max-h-40">
|
||||
<div class="relative h-44">
|
||||
<Line {data} {options} />
|
||||
</div>
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<script lang="ts">
|
||||
import DropdownV2 from '$lib/components/DropdownV2.svelte'
|
||||
import { ChevronDown } from 'lucide-svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { Item } from '$lib/utils'
|
||||
|
||||
interface Props {
|
||||
items?: Item[]
|
||||
extraLabel?: import('svelte').Snippet
|
||||
selected: string
|
||||
selectedDisplayName?: string
|
||||
btnClasses?: string
|
||||
}
|
||||
|
||||
let { items = [], extraLabel, selected, selectedDisplayName, btnClasses }: Props = $props()
|
||||
|
||||
const filteredItems = $derived(items.filter((item) => item.id !== selected))
|
||||
</script>
|
||||
|
||||
<DropdownV2 items={filteredItems}>
|
||||
{#snippet buttonReplacement()}
|
||||
<div
|
||||
class={twMerge(
|
||||
'p-2 h-8 flex flex-row items-center gap-2 border hover:bg-surface-hover cursor-pointer rounded-md',
|
||||
btnClasses
|
||||
)}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-1 pr-2 justify-between w-full">
|
||||
<span class="text-xs whitespace-nowrap">
|
||||
{selectedDisplayName ?? items.find((item) => item.id === selected)?.displayName ?? ''}
|
||||
</span>
|
||||
|
||||
{@render extraLabel?.()}
|
||||
</div>
|
||||
<ChevronDown size={12} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</DropdownV2>
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import 'chartjs-adapter-date-fns'
|
||||
import zoomPlugin from 'chartjs-plugin-zoom'
|
||||
import Tooltip2 from '$lib/components/Tooltip.svelte'
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
Title,
|
||||
@@ -17,7 +16,6 @@
|
||||
} from 'chart.js'
|
||||
import type { CompletedJob } from '$lib/gen'
|
||||
import { getDbClockNow } from '$lib/forLater'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { Scatter } from '$lib/components/chartjs-wrappers/chartJs'
|
||||
import DarkModeObserver from './DarkModeObserver.svelte'
|
||||
|
||||
@@ -28,10 +26,7 @@
|
||||
maxTimeSet?: string | null
|
||||
selectedIds?: string[]
|
||||
canSelect?: boolean
|
||||
lastFetchWentToEnd?: boolean
|
||||
totalRowsFetched: number
|
||||
onPointClicked: (ids: string[]) => void
|
||||
onLoadExtra: () => void
|
||||
onZoom: (zoom: { min: Date; max: Date }) => void
|
||||
}
|
||||
|
||||
@@ -42,10 +37,7 @@
|
||||
maxTimeSet = null,
|
||||
selectedIds = $bindable([]),
|
||||
canSelect = true,
|
||||
lastFetchWentToEnd = false,
|
||||
totalRowsFetched,
|
||||
onPointClicked,
|
||||
onLoadExtra,
|
||||
onZoom
|
||||
}: Props = $props()
|
||||
|
||||
@@ -299,23 +291,6 @@
|
||||
|
||||
<DarkModeObserver bind:darkMode />
|
||||
|
||||
<!-- {JSON.stringify(minTime)}
|
||||
{JSON.stringify(maxTime)}
|
||||
|
||||
{JSON.stringify(jobs?.map((x) => x.started_at))} -->
|
||||
<!-- {minTime}
|
||||
{maxTime} -->
|
||||
<!-- {JSON.stringify(jobs?.map((x) => x.started_at))} -->
|
||||
<div class="relative max-h-40">
|
||||
{#if !lastFetchWentToEnd}
|
||||
<div class="absolute top-[-28px] left-[220px]">
|
||||
<Button size="xs" color="transparent" variant="contained" on:click={() => onLoadExtra()}>
|
||||
Load more
|
||||
<Tooltip2>
|
||||
There are more jobs to load but only the first {totalRowsFetched} were fetched
|
||||
</Tooltip2>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="relative h-44">
|
||||
<Scatter {data} options={scatterOptions} />
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { userStore, workspaceStore, userWorkspaces } from '$lib/stores'
|
||||
import { Button, Drawer, DrawerContent, Skeleton } from '$lib/components/common'
|
||||
import { Button, Drawer, DrawerContent, Skeleton, Tab, Tabs } from '$lib/components/common'
|
||||
import RunChart from '$lib/components/RunChart.svelte'
|
||||
|
||||
import JobRunsPreview from '$lib/components/runs/JobRunsPreview.svelte'
|
||||
@@ -27,25 +27,20 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ManuelDatePicker from '$lib/components/runs/ManuelDatePicker.svelte'
|
||||
import { computeJobKinds, useJobsLoader } from '$lib/components/runs/useJobsLoader.svelte'
|
||||
import { Calendar, Clock, TriangleAlert } from 'lucide-svelte'
|
||||
import ConcurrentJobsChart from '$lib/components/ConcurrentJobsChart.svelte'
|
||||
import { isJobSelectable, type RunsSelectionMode } from '$lib/utils'
|
||||
import { isJobSelectable, pluralize, type RunsSelectionMode } from '$lib/utils'
|
||||
import BatchReRunOptionsPane, {
|
||||
type BatchReRunOptions
|
||||
} from '$lib/components/runs/BatchReRunOptionsPane.svelte'
|
||||
import { untrack } from 'svelte'
|
||||
import { page } from '$app/state'
|
||||
import RunOption from '$lib/components/runs/RunOption.svelte'
|
||||
import TooltipV2 from '$lib/components/meltComponents/Tooltip.svelte'
|
||||
import DropdownSelect from '$lib/components/DropdownSelect.svelte'
|
||||
import RunsBatchActionsDropdown from '$lib/components/runs/RunsBatchActionsDropdown.svelte'
|
||||
import { createBubbler } from 'svelte/legacy'
|
||||
import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte'
|
||||
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
|
||||
import Select from '$lib/components/select/Select.svelte'
|
||||
import AnimatedPane from '$lib/components/splitPanes/AnimatedPane.svelte'
|
||||
import { useSearchParams } from '$lib/svelte5UtilsKit.svelte'
|
||||
import { StaleWhileLoading } from '$lib/svelte5Utils.svelte'
|
||||
import { TriangleAlertIcon } from 'lucide-svelte'
|
||||
|
||||
interface Props {
|
||||
/** Initial path from route params (e.g., /runs/u/user/script) */
|
||||
@@ -130,7 +125,6 @@
|
||||
let graph: 'RunChart' | 'ConcurrencyChart' = $state(
|
||||
typeOfChart(page.url.searchParams.get('graph'))
|
||||
)
|
||||
let graphIsRunsChart: boolean = $state(untrack(() => graph) === 'RunChart')
|
||||
let innerWidth = $state(window.innerWidth)
|
||||
let jobsLoader = useJobsLoader(() => ({
|
||||
filters,
|
||||
@@ -139,7 +133,7 @@
|
||||
autoRefresh,
|
||||
argError,
|
||||
resultError,
|
||||
lookback: graphIsRunsChart ? 0 : lookback,
|
||||
lookback: graph === 'RunChart' ? 0 : lookback,
|
||||
onSetPerPage: (p) => (filters.per_page = p),
|
||||
onSetMinMaxTs: (minTs, maxTs) => ((filters.min_ts = minTs), (filters.max_ts = maxTs)),
|
||||
currentWorkspace: $workspaceStore ?? ''
|
||||
@@ -456,10 +450,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function setLookback(lookbackInDays: number) {
|
||||
lookback = lookbackInDays
|
||||
}
|
||||
|
||||
async function loadExtra() {
|
||||
await jobsLoader?.loadExtraJobs()
|
||||
}
|
||||
@@ -524,8 +514,6 @@
|
||||
return jobs?.filter(isJobSelectable(selectionMode)).length ?? 0
|
||||
})
|
||||
|
||||
let tableTopBarWidth = $state(0)
|
||||
|
||||
const smallScreenWidth = 1920
|
||||
const verySmallScreenWidth = 1300
|
||||
|
||||
@@ -603,7 +591,7 @@
|
||||
{:else}
|
||||
<div class="w-full h-screen flex flex-col" bind:clientWidth={innerWidth}>
|
||||
<!-- Header and filters -->
|
||||
<div class="flex flex-row items-start w-full border-b px-4 gap-8">
|
||||
<div class="flex flex-row items-start w-full px-4 gap-8">
|
||||
<div class="flex flex-row items-center h-full gap-6">
|
||||
<div class="flex flex-row items-center gap-1">
|
||||
<h1
|
||||
@@ -645,7 +633,7 @@
|
||||
{#if filters.min_ts || filters.max_ts}
|
||||
<input
|
||||
type="text"
|
||||
class="!text-sm text-primary !bg-surface-secondary h-9 !border-none"
|
||||
class="!text-sm text-primary !bg-surface-sunken h-9 !border-none"
|
||||
value={filters.min_ts
|
||||
? new Date(filters.min_ts).toLocaleString()
|
||||
: 'zoom x axis to set min'}
|
||||
@@ -733,78 +721,41 @@
|
||||
</div>
|
||||
|
||||
<!-- Graph -->
|
||||
<div class="p-2 px-4 pt-8 w-full border-b">
|
||||
<div class="relative z-10">
|
||||
<div class="absolute left-0 -top-7 flex flex-row gap-2 items-center min-w-24">
|
||||
<ToggleButtonGroup
|
||||
selected={graph}
|
||||
on:selected={({ detail }) => {
|
||||
graph = detail
|
||||
graphIsRunsChart = graph === 'RunChart'
|
||||
}}
|
||||
>
|
||||
{#snippet children({ item })}
|
||||
<ToggleButton value="RunChart" label="Duration" {item} />
|
||||
<ToggleButton
|
||||
{item}
|
||||
value="ConcurrencyChart"
|
||||
label="Concurrency"
|
||||
icon={warnJobLimit ? TriangleAlert : undefined}
|
||||
tooltip={warnJobLimit ? warnJobLimitMsg : undefined}
|
||||
/>
|
||||
<div class="p-2 px-4 bg-surface-tertiary mx-4 mt-2 drop-shadow-base rounded-md">
|
||||
<div class="relative z-10 mb-2 flex gap-2">
|
||||
<Tabs bind:selected={graph}>
|
||||
<Tab value="RunChart" label="Duration" />
|
||||
<Tab value="ConcurrencyChart" label="Concurrency">
|
||||
{#snippet extra()}
|
||||
{#if warnJobLimit}
|
||||
<Tooltip Icon={TriangleAlertIcon}>{warnJobLimitMsg}</Tooltip>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</ToggleButtonGroup>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
{#if !graphIsRunsChart}
|
||||
<DropdownSelect
|
||||
items={[
|
||||
{
|
||||
displayName: 'None',
|
||||
action: () => setLookback(0),
|
||||
id: '0'
|
||||
},
|
||||
{
|
||||
displayName: '1 day',
|
||||
action: () => setLookback(1),
|
||||
id: '1'
|
||||
},
|
||||
{
|
||||
displayName: '3 days',
|
||||
action: () => setLookback(3),
|
||||
id: '3'
|
||||
},
|
||||
{
|
||||
displayName: '7 days',
|
||||
action: () => setLookback(7),
|
||||
id: '7'
|
||||
}
|
||||
]}
|
||||
selected={lookback.toString()}
|
||||
selectedDisplayName={`${lookback} days lookback`}
|
||||
>
|
||||
{#snippet extraLabel()}
|
||||
<TooltipV2>
|
||||
{#snippet text()}
|
||||
How far behind the min datetime to start considering jobs for the concurrency
|
||||
graph. Change this value to include jobs started before the set time window for
|
||||
the computation of the graph
|
||||
{/snippet}
|
||||
</TooltipV2>
|
||||
{/snippet}
|
||||
</DropdownSelect>
|
||||
{/if}
|
||||
</div>
|
||||
{#if graph !== 'RunChart'}
|
||||
<Select
|
||||
class="ml-auto"
|
||||
bind:value={lookback}
|
||||
items={[
|
||||
{ label: 'None', value: 0 },
|
||||
{ label: '1 day', value: 1 },
|
||||
{ label: '3 days', value: 3 },
|
||||
{ label: '7 days', value: 7 }
|
||||
]}
|
||||
transformInputSelectedText={(_, v) => `${pluralize(v, 'day')} lookback`}
|
||||
tooltip={'How far behind the min datetime to start considering jobs for the concurrency graph. Change this value to include jobs started before the set time window for the computation of the graph'}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if graph === 'RunChart'}
|
||||
<RunChart
|
||||
{lastFetchWentToEnd}
|
||||
bind:selectedIds
|
||||
canSelect={!selectionMode}
|
||||
minTimeSet={filters.min_ts}
|
||||
maxTimeSet={filters.max_ts}
|
||||
totalRowsFetched={jobs?.length ?? 0}
|
||||
maxIsNow={filters.max_ts == undefined}
|
||||
onLoadExtra={loadExtra}
|
||||
jobs={completedJobs}
|
||||
onZoom={async (zoom) => {
|
||||
filters.min_ts = zoom.min.toISOString()
|
||||
@@ -831,106 +782,10 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="grow min-h-0">
|
||||
<div class="grow min-h-0 mt-4">
|
||||
<Splitpanes>
|
||||
<Pane minSize={40}>
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Runs table top bar -->
|
||||
<div
|
||||
class="flex flex-row gap-4 items-center px-2 py-1 grow-0 justify-between"
|
||||
bind:clientWidth={tableTopBarWidth}
|
||||
>
|
||||
<div class="flex flex-row gap-4 items-center">
|
||||
{#if selectionMode && selectableJobCount}
|
||||
<div class="flex flex-row items-center font-semibold text-sm">
|
||||
<div class="px-2">
|
||||
<input
|
||||
onfocus={bubble('focus')}
|
||||
type="checkbox"
|
||||
checked={allSelected}
|
||||
id="select-all"
|
||||
class={twMerge(
|
||||
'cursor-pointer',
|
||||
allSelected ? 'bg-blue-50 dark:bg-blue-900/50' : '',
|
||||
'flex flex-row items-center p-2 pr-4 top-0 font-semibold text-sm'
|
||||
)}
|
||||
onclick={selectAll}
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
class="cursor-pointer whitespace-nowrap text-xs text-emphasis font-semibold"
|
||||
for="select-all">Select all</label
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<RunsBatchActionsDropdown
|
||||
isLoading={loadingSelectedIds}
|
||||
{selectionMode}
|
||||
selectionCount={selectedIds.length}
|
||||
{onSetSelectionMode}
|
||||
{onCancelFilteredJobs}
|
||||
{onCancelSelectedJobs}
|
||||
{onReRunFilteredJobs}
|
||||
{onReRunSelectedJobs}
|
||||
small={tableTopBarWidth < 800}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-4 items-center">
|
||||
{#if !filters.job_trigger_kind}
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
<Toggle
|
||||
id="cron-schedules"
|
||||
bind:checked={filters.show_schedules}
|
||||
options={tableTopBarWidth < 800 || selectionMode
|
||||
? {}
|
||||
: { right: 'Schedules' }}
|
||||
/>
|
||||
<span title="Schedules">
|
||||
<Calendar size="14" />
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
<Toggle
|
||||
size="sm"
|
||||
bind:checked={filters.show_future_jobs}
|
||||
id="planned-later"
|
||||
options={tableTopBarWidth < 800 || selectionMode
|
||||
? {}
|
||||
: { right: 'Planned later' }}
|
||||
/>
|
||||
<span title="Planned later">
|
||||
<Clock size={14} />
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<ManuelDatePicker
|
||||
on:loadJobs={() => {
|
||||
jobsLoader?.loadJobs(true)
|
||||
}}
|
||||
bind:minTs={filters.min_ts}
|
||||
bind:maxTs={filters.max_ts}
|
||||
bind:selectedManualDate
|
||||
{loading}
|
||||
bind:this={manualDatePicker}
|
||||
numberOfLastJobsToFetch={filters.per_page}
|
||||
/>
|
||||
<Toggle
|
||||
size="sm"
|
||||
bind:checked={autoRefresh}
|
||||
on:change={() => {
|
||||
localStorage.setItem('auto_refresh_in_runs', autoRefresh ? 'true' : 'false')
|
||||
}}
|
||||
options={{ right: 'Auto-refresh' }}
|
||||
textClass="whitespace-nowrap"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Runs table. Add overflow-hidden because scroll is handled inside the runs table based on this wrapper height -->
|
||||
<div class="grow min-h-0 overflow-y-hidden overflow-x-auto">
|
||||
{#if jobs}
|
||||
@@ -938,7 +793,7 @@
|
||||
{jobs}
|
||||
externalJobs={externalJobs ?? []}
|
||||
omittedObscuredJobs={extendedJobs?.omitted_obscured_jobs ?? false}
|
||||
showExternalJobs={!graphIsRunsChart}
|
||||
showExternalJobs={graph !== 'RunChart'}
|
||||
activeLabel={filters.label}
|
||||
{selectionMode}
|
||||
{lastFetchWentToEnd}
|
||||
@@ -964,12 +819,30 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div
|
||||
class="bg-surface-secondary border-t flex text-xs px-2 py-1 items-center justify-end gap-2"
|
||||
>
|
||||
Per page:
|
||||
<div class="bg-surface border-t flex text-xs px-2 py-1 items-center gap-4">
|
||||
<ManuelDatePicker
|
||||
on:loadJobs={() => {
|
||||
jobsLoader?.loadJobs(true)
|
||||
}}
|
||||
bind:minTs={filters.min_ts}
|
||||
bind:maxTs={filters.max_ts}
|
||||
bind:selectedManualDate
|
||||
{loading}
|
||||
bind:this={manualDatePicker}
|
||||
numberOfLastJobsToFetch={filters.per_page}
|
||||
/>
|
||||
<Toggle
|
||||
size="xs"
|
||||
bind:checked={autoRefresh}
|
||||
on:change={() => {
|
||||
localStorage.setItem('auto_refresh_in_runs', autoRefresh ? 'true' : 'false')
|
||||
}}
|
||||
options={{ right: 'Auto-refresh' }}
|
||||
textClass="whitespace-nowrap"
|
||||
/>
|
||||
<div class="flex-1"></div>
|
||||
<Select
|
||||
class="w-20"
|
||||
class="w-24"
|
||||
bind:value={
|
||||
() => filters.per_page,
|
||||
(newPerPage) => {
|
||||
@@ -984,6 +857,7 @@
|
||||
{ value: 1000, label: '1000' },
|
||||
{ value: 10000, label: '10000' }
|
||||
]}
|
||||
transformInputSelectedText={(_, v) => `${v} / page`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
markdownTooltip?: string | undefined
|
||||
customSize?: string
|
||||
class?: string
|
||||
Icon?: typeof InfoIcon
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
@@ -31,6 +32,7 @@
|
||||
markdownTooltip = undefined,
|
||||
customSize = '100%',
|
||||
class: classNames = '',
|
||||
Icon = InfoIcon,
|
||||
children
|
||||
}: Props = $props()
|
||||
const plugins = [gfmPlugin()]
|
||||
@@ -53,7 +55,7 @@
|
||||
? 'text-primary-inverse'
|
||||
: 'text-primary'} {classNames} relative"
|
||||
>
|
||||
<InfoIcon class="{small ? 'bottom-0' : '-bottom-0.5'} absolute" size={small ? 12 : 14} />
|
||||
<Icon class="{small ? 'bottom-0' : '-bottom-0.5'} absolute" size={small ? 12 : 14} />
|
||||
</div>
|
||||
{#snippet text()}
|
||||
{#if markdownTooltip}
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
import Select from '../select/Select.svelte'
|
||||
import { safeSelectItems } from '../select/utils.svelte'
|
||||
import RunOption from './RunOption.svelte'
|
||||
import DropdownSelect from '../DropdownSelect.svelte'
|
||||
import TooltipV2 from '$lib/components/meltComponents/Tooltip.svelte'
|
||||
import TextInput from '../text_input/TextInput.svelte'
|
||||
import { jobTriggerKinds, triggerDisplayNamesMap } from '../triggers/utils'
|
||||
@@ -528,50 +527,15 @@
|
||||
<!-- Kind -->
|
||||
<RunOption label="Kind" for="kind">
|
||||
{#if small && !calendarSmall}
|
||||
<DropdownSelect
|
||||
btnClasses="min-w-24 h-9 bg-surface-secondary font-normal"
|
||||
<Select
|
||||
items={[
|
||||
{
|
||||
displayName: 'All',
|
||||
action: () => {
|
||||
jobKindsCat = 'all'
|
||||
},
|
||||
id: 'all'
|
||||
},
|
||||
{
|
||||
displayName: 'Runs',
|
||||
action: () => {
|
||||
jobKindsCat = 'runs'
|
||||
},
|
||||
id: 'runs',
|
||||
extra: runsTooltip
|
||||
},
|
||||
{
|
||||
displayName: 'Previews',
|
||||
action: () => {
|
||||
jobKindsCat = 'previews'
|
||||
},
|
||||
id: 'previews',
|
||||
extra: previewsTooltip
|
||||
},
|
||||
{
|
||||
displayName: 'Deps',
|
||||
action: () => {
|
||||
jobKindsCat = 'dependencies'
|
||||
},
|
||||
id: 'dependencies',
|
||||
extra: dependenciesTooltip
|
||||
},
|
||||
{
|
||||
displayName: 'Sync',
|
||||
action: () => {
|
||||
jobKindsCat = 'deploymentcallbacks'
|
||||
},
|
||||
id: 'deploymentcallbacks',
|
||||
extra: syncTooltip
|
||||
}
|
||||
{ label: 'All', value: 'all' },
|
||||
{ label: 'Runs', value: 'runs', extra: runsTooltip }, // TODO fix tooltip
|
||||
{ label: 'Previews', value: 'previews', extra: previewsTooltip }, // TODO fix tooltip
|
||||
{ label: 'Deps', value: 'dependencies', extra: dependenciesTooltip }, // TODO fix tooltip
|
||||
{ label: 'Sync', value: 'deploymentcallbacks', extra: syncTooltip } // TODO fix tooltip
|
||||
]}
|
||||
selected={jobKindsCat}
|
||||
bind:value={jobKindsCat}
|
||||
/>
|
||||
{:else}
|
||||
<ToggleButtonGroup bind:selected={jobKindsCat}>
|
||||
|
||||
@@ -199,13 +199,13 @@
|
||||
<svelte:window onresize={() => computeHeight()} />
|
||||
|
||||
<div
|
||||
class="divide-y h-full border min-w-[650px]"
|
||||
class="divide-y h-full min-w-[650px]"
|
||||
id="runs-table-wrapper"
|
||||
bind:clientWidth={containerWidth}
|
||||
>
|
||||
<div bind:clientHeight={headerHeight}>
|
||||
<div
|
||||
class="grid bg-surface-secondary sticky top-0 w-full py-2 pr-4"
|
||||
class="grid sticky top-0 w-full min-h-6 mb-2 pr-4 items-end"
|
||||
class:grid-runs-table={!containsLabel && !selectionMode && showTag}
|
||||
class:grid-runs-table-with-labels={containsLabel && !selectionMode && showTag}
|
||||
class:grid-runs-table-selection={!containsLabel && selectionMode && showTag}
|
||||
@@ -220,7 +220,7 @@
|
||||
{#if selectionMode}
|
||||
<div class="text-xs font-semibold pl-4"></div>
|
||||
{/if}
|
||||
<div class="text-2xs px-2 flex flex-row items-center gap-2">
|
||||
<div class="text-2xs px-2 flex flex-row items-center gap-2 leading-3">
|
||||
{#if showExternalJobs && externalJobs.length > 0}
|
||||
<div class="flex flex-row">
|
||||
{jobs
|
||||
@@ -242,15 +242,15 @@
|
||||
{jobs ? jobCountString(jobs.length, lastFetchWentToEnd) : ''}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="text-xs font-semibold">Started</div>
|
||||
<div class="text-xs font-semibold">Duration</div>
|
||||
<div class="text-xs font-semibold">Path</div>
|
||||
<div class="text-xs font-semibold leading-3">Started</div>
|
||||
<div class="text-xs font-semibold leading-3">Duration</div>
|
||||
<div class="text-xs font-semibold leading-3">Path</div>
|
||||
{#if containsLabel}
|
||||
<div class="text-xs font-semibold">Label</div>
|
||||
<div class="text-xs font-semibold leading-3">Label</div>
|
||||
{/if}
|
||||
<div class="text-xs font-semibold">Triggered by</div>
|
||||
<div class="text-xs font-semibold leading-3">Triggered by</div>
|
||||
{#if showTag}
|
||||
<div class="text-xs font-semibold">Tag</div>
|
||||
<div class="text-xs font-semibold leading-3">Tag</div>
|
||||
{/if}
|
||||
<div class=""></div>
|
||||
</div>
|
||||
|
||||
@@ -532,6 +532,8 @@ export function useJobsLoader(args: () => UseJobLoaderArgs) {
|
||||
})
|
||||
$effect(() => {
|
||||
Object.keys(filters ?? {}).map((k) => filters?.[k as keyof RunsFilters])
|
||||
currentWorkspace
|
||||
lookback
|
||||
let p = untrack(() => onParamChanges())
|
||||
return () => p.cancel()
|
||||
})
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
inputSizeClasses
|
||||
} from '../text_input/TextInput.svelte'
|
||||
import { ButtonType } from '../common/button/model'
|
||||
import Tooltip from '../Tooltip.svelte'
|
||||
|
||||
type Value = Item['value']
|
||||
|
||||
@@ -37,6 +38,7 @@
|
||||
RightIcon,
|
||||
createText,
|
||||
noItemsMsg,
|
||||
tooltip,
|
||||
open = $bindable(false),
|
||||
id,
|
||||
itemLabelWrapperClasses,
|
||||
@@ -72,12 +74,13 @@
|
||||
createText?: string
|
||||
noItemsMsg?: string
|
||||
open?: boolean
|
||||
tooltip?: string
|
||||
id?: string
|
||||
itemLabelWrapperClasses?: string
|
||||
itemButtonWrapperClasses?: string
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
showPlaceholderOnOpen?: boolean
|
||||
transformInputSelectedText?: (text: string) => string
|
||||
transformInputSelectedText?: (text: string, value: Value) => string
|
||||
groupBy?: (item: Item) => string
|
||||
sortBy?: (a: Item, b: Item) => number
|
||||
onFocus?: () => void
|
||||
@@ -106,7 +109,9 @@
|
||||
if (!open) filterText = ''
|
||||
})
|
||||
|
||||
let valueEntry = $derived(value && processedItems?.find((item) => deepEqual(item.value, value)))
|
||||
let valueEntry = $derived(
|
||||
value != null ? processedItems?.find((item) => deepEqual(item.value, value)) : undefined
|
||||
)
|
||||
|
||||
function setValue(item: ProcessedItem<Value>) {
|
||||
if (item.__is_create && onCreateItem) {
|
||||
@@ -126,12 +131,12 @@
|
||||
|
||||
let inputText = $derived.by(() => {
|
||||
let text = valueEntry?.label ?? getLabel({ value }) ?? ''
|
||||
return transformInputSelectedText?.(text) ?? text
|
||||
return transformInputSelectedText?.(text, value) ?? text
|
||||
})
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={`relative ${className}`}
|
||||
class={`relative h-fit ${className}`}
|
||||
use:clickOutside={{ onClickOutside: () => (open = false) }}
|
||||
onpointerdown={() => onFocus?.()}
|
||||
onfocus={() => onFocus?.()}
|
||||
@@ -155,6 +160,13 @@
|
||||
<RightIcon size={iconSize} class="text-secondary" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if tooltip}
|
||||
<div class="absolute z-10 right-2 h-full flex items-center">
|
||||
<Tooltip>{tooltip}</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- svelte-ignore a11y_autofocus -->
|
||||
<input
|
||||
{autofocus}
|
||||
|
||||
Reference in New Issue
Block a user