feat: show path in flow script picker (#4574)

* Add popover with path to flow modules

* Add path to items in the flow picker

* fix virtual item display issue

* fix min size

* open popover on keyboard selection

---------

Co-authored-by: Guilhem <guilhem@mbp-de-windmill.home>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
This commit is contained in:
Guilhem
2024-11-05 08:58:29 +01:00
committed by GitHub
parent 95f635bf12
commit f7a03ee851
8 changed files with 146 additions and 65 deletions

View File

@@ -2,6 +2,7 @@
import { createPopperActions, type PopperOptions } from 'svelte-popperjs'
import type { PopoverPlacement } from './Popover.model'
import Portal from '$lib/components/Portal.svelte'
import { twMerge } from 'tailwind-merge'
import { ExternalLink } from 'lucide-svelte'
@@ -13,6 +14,7 @@
export let appearTimeout = 300
export let documentationLink: string | undefined = undefined
export let style: string | undefined = undefined
export let forceOpen = false
const [popperRef, popperContent] = createPopperActions({ placement })
@@ -47,6 +49,8 @@
inTimeout = undefined
timeout = setTimeout(() => (showTooltip = false), disappearTimeout)
}
$: forceOpen ? open() : close()
</script>
{#if notClickable}
@@ -73,7 +77,10 @@
use:popperContent={popperOptions}
on:mouseenter={open}
on:mouseleave={close}
class="z-[5001] py-2 px-3 rounded-md text-sm font-normal !text-gray-300 bg-gray-800 whitespace-normal text-left {popupClass}"
class={twMerge(
'z-[5001] py-2 px-3 rounded-md text-sm font-normal !text-gray-300 bg-gray-800 whitespace-normal text-left',
popupClass
)}
>
<div class="max-w-sm break-words">
<slot name="text" />

View File

@@ -41,6 +41,7 @@
export let kind: 'trigger' | 'script' | 'preprocessor' | 'failure' | 'approval'
export let selectedKind: 'script' | 'flow' | 'approval' | 'trigger' | 'preprocessor' | 'failure' =
kind
export let displayPath = false
let lang: FlowCopilotModule['lang'] = undefined
let selectedCompletion: FlowCopilotModule['selectedCompletion'] = undefined
@@ -424,6 +425,7 @@
selected={selectedByKeyboard - inlineScripts?.length - aiLength - topLevelNodes.length}
on:pickScript
on:pickFlow
{displayPath}
/>
{/if}
@@ -446,6 +448,7 @@
topLevelNodes.length}
on:pickScript
bind:loading
{displayPath}
/>
{/if}
{/if}

View File

@@ -41,6 +41,7 @@
export let bold: boolean = false
export let id: string | undefined = undefined
export let label: string
export let path: string = ''
export let modType: string | undefined = undefined
export let bgColor: string = ''
export let concurrency: boolean = false
@@ -248,11 +249,22 @@
<slot name="icon" />
</div>
{/if}
<div
class="absolute left-1/2 transform -translate-x-1/2 text-center truncate"
class:font-bold={bold}
style="max-width: calc(100% - {marginLeft}px)">{label}</div
<Popover
class="absolute left-1/2 transform -translate-x-1/2 center-center"
style="max-width: calc(100% - {marginLeft}px)"
>
<div class="text-center truncate {bold ? '!font-bold' : 'font-normal'}">
{label}
</div>
<svelte:fragment slot="text">
<div>
<div>{label}</div>
{#if path != ''}<div>{path}</div>{/if}
</div>
</svelte:fragment>
</Popover>
<div class="flex items-center space-x-2 relative max-w-[25%]" bind:clientWidth={idBadgeWidth}>
{#if id && id !== 'preprocessor' && !id.startsWith('failure')}
<Badge color="indigo" wrapperClass="max-w-full" baseClass="max-w-full truncate" title={id}>

View File

@@ -46,6 +46,11 @@
let small = false
let open = false
let width = 0
let height = 0
$: displayPath = width > 650 || height > 400
$: small = kind === 'preprocessor' || kind === 'failure'
</script>
@@ -90,11 +95,17 @@ shouldUsePortal={true} -->
</svelte:fragment>
<div
id="flow-editor-insert-module"
class="flex flex-col h-[400px] {small ? 'w-[450px]' : 'w-[650px]'} pt-1 pr-1 pl-1 gap-1.5"
class="flex flex-col h-[400px] {small
? 'w-[450px]'
: 'w-[650px]'} pt-1 pr-1 pl-1 gap-1.5 resize overflow-auto {small
? 'min-w-[450px]'
: 'min-w-[650px]'} min-h-[400px]"
on:wheel={(e) => {
e.stopPropagation()
}}
role="none"
bind:clientWidth={width}
bind:clientHeight={height}
>
<div class="flex flex-row items-center gap-2">
<StepGenQuick
@@ -203,6 +214,7 @@ shouldUsePortal={true} -->
on:pickFlow
{preFilter}
{small}
{displayPath}
/>
</div>
</div>

View File

@@ -175,6 +175,7 @@
(mod.value.type === 'rawscript'
? `Inline ${prettyLanguage(mod.value.language)}`
: 'To be defined')}
path={`path` in mod.value && mod.summary ? mod.value.path : ''}
isTrigger={isTriggerStep(mod)}
>
<div slot="icon">

View File

@@ -30,7 +30,7 @@
>
<div
style={borderColor ? `border-color: ${borderColor};` : 'border: 0'}
class="flex gap-1 justify-between {center
class="flex flex-row gap-1 justify-between {center
? 'items-center'
: 'items-baseline'} w-full overflow-hidden rounded-sm border p-2 text-2xs module text-primary border-gray-400 dark:border-gray-600"
>
@@ -38,8 +38,7 @@
<slot name="icon" />
<span class="mr-2" />
{/if}
<div />
<div class="flex flex-col w-full">
<div class="flex flex-col flex-grow shrink-0 max-w-full min-w-0">
{#if label}
<div class="truncate text-center">{label}</div>
{/if}
@@ -47,10 +46,12 @@
<div class="truncate text-2xs text-center"><pre>{preLabel}</pre></div>
{/if}
</div>
<div class="flex items-center space-x-2">
{#if id && !hideId}
<Badge color="indigo">{id}</Badge>
{/if}
</div>
{#if id && !hideId}
<div class="flex items-center shrink min-w-0">
<Badge color="indigo" wrapperClass="w-full" baseClass="max-w-full" title={id}>
<span class="max-w-full text-2xs truncate">{id}</span>
</Badge>
</div>
{/if}
</div>
</VirtualItemWrapper>

View File

@@ -5,6 +5,7 @@
import { APP_TO_ICON_COMPONENT } from '$lib/components/icons'
import { IntegrationService, ScriptService, type HubScriptKind } from '$lib/gen'
import { Circle } from 'lucide-svelte'
import Popover from '$lib/components/Popover.svelte'
export let kind: HubScriptKind & string = 'script'
export let filter = ''
@@ -25,6 +26,7 @@
app: string
kind: HubScriptKind
}[] = []
export let displayPath = false
export let apps: string[] = []
let allApps: string[] = []
@@ -138,32 +140,56 @@
<ul>
{#each items as item, index (item.path)}
<li class="w-full">
<button
class="px-3 py-2 gap-2 flex flex-row w-full hover:bg-surface-hover transition-all items-center rounded-md {index ===
selected
? 'bg-surface-hover'
: ''}"
on:click={() => dispatch('pickScript', item)}
>
<div class={classNames('flex justify-center items-center')}>
{#if item['app'] in APP_TO_ICON_COMPONENT}
<svelte:component this={APP_TO_ICON_COMPONENT[item['app']]} height={14} width={14} />
{:else}
<div
class="w-[14px] h-[14px] text-gray-400 flex flex-row items-center justify-center"
<Popover class="w-full" placement="right" forceOpen={index === selected}>
<svelte:fragment slot="text">
<div class="flex flex-col">
<div class="text-left text-xs font-normal leading-tight py-0"
>{item.summary ?? ''}</div
>
<Circle size="12" />
<div class="text-left text-2xs font-normal">
{item.path ?? ''}
</div>
{/if}
</div>
</div>
</svelte:fragment>
<button
class="px-3 py-2 gap-2 flex flex-row w-full hover:bg-surface-hover transition-all items-center rounded-md {index ===
selected
? 'bg-surface-hover'
: ''}"
on:click={() => dispatch('pickScript', item)}
>
<div class={classNames('flex justify-center items-center')}>
{#if item['app'] in APP_TO_ICON_COMPONENT}
<svelte:component
this={APP_TO_ICON_COMPONENT[item['app']]}
height={14}
width={14}
/>
{:else}
<div
class="w-[14px] h-[14px] text-gray-400 flex flex-row items-center justify-center"
>
<Circle size="12" />
</div>
{/if}
</div>
<span class="grow truncate text-left text-2xs text-primary font-normal">
{item.summary ?? ''}
</span>
{#if index === selected}
<kbd class="!text-xs">&crarr;</kbd>
{/if}
</button>
<div class="flex flex-col grow min-w-0">
<div
class="grow truncate text-left text-2xs text-primary font-normal leading-tight py-0.5"
>{item.summary ?? ''}</div
>
{#if displayPath && item.path}
<div class="grow truncate text-left text-2xs text-secondary font-[220]">
{item.path}
</div>
{/if}
</div>
{#if index === selected}
<kbd class="!text-xs">&crarr;</kbd>
{/if}
</button>
</Popover>
</li>
{/each}
</ul>

View File

@@ -7,11 +7,13 @@
import { emptyString } from '$lib/utils'
import { Code2 } from 'lucide-svelte'
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
import Popover from '$lib/components/Popover.svelte'
export let kind: 'script' | 'trigger' | 'approval' | 'failure' | 'flow' | 'preprocessor' =
'script'
export let isTemplate: boolean | undefined = undefined
export let selected: number | undefined = undefined
export let displayPath = false
type Item = {
path: string
@@ -105,35 +107,52 @@
<ul>
{#each filteredWithOwner ?? [] as { path, hash, summary, marked }, index}
<li class="w-full">
<button
class="px-3 py-2 gap-2 flex flex-row w-full hover:bg-surface-hover transition-all items-center rounded-md {index ===
selected
? 'bg-surface-hover'
: ''}"
on:click={() => {
if (kind == 'flow') {
dispatch('pickFlow', { path: path })
} else {
dispatch('pickScript', { path: path, hash: lockHash ? hash : undefined, kind })
}
}}
>
{#if kind == 'flow'}
<BarsStaggered size={14} class="shrink-0" />
{:else}
<Code2 size={14} />
{/if}
<span class="grow min-w-0 truncate text-left text-2xs text-primary font-normal">
{#if marked}
{@html marked}
{:else}
{!summary || summary.length == 0 ? path : summary}
{/if}</span
<Popover class="w-full " placement="right" forceOpen={index === selected}>
<svelte:fragment slot="text">
<div class="flex flex-col">
<div class="text-left text-xs font-normal leading-tight py-0">{summary ?? ''}</div>
<div class="text-left text-2xs font-normal">
{path ?? ''}
</div>
</div>
</svelte:fragment>
<button
class="px-3 py-2 gap-2 flex flex-row w-full hover:bg-surface-hover transition-all items-center rounded-md {index ===
selected
? 'bg-surface-hover'
: ''}"
on:click={() => {
if (kind == 'flow') {
dispatch('pickFlow', { path: path })
} else {
dispatch('pickScript', { path: path, hash: lockHash ? hash : undefined, kind })
}
}}
>
{#if index === selected}
<kbd class="!text-xs">&crarr;</kbd>
{/if}
</button>
{#if kind == 'flow'}
<BarsStaggered size={14} class="shrink-0" />
{:else}
<Code2 size={14} />
{/if}
<div class="flex flex-col grow min-w-0">
<div class="grow min-w-0 truncate text-left text-2xs text-primary font-normal">
{#if marked}
{@html marked}
{:else}
{!summary || summary.length == 0 ? path : summary}
{/if}
</div>
{#if displayPath && path}
<div class="grow min-w-0 truncate text-left text-2xs text-secondary font-[220]">
{path}
</div>
{/if}
</div>
{#if index === selected}
<kbd class="!text-xs">&crarr;</kbd>
{/if}
</button>
</Popover>
</li>
{/each}
</ul>