mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 00:02:13 +00:00
fix: improve app decision tree behavior
This commit is contained in:
@@ -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}
|
||||
|
||||
+29
-46
@@ -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} />
|
||||
|
||||
+4
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user