Files
windmill/frontend/src/lib/components/tutorials/FlowBuilderTutorialsForLoop.svelte
2024-02-02 19:08:29 +01:00

284 lines
6.5 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
import { createEventDispatcher, getContext } from 'svelte'
import type { FlowEditorContext } from '../flows/types'
import { emptyFlowModuleState } from '../flows/utils'
import {
clickButtonBySelector,
triggerAddFlowStep,
selectFlowStepKind,
updateFlowModuleById
} from './utils'
import Tutorial from './Tutorial.svelte'
import { updateProgress } from '$lib/tutorialUtils'
import { nextId } from '../flows/flowModuleNextId'
const dispatch = createEventDispatcher()
const { flowStore, selectedId, flowStateStore } =
getContext<FlowEditorContext>('FlowEditorContext')
let tutorial: Tutorial | undefined = undefined
export function runTutorial(indexToInsertAt?: number | undefined) {
tutorial?.runTutorial({ indexToInsertAt })
}
</script>
<Tutorial
bind:this={tutorial}
index={1}
name="forloop"
tainted={false}
on:error
on:skipAll
getSteps={(driver, options) => {
const id = nextId($flowStateStore, $flowStore)
const index = options?.indexToInsertAt ?? $flowStore.value.modules.length
const isFirst = id === 'a'
let tempId = ''
return [
{
popover: {
title: 'For loops tutorial',
description:
'Learn how to build our first for loop to iterate on. You can use arrow keys to navigate.'
}
},
{
element: `#flow-editor-add-step-${index}`,
popover: {
title: 'Add a step',
description: 'Click here to add a step to your flow',
onNextClick: () => {
triggerAddFlowStep(index)
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
popover: {
title: 'Steps kind',
description: "Choose the kind of step you want to add. Let's start with a simple action"
},
element: '#flow-editor-insert-module'
},
{
popover: {
title: 'Insert loop',
description: "Let's pick forloop",
onNextClick: () => {
selectFlowStepKind(isFirst ? 4 : 3)
setTimeout(() => {
driver.moveNext()
})
}
},
element: `#flow-editor-insert-module > div > button:nth-child(${isFirst ? 4 : 3})`
},
{
element: '#flow-editor-iterator-expression',
popover: {
title: 'Iterator expression',
description:
'The iterator expression is a javascript expression that respresents the array to iterate on. Here we will iterate on the firstname input letter by letter',
onNextClick: () => {
updateFlowModuleById($flowStore, id, (module) => {
if (module.value.type === 'forloopflow') {
if (module.value.iterator.type === 'javascript') {
module.value.iterator.expr = '[1,2,3]'
}
}
})
dispatch('reload')
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
element: '#flow-editor-iterator-expression',
popover: {
title: 'Iterator expression',
description:
'We can refer to the result of previous steps using the results object: results.a or use static values like [1,2,3] in this case.',
onNextClick: () => {
updateFlowModuleById($flowStore, id, (module) => {
const newId = nextId($flowStateStore, $flowStore)
tempId = newId
if (module.value.type === 'forloopflow') {
module.value.modules = [
{
id: newId,
value: {
type: 'rawscript',
content: 'def main(x):\n return x',
// @ts-ignore
language: 'python3',
input_transforms: {
x: {
type: 'javascript',
// @ts-ignore
value: '',
expr: ''
}
}
}
}
]
}
$flowStateStore[newId] = emptyFlowModuleState()
$flowStateStore[newId].schema.properties = {
x: {
type: 'string',
description: '',
default: null
}
}
})
dispatch('reload')
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
popover: {
title: 'Step of the loop',
description: 'We added an action to the loop. Lets configure it',
onNextClick: () => {
$selectedId = tempId
$flowStore = $flowStore
dispatch('reload')
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
element: '#flow-editor-editor',
popover: {
title: 'Python step',
description:
'We can write python code in the editor. In this example we will capitalize the letter'
}
},
{
element: '#flow-editor-step-input',
popover: {
title: 'Flow inputs',
description: 'UI is autogenerated from your code.'
}
},
{
element: '#flow-editor-plug',
popover: {
title: 'Input configuration',
description: 'Lets connect the input to the letter input',
onNextClick: () => {
clickButtonBySelector('#flow-editor-plug')
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
element: '.key',
popover: {
title: 'Connect',
description: 'As we did before, we can connect to the iterator of the loop',
onNextClick: () => {
updateFlowModuleById($flowStore, id, (module) => {
if (
module.value.type === 'forloopflow' &&
module.value.modules[0].value.type === 'rawscript'
) {
module.value.modules[0].value.input_transforms = {
x: {
type: 'javascript',
expr: 'flow_input.iter.value'
}
}
}
})
dispatch('reload')
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
element: '#flow-editor-step-input',
popover: {
title: 'Iterator',
description:
'Loops expose an iterator object that contains the current value of the loop and the index',
onNextClick: () => {
setTimeout(() => {
driver.moveNext()
updateProgress(1)
})
}
}
},
{
element: '#flow-editor-test-flow',
popover: {
title: 'Test your flow',
description: 'We can now test our flow',
onNextClick: () => {
clickButtonBySelector('#flow-editor-test-flow')
setTimeout(() => {
driver.moveNext()
})
}
}
},
{
element: '#flow-editor-test-flow-drawer',
popover: {
title: 'Test your flow',
description: 'Finally we can test our flow, and view the results!',
onNextClick: () => {
clickButtonBySelector('#flow-editor-test-flow-drawer')
setTimeout(() => {
driver.moveNext()
updateProgress(0)
})
}
}
}
]
}}
/>