mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
remove connected from runnable inputs
This commit is contained in:
@@ -145,7 +145,7 @@
|
||||
const input = inputs[key]
|
||||
|
||||
if (
|
||||
['static', 'eval', 'connected'].includes(input.type) &&
|
||||
['static', 'eval', 'connected', 'evalv2'].includes(input.type) &&
|
||||
schemaStripped !== undefined &&
|
||||
schemaStripped.properties
|
||||
) {
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
Click on the output of the component you want to connect to on the left panel.
|
||||
<div class="my-2">
|
||||
<ol class="list-disc flex gap-2 flex-col">
|
||||
<li>
|
||||
You can also navigate your app in a viewer mode: You won't be able to fire any events.
|
||||
</li>
|
||||
<li> App is in a frozen state. </li>
|
||||
<li> Clicking on a component will open the component's output on the left. </li>
|
||||
<li> Hovering an other component will highlight its outputs in orange. </li>
|
||||
<li> Hover on a component to see its output</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { parseOutputs } from '$lib/infer'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import type { EvalV2AppInput } from '../inputType'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import type { App } from '../types'
|
||||
|
||||
export async function inferDeps(
|
||||
code: string,
|
||||
worldOutputs: Record<string, any>,
|
||||
componentInput: EvalV2AppInput,
|
||||
app: Writable<App>
|
||||
) {
|
||||
const outputs = await parseOutputs(code, true)
|
||||
if (outputs && componentInput) {
|
||||
const noutputs = outputs
|
||||
.filter(([key, id]) => key == 'row' || key == 'iter' || id in (worldOutputs[key] ?? {}))
|
||||
.map(([key, id]) => ({
|
||||
componentId: key,
|
||||
id: id
|
||||
}))
|
||||
if (!deepEqual(noutputs, componentInput.connections)) {
|
||||
componentInput.connections = noutputs
|
||||
app.update((old) => old)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@
|
||||
import { Delete, ExternalLink } from 'lucide-svelte'
|
||||
import GridCondition from './GridCondition.svelte'
|
||||
import { isTriggerable } from './script/utils'
|
||||
import ScriptSettingsSection from './script/shared/ScriptSettingsSection.svelte'
|
||||
|
||||
export let componentSettings: { item: GridItem; parent: string | undefined } | undefined =
|
||||
undefined
|
||||
@@ -171,7 +172,7 @@
|
||||
bind:componentInput={componentSettings.item.data.componentInput}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col w-full gap-2 my-2">
|
||||
<div class="flex flex-col w-full gap-2 mt-2">
|
||||
{#if componentSettings.item.data.componentInput.type === 'static'}
|
||||
<StaticInputEditor
|
||||
fieldType={componentInput?.fieldType}
|
||||
@@ -204,28 +205,24 @@
|
||||
{#key $stateId}
|
||||
{#if componentSettings.item.data.componentInput?.type === 'runnable'}
|
||||
{#if Object.keys(componentSettings.item.data.componentInput.fields ?? {}).length > 0}
|
||||
<div class="border w-full">
|
||||
<PanelSection
|
||||
title={`Runnable Inputs (${
|
||||
Object.keys(componentSettings.item.data.componentInput.fields ?? {}).length
|
||||
})`}
|
||||
>
|
||||
<svelte:fragment slot="action">
|
||||
<Tooltip>
|
||||
The runnable inputs are inferred from the inputs of the flow or script
|
||||
parameters this component is attached to.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
<div class="w-full">
|
||||
<div class="flex flex-row items-center gap-2 text-sm font-semibold">
|
||||
Runnable Inputs
|
||||
|
||||
<InputsSpecsEditor
|
||||
id={component.id}
|
||||
shouldCapitalize={false}
|
||||
displayType
|
||||
bind:inputSpecs={componentSettings.item.data.componentInput.fields}
|
||||
userInputEnabled={component.type === 'formcomponent' ||
|
||||
component.type === 'formbuttoncomponent'}
|
||||
/>
|
||||
</PanelSection>
|
||||
<Tooltip wrapperClass="flex">
|
||||
The runnable inputs are inferred from the inputs of the flow or script
|
||||
parameters this component is attached to.
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<InputsSpecsEditor
|
||||
id={component.id}
|
||||
shouldCapitalize={false}
|
||||
displayType
|
||||
bind:inputSpecs={componentSettings.item.data.componentInput.fields}
|
||||
userInputEnabled={component.type === 'formcomponent' ||
|
||||
component.type === 'formbuttoncomponent'}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
import type { InputConnection, InputType, UploadAppInput } from '../../inputType'
|
||||
import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte'
|
||||
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
|
||||
import { FunctionSquare, Pen, Plug2, Upload, User } from 'lucide-svelte'
|
||||
import { FunctionSquare, Pen, Plug, Plug2, Upload, User } from 'lucide-svelte'
|
||||
import { fieldTypeToTsType } from '../../utils'
|
||||
import EvalV2InputEditor from './inputEditor/EvalV2InputEditor.svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: RichConfiguration
|
||||
@@ -34,11 +35,18 @@
|
||||
|
||||
const { connectingInput, app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let evalV2editor: EvalV2InputEditor
|
||||
function applyConnection(connection: InputConnection) {
|
||||
if (componentInput.type === 'connected') {
|
||||
componentInput.connection = connection
|
||||
$app = $app
|
||||
const expr = `${connection.componentId}.${connection.path}`
|
||||
//@ts-ignore
|
||||
componentInput = {
|
||||
...componentInput,
|
||||
type: 'evalv2',
|
||||
expr: expr,
|
||||
connections: [{ componentId: connection.componentId, id: connection.path.split('.')[0] }]
|
||||
}
|
||||
evalV2editor.setCode(expr)
|
||||
$app = $app
|
||||
}
|
||||
|
||||
$: if (componentInput == undefined) {
|
||||
@@ -75,7 +83,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class={classNames('flex gap-x-2 gap-y-1 flex-wrap justify-end items-center')}>
|
||||
<div class={classNames('flex gap-x-2 gap-y-1 justify-end items-center')}>
|
||||
{#if componentInput?.type}
|
||||
<ToggleButtonGroup
|
||||
class="h-7"
|
||||
@@ -104,12 +112,30 @@
|
||||
{#if fileUpload}
|
||||
<ToggleButton value="upload" icon={Upload} iconOnly tooltip="Upload" />
|
||||
{/if}
|
||||
<ToggleButton value="connected" icon={Plug2} iconOnly tooltip="Connect" />
|
||||
{#if componentInput?.type === 'connected'}
|
||||
<ToggleButton value="connected" icon={Plug2} iconOnly tooltip="Connect" />
|
||||
{/if}
|
||||
{#if componentInput?.type === 'eval'}
|
||||
<ToggleButton value="eval" icon={FunctionSquare} iconOnly tooltip="Eval Legacy" />
|
||||
{/if}
|
||||
<ToggleButton value="evalv2" icon={FunctionSquare} iconOnly tooltip="Eval" />
|
||||
</ToggleButtonGroup>
|
||||
<Button
|
||||
size="xs"
|
||||
variant="border"
|
||||
color="light"
|
||||
title="Connect"
|
||||
on:click={() => {
|
||||
$connectingInput = {
|
||||
opened: true,
|
||||
input: undefined,
|
||||
hoveredComponent: undefined,
|
||||
onConnect: applyConnection
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Plug size={12} />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,7 +158,7 @@
|
||||
{:else if componentInput?.type === 'eval'}
|
||||
<EvalInputEditor {id} bind:componentInput />
|
||||
{:else if componentInput?.type === 'evalv2'}
|
||||
<EvalV2InputEditor {id} bind:componentInput />
|
||||
<EvalV2InputEditor bind:this={evalV2editor} {id} bind:componentInput />
|
||||
{:else if componentInput?.type === 'upload'}
|
||||
<UploadInputEditor bind:componentInput {fileUpload} />
|
||||
{:else if componentInput?.type === 'user'}
|
||||
|
||||
+13
-20
@@ -5,14 +5,18 @@
|
||||
import type { AppViewerContext } from '$lib/components/apps/types'
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import { buildExtraLib } from '$lib/components/apps/utils'
|
||||
import { parseOutputs } from '$lib/infer'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { inferDeps } from '../../appUtilsInfer'
|
||||
|
||||
export let componentInput: EvalV2AppInput | undefined
|
||||
export let id: string
|
||||
|
||||
const { onchange, worldStore, state, app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let editor: SimpleEditor
|
||||
export function setCode(code: string) {
|
||||
editor?.setCode(code)
|
||||
}
|
||||
|
||||
$: extraLib =
|
||||
componentInput?.expr && $worldStore
|
||||
? buildExtraLib($worldStore?.outputsById ?? {}, id, $state, false)
|
||||
@@ -24,27 +28,15 @@
|
||||
componentInput.expr != '' &&
|
||||
componentInput.connections == undefined
|
||||
) {
|
||||
inferDeps(componentInput.expr)
|
||||
inferDepsFromCode(componentInput.expr)
|
||||
}
|
||||
if (componentInput && componentInput.connections == undefined) {
|
||||
componentInput.connections = []
|
||||
}
|
||||
async function inferDeps(code: string) {
|
||||
const outputs = await parseOutputs(code, true)
|
||||
if (outputs && componentInput) {
|
||||
const noutputs = outputs
|
||||
.filter(
|
||||
([key, id]) =>
|
||||
key == 'row' || key == 'iter' || id in ($worldStore?.outputsById[key] ?? {})
|
||||
)
|
||||
.map(([key, id]) => ({
|
||||
componentId: key,
|
||||
id: id
|
||||
}))
|
||||
if (!deepEqual(noutputs, componentInput.connections)) {
|
||||
componentInput.connections = noutputs
|
||||
$app = $app
|
||||
}
|
||||
|
||||
function inferDepsFromCode(code: string) {
|
||||
if (componentInput) {
|
||||
inferDeps(code, $worldStore.outputsById, componentInput, app)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -52,6 +44,7 @@
|
||||
{#if componentInput?.type === 'evalv2'}
|
||||
<div class="border">
|
||||
<SimpleEditor
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={componentInput.expr}
|
||||
shouldBindKey={false}
|
||||
@@ -61,7 +54,7 @@
|
||||
if (onchange) {
|
||||
onchange()
|
||||
}
|
||||
inferDeps(e.detail.code)
|
||||
inferDepsFromCode(e.detail.code)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={'border divide-y'}>
|
||||
<div>
|
||||
<ScriptSettingHeader
|
||||
name={runnable?.type === 'runnableByName'
|
||||
? runnable.name
|
||||
@@ -59,7 +59,7 @@
|
||||
{actions}
|
||||
/>
|
||||
{#if !isTriggerable(appComponent.type)}
|
||||
<div class="flex items-center justify-between w-full px-2">
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<div class="flex flex-row items-center gap-2 text-xs"> Hide Refresh Button </div>
|
||||
|
||||
<Toggle bind:checked={appInput.hideRefreshButton} size="xs" />
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
export let tooltip: string | undefined = undefined
|
||||
</script>
|
||||
|
||||
<div class="p-2">
|
||||
<div class="py-2">
|
||||
<div class="mb-2 text-sm font-semibold justify-between flex flex-row items-center">
|
||||
{title}
|
||||
|
||||
|
||||
+32
-34
@@ -13,40 +13,38 @@
|
||||
$: checked = Boolean(appInput.transformer)
|
||||
</script>
|
||||
|
||||
<div class="p-2">
|
||||
<div class="text-sm font-semibold justify-between flex flex-row items-center">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
Transformer
|
||||
<div class="text-sm font-semibold justify-between flex flex-row items-center">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
Transformer
|
||||
|
||||
<Tooltip wrapperClass="flex">
|
||||
{"A transformer is an optional frontend script that is executed right after the component's script whose purpose is to do lightweight transformation in the browser. It takes the previous computation's result as `result`"}
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Button
|
||||
size="xs"
|
||||
color={checked ? 'red' : 'light'}
|
||||
variant="border"
|
||||
on:click={() => {
|
||||
if (appInput.transformer) {
|
||||
appInput.transformer = undefined
|
||||
} else {
|
||||
appInput.transformer = {
|
||||
language: 'frontend',
|
||||
content: 'return result'
|
||||
}
|
||||
$selectedComponentInEditor = id + '_transformer'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
{#if checked}
|
||||
<X size={16} />
|
||||
Remove
|
||||
{:else}
|
||||
<Plus size={16} />
|
||||
Add
|
||||
{/if}
|
||||
</div>
|
||||
</Button>
|
||||
<Tooltip wrapperClass="flex">
|
||||
{"A transformer is an optional frontend script that is executed right after the component's script whose purpose is to do lightweight transformation in the browser. It takes the previous computation's result as `result`"}
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Button
|
||||
size="xs"
|
||||
color={checked ? 'red' : 'light'}
|
||||
variant="border"
|
||||
on:click={() => {
|
||||
if (appInput.transformer) {
|
||||
appInput.transformer = undefined
|
||||
} else {
|
||||
appInput.transformer = {
|
||||
language: 'frontend',
|
||||
content: 'return result'
|
||||
}
|
||||
$selectedComponentInEditor = id + '_transformer'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
{#if checked}
|
||||
<X size={16} />
|
||||
Remove
|
||||
{:else}
|
||||
<Plus size={16} />
|
||||
Add
|
||||
{/if}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -48,6 +48,6 @@
|
||||
</Tab>
|
||||
|
||||
<svelte:fragment slot="text">
|
||||
{tooltip}
|
||||
{tooltip ?? label}
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
|
||||
Reference in New Issue
Block a user