Files
windmill/frontend/src/lib/components/FirstStepInputs.svelte
T
GuilhemandRuben Fiszel 59bcce7a96 feat (frontend): improve capture UI (#5051)
* feat (frontend): improve capture UI

* show schema diff

* add accept reject form

* add diff for first node input

* move update schema button

* change modified properties display

* propagate change through nested components

* allow modification of nested object in schema

* reject nested changes

* clean logic

* clean code

* clean

* nit

* fix first strep input

* fix argument preview

* clean

* restore indentation for nested objects

* ignore undefined field in diff computation

* fix run button disabled update

* nit

* fix update JSON

* fix deletion of nested components

* dark mode

* clean

* replace dropdown with sidebar

* only check type for compatibility

* add shadow

* disbale dnd on edit

* auto-scroll within schema

* fix nested not dnd object diff viewer

* fix captures drawer

* open edit tab on add new arg

* change button label when schema is the same

* ajust padding

* fix arg update

* fix oneof display

* propagate change event through nested schema

* handle oneOf

* fix preview arg sync

* handle s3 object

* fix arg sync

* update schema input compatibility

* clean compatible

* accept empty array items

* clean

* increase of schema args gap

* fix nested schema update

* allow number and int compatibility

* reset args when modifying schema

* open fields on add with addPropertyV2

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-01-22 12:51:14 +01:00

125 lines
3.5 KiB
Svelte

<script lang="ts">
import { createEventDispatcher, onDestroy, getContext } from 'svelte'
import { getFirstStepSchema } from '$lib/components/flows/flowStore'
import type { FlowEditorContext } from '$lib/components/flows/types'
import { twMerge } from 'tailwind-merge'
import { clickOutside } from '$lib/utils'
import { Alert } from '$lib/components/common'
import FlowModuleSchemaItemViewer from '$lib/components/flows/map/FlowModuleSchemaItemViewer.svelte'
import LanguageIcon from '$lib/components/common/languageIcons/LanguageIcon.svelte'
import { prettyLanguage } from '$lib/common'
import IconedResourceType from '$lib/components/IconedResourceType.svelte'
import { Building } from 'lucide-svelte'
const { flowStore, flowStateStore } = getContext<FlowEditorContext>('FlowEditorContext')
const dispatch = createEventDispatcher()
let schema: Record<string, any> | undefined = undefined
let error: string | undefined = undefined
let mod: any | undefined = undefined
async function loadSchema() {
try {
const res = await getFirstStepSchema($flowStateStore, flowStore)
schema = res.schema
mod = res.mod
dispatch('connectFirstNode', { connectFirstNode: res.connectFirstNode })
} catch (e) {
error = e
}
}
$: $flowStore && $flowStateStore && loadSchema()
function handleClick() {
selected = !selected
dispatch('select', selected ? schema : undefined)
}
onDestroy(() => {
selected = false
dispatch('select', undefined)
})
let selected: boolean = false
async function getPropPickerElements(): Promise<HTMLElement[]> {
return Array.from(
document.querySelectorAll('[data-schema-picker], [data-schema-picker] *')
) as HTMLElement[]
}
function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape' && selected) {
selected = false
dispatch('select', undefined)
event.stopPropagation()
event.preventDefault()
}
}
let firstUpdate = true
$: if (schema && !selected && firstUpdate) {
firstUpdate = false
setTimeout(() => {
selected = true
dispatch('select', schema)
}, 200)
}
</script>
<svelte:window on:keydown={handleKeydown} />
<div class="h-full">
{#if schema && mod}
<button
class={twMerge(
'w-full shadow-md rounded-sm',
selected ? 'bg-surface-selected' : 'hover:bg-surface-hover'
)}
disabled={!schema}
on:click={handleClick}
use:clickOutside={{ capture: false, exclude: getPropPickerElements }}
on:click_outside={() => {
if (selected) {
selected = false
dispatch('select', undefined)
}
}}
>
<FlowModuleSchemaItemViewer
on:click={handleClick}
deletable={false}
id={mod.id}
label={mod.summary ||
(`path` in mod.value ? mod.value.path : undefined) ||
(mod.value.type === 'rawscript'
? `Inline ${prettyLanguage(mod.value.language)}`
: 'To be defined')}
path={`path` in mod.value && mod.summary ? mod.value.path : ''}
>
<div slot="icon">
{#if mod.value.type === 'rawscript'}
<LanguageIcon lang={mod.value.language} width={16} height={16} />
{:else if mod.value.type === 'script'}
{#if mod.value.path.startsWith('hub/')}
<div>
<IconedResourceType
width="20px"
height="20px"
name={mod.value.path.split('/')[2]}
silent={true}
/>
</div>
{:else}
<Building size={14} />
{/if}
{/if}
</div>
</FlowModuleSchemaItemViewer>
</button>
{:else}
<Alert type="warning" title="Cannot load first step's inputs" size="xs">
{error}
</Alert>
{/if}
</div>