fix: prop picker values correspond to test values (#628)

* progress

* progress
This commit is contained in:
Ruben Fiszel
2022-09-27 03:29:32 +02:00
committed by GitHub
parent d2e5168222
commit 4e791b039d
11 changed files with 158 additions and 132 deletions
@@ -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
+28 -15
View File
@@ -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
})
}