Files
windmill/frontend/src/lib/components/runs/RunLabels.svelte
T
Guilhem 768c600494 fix(frontend): Improve runs page ux (#6485)
* improve arg layout

* improve runs row (wip)

* Add job badges

* group filters in dropdown

* improve runs row layout

* Improve filter layout

* use select for graph display

* handle width modification

* Remove useless headers

* fix bad display when result is null

* Display all jobs tags

* Improve display for 'step of flow' jobs

* Add empty message for JobAssetsViewer

* Move job preview assets tab to flow result for flows

* Only show tag in the tag column

* Add job kind to rows

* Add padding to the run preview

* nit

* move refresh on top of table

* Move filters into header bar

* move runs table topbar outside table

* Simplify layout

* Use toggle for kind for large screen

* move sync job and add batch actions breakpoint

* revert dropdown to toggle for conurrency/duration

* handle run labels overflow

* improve time display

* fix flow preview with no path display

* Add titles

* Prevent tab shift for script and flow result

* nit

* Allow job deselect

* Make job link more visible

* Fix filtering for queued job

* Fix filter not reseting after select from toggleMore

* Allways show assets for flow status viewer

* Update run chart to svelte 5 and fix reactivity issue

* migrate concurrency chart to svelte 5

* Improve admmin workspace display and fix missing in add filter popover

* nit

* fix run table resize

* Add breakpoint to hide tag in small screens

* use a css file for gathering RunRow and RunTable classes

* nit

* nit

* remove debug log

* nit

* fix typo

* Have too icons for queued workers and suspended

* add gap before auto-refresh

* Replace min max to from to calendar picker

* Add loading state for job preview

* Move duration

* Display kind full width when calendar not set

* Only show 2 digits for jobs duration

* Replace Scheduled for by a clock un the run row

* Fix typpo in dropown select to dropdown select

* Hide sync and previews in toggle more

* Fix runs row padding

* Change notification colors for queued jobs

* use utils debounce function

* fix typo

* nit

* use class instead of classNames

* clean select filter side effects
2025-09-01 09:49:15 +00:00

113 lines
3.2 KiB
Svelte

<script lang="ts">
import { twMerge } from 'tailwind-merge'
import { ListFilterPlus } from 'lucide-svelte'
import Tooltip from '$lib/components/meltComponents/Tooltip.svelte'
import DropdownV2 from '$lib/components/DropdownV2.svelte'
import type { Job } from '$lib/gen'
import type { Item } from '$lib/utils'
interface Props {
job: Job
activeLabel: string | null
onFilterByLabel: (label: string) => void
labelWidth: number
}
let { job, activeLabel, onFilterByLabel, labelWidth }: Props = $props()
const GAP = 4
const LABEL_MAX_WIDTH = 84
const MORE_LABEL_WIDTH = 30
// Min width for labels columns is 120px
const labels = $derived(job && Array.isArray(job?.['labels']) ? (job['labels'] as string[]) : [])
const labelSplit = $derived.by(() => {
if (!labels || labels.length === 0 || labelWidth <= 0) {
return { visibleLabels: [], hiddenLabels: [] }
}
if (labels.length === 1) {
return { visibleLabels: labels, hiddenLabels: [] }
}
let currentWidth = 0
const visible: string[] = []
const hidden: string[] = []
const margin = 20
for (let i = 0; i < labels.length; i++) {
const label = labels[i]
// Check if we need to reserve space for overflow badge
const needsOverflowBadge = i < labels.length - 1
const remainingWidth = labelWidth - currentWidth
const requiredWidth =
LABEL_MAX_WIDTH + (needsOverflowBadge ? MORE_LABEL_WIDTH + GAP : 0) + margin
if (remainingWidth >= requiredWidth || visible.length === 0) {
visible.push(label)
currentWidth += LABEL_MAX_WIDTH + GAP
} else {
hidden.push(...labels.slice(i))
break
}
}
return { visibleLabels: visible, hiddenLabels: hidden }
})
const visibleLabels = $derived(labelSplit.visibleLabels || [])
const hiddenLabels = $derived(labelSplit.hiddenLabels || [])
const dropdownItems = $derived(
hiddenLabels.map(
(label): Item => ({
displayName: label,
action: () => onFilterByLabel(label),
icon: ListFilterPlus
})
)
)
</script>
{#if labels && labels.length > 0}
<div class="flex flex-row items-center" style="gap: {GAP}px">
{#each visibleLabels as label}
<Tooltip openDelay={500} placement="bottom">
<button
class={twMerge(
activeLabel == label ? 'bg-blue-50 dark:bg-blue-900/50' : '',
'flex flex-row items-center px-2 group py-1 rounded-md bg-surface-secondary hover:bg-surface'
)}
style="gap: {GAP}px; width: {LABEL_MAX_WIDTH}px"
onclick={() => {
onFilterByLabel(label)
}}
>
<span class="truncate text-2xs font-normal">{label}</span>
<ListFilterPlus size={12} class="shrink-0 text-gray-300 group-hover:text-primary" />
</button>
{#snippet text()}
{`Filter by label: ${label}`}
{/snippet}
</Tooltip>
{/each}
{#if hiddenLabels.length > 0}
<DropdownV2 placement="bottom-start" items={dropdownItems} customWidth={224}>
{#snippet buttonReplacement()}
<button
class="flex flex-row items-center justify-center px-2 py-1 text-2xs font-semibold hover:bg-surface bg-surface-secondary text-secondary rounded-md"
style="gap: {GAP}px; width: {MORE_LABEL_WIDTH}px"
>
+{hiddenLabels.length}
</button>
{/snippet}
</DropdownV2>
{/if}
</div>
{:else}
<span class="text-2xs text-secondary">-</span>
{/if}