mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-12 00:06:14 +00:00
fix: prop picker values correspond to test values (#628)
* progress * progress
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
} from '$lib/utils'
|
||||
import { faGlobe } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Breadcrumb, BreadcrumbItem } from 'flowbite-svelte'
|
||||
import { onDestroy, onMount, setContext } from 'svelte'
|
||||
import { onMount, setContext } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { writable } from 'svelte/store'
|
||||
import CenteredPage from './CenteredPage.svelte'
|
||||
@@ -163,13 +163,6 @@
|
||||
onMount(() => {
|
||||
loadHubScripts()
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
//@ts-ignore
|
||||
$flowStore = undefined
|
||||
//@ts-ignore
|
||||
$flowStateStore = undefined
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col flex-1 h-full">
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
const [parentIndex] = $selectedId.split('-')
|
||||
const upToIndex =
|
||||
previewMode === 'upTo' ? Number(parentIndex) + 1 : $flowStateStore.modules.length
|
||||
mapJobResultsToFlowState(e.detail, 'upto', upToIndex, undefined)
|
||||
mapJobResultsToFlowState(e.detail, upToIndex)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import { mapJobResultsToFlowState } from './flows/flowStateUtils'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { faRotateRight } from '@fortawesome/free-solid-svg-icons'
|
||||
import { flowStateStore } from './flows/flowState'
|
||||
|
||||
let testJobLoader: TestJobLoader
|
||||
|
||||
@@ -21,9 +22,14 @@
|
||||
|
||||
export let mod: FlowModule
|
||||
export let schema: Schema
|
||||
export let indices: [number, number | undefined]
|
||||
|
||||
let stepArgs: Record<string, any> = {}
|
||||
|
||||
export function runTestWithStepArgs() {
|
||||
runTest(stepArgs)
|
||||
}
|
||||
|
||||
export async function runTest(args: any) {
|
||||
const val = mod.value
|
||||
if (val.type == 'rawscript') {
|
||||
@@ -38,8 +44,20 @@
|
||||
}
|
||||
|
||||
function jobDone() {
|
||||
if (testJob && !testJob.canceled && testJob.type == 'CompletedJob') {
|
||||
//mapJobResultsToFlowState(testJob.result, 'justthis', 0, 0)
|
||||
if (testJob && !testJob.canceled && testJob.type == 'CompletedJob' && `result` in testJob) {
|
||||
const result = testJob.result
|
||||
const pMod = $flowStateStore.modules[indices[0]]
|
||||
if (pMod) {
|
||||
if (indices[1] != undefined && pMod.childFlowModules) {
|
||||
const cMod = pMod.childFlowModules[indices[1]]
|
||||
if (cMod) {
|
||||
cMod.previewResult = result
|
||||
}
|
||||
} else {
|
||||
pMod.previewResult = result
|
||||
}
|
||||
$flowStateStore.modules[indices[0]] = pMod
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -57,9 +75,9 @@
|
||||
runnable={{ summary: mod.summary ?? '', schema, description: '' }}
|
||||
runAction={(_, args) => runTest(args)}
|
||||
schedulable={false}
|
||||
buttonText="Test just this step"
|
||||
buttonText="Test just this step (Ctrl+Enter)"
|
||||
detailed={false}
|
||||
args={stepArgs}
|
||||
bind:args={stepArgs}
|
||||
/>
|
||||
{#if testIsLoading}
|
||||
<Button
|
||||
|
||||
@@ -103,30 +103,43 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex justify-between mt-2 md:mt-6 mb-6">
|
||||
<button
|
||||
type="submit"
|
||||
class="mr-6 text-sm underline text-gray-700 inline-flex items-center"
|
||||
on:click={() => {
|
||||
viewOptions = !viewOptions
|
||||
}}
|
||||
>
|
||||
{#if schedulable}
|
||||
{#if schedulable}
|
||||
<div class="flex justify-between mt-2 md:mt-6 mb-6">
|
||||
<button
|
||||
type="submit"
|
||||
class="mr-6 text-sm underline text-gray-700 inline-flex items-center"
|
||||
on:click={() => {
|
||||
viewOptions = !viewOptions
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
Schedule to run later
|
||||
<Icon data={viewOptions ? faChevronUp : faChevronDown} scale={0.5} />
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isValid}
|
||||
class="{isValid ? 'default-button' : 'default-button-disabled'} w-min px-6"
|
||||
on:click={() => {
|
||||
runAction(scheduledForStr, args)
|
||||
}}
|
||||
>
|
||||
{scheduledForStr ? 'Schedule run to a later time' : buttonText}
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isValid}
|
||||
class="{isValid ? 'default-button' : 'default-button-disabled'} w-min px-6"
|
||||
class="{isValid
|
||||
? 'default-button'
|
||||
: 'default-button-disabled'} w-full rounded rounded-md px-6 mb-4"
|
||||
on:click={() => {
|
||||
runAction(scheduledForStr, args)
|
||||
runAction(undefined, args)
|
||||
}}
|
||||
>
|
||||
{scheduledForStr ? 'Schedule run to a later time' : buttonText}
|
||||
{buttonText}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
} else {
|
||||
job = await JobService.getJob({ workspace: $workspaceStore!, id })
|
||||
}
|
||||
if (job?.type === 'CompletedJob') {
|
||||
if (job?.type === 'CompletedJob' && isLoading) {
|
||||
//only CompletedJob has success property
|
||||
dispatch('done', job)
|
||||
clearInterval(intervalId)
|
||||
@@ -103,21 +103,15 @@
|
||||
}
|
||||
|
||||
function syncer(id: string): void {
|
||||
if (syncIteration > ITERATIONS_BEFORE_SLOW_REFRESH) {
|
||||
loadTestJob(id)
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId)
|
||||
intervalId = setInterval(() => loadTestJob(id), 2000)
|
||||
}
|
||||
} else {
|
||||
syncIteration++
|
||||
loadTestJob(id)
|
||||
if (syncIteration == ITERATIONS_BEFORE_SLOW_REFRESH) {
|
||||
intervalId && clearInterval(intervalId)
|
||||
intervalId = setInterval(() => syncer(id), 2000)
|
||||
}
|
||||
syncIteration++
|
||||
loadTestJob(id)
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId)
|
||||
}
|
||||
intervalId && clearInterval(intervalId)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
import type { TabsContext } from './Tabs.svelte'
|
||||
|
||||
export let value: string
|
||||
export let alwaysMounted: boolean = false
|
||||
|
||||
let clazz: string = ''
|
||||
export { clazz as class }
|
||||
const { selected } = getContext<TabsContext>('Tabs')
|
||||
</script>
|
||||
|
||||
{#if value === $selected}
|
||||
<div class={clazz}>
|
||||
{#if value === $selected || alwaysMounted}
|
||||
<div class={`${clazz} ${value === $selected ? 'visible' : 'hidden'}`}>
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
{#if $flowStore.value.failure_module}
|
||||
<FlowModule
|
||||
args={previewArgs}
|
||||
previewArgs={previewArgs}
|
||||
bind:flowModule={$flowStore.value.failure_module}
|
||||
bind:flowModuleState={$flowStateStore.failureModule}
|
||||
on:delete={() => {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
fork,
|
||||
getStepPropPicker,
|
||||
isEmptyFlowModule,
|
||||
loadFlowModuleSchema,
|
||||
pickScript
|
||||
} from '$lib/components/flows/flowStateUtils'
|
||||
import { flowStore } from '$lib/components/flows/flowStore'
|
||||
@@ -30,39 +29,54 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
import FlowModuleAdvancedSettings from './FlowModuleAdvancedSettings.svelte'
|
||||
import { loadSchemaFromModule } from '../utils'
|
||||
|
||||
const { selectedId, select } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
export let flowModule: FlowModule
|
||||
export let args: Record<string, any> = {}
|
||||
export let previewArgs: Record<string, any> = {}
|
||||
export let flowModuleState: FlowModuleState
|
||||
|
||||
$: [parentIndex, childIndex] = $selectedId.split('-').map(Number)
|
||||
|
||||
let editor: Editor
|
||||
let modulePreview: ModulePreview
|
||||
let websocketAlive = { pyright: false, black: false, deno: false }
|
||||
let selected = 'inputs'
|
||||
|
||||
$: shouldPick = isEmptyFlowModule(flowModule)
|
||||
$: stepPropPicker = getStepPropPicker(
|
||||
$selectedId.split('-').map(Number),
|
||||
$flowStore.schema,
|
||||
$flowStateStore,
|
||||
args
|
||||
previewArgs
|
||||
)
|
||||
|
||||
function onKeyDown(event: KeyboardEvent) {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key == 'Enter') {
|
||||
event.preventDefault()
|
||||
selected = 'test'
|
||||
modulePreview?.runTestWithStepArgs()
|
||||
}
|
||||
}
|
||||
|
||||
async function apply<T>(fn: (arg: T) => Promise<[FlowModule, FlowModuleState]>, arg: T) {
|
||||
const [module, moduleState] = await fn(arg)
|
||||
|
||||
flowModule = module
|
||||
flowModuleState = moduleState
|
||||
}
|
||||
|
||||
async function applyState<T>(fn: (arg: T) => Promise<FlowModuleState>, arg: T) {
|
||||
flowModuleState = await fn(arg)
|
||||
if (
|
||||
JSON.stringify(flowModule) != JSON.stringify(module) ||
|
||||
JSON.stringify(flowModuleState) != JSON.stringify(moduleState)
|
||||
) {
|
||||
flowModule = module
|
||||
flowModuleState = moduleState
|
||||
}
|
||||
}
|
||||
|
||||
async function reload(flowModule: FlowModule) {
|
||||
applyState(loadFlowModuleSchema, flowModule)
|
||||
const { input_transforms, schema } = await loadSchemaFromModule(flowModule)
|
||||
|
||||
flowModuleState.schema = schema
|
||||
flowModule.input_transforms = input_transforms
|
||||
}
|
||||
|
||||
async function applyCreateLoop() {
|
||||
@@ -70,6 +84,8 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<div class="flex flex-col h-full ">
|
||||
<FlowCard {flowModule}>
|
||||
<svelte:fragment slot="header">
|
||||
@@ -131,6 +147,10 @@
|
||||
deno={flowModule.value.language === RawScript.language.DENO}
|
||||
lang={scriptLangToEditorLang(flowModule.value.language)}
|
||||
automaticLayout={true}
|
||||
cmdEnterAction={() => {
|
||||
selected = 'test'
|
||||
modulePreview?.runTestWithStepArgs()
|
||||
}}
|
||||
formatAction={() => reload(flowModule)}
|
||||
/>
|
||||
</div>
|
||||
@@ -138,7 +158,7 @@
|
||||
</top>
|
||||
|
||||
<down slot="down" class="flex flex-col flex-1 h-full">
|
||||
<Tabs selected="inputs">
|
||||
<Tabs bind:selected>
|
||||
<Tab value="inputs">Inputs</Tab>
|
||||
<Tab value="test">Test</Tab>
|
||||
{#if !$selectedId.includes('failure')}
|
||||
@@ -159,8 +179,13 @@
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</TabContent>
|
||||
<TabContent value="test" class="flex flex-col flex-1 h-full">
|
||||
<ModulePreview mod={flowModule} schema={flowModuleState.schema} />
|
||||
<TabContent value="test" class="flex flex-col flex-1 h-full" alwaysMounted={true}>
|
||||
<ModulePreview
|
||||
bind:this={modulePreview}
|
||||
mod={flowModule}
|
||||
schema={flowModuleState.schema}
|
||||
indices={[parentIndex, childIndex]}
|
||||
/>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="advanced" class="flex flex-col flex-1 h-full">
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
{#each [$flowStateStore.modules[parentIndex].childFlowModules] as state}
|
||||
{#if mod.type == 'forloopflow' && state != undefined}
|
||||
<FlowModule
|
||||
args={$previewArgs}
|
||||
previewArgs={$previewArgs}
|
||||
bind:flowModule={mod.modules[childIndex]}
|
||||
bind:flowModuleState={state[childIndex]}
|
||||
on:delete={() => {
|
||||
@@ -37,9 +37,9 @@
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
{:else}
|
||||
{:else if $flowStore.value.modules[parentIndex]}
|
||||
<FlowModule
|
||||
args={$previewArgs}
|
||||
previewArgs={$previewArgs}
|
||||
bind:flowModule={$flowStore.value.modules[parentIndex]}
|
||||
bind:flowModuleState={$flowStateStore.modules[parentIndex]}
|
||||
on:delete={() => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { emptyFlowModuleState, isEmptyFlowModule, loadFlowModuleSchema } from '.
|
||||
export type FlowModuleState = {
|
||||
schema: Schema
|
||||
childFlowModules?: FlowModuleState[]
|
||||
previewArgs?: any
|
||||
previewResult?: any
|
||||
}
|
||||
|
||||
|
||||
@@ -200,21 +200,22 @@ export function getStepPropPicker(
|
||||
flowState: FlowState,
|
||||
args: Record<string, any>
|
||||
): StepPropPicker {
|
||||
const isInsideLoop: boolean = indexes.length > 1
|
||||
const [parentIndex, childIndex] = indexes
|
||||
const isInsideLoop: boolean = childIndex !== undefined
|
||||
|
||||
const flowInput = schemaToObject(flowInputSchema, args)
|
||||
const results = getPreviousResults(flowState.modules, parentIndex)
|
||||
|
||||
|
||||
const lastResult =
|
||||
parentIndex == 0
|
||||
? flowInput
|
||||
: results.length > 0
|
||||
? results[results.length - 1]
|
||||
: NEVER_TESTED_THIS_FAR
|
||||
? results[results.length - 1]
|
||||
: NEVER_TESTED_THIS_FAR
|
||||
|
||||
if (isInsideLoop) {
|
||||
const forLoopFlowInput = {
|
||||
let forLoopFlowInput = {
|
||||
...flowInput,
|
||||
iter: {
|
||||
value: "Iteration's value",
|
||||
@@ -222,13 +223,8 @@ export function getStepPropPicker(
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(lastResult) && lastResult.length > 0) {
|
||||
const last = lastResult[lastResult.length - 1]
|
||||
|
||||
forLoopFlowInput.iter = {
|
||||
value: last,
|
||||
index: `Iteration's index (0 to ${lastResult.length - 1})`
|
||||
}
|
||||
if (flowState.modules[parentIndex]?.previewArgs) {
|
||||
forLoopFlowInput = flowState.modules[parentIndex]?.previewArgs
|
||||
}
|
||||
|
||||
const innerResults = getPreviousResults(
|
||||
@@ -240,8 +236,8 @@ export function getStepPropPicker(
|
||||
childIndex == 0
|
||||
? forLoopFlowInput
|
||||
: innerResults.length > 0
|
||||
? innerResults[innerResults.length - 1]
|
||||
: NEVER_TESTED_THIS_FAR
|
||||
? innerResults[innerResults.length - 1]
|
||||
: NEVER_TESTED_THIS_FAR
|
||||
|
||||
const extraLib = buildExtraLib(
|
||||
objectToTsType(forLoopFlowInput),
|
||||
@@ -292,64 +288,48 @@ export type JobResult = {
|
||||
loopJobs?: JobResult[]
|
||||
}
|
||||
|
||||
export function mapJobResultsToFlowState(
|
||||
jobs: JobResult,
|
||||
config: 'upto' | 'justthis',
|
||||
parentIndex: number,
|
||||
j: number | undefined
|
||||
): void {
|
||||
if (config === 'justthis') {
|
||||
const job = jobs.job as CompletedJob
|
||||
|
||||
flowStateStore.update((flowState: FlowState) => {
|
||||
if (flowState.modules) {
|
||||
const childFlowModules = flowState.modules[parentIndex].childFlowModules
|
||||
if (j && childFlowModules) {
|
||||
childFlowModules[j].previewResult = job.result
|
||||
flowState.modules[parentIndex].childFlowModules = childFlowModules
|
||||
} else {
|
||||
flowState.modules[parentIndex].previewResult = job.result
|
||||
}
|
||||
}
|
||||
|
||||
return flowState
|
||||
})
|
||||
} else {
|
||||
if (jobs.innerJobs.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const results = jobs.innerJobs.map(({ job, loopJobs }) => {
|
||||
if (Array.isArray(loopJobs) && loopJobs.length > 0) {
|
||||
return loopJobs.map(({ job }) => {
|
||||
if (job && 'result' in job) {
|
||||
return job.result
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (job && 'result' in job) {
|
||||
return job.result
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
flowStateStore.update((flowState: FlowState) => {
|
||||
if (!Array.isArray(flowState.modules)) {
|
||||
return flowState
|
||||
}
|
||||
|
||||
const modules = flowState.modules.map((flowModuleState: FlowModuleState, index: number) => {
|
||||
if (index <= parentIndex) {
|
||||
flowModuleState.previewResult = results[index]
|
||||
}
|
||||
|
||||
return flowModuleState
|
||||
})
|
||||
|
||||
return {
|
||||
modules,
|
||||
failureModule: flowState.failureModule
|
||||
}
|
||||
})
|
||||
function getResult(job: Job | undefined): Result | undefined {
|
||||
if (job && 'result' in job) {
|
||||
return job.result
|
||||
}
|
||||
}
|
||||
|
||||
export function mapJobResultsToFlowState(
|
||||
jobs: JobResult,
|
||||
upto: number
|
||||
): void {
|
||||
|
||||
const results = jobs.innerJobs.map(({ job, loopJobs }) => {
|
||||
if (loopJobs && loopJobs.length > 0) {
|
||||
return [job?.args, loopJobs.map(({ job }) => {
|
||||
return getResult(job)
|
||||
})]
|
||||
} else {
|
||||
return [job?.args, getResult(job)]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
const old = get(flowStateStore)
|
||||
const modules = old.modules.map((flowModuleState: FlowModuleState, index: number) => {
|
||||
if (results[index] && index <= upto) {
|
||||
if (results[index][1] != NEVER_TESTED_THIS_FAR || flowModuleState.previewResult == undefined) {
|
||||
flowModuleState.previewArgs = results[index][0]
|
||||
flowModuleState.previewResult = results[index][1]
|
||||
flowModuleState.childFlowModules?.map((innerMod, j) => {
|
||||
const lastLoopJob = jobs.innerJobs[index].loopJobs?.length ?? 0
|
||||
innerMod.previewResult = getResult(jobs.innerJobs[index].loopJobs?.[lastLoopJob - 1]?.innerJobs?.[j]?.job)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return flowModuleState
|
||||
})
|
||||
|
||||
flowStateStore.set({
|
||||
modules,
|
||||
failureModule: old.failureModule
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user