Files
windmill/frontend/src/lib/components/ModuleTest.svelte
T
Guilhem dc5e764d9d fix(frontend): load all flow jobs on page load (#6029)
* Add initial loading status for flow steps

* Add loading state

* reset module initial if test flow initial is reset

* ensure all jobs are loaded before unmouning the preview

* only use loadIndividualStepsStates when no history

* Revert "only use loadIndividualStepsStates when no history"

This reverts commit bfc37b7e7f.

* wait for all flow child to be loaded befor loading flowSteps

* Revert "wait for all flow child to be loaded befor loading flowSteps"

This reverts commit 7da81756b0.

* Load individual steps on flow load

* Add loading status in graph

* Use a context to manage initial state and save to local storage

* Handle new flow

* nit

* nit

* nit

* Prevent loading step when mock is enabled

* Load jobs based on last flow run

* Revert "Load jobs based on last flow run"

This reverts commit 212cb7f785.

* Change step initial display status

* nit

* Add parallelisation limit on step job loading
2025-06-25 13:07:49 +02:00

142 lines
4.0 KiB
Svelte

<script lang="ts" module>
type testModuleState = {
loading: boolean
instances: number
cancel?: () => void
}
let testModulesState = $state<Record<string, testModuleState>>({})
</script>
<script lang="ts">
import { ScriptService, type FlowModule, type Job } from '$lib/gen'
import { workspaceStore } from '$lib/stores'
import { getScriptByPath } from '$lib/scripts'
import { getContext, onMount } from 'svelte'
import type { FlowEditorContext } from './flows/types'
import TestJobLoader from './TestJobLoader.svelte'
import { getStepHistoryLoaderContext } from './stepHistoryLoader.svelte'
interface Props {
mod: FlowModule
testJob?: Job | undefined
testIsLoading?: boolean
noEditor?: boolean
scriptProgress?: any
}
let {
mod,
testJob = $bindable(undefined),
testIsLoading = $bindable(false),
noEditor = false,
scriptProgress = $bindable(undefined)
}: Props = $props()
const { flowStore, flowStateStore, pathStore, testSteps, previewArgs } =
getContext<FlowEditorContext>('FlowEditorContext')
let testJobLoader: TestJobLoader | undefined = $state(undefined)
let jobProgressReset: () => void = () => {}
let stepHistoryLoader = getStepHistoryLoaderContext()
export function runTestWithStepArgs() {
runTest(testSteps.getStepArgs(mod.id)?.value)
}
export function loadArgsAndRunTest() {
testSteps?.updateStepArgs(mod.id, $flowStateStore, flowStore?.val, previewArgs?.val)
runTest(testSteps.getStepArgs(mod.id)?.value)
}
export async function runTest(args: any) {
// Not defined if JobProgressBar not loaded
if (jobProgressReset) jobProgressReset()
testModulesState[mod.id].cancel = testJobLoader?.cancelJob
const val = mod.value
// let jobId: string | undefined = undefined
if (val.type == 'rawscript') {
await testJobLoader?.runPreview(
val.path ?? ($pathStore ?? '') + '/' + mod.id,
val.content,
val.language,
mod.id === 'preprocessor' ? { _ENTRYPOINT_OVERRIDE: 'preprocessor', ...args } : args,
flowStore?.val?.tag ?? val.tag
)
} else if (val.type == 'script') {
const script = val.hash
? await ScriptService.getScriptByHash({ workspace: $workspaceStore!, hash: val.hash })
: await getScriptByPath(val.path)
await testJobLoader?.runPreview(
val.path,
script.content,
script.language,
mod.id === 'preprocessor' ? { _ENTRYPOINT_OVERRIDE: 'preprocessor', ...args } : args,
flowStore?.val?.tag ?? (val.tag_override ? val.tag_override : script.tag),
script.lock,
val.hash ?? script.hash
)
} else if (val.type == 'flow') {
await testJobLoader?.runFlowByPath(val.path, args)
} else {
throw Error('Not supported module type')
}
}
function jobDone() {
if (testJob && !testJob.canceled && testJob.type == 'CompletedJob' && `result` in testJob) {
if ($flowStateStore[mod.id]) {
$flowStateStore[mod.id].previewResult = testJob.result
$flowStateStore[mod.id].previewSuccess = testJob.success
$flowStateStore[mod.id].previewJobId = testJob.id
$flowStateStore[mod.id].previewWorkspaceId = testJob.workspace_id
$flowStateStore = $flowStateStore
}
stepHistoryLoader?.resetInitial(mod.id)
}
testJob = undefined
}
export function cancelJob() {
testModulesState[mod.id]?.cancel?.()
}
$effect(() => {
testIsLoading = testModulesState[mod.id]?.loading ?? false
})
onMount(() => {
const modId = mod.id
testModulesState[modId] = {
...(testModulesState[modId] ?? { loading: false, instances: 0 }),
loading: testIsLoading,
instances: testModulesState[modId]!.instances + 1
}
return () => {
testModulesState[modId].instances -= 1
if (testModulesState[modId].instances < 1) {
delete testModulesState[modId]
}
}
})
</script>
<TestJobLoader
toastError={noEditor}
on:done={() => jobDone()}
bind:scriptProgress
bind:this={testJobLoader}
bind:isLoading={
() => testModulesState[mod.id]?.loading ?? false,
(v) =>
(testModulesState[mod.id] = {
...testModulesState[mod.id],
loading: v ?? false,
instances: testModulesState[mod.id]?.instances ?? 0
})
}
bind:job={testJob}
/>