fix: improve app decision tree behavior

This commit is contained in:
Ruben Fiszel
2025-08-11 15:29:17 +00:00
parent 845d02233b
commit fca5bb4f55
6 changed files with 80 additions and 81 deletions
@@ -370,6 +370,7 @@
return
}
try {
console.log('fixedOverflowWidgets', fixedOverflowWidgets)
editor = meditor.create(divEl as HTMLDivElement, {
...editorConfig(code ?? '', lang, automaticLayout, fixedOverflowWidgets),
model,
@@ -7,7 +7,11 @@
import InputValue from '../helpers/InputValue.svelte'
import InitializeComponent from '../helpers/InitializeComponent.svelte'
let { id, configuration, render }: {
let {
id,
configuration,
render
}: {
id: string
configuration: RichConfigurations
render: boolean
@@ -16,10 +20,9 @@
const { componentControl, worldStore, selectedComponent, connectingInput, mode } =
getContext<AppViewerContext>('AppViewerContext')
let resolvedConfig = $state(initConfig(
components['codeinputcomponent'].initialData.configuration,
configuration
))
let resolvedConfig = $state(
initConfig(components['codeinputcomponent'].initialData.configuration, configuration)
)
let code = $state<string | undefined>(undefined)
let placeholder = $state<string | undefined>(undefined)
@@ -28,9 +31,11 @@
let lastDefaultValue = $state<string | undefined>(undefined)
let lang = $derived(resolvedConfig?.lang ?? 'javascript')
let outputs = $state(initOutput($worldStore, id, {
result: ''
}))
let outputs = $state(
initOutput($worldStore, id, {
result: ''
})
)
$effect(() => {
if (defaultValue !== lastDefaultValue) {
@@ -96,9 +101,3 @@
{/await}
</div>
{/if}
<style lang="postcss">
:global(.suggest-widget) {
position: fixed !important;
}
</style>
@@ -13,6 +13,7 @@
import Badge from '$lib/components/common/badge/Badge.svelte'
import { getFirstNode, isDebugging } from '../../editor/settingsPanel/decisionTree/utils'
import InputValue from '../helpers/InputValue.svelte'
import { sendUserToast } from '$lib/toast'
interface Props {
id: string
@@ -42,10 +43,12 @@
}, {})
}
let counter = $state(0)
$effect(() => {
nodes
resolvedConditions = untrack(() => createResolvedConditions())
resolvedNext = untrack(() => createResolvedNext())
untrack(() => (counter += 1))
})
let everRender = $state(render)
@@ -112,6 +115,7 @@
return
}
}
sendUserToast('No next node was an available option', true)
}
function updateFocusedGrid(nodeId) {
currentNodeId = nodeId
@@ -177,30 +181,37 @@
<!-- {JSON.stringify(resolvedConditions)}
{JSON.stringify(resolvedNext)} -->
{#if Object.keys(resolvedConditions).length === nodes.length}
{#each nodes ?? [] as node (node.id)}
{#each node.next ?? [] as next, conditionIndex}
{#if next.condition}
{#key counter}
{#if Object.keys(resolvedConditions).length === nodes.length}
{#each nodes ?? [] as node (node.id)}
{#each node.next ?? [] as next, conditionIndex}
{#if next.condition}
<InputValue
key={`condition-${node.id}-${conditionIndex}`}
{id}
input={next.condition}
bind:value={resolvedConditions[node.id][conditionIndex]}
field={`condition-${node.id}-${conditionIndex}`}
/>
{/if}
{/each}
{/each}
{/if}
{#if Object.keys(resolvedConditions).length === nodes.length}
{#each nodes ?? [] as node (node.id)}
{#if node.allowed}
<InputValue
key={`condition-${node.id}-${conditionIndex}`}
key="allowed-{node.id}"
{id}
input={next.condition}
bind:value={resolvedConditions[node.id][conditionIndex]}
field={`condition-${node.id}-${conditionIndex}`}
input={node.allowed}
bind:value={resolvedNext[node.id]}
/>
{/if}
{/each}
{/each}
{/if}
{#if Object.keys(resolvedConditions).length === nodes.length}
{#each nodes ?? [] as node (node.id)}
{#if node.allowed}
<InputValue key="allowed" {id} input={node.allowed} bind:value={resolvedNext[node.id]} />
{/if}
{/each}
{/if}
{/if}
{/key}
{#each Object.keys(css ?? {}) as key (key)}
<ResolveStyle
{id}
@@ -1,6 +1,6 @@
<script lang="ts">
import { Alert, Button, Drawer, DrawerContent } from '$lib/components/common'
import { Network, Plus, Trash } from 'lucide-svelte'
import { Network, Trash } from 'lucide-svelte'
import type { AppComponent, DecisionTreeNode } from '../component'
import { Pane, Splitpanes } from 'svelte-splitpanes'
import { getContext, setContext } from 'svelte'
@@ -8,7 +8,7 @@
import Section from '$lib/components/Section.svelte'
import { writable } from 'svelte/store'
import DecisionTreePreview from './decisionTree/DecisionTreePreview.svelte'
import { addNewBranch, removeNode } from './decisionTree/utils'
import { removeNode } from './decisionTree/utils'
import Label from '$lib/components/Label.svelte'
import { debounce } from '$lib/utils'
import type { AppViewerContext } from '../../types'
@@ -38,17 +38,14 @@
let selectedNode = $derived(nodes?.find((node) => node.id == $selectedNodeId))
setContext('DecisionTreeEditor', { selectedNodeId })
let sortedSelectedNextNodes = $derived(
[...(selectedNode?.next ?? [])].sort((n1, n2) => n1.id.localeCompare(n2.id))
)
</script>
<Drawer bind:this={drawer} on:close={() => {}} on:open={() => {}} size="1200px">
<Drawer bind:this={drawer} size="1800px" on:close={() => {}} on:open={() => {}}>
<DrawerContent
title="Decision tree"
on:close={drawer.closeDrawer}
noPadding
forceOverflowVisible
tooltip="Decision tree graph editor"
>
<Splitpanes>
@@ -114,8 +111,8 @@
/>
</Label>
{#if selectedNode.next.length > 1 && sortedSelectedNextNodes}
{#each sortedSelectedNextNodes as subNode, index (subNode.id)}
{#if selectedNode.next.length > 1}
{#each selectedNode.next ?? [] as subNode, index (subNode.id)}
{#if subNode.condition}
<div class="flex flex-row gap-4 items-center w-full justify-center">
<div class="grow relative">
@@ -129,16 +126,22 @@
userInputEnabled={false}
shouldCapitalize={true}
resourceOnly={false}
fieldType={subNode.condition?.['fieldType']}
subFieldType={subNode.condition?.['subFieldType']}
format={subNode.condition?.['format']}
selectOptions={subNode.condition?.['selectOptions']}
tooltip={subNode.condition?.['tooltip']}
fileUpload={subNode.condition?.['fileUpload']}
placeholder={subNode.condition?.['placeholder']}
fieldType={'boolean'}
subFieldType={undefined}
format={undefined}
selectOptions={undefined}
tooltip={undefined}
fileUpload={undefined}
placeholder={undefined}
displayType={false}
fixedOverflowWidgets={false}
/>
{#if index == selectedNode.next.length - 1}
<div class="text-xs text-secondary">
If no branch evaluates to true, clicking next will show an error toast.
</div>
{/if}
<div class="flex flex-row gap-1 mt-2">
<Badge>
{`Next node id: ${subNode.id}`}
@@ -151,7 +154,6 @@
</div>
{/if}
{/each}
<Alert type="info" class="mt-4" title="Multiple branches" size="xs">
The conditions above are evaluated in order. The first condition that is met will
be the branch that is taken.
@@ -160,44 +162,25 @@
{#key selectedNode.id}
{#if selectedNode.allowed}
<InputsSpecEditor
key={`Can proceed to next step if:`}
customTitle={`Can proceed to next step if:`}
key={`allowed-${selectedNode.id}`}
bind:componentInput={selectedNode.allowed}
id={'allowed'}
id={component.id}
userInputEnabled={false}
shouldCapitalize={true}
fieldType={'boolean'}
subFieldType={undefined}
format={undefined}
selectOptions={undefined}
tooltip={undefined}
fileUpload={undefined}
placeholder={undefined}
resourceOnly={false}
fieldType={selectedNode.allowed?.['fieldType']}
subFieldType={selectedNode.allowed?.['subFieldType']}
format={selectedNode.allowed?.['format']}
selectOptions={selectedNode.allowed?.['selectOptions']}
tooltip={selectedNode.allowed?.['tooltip']}
fileUpload={selectedNode.allowed?.['fileUpload']}
placeholder={selectedNode.allowed?.['placeholder']}
customTitle={selectedNode.allowed?.['customTitle']}
displayType={false}
fixedOverflowWidgets={false}
/>
{/if}
{/key}
{#if selectedNode?.next.length > 0}
<div>
<Button
startIcon={{ icon: Plus }}
color="light"
variant="border"
size="xs"
on:click={() => {
if (!selectedNode) return
nodes = addNewBranch(nodes, selectedNode)
renderCount++
}}
>
Add branch
</Button>
</div>
{/if}
</Section>
{/if}
</div>
@@ -56,6 +56,7 @@
documentationLink?: string | undefined
markdownTooltip?: string | undefined
securedContext?: boolean
disabled?: boolean
}
let {
@@ -76,6 +77,7 @@
customTitle = undefined,
displayType = false,
allowTypeChange = true,
disabled = false,
shouldFormatExpression = false,
fixedOverflowWidgets = true,
loading = false,
@@ -274,6 +276,7 @@
{recomputeOnInputChanged}
{showOnDemandOnlyToggle}
{securedContext}
{disabled}
/>
{:else if componentInput?.type === 'upload'}
<UploadInputEditor bind:componentInput {fileUpload} />
@@ -22,6 +22,7 @@
recomputeOnInputChanged?: boolean
showOnDemandOnlyToggle?: boolean
securedContext?: boolean
disabled?: boolean
}
let {
@@ -32,7 +33,8 @@
acceptSelf = false,
recomputeOnInputChanged = true,
showOnDemandOnlyToggle = false,
securedContext = false
securedContext = false,
disabled = false
}: Props = $props()
const {
@@ -68,7 +70,6 @@
}
function inferDepsFromCode(code: string) {
console.log('inferDepsFromCode', id)
if (componentInput) {
inferDeps(code, $worldStore.outputsById, componentInput, app)
}
@@ -137,6 +138,7 @@
shouldBindKey={false}
{extraLib}
autoHeight
{disabled}
{fixedOverflowWidgets}
on:focus={() => {
focus = true