remove connected from runnable inputs

This commit is contained in:
Ruben Fiszel
2023-08-24 00:59:03 +02:00
parent 35bf7b0e53
commit de3369706d
10 changed files with 130 additions and 92 deletions
@@ -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'}
@@ -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>
@@ -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" />
@@ -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}
@@ -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>