Files
windmill/frontend/src/lib/components/InputTransformForm.svelte
T
Diego Imbert a689c0b0f1 feat: Batch re-run (#5553)
* runs on svelte 5

* Line component from svelte-chartjs

* Replaced all svelte-chartjs occurrences with custom wrapper

* Fix props mistake

* Fix illegal table structures

* self-closing-tags fix

* aria labels

* Fixed trivial warnings and errors

* @tanstack/svelte-table fix

* upgrade to vite 6

* svelte-kit sync before running svelte-check

* Remove on:clear which is actually on:removeAll and already handled by on:change

* fix worker tags not displaying in Autoscaling

* Try to fix svelte-kit sync not working during CI

* remove warnings

* Fix add flow page crashing

* access worldStore before assignment fix

* fix infinite recursions in App Editor

* Replaced JSON.stringify with proper deepEqual

* component mount api changed (no longer classes)

* fix ci errors

* Fix infinite loops in background runnable panel

* factored effect on deep equal logic in onObjChange

* fix "Add" not working in AgGrid Table

* Replaced legacy component.$set api

* Fix multiselect infinite value reaction

* Fix flow input fields resetting when opening their edit tab

* fix date input resetting when typing year

* Remove !p-0 affecting subgrid dotted borders

* fix missing debounceTemplate causing hundreds of updates

* Fix AgGrid action refreshes and disppearing

* resolve getItems generating random ids every rerun

* fix cannot access items before init

* fix sort lambda arguments being undefined

* Revert "Remove !p-0 affecting subgrid dotted borders"

This reverts commit c62809bb45d682a48376b071680645ed4e1c601b.

* fix input not updating in decision tree editor

* Update frontend/src/lib/components/schema/EditableSchemaWrapper.svelte

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Re-added padding affecting subgrid dotted borders (#5479)

* remove !p-0 in preset components

* removed extra padding on accordion tabs subgrid

* Fix non-reactive SchemaForm

* dirty fix for the oneOf bug

* feat: add nu-lang support (#5217)

* feat: add nu (nushell) support

* add worker tests

* deactivate tables and non-any types below top-level

full support will come in V1
for V0 it's better to keep things minimal and simple

* add syntax highlighting

used python's grammar, since nushell isn't supported by monaco nor svelte-highlights

for V1 nu will get it`s own grammar

* add logo

* partially implement plugin support

* change logo + ability to deploy + nsjail draft

* static variables + get_resource + get_variable

* lsp/dev.nu + initial nu lsp (not working yet)

* make it work with nsjail

* nullguard

* Much more flexible signature parsing and better error-messages

* add init script

* rename nulsp to nu

* install nu to dockerfile

* fix merge

* implement Default for MainArgSignature

* stage NU_CACHE_DIR

* improve dockerfiles

* dev.nu for parser-wasm + flake.nix

* update code for windows

* add nushell to flake

* upload Cargo.lock

* make build.sh work on nixos

* build wasm cli parsers

* add docs to README_DEV.md

* add helper script docker/dev.nu

* improve docker/dev.nu

* fix windows

* commit frontend/package(lock).json

* update cargo.lock

* correctly update cargo.lock

* remove lsp

* update flake.nix to include svelte server and nushell

* Revert base.sql to main

* remove PLUGIN_USE_RE

* make CARGO_PATH private

* add nu to cli

* Change flags to build wasm-nu-parser

* remove flake.nix from parser-wasm

* update wasm-build target

* remove unused import

* add cli support for nu

* update github workflows

* wasm-build 0.17 -> 0.19

* update build script

* update cargo.lock

* Fix typographical error

* update Cargo.lock

* update ENV_SETTINGS

* use published nu parser

* update package.lock

* rewrite parser in tree-sitter

* implement parser from scratch

* polishing

* change init script to match new parser

* fix imports

* fix cli build

* fix cli build

* merge

* update wasm

* use MiniPulledJob

* update cli

* change cli wasm schema

* change cli

* update deno.json

* make wasm modules load lazily

* regenerate parsers

* remove leftover

* update cargo.lock

* clean up dnt.ts

* add docs to cli/test.nu

* add schema validation option

* add Nu to try_validate_schema

* reference frontend to new parser version

* feat: unsafe parameters for sql queries (table names, column names) (#5488)

* Make schema validation struct

Schema Validation rules that are constructed from the schema or from the
MainArgSig(TODO).

* Make other validator builder

* Fail dependency job like with lockfile failing for schema validator

* Add last types + tests

* Remove unused dependency

* fix typos

* Migration ID was colliding with another, changed it manually

* Add Oneof + other fixes

* fix: cache for querying scripts correclty handles ScriptMetadata

* Add cache for schema validation from main arg sig

* Prepare sqlx

* Remove default features

* Feature flags

* WIP: unsafe sql params for sql langauges

* Fix down migration table name

* cleanup: put validation logic inside a function

* Refactor to cache the should_validate boolean

Changed the schemavalidators cache to take in an
Option<SchemaValidator>, effectively storing the `should_validate_schema` information.

Also pass the schema when avaialble to construct the schema validator

* Add other job kinds to u8 cache key just in case

* Change sql languages to all get arguments as Values instead of RawValue

* Only cache if not preview

* Add last sql languages and some CI fixes

* Rename after typo on `sanitized`

* Finish rename

* Remove unused import

* Fix wrong test

* Add newly published regex parser version

* Remove default features from cargo.toml

* Change to a cleaner syntax for the interpolated args

* Update republished parser

* fix win build (#5494)

* add sysinfoapi feature flag for winapi dependency

* add ff

* add ff at the right place

* fix(frontend): use stable path for capture tables + nits (#5495)

* add missing capture move on first time deploy (#5496)

* avoid regen client as build step

* perf: cache workspace env variables to avoid one query (#5499)

* perf: optimize number of queries needed for job run (#5504)

* optPerf

* update sqlx

* update sqlx

* fix: improve cancel for flows with many substeps

* feat: list references upon renaming a script or a flow (#5487)

* Refactored flow_workspace_runnables to more generic workspace_runnable_dependencies

* list flows referencing an item upon renaming it

* Refactor with two exclusive columns to avoid breaking FK constraints

* Show apps depending on item upon renaming

* sqlx prepare

* list-disc instead of •

* on delete and on update cascade

* displayPathChangedWarning oneOf check instead noneOf

* combine migrations + add "on update cascade" to flow fk

* unique index on app dependencies to avoid duplicates

* create new workspace_runnable_dependencies instead of renaming old table

* Add "looking for references" loading msg

* Revert "create new workspace_runnable_dependencies instead of renaming old table"

This reverts commit 015c38ca8f.

* flow_workspace_runnables view for backwards compatibility

* Add warning for script imports on rename

* support import dependency tracking in deno

* number of using scripts / flows / apps tooltip

* forgot sqlx prepare

* delete app-related rows in down migration

* Made selection more generic

* RunsBatchActionsDropdown refactor

* started BatchReRunOptionsPane

* fix overflow quirk

* fetch schema

* refactor to group jobs by (kind, path)

* auto select

* computePropertyMap

* InputTransformForm works

* Pickable properties

* remove PropPickerWrapper and make it optional in InputTransformForm

* hide help btn

* available expressions info alert

* extraLib for editor linting

* fix selected group not updating

* nit

* Refactor async logic in script tag

* persist changes in state

* correct typing

* count for each (path, kind) group

* support flows

* use dot operator when possible

* count jobs and fix wrong number

* fix selectedJobs recomputing periodically

* (v0) individual api requests to re-run jobs

* move batchReRunChangedArgs state upwards

* Support static arg

* mistake

* Single confirmation modal + removed unnecessary state

* change confirmation modal color

* use runes in confirmation modal

* listSelectedJobsSchema API endpoint

* refactored batch rerun pane for listSelectedJobsSchema

* eliminated selectedJobs

* batch rerun works backend (v0 same args)

* Static input transforms

* simpler list_selected_jobs_schemas sql query with coalesce

* use latest schema UI + refactor

* run latest version in backend

* add deno_core dependency to windmill-api

* stream jobs from db

* basic js evaluation

* sqlx prepare

* add id path and hash in editor lint

* js works with job object!

* moved deno_core logic to separate function

* openapi yaml mistake

* unnecessary bind

* fix date as string

* Stream re-ran uuids

* handle SSE multiple values at once

* don't select all by default on batch action

* nit ui

* check that schema has property backend

* Better JobGroup query + cache

* handle multi type properties

* Notify user on error

* stupid mistake

* Fix warnings and update svelte-exmarkdown for svelte 5

* regen package-lock to fix crash on vite preview

* batch re-run all filtered jobs

* merge schemas to common type

* more explicit tooltips

* changed sse counter ui

* typos

* fix tutorial first part

* nit mistake

* package lock + elipsis nit

* fix: latest_schema option still checked on the job original schema

* always gotta forget sqlx prepare

* fix flashing loading screen

* fix batch re-run select all filtered

* better tooltip

* fix batch actions btn growing on wide screen

* revert disableBatchActions

* fix selectable step jobs

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com>
Co-authored-by: wendrul <53628737+wendrul@users.noreply.github.com>
Co-authored-by: Alexander Petric <alpetric@users.noreply.github.com>
Co-authored-by: HugoCasa <hugo@casademont.ch>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-04-14 16:25:41 +02:00

632 lines
18 KiB
Svelte

<script context="module">
const dynamicTemplateRegexPairs = buildPrefixRegex([
'flow_input',
'results',
'resource',
'variable'
])
</script>
<script lang="ts">
import type { Schema } from '$lib/common'
import type { InputCat } from '$lib/utils'
import { createEventDispatcher, getContext } from 'svelte'
import ArgInput from './ArgInput.svelte'
import FieldHeader from './FieldHeader.svelte'
import DynamicInputHelpBox from './flows/content/DynamicInputHelpBox.svelte'
import type { PropPickerWrapperContext } from './flows/propPicker/PropPickerWrapper.svelte'
import { codeToStaticTemplate, getDefaultExpr } from './flows/utils'
import SimpleEditor from './SimpleEditor.svelte'
import { Button } from '$lib/components/common'
import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte'
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
import { tick } from 'svelte'
import { fade } from 'svelte/transition'
import { buildPrefixRegex } from './flows/previousResults'
import type VariableEditor from './VariableEditor.svelte'
import type ItemPicker from './ItemPicker.svelte'
import type { InputTransform } from '$lib/gen'
import TemplateEditor from './TemplateEditor.svelte'
import { setInputCat as computeInputCat, isCodeInjection } from '$lib/utils'
import { FunctionSquare, InfoIcon } from 'lucide-svelte'
import { getResourceTypes } from './resourceTypesStore'
import type { FlowCopilotContext } from './copilot/flow'
import StepInputGen from './copilot/StepInputGen.svelte'
import type { PickableProperties } from './flows/previousResults'
import { twMerge } from 'tailwind-merge'
import FlowPlugConnect from './FlowPlugConnect.svelte'
export let schema: Schema | { properties?: Record<string, any>; required?: string[] }
export let arg: InputTransform | any
export let argName: string
export let headerTooltip: string | undefined = undefined
export let headerTooltipIconClass = ''
export let HeaderTooltipIcon = InfoIcon
export let extraLib: string = 'missing extraLib'
export let inputCheck: boolean = true
export let previousModuleId: string | undefined
export let pickForField: string | undefined = undefined
export let variableEditor: VariableEditor | undefined = undefined
export let itemPicker: ItemPicker | undefined = undefined
export let noDynamicToggle = false
export let argExtra: Record<string, any> = {}
export let pickableProperties: PickableProperties | undefined = undefined
export let enableAi = false
export let hideHelpButton = false
let monaco: SimpleEditor | undefined = undefined
let monacoTemplate: TemplateEditor | undefined = undefined
let argInput: ArgInput | undefined = undefined
let focusedPrev = false
const dispatch = createEventDispatcher()
$: inputCat = computeInputCat(
schema?.properties?.[argName].type,
schema?.properties?.[argName].format,
schema?.properties?.[argName].items?.type,
schema?.properties?.[argName].enum,
schema?.properties?.[argName].contentEncoding
)
let propertyType = getPropertyType(arg)
const { shouldUpdatePropertyType, exprsToSet } =
getContext<FlowCopilotContext | undefined>('FlowCopilotContext') || {}
const propPickerWrapperContext: PropPickerWrapperContext | undefined =
getContext<PropPickerWrapperContext>('PropPickerWrapper')
const { inputMatches, focusProp, propPickerConfig, clearFocus } = propPickerWrapperContext ?? {}
function setExpr() {
const newArg = $exprsToSet?.[argName]
if (newArg) {
if (newArg.type === 'javascript') {
propertyType = 'javascript'
arg = {
type: 'javascript',
expr: newArg.expr
}
monaco?.setCode(arg.expr)
}
// copilot only sets javascript so static case is not handled
}
exprsToSet?.set({
...$exprsToSet,
[argName]: undefined
})
}
$: $exprsToSet?.[argName] && setExpr()
function updatePropertyType() {
propertyType = $shouldUpdatePropertyType?.[argName] || 'static'
shouldUpdatePropertyType?.set({
...$shouldUpdatePropertyType,
[argName]: undefined
})
}
$: $shouldUpdatePropertyType?.[argName] &&
arg?.type === $shouldUpdatePropertyType?.[argName] &&
updatePropertyType()
function getPropertyType(arg: InputTransform | any): 'static' | 'javascript' {
let type: 'static' | 'javascript' = arg?.type ?? 'static'
if (
type == 'javascript' &&
isStaticTemplate(inputCat) &&
(arg?.expr?.length === 0 || arg?.expr?.[0] === '`')
) {
const newValue = codeToStaticTemplate(arg.expr)
if (newValue) {
type = 'static'
arg.value = newValue
}
}
return type
}
function setPropertyType(rawValue: string) {
if (!arg) {
return
}
if (isCodeInjection(rawValue)) {
arg.expr = getDefaultExpr(
argName,
previousModuleId,
`\`${rawValue.toString().replaceAll('`', '\\`')}\``
)
arg.type = 'javascript'
propertyType = 'static'
} else {
if (arg.type === 'javascript' && propertyType === 'static') {
arg.type = 'static'
}
if (arg.type) {
propertyType = arg.type
}
}
}
let codeInjectionDetected = false
function checkCodeInjection(rawValue: string) {
if (!arg || !rawValue || rawValue.length < 3 || !dynamicTemplateRegexPairs) {
return undefined
}
if (rawValue.trim() !== rawValue) {
return undefined
}
const matches = dynamicTemplateRegexPairs.filter(({ regex }) => regex.test(rawValue))
if (matches.length > 0) {
return matches.map((m) => ({ word: m.word, value: rawValue }))
}
return undefined
}
async function setJavaScriptExpr(rawValue: string) {
arg = {
type: 'javascript',
expr: rawValue
}
propertyType = 'javascript'
monaco?.setCode('')
monaco?.insertAtCursor(rawValue)
await tick()
monaco?.focus()
await tick()
monaco?.setCursorToEnd()
}
function handleKeyUp(e: KeyboardEvent) {
if (
e.key === 'Tab' &&
isStaticTemplate(inputCat) &&
propertyType == 'static' &&
!noDynamicToggle &&
codeInjectionDetected
) {
setJavaScriptExpr(arg.value)
} else {
stepInputGen?.onKeyUp?.(e)
}
}
function isStaticTemplate(inputCat: InputCat) {
return inputCat === 'string' || inputCat === 'sql' || inputCat == 'yaml'
}
function connectProperty(rawValue: string) {
// Extract path from variable('x') or resource('x') format
const varMatch = rawValue.match(/^variable\('([^']+)'\)$/)
const resourceMatch = rawValue.match(/^resource\('([^']+)'\)$/)
if (varMatch) {
arg.type = 'static'
propertyType = 'static'
arg.value = '$var:' + varMatch[1]
monacoTemplate?.setCode(arg.value)
} else if (resourceMatch) {
arg.type = 'static'
propertyType = 'static'
arg.value = '$res:' + resourceMatch[1]
monacoTemplate?.setCode(arg.value)
} else {
arg.expr = getDefaultExpr(undefined, previousModuleId, rawValue)
arg.type = 'javascript'
propertyType = 'javascript'
monaco?.setCode(arg.expr)
}
}
function onFocus() {
focused = true
if (isStaticTemplate(inputCat)) {
focusProp?.(argName, 'append', (path) => {
const toAppend = `\$\{${path}}`
arg.value = `${arg.value ?? ''}${toAppend}`
monacoTemplate?.setCode(arg.value)
setPropertyType(arg.value)
argInput?.focus()
return false
})
} else {
focusProp?.(argName, 'insert', (path) => {
arg.expr = path
arg.type = 'javascript'
propertyType = 'javascript'
monaco?.setCode(arg.expr)
return true
})
}
}
$: updateStaticInput(inputCat, propertyType, arg)
function updateStaticInput(
inputCat: InputCat,
propertyType: 'static' | 'javascript',
arg: InputTransform | any
) {
if (!isStaticTemplate(inputCat)) {
return
}
if (propertyType == 'static') {
setPropertyType(arg?.value)
codeInjectionDetected = checkCodeInjection(arg?.value) != undefined
} else if (propertyType == 'javascript' && focused && inputMatches) {
// setPropertyType(arg?.expr)
$inputMatches = checkCodeInjection(arg?.expr)
}
}
function setDefaultCode() {
if (!arg?.value) {
monacoTemplate?.setCode(schema.properties?.[argName].default)
}
}
function updateFocused(newFocused: boolean) {
if (focusedPrev && !newFocused && inputMatches) {
$inputMatches = undefined
}
focusedPrev = focused
}
$: updateFocused(focused)
$: schema?.properties?.[argName].default && setDefaultCode()
let resourceTypes: string[] | undefined = undefined
async function loadResourceTypes() {
resourceTypes = await getResourceTypes()
}
let focused = false
let stepInputGen: StepInputGen | undefined = undefined
loadResourceTypes()
$: connecting =
$propPickerConfig?.propName == argName && $propPickerConfig?.insertionMode == 'connect'
</script>
{#if arg != undefined}
<div
class={twMerge(
'pl-2 pt-2 pb-2 ml-2 relative hover:bg-surface hover:shadow-md transition-all duration-200',
$propPickerConfig?.propName == argName
? 'bg-surface border-l-4 border-blue-500 shadow-md rounded-l-md z-50 '
: 'hover:rounded-md',
$$props.class
)}
>
<div class="flex flex-row justify-between gap-1 pb-1 px-2">
<div class="flex flex-wrap grow">
<FieldHeader
label={argName}
simpleTooltip={headerTooltip}
simpleTooltipIconClass={headerTooltipIconClass}
SimpleTooltipIcon={HeaderTooltipIcon}
format={schema?.properties?.[argName].format}
contentEncoding={schema?.properties?.[argName].contentEncoding}
required={schema.required?.includes(argName)}
type={schema.properties?.[argName].type}
/>
{#if isStaticTemplate(inputCat)}
<div>
<span
class="bg-blue-100 text-blue-800 text-sm font-medium mr-2 px-2.5 !py-0.5 rounded ml-2 {propertyType ==
'static' && arg.type === 'javascript'
? 'visible'
: 'invisible'}"
>
{'${...}'}
</span>
</div>
{/if}
</div>
{#if !noDynamicToggle}
<div class="flex flex-row gap-x-2 gap-y-1 flex-wrap z-10 items-center">
{#if enableAi}
<StepInputGen
bind:this={stepInputGen}
{focused}
{arg}
schemaProperty={schema?.properties?.[argName]}
showPopup={(isStaticTemplate(inputCat) && propertyType == 'static') ||
propertyType === undefined ||
propertyType === 'static' ||
arg?.expr?.length > 0}
on:showExpr={(e) => {
setTimeout(() => {
if (monaco && propertyType === 'javascript') {
monaco.setSuggestion(e.detail)
}
}, 0)
}}
on:setExpr={(e) => {
arg = {
type: 'javascript',
expr: e.detail
}
propertyType = 'javascript'
monaco?.setCode('')
monaco?.insertAtCursor(e.detail)
}}
{pickableProperties}
{argName}
/>
{/if}
<div>
<ToggleButtonGroup
selected={propertyType}
let:item
on:selected={(e) => {
if (e.detail == propertyType) return
const staticTemplate = isStaticTemplate(inputCat)
if (e.detail === 'javascript') {
if (arg.expr == undefined) {
arg.expr = getDefaultExpr(
argName,
previousModuleId,
staticTemplate
? `\`${arg?.value?.toString().replaceAll('`', '\\`') ?? ''}\``
: arg.value
? '(' + JSON.stringify(arg?.value, null, 4) + ')'
: ''
)
}
if (arg) {
arg.value = undefined
arg.type = 'javascript'
}
propertyType = 'javascript'
} else {
if (staticTemplate) {
if (arg) {
arg.value = codeToStaticTemplate(arg.expr)
arg.expr = undefined
}
setPropertyType(arg?.value)
} else if (inputCat == 'list' || inputCat == 'object') {
if (arg) {
try {
let newExpr = arg.expr
if (newExpr.startsWith('(') && newExpr.endsWith(')')) {
newExpr = newExpr.slice(1, -1)
}
arg.value = JSON.parse(newExpr)
} catch (e) {
arg.value = undefined
}
arg.expr = undefined
arg.type = 'static'
}
} else {
if (arg) {
arg.type = 'static'
arg.value = undefined
arg.expr = undefined
}
}
propertyType = 'static'
}
}}
>
{#if isStaticTemplate(inputCat)}
<ToggleButton
tooltip={`Write text or surround javascript with \`\$\{\` and \`\}\`. Use \`results\` to connect to another node\'s output.`}
light
value="static"
size="xs2"
label={'${}'}
{item}
/>
{:else}
<ToggleButton small label="Static" value="static" {item} />
{/if}
{#if codeInjectionDetected && propertyType == 'static'}
<Button
size="xs2"
color="light"
btnClasses="font-normal text-xs w-fit bg-green-100 text-green-800 hover:bg-green-100 dark:text-green-300 dark:bg-green-700 dark:hover:bg-green-600"
on:click={() => setJavaScriptExpr(arg.value)}
>
<span class="font-normal whitespace-nowrap flex gap-2 items-center"
><FunctionSquare size={14} /> detected -
<span class="font-bold">TAB</span>
</span>
</Button>
{:else}
<ToggleButton
small
light
tooltip="JavaScript expression ('flow_input' or 'results')."
value="javascript"
icon={FunctionSquare}
{item}
/>
{/if}
</ToggleButtonGroup>
</div>
{#if propPickerWrapperContext}
<FlowPlugConnect
id="flow-editor-plug"
{connecting}
on:click={() => {
if (
$propPickerConfig?.propName == argName &&
$propPickerConfig?.insertionMode == 'connect'
) {
clearFocus()
} else {
focusProp?.(argName, 'connect', (path) => {
connectProperty(path)
dispatch('change', { argName })
return true
})
}
}}
/>
{/if}
</div>
{/if}
</div>
<div class="max-w-xs"></div>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="relative" on:keyup={handleKeyUp}>
<!-- {#if $propPickerConfig?.propName == argName && $propPickerConfig?.insertionMode == 'connect'}
<span
class={'text-white z-50 px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute top-0 right-0 bg-blue-500'}
>
Connect input &rightarrow;
</span>
{/if} -->
<!-- {inputCat}
{propertyType} -->
<div class="relative flex flex-row items-top gap-2 justify-between">
<div class="min-w-0 grow">
{#if isStaticTemplate(inputCat) && propertyType == 'static' && !noDynamicToggle}
{#if argName && schema?.properties?.[argName]?.description}
<div class="text-xs italic pb-1 text-secondary">
<pre class="font-main">{schema.properties[argName].description}</pre>
</div>
{/if}
<div class="mt-2 min-h-[28px]">
{#if arg}
<TemplateEditor
bind:this={monacoTemplate}
{extraLib}
on:focus={onFocus}
on:blur={() => {
focused = false
}}
bind:code={arg.value}
fontSize={14}
on:change={() => {
dispatch('change', { argName, arg })
}}
/>
{/if}
</div>
{:else if (propertyType === undefined || propertyType == 'static') && schema?.properties?.[argName]}
<ArgInput
{resourceTypes}
noMargin
compact
bind:this={argInput}
on:focus={onFocus}
on:blur={() => {
focused = false
}}
shouldDispatchChanges
on:change={() => {
dispatch('change', { argName, arg })
}}
label={argName}
bind:editor={monaco}
bind:description={schema.properties[argName].description}
bind:value={arg.value}
type={schema.properties[argName].type}
oneOf={schema.properties[argName].oneOf}
required={schema.required?.includes(argName)}
bind:pattern={schema.properties[argName].pattern}
bind:valid={inputCheck}
defaultValue={schema.properties[argName].default}
bind:enum_={schema.properties[argName].enum}
bind:format={schema.properties[argName].format}
contentEncoding={schema.properties[argName].contentEncoding}
bind:itemsType={schema.properties[argName].items}
properties={schema.properties[argName].properties}
nestedRequired={schema.properties[argName].required}
displayHeader={false}
extra={argExtra}
{variableEditor}
{itemPicker}
bind:pickForField
showSchemaExplorer
nullable={schema.properties[argName].nullable}
bind:title={schema.properties[argName].title}
bind:placeholder={schema.properties[argName].placeholder}
/>
{:else if arg.expr != undefined}
<div class="border mt-2">
<SimpleEditor
bind:this={monaco}
bind:code={arg.expr}
on:change={() => {
dispatch('change', { argName, arg })
}}
{extraLib}
lang="javascript"
shouldBindKey={false}
on:focus={() => {
focused = true
focusProp?.(argName, 'insert', (path) => {
monaco?.insertAtCursor(path)
return false
})
}}
on:change={() => {
dispatch('change', { argName, arg })
}}
on:blur={() => {
focused = false
}}
autoHeight
/>
</div>
{#if !hideHelpButton}
<DynamicInputHelpBox />
{/if}
<div class="mb-2"></div>
{:else}
Not recognized input type {argName} ({arg.expr}, {propertyType})
<div class="flex mt-2">
<Button
variant="border"
size="xs"
on:click={() => {
arg.expr = ''
}}>Set expr to empty string</Button
></div
>
{/if}
</div>
{#if $propPickerConfig?.propName == argName}
<div
class="text-blue-500 absolute top-2 lg:-right-2.5 -right-1"
in:fade={{ duration: 200 }}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="24 24 12 12 24 0" />
</svg>
</div>
{:else}
<div class="w-0"></div>
{/if}
</div>
</div>
</div>
{/if}