mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-12 16:02:56 +00:00
feat: compact inline title badges on home rows
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
acd13b0f9c
commit
1ab2c6d681
@@ -237,9 +237,6 @@
|
||||
</span>
|
||||
{:else}
|
||||
<Badge small color="indigo" class="gap-0.5">
|
||||
{#if orderedUsers.length > 0}
|
||||
{@render circleStack()}
|
||||
{/if}
|
||||
{draft_only ? 'Draft only' : 'Draft'}
|
||||
</Badge>
|
||||
{/if}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import { Badge } from './common'
|
||||
</script>
|
||||
|
||||
<Popover notClickable>
|
||||
<Popover notClickable class="inline-flex items-center">
|
||||
{#snippet text()}
|
||||
Library script (no exported main function)
|
||||
{/snippet}
|
||||
<Badge small color="yellow" baseClass="border">Library</Badge>
|
||||
<Badge small color="yellow">Library</Badge>
|
||||
</Popover>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</script>
|
||||
|
||||
{#if kind === 'read' || kind === 'write'}
|
||||
<Popover notClickable>
|
||||
<Popover notClickable class="inline-flex items-center">
|
||||
<Badge capitalize color="blue" icon={{ icon: Users, position: 'right' }}></Badge>
|
||||
{#snippet text()}
|
||||
<span>{kind == 'read' ? 'Read & Run only' : 'Read & Write'} {reason}</span>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { type BadgeColor, type BadgeIconProps, ColorModifier } from './model'
|
||||
import { X } from 'lucide-svelte'
|
||||
import { isCompactBadges } from './density'
|
||||
|
||||
interface Props {
|
||||
color?: BadgeColor
|
||||
@@ -48,6 +49,7 @@
|
||||
}: Props = $props()
|
||||
|
||||
let hidden = $state(false)
|
||||
const compact = isCompactBadges()
|
||||
const colors: Record<BadgeColor, string> = {
|
||||
gray: 'bg-surface-sunken text-primary',
|
||||
blue: 'bg-blue-50 text-blue-800 dark:text-blue-100 dark:bg-blue-700/40',
|
||||
@@ -126,7 +128,8 @@
|
||||
: 'rounded-md px-2 py-0.5',
|
||||
verySmall ? 'px-0.5 py-0.5' : '',
|
||||
'flex flex-row gap-1 items-center justify-center',
|
||||
classNames
|
||||
classNames,
|
||||
compact ? 'text-3xs px-1 py-0 gap-0.5' : ''
|
||||
)
|
||||
)
|
||||
const handleHide = () => (hidden = !hidden)
|
||||
@@ -148,11 +151,19 @@
|
||||
role={clickable ? 'button' : undefined}
|
||||
>
|
||||
{#if icon?.icon && icon.position === 'left'}
|
||||
<icon.icon size={12} />
|
||||
<icon.icon size={compact ? 10 : 12} />
|
||||
{/if}
|
||||
{#if compact}
|
||||
<!-- `contents` keeps the children in the badge's flex layout; only the
|
||||
text colour is softened, not the background. -->
|
||||
<span class="contents [color:color-mix(in_srgb,currentColor_85%,transparent)]">
|
||||
{@render children?.()}
|
||||
</span>
|
||||
{:else}
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
{@render children?.()}
|
||||
{#if icon?.icon && icon.position === 'right'}
|
||||
<icon.icon size={12} />
|
||||
<icon.icon size={compact ? 10 : 12} />
|
||||
{/if}
|
||||
{#if dismissable}
|
||||
<button onclick={handleHide}>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { getContext, setContext } from 'svelte'
|
||||
|
||||
const CONTEXT_KEY = 'compactBadges'
|
||||
|
||||
/** Render every `Badge` below the calling component in its compact density. */
|
||||
export function setCompactBadges() {
|
||||
setContext(CONTEXT_KEY, true)
|
||||
}
|
||||
|
||||
export function isCompactBadges(): boolean {
|
||||
return getContext<boolean | undefined>(CONTEXT_KEY) ?? false
|
||||
}
|
||||
@@ -157,7 +157,7 @@
|
||||
<InheritedLabels labels={app.inherited_labels} />
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
<span class="hidden md:inline-flex gap-x-1">
|
||||
<span class="hidden md:inline-flex gap-x-2">
|
||||
{#if !$userStore?.operator}
|
||||
{#if showEditButton && app.canWrite}
|
||||
<div>
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
<InheritedLabels labels={flow.inherited_labels} />
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
<span class="hidden md:inline-flex gap-x-1">
|
||||
<span class="hidden md:inline-flex gap-x-2">
|
||||
{#if !hideForOperator && showEditButton && flow.canWrite && !flow.archived}
|
||||
<div>
|
||||
<Button
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import Checkbox from '../checkbox/Checkbox.svelte'
|
||||
import type { RowSelection } from './rowSelection'
|
||||
import RunnableActivityCells from '$lib/components/home/RunnableActivityCells.svelte'
|
||||
import { setCompactBadges } from '../badge/density'
|
||||
|
||||
interface Props {
|
||||
marked: string | undefined
|
||||
@@ -118,6 +119,8 @@
|
||||
?.split('/')
|
||||
?.slice(-1)?.[0]) ?? ''
|
||||
|
||||
setCompactBadges()
|
||||
|
||||
let rowEl: HTMLDivElement | undefined = $state()
|
||||
$effect(() => {
|
||||
if (keyboardSelected) {
|
||||
@@ -181,7 +184,7 @@
|
||||
data-row-selection-key={rowSelection?.key}
|
||||
data-row-keyboard-selected={keyboardSelected ? 'true' : undefined}
|
||||
class={twMerge(
|
||||
'group/row relative w-full inline-flex items-center gap-4 first-of-type:!border-t-0 first-of-type:rounded-t-md last-of-type:rounded-b-md [*:not(:last-child)]:border-b px-4 py-3 border-b last:border-b-0',
|
||||
'group/row relative w-full inline-flex items-center gap-4 first-of-type:!border-t-0 first-of-type:rounded-t-md last-of-type:rounded-b-md [*:not(:last-child)]:border-b pl-4 pr-1 py-3 border-b last:border-b-0',
|
||||
depth > 0 ? '!rounded-none' : '',
|
||||
disabled ? 'opacity-25' : 'hover:bg-surface-hover',
|
||||
clickToSelect || inSelectionMode ? 'cursor-pointer select-none' : '',
|
||||
@@ -246,30 +249,22 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- The link covers the whole row rather than wrapping the title, so the
|
||||
badges on the title line can hold their own popovers and buttons. -->
|
||||
{#if href && !inSelectionMode}
|
||||
<a
|
||||
{href}
|
||||
class="min-w-0 hover:underline decoration-gray-400 inline-flex items-center gap-4 after:absolute after:inset-0 after:content-['']"
|
||||
>
|
||||
{@render rowContent(!rowSelection)}
|
||||
</a>
|
||||
{:else}
|
||||
{@render rowContent(!rowSelection)}
|
||||
aria-label={!summary || summary.length == 0 ? displayPath : summary}
|
||||
class="absolute inset-0"
|
||||
></a>
|
||||
{/if}
|
||||
|
||||
{#if badges}
|
||||
<div class="relative z-[1] hidden lg:flex flex-row gap-1.5 items-center">
|
||||
{@render badges?.()}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="grow"></div>
|
||||
{@render rowContent(!rowSelection, !!href && !inSelectionMode)}
|
||||
|
||||
{#if errorHandlerMuted}
|
||||
<BellOff class="w-8 opacity-60" size={12} fill="currentcolor" />
|
||||
{/if}
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-1.5 shrink-0">
|
||||
<div class="relative z-[1] flex items-center gap-3 shrink-0">
|
||||
{#if kind == 'script' || kind == 'flow' || kind == 'app' || kind == 'raw_app' || kind == 'agent'}
|
||||
<RunnableActivityCells
|
||||
kind={kind == 'script' || kind == 'flow' ? kind : undefined}
|
||||
@@ -291,33 +286,41 @@
|
||||
<div class="w-7"></div>
|
||||
{/if}
|
||||
|
||||
<div data-row-actions class="flex gap-1 items-center justify-end pr-2">
|
||||
<div data-row-actions class="flex gap-2 items-center justify-end">
|
||||
{@render actions?.()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#snippet rowContent(withIcon: boolean)}
|
||||
{#snippet rowContent(withIcon: boolean, linked: boolean)}
|
||||
{#if withIcon}
|
||||
<div class="shrink">
|
||||
<RowIcon {kind} {triggerKind} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="min-w-0">
|
||||
<div
|
||||
class={twMerge(
|
||||
'text-emphasis flex-wrap text-left text-xs font-semibold',
|
||||
titleBadge ? 'inline-flex items-center gap-2' : ''
|
||||
)}
|
||||
>
|
||||
{#if customSummary}
|
||||
{@render customSummary?.()}
|
||||
{:else if marked}
|
||||
{@html marked}
|
||||
{:else}
|
||||
{!summary || summary.length == 0 ? displayPath : summary}
|
||||
<div class="min-w-0 grow">
|
||||
<div class="flex items-center gap-1.5 min-w-0">
|
||||
<div
|
||||
class={twMerge(
|
||||
'text-emphasis flex-wrap text-left text-xs font-semibold min-w-0',
|
||||
titleBadge ? 'inline-flex items-center gap-2' : '',
|
||||
linked ? 'group-hover/row:underline decoration-gray-400' : ''
|
||||
)}
|
||||
>
|
||||
{#if customSummary}
|
||||
{@render customSummary?.()}
|
||||
{:else if marked}
|
||||
{@html marked}
|
||||
{:else}
|
||||
{!summary || summary.length == 0 ? displayPath : summary}
|
||||
{/if}
|
||||
{@render titleBadge?.()}
|
||||
</div>
|
||||
{#if badges}
|
||||
<div class="relative z-[1] hidden lg:flex flex-row gap-1 items-center shrink-0">
|
||||
{@render badges()}
|
||||
</div>
|
||||
{/if}
|
||||
{@render titleBadge?.()}
|
||||
</div>
|
||||
<div class="text-hint text-3xs truncate text-left font-normal" title={path}>
|
||||
{#if pathDisplay}
|
||||
|
||||
@@ -173,6 +173,9 @@
|
||||
{rowSelection}
|
||||
>
|
||||
{#snippet badges()}
|
||||
{#if script.language}
|
||||
<LanguageIcon lang={script.language} width={14} height={14} />
|
||||
{/if}
|
||||
{#if script.lock_error_logs}
|
||||
<Badge color="red" baseClass="border border-red-200">Deployment failed</Badge>
|
||||
{/if}
|
||||
@@ -185,7 +188,7 @@
|
||||
<NoMainFuncBadge />
|
||||
{/if}
|
||||
{#if script.auto_kind === 'wac'}
|
||||
<Popover notClickable>
|
||||
<Popover notClickable class="inline-flex items-center">
|
||||
{#snippet text()}
|
||||
Workflow-as-Code
|
||||
{/snippet}
|
||||
@@ -193,7 +196,7 @@
|
||||
</Popover>
|
||||
{/if}
|
||||
{#if script.auto_kind === 'test'}
|
||||
<Popover notClickable>
|
||||
<Popover notClickable class="inline-flex items-center">
|
||||
{#snippet text()}
|
||||
CI test script
|
||||
{/snippet}
|
||||
@@ -237,13 +240,10 @@
|
||||
</div>
|
||||
{/if}
|
||||
<InheritedLabels labels={script.inherited_labels} />
|
||||
<div class="w-5 center-center">
|
||||
<LanguageIcon lang={script.language} width={16} height={16} />
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#snippet actions()}
|
||||
<span class="hidden md:inline-flex gap-x-1">
|
||||
<span class="hidden md:inline-flex gap-x-2">
|
||||
{#if !$userStore?.operator}
|
||||
{#if showEditButton}
|
||||
{#if script.use_codebase}
|
||||
|
||||
Reference in New Issue
Block a user