diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index b3f1105a19..a184eb2184 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -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 - })
diff --git a/frontend/src/lib/components/FlowPreviewContent.svelte b/frontend/src/lib/components/FlowPreviewContent.svelte index 07b2965811..11a51c7046 100644 --- a/frontend/src/lib/components/FlowPreviewContent.svelte +++ b/frontend/src/lib/components/FlowPreviewContent.svelte @@ -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} diff --git a/frontend/src/lib/components/ModulePreview.svelte b/frontend/src/lib/components/ModulePreview.svelte index 7ab472c826..109f0293cf 100644 --- a/frontend/src/lib/components/ModulePreview.svelte +++ b/frontend/src/lib/components/ModulePreview.svelte @@ -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 = {} + 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 + } } } @@ -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}
{/if} -
- + + +
+ {:else} - + {/if} diff --git a/frontend/src/lib/components/TestJobLoader.svelte b/frontend/src/lib/components/TestJobLoader.svelte index e2981c84f7..f3838a3a2e 100644 --- a/frontend/src/lib/components/TestJobLoader.svelte +++ b/frontend/src/lib/components/TestJobLoader.svelte @@ -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) }) diff --git a/frontend/src/lib/components/common/tabs/TabContent.svelte b/frontend/src/lib/components/common/tabs/TabContent.svelte index 2c4e8b3bd4..938bfb91ca 100644 --- a/frontend/src/lib/components/common/tabs/TabContent.svelte +++ b/frontend/src/lib/components/common/tabs/TabContent.svelte @@ -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('Tabs') -{#if value === $selected} -
+{#if value === $selected || alwaysMounted} +
{/if} diff --git a/frontend/src/lib/components/flows/content/FlowFailureModule.svelte b/frontend/src/lib/components/flows/content/FlowFailureModule.svelte index f31c99178d..a36bdae218 100644 --- a/frontend/src/lib/components/flows/content/FlowFailureModule.svelte +++ b/frontend/src/lib/components/flows/content/FlowFailureModule.svelte @@ -12,7 +12,7 @@ {#if $flowStore.value.failure_module} { diff --git a/frontend/src/lib/components/flows/content/FlowModule.svelte b/frontend/src/lib/components/flows/content/FlowModule.svelte index 85c68081d1..b070b2a358 100644 --- a/frontend/src/lib/components/flows/content/FlowModule.svelte +++ b/frontend/src/lib/components/flows/content/FlowModule.svelte @@ -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') export let flowModule: FlowModule - export let args: Record = {} + export let previewArgs: Record = {} 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(fn: (arg: T) => Promise<[FlowModule, FlowModuleState]>, arg: T) { const [module, moduleState] = await fn(arg) - flowModule = module - flowModuleState = moduleState - } - - async function applyState(fn: (arg: T) => Promise, 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 @@ } + +
@@ -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)} />
@@ -138,7 +158,7 @@ - + Inputs Test {#if !$selectedId.includes('failure')} @@ -159,8 +179,13 @@ /> - - + + diff --git a/frontend/src/lib/components/flows/content/FlowModuleWrapper.svelte b/frontend/src/lib/components/flows/content/FlowModuleWrapper.svelte index d9fe5f8989..9469660fd1 100644 --- a/frontend/src/lib/components/flows/content/FlowModuleWrapper.svelte +++ b/frontend/src/lib/components/flows/content/FlowModuleWrapper.svelte @@ -19,7 +19,7 @@ {#each [$flowStateStore.modules[parentIndex].childFlowModules] as state} {#if mod.type == 'forloopflow' && state != undefined} { @@ -37,9 +37,9 @@ {/if} {/each} {/each} -{:else} +{:else if $flowStore.value.modules[parentIndex]} { diff --git a/frontend/src/lib/components/flows/flowState.ts b/frontend/src/lib/components/flows/flowState.ts index 3cc953c8d7..506d9786a5 100644 --- a/frontend/src/lib/components/flows/flowState.ts +++ b/frontend/src/lib/components/flows/flowState.ts @@ -6,6 +6,7 @@ import { emptyFlowModuleState, isEmptyFlowModule, loadFlowModuleSchema } from '. export type FlowModuleState = { schema: Schema childFlowModules?: FlowModuleState[] + previewArgs?: any previewResult?: any } diff --git a/frontend/src/lib/components/flows/flowStateUtils.ts b/frontend/src/lib/components/flows/flowStateUtils.ts index 8ad4f05d7b..b22a74c48d 100644 --- a/frontend/src/lib/components/flows/flowStateUtils.ts +++ b/frontend/src/lib/components/flows/flowStateUtils.ts @@ -200,21 +200,22 @@ export function getStepPropPicker( flowState: FlowState, args: Record ): 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 + }) +} +