mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 16:02:24 +00:00
c8e1f65ac4
* draft flow diff * add missing import * cleaning * code cleaning * fix for recursive renderings * fix typo * cleaning --------- Co-authored-by: HugoCasa <hugo@casademont.ch>
272 lines
8.6 KiB
Svelte
272 lines
8.6 KiB
Svelte
<script lang="ts">
|
|
import {
|
|
type BranchAll,
|
|
type BranchOne,
|
|
type FlowModule,
|
|
type ForloopFlow,
|
|
type WhileloopFlow
|
|
} from '$lib/gen'
|
|
import { getContext } from 'svelte'
|
|
|
|
import type { FlowEditorContext } from '../types'
|
|
import FlowLoop from './FlowLoop.svelte'
|
|
import FlowModuleComponent from './FlowModuleComponent.svelte'
|
|
import FlowBranchAllWrapper from './FlowBranchAllWrapper.svelte'
|
|
import FlowBranchOneWrapper from './FlowBranchOneWrapper.svelte'
|
|
import {
|
|
createInlineScriptModule,
|
|
pickFlow,
|
|
pickScript
|
|
} from '$lib/components/flows/flowStateUtils'
|
|
import FlowInputs from './FlowInputs.svelte'
|
|
import { Alert } from '$lib/components/common'
|
|
import FlowInputsFlow from './FlowInputsFlow.svelte'
|
|
import FlowBranchesAllWrapper from './FlowBranchesAllWrapper.svelte'
|
|
import FlowBranchesOneWrapper from './FlowBranchesOneWrapper.svelte'
|
|
import FlowWhileLoop from './FlowWhileLoop.svelte'
|
|
import { initFlowStepWarnings } from '../utils'
|
|
import { dfs } from '../dfs'
|
|
import type { TriggerContext } from '$lib/components/triggers'
|
|
|
|
export let flowModule: FlowModule
|
|
export let noEditor: boolean = false
|
|
export let enableAi = false
|
|
export let savedModule: FlowModule | undefined = undefined
|
|
|
|
const { selectedId, flowStateStore, flowInputsStore, flowStore } =
|
|
getContext<FlowEditorContext>('FlowEditorContext')
|
|
|
|
const { primarySchedule } = getContext<TriggerContext>('TriggerContext')
|
|
|
|
let scriptKind: 'script' | 'trigger' | 'approval' = 'script'
|
|
let scriptTemplate: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' = 'script'
|
|
|
|
// These pointers are used to easily access previewArgs of parent module, and previous module
|
|
// Pointer to parent module, only defined within Branches or Loops.
|
|
export let parentModule: FlowModule | undefined = undefined
|
|
// Pointer to previous module, for easy access to testing results
|
|
export let previousModule: FlowModule | undefined = undefined
|
|
|
|
function initializePrimaryScheduleForTriggerScript(module: FlowModule) {
|
|
if (!$primarySchedule) {
|
|
$primarySchedule = {
|
|
summary: 'Scheduled poll of flow',
|
|
args: {},
|
|
cron: '0 */15 * * *',
|
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
enabled: true
|
|
}
|
|
}
|
|
if (!$primarySchedule.cron) {
|
|
$primarySchedule.cron = '0 */15 * * *'
|
|
}
|
|
$primarySchedule.enabled = true
|
|
|
|
module.stop_after_if = {
|
|
expr: 'result == undefined || Array.isArray(result) && result.length == 0',
|
|
skip_if_stopped: true
|
|
}
|
|
}
|
|
async function createModuleFromScript(
|
|
path: string,
|
|
summary: string,
|
|
kind: string,
|
|
hash: string | undefined
|
|
) {
|
|
const [module, state] = await pickScript(path, summary, flowModule.id, hash)
|
|
|
|
if (kind == 'approval') {
|
|
module.suspend = { required_events: 1, timeout: 1800 }
|
|
}
|
|
|
|
if (kind == 'trigger') {
|
|
initializePrimaryScheduleForTriggerScript(module)
|
|
}
|
|
|
|
flowModule = module
|
|
$flowStateStore[module.id] = state
|
|
|
|
if ($flowInputsStore) {
|
|
$flowInputsStore[module?.id] = {
|
|
flowStepWarnings: await initFlowStepWarnings(
|
|
module?.value,
|
|
$flowStateStore[module?.id]?.schema,
|
|
dfs($flowStore.value.modules, (fm) => fm.id)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
{#if flowModule.id === $selectedId}
|
|
{#if flowModule.value.type === 'forloopflow'}
|
|
<FlowLoop {noEditor} bind:mod={flowModule} {parentModule} {previousModule} {enableAi} />
|
|
{:else if flowModule.value.type === 'whileloopflow'}
|
|
<FlowWhileLoop {noEditor} bind:mod={flowModule} {previousModule} {parentModule} />
|
|
{:else if flowModule.value.type === 'branchone'}
|
|
<FlowBranchesOneWrapper {noEditor} {previousModule} {parentModule} bind:flowModule {enableAi} />
|
|
{:else if flowModule.value.type === 'branchall'}
|
|
<FlowBranchesAllWrapper {noEditor} {previousModule} {parentModule} bind:flowModule />
|
|
{:else if flowModule.value.type === 'identity'}
|
|
{#if $selectedId == 'failure'}
|
|
<div class="p-4">
|
|
<Alert type="info" title="Error handlers are triggered upon non recovered errors">
|
|
If defined, the error handler will take the error as input.
|
|
</Alert>
|
|
</div>
|
|
{:else if $selectedId == 'preprocessor'}
|
|
<div class="p-4">
|
|
<Alert
|
|
type="info"
|
|
title="Preprocessor is called when the flow is triggered by API or email"
|
|
>
|
|
It prepares arguments for the flow. Besides request arguments, the preprocessor receives a
|
|
`wm_trigger` argument with trigger details.
|
|
</Alert>
|
|
</div>
|
|
{/if}
|
|
|
|
{#if flowModule.value.flow}
|
|
<FlowInputsFlow
|
|
on:pick={async ({ detail }) => {
|
|
const { path, summary } = detail
|
|
const [module, state] = await pickFlow(path, summary, flowModule.id)
|
|
|
|
flowModule = module
|
|
$flowStateStore[module.id] = state
|
|
}}
|
|
/>
|
|
{:else}
|
|
<FlowInputs
|
|
{noEditor}
|
|
summary={flowModule.summary}
|
|
shouldDisableTriggerScripts={parentModule !== undefined ||
|
|
previousModule !== undefined ||
|
|
$selectedId == 'failure' ||
|
|
$selectedId == 'preprocessor'}
|
|
on:pick={async ({ detail }) => {
|
|
const { path, summary, kind, hash } = detail
|
|
createModuleFromScript(path, summary, kind, hash)
|
|
}}
|
|
on:new={async ({ detail }) => {
|
|
const { language, kind, subkind, summary } = detail
|
|
|
|
const [module, state] = await createInlineScriptModule(
|
|
language,
|
|
kind,
|
|
subkind,
|
|
flowModule.id,
|
|
summary
|
|
)
|
|
scriptKind = kind
|
|
scriptTemplate = subkind
|
|
|
|
if (kind == 'trigger') {
|
|
initializePrimaryScheduleForTriggerScript(module)
|
|
}
|
|
|
|
if (kind == 'approval') {
|
|
module.suspend = { required_events: 1, timeout: 1800 }
|
|
}
|
|
|
|
flowModule = module
|
|
$flowStateStore[module.id] = state
|
|
|
|
if ($flowInputsStore) {
|
|
$flowInputsStore[module.id] = {
|
|
flowStepWarnings: await initFlowStepWarnings(
|
|
module.value,
|
|
$flowStateStore[module.id].schema,
|
|
dfs($flowStore.value.modules, (fm) => fm.id)
|
|
)
|
|
}
|
|
}
|
|
}}
|
|
failureModule={$selectedId === 'failure'}
|
|
preprocessorModule={$selectedId === 'preprocessor'}
|
|
/>
|
|
{/if}
|
|
{:else if flowModule.value.type === 'rawscript' || flowModule.value.type === 'script' || flowModule.value.type === 'flow'}
|
|
<FlowModuleComponent
|
|
{noEditor}
|
|
bind:flowModule
|
|
{parentModule}
|
|
{previousModule}
|
|
failureModule={$selectedId === 'failure'}
|
|
preprocessorModule={$selectedId === 'preprocessor'}
|
|
{scriptKind}
|
|
{scriptTemplate}
|
|
{enableAi}
|
|
{savedModule}
|
|
/>
|
|
{/if}
|
|
{:else if flowModule.value.type === 'forloopflow' || flowModule.value.type == 'whileloopflow'}
|
|
{#each flowModule.value.modules as _, index (index)}
|
|
<svelte:self
|
|
{noEditor}
|
|
bind:flowModule={flowModule.value.modules[index]}
|
|
bind:parentModule={flowModule}
|
|
previousModule={flowModule.value.modules[index - 1]}
|
|
savedModule={(savedModule?.value as ForloopFlow | WhileloopFlow).modules[index]}
|
|
{enableAi}
|
|
/>
|
|
{/each}
|
|
{:else if flowModule.value.type === 'branchone'}
|
|
{#if $selectedId === `${flowModule?.id}-branch-default`}
|
|
<div class="p-2">
|
|
<h3 class="mb-4">Default branch</h3>
|
|
Nothing to configure, this is the default branch if none of the predicates are met.
|
|
</div>
|
|
{:else}
|
|
{#each flowModule.value.default as _, index}
|
|
<svelte:self
|
|
{noEditor}
|
|
bind:flowModule={flowModule.value.default[index]}
|
|
bind:parentModule={flowModule}
|
|
previousModule={flowModule.value.default[index - 1]}
|
|
savedModule={flowModule.value.default[index]}
|
|
{enableAi}
|
|
/>
|
|
{/each}
|
|
{/if}
|
|
{#each flowModule.value.branches as branch, branchIndex (branchIndex)}
|
|
{#if $selectedId === `${flowModule?.id}-branch-${branchIndex}`}
|
|
<FlowBranchOneWrapper
|
|
{noEditor}
|
|
bind:branch
|
|
parentModule={flowModule}
|
|
{previousModule}
|
|
{enableAi}
|
|
/>
|
|
{:else}
|
|
{#each branch.modules as _, index}
|
|
<svelte:self
|
|
{noEditor}
|
|
bind:flowModule={flowModule.value.branches[branchIndex].modules[index]}
|
|
bind:parentModule={flowModule}
|
|
previousModule={flowModule.value.branches[branchIndex].modules[index - 1]}
|
|
savedModule={(savedModule?.value as BranchOne).branches[branchIndex].modules[index]}
|
|
{enableAi}
|
|
/>
|
|
{/each}
|
|
{/if}
|
|
{/each}
|
|
{:else if flowModule.value.type === 'branchall'}
|
|
{#each flowModule.value.branches as branch, branchIndex (branchIndex)}
|
|
{#if $selectedId === `${flowModule?.id}-branch-${branchIndex}`}
|
|
<FlowBranchAllWrapper {noEditor} bind:branch />
|
|
{:else}
|
|
{#each branch.modules as _, index}
|
|
<svelte:self
|
|
{noEditor}
|
|
bind:flowModule={flowModule.value.branches[branchIndex].modules[index]}
|
|
bind:parentModule={flowModule}
|
|
previousModule={flowModule.value.branches[branchIndex].modules[index - 1]}
|
|
{enableAi}
|
|
savedModule={(savedModule?.value as BranchAll).branches[branchIndex].modules[index]}
|
|
/>
|
|
{/each}
|
|
{/if}
|
|
{/each}
|
|
{/if}
|