Files
windmill/frontend/src/lib/components/tutorials/FlowBuilderTutorialsForLoop.svelte
T
Faton Ramadani e8dfea3f0a feat(frontend): app editor tutorials (#2443)
* feat(frontend): wip

* feat(frontend): skeleton done

* feat(frontend): background runnables

* feat(frontend): fix build

* feat(frontend): finish background runnable tuto

* feat(frontend): connection output

* feat(frontend): add simple app tutorial

* feat(frontend): add simple app trigger

* feat(frontend): fix wording

* feat(frontend): remove duplicate code

* feat(frontend): wip tutorial rework

* feat(frontend): Tutorial done

* feat(frontend): Fix build
2023-10-17 22:44:47 +02:00

253 lines
5.8 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 { nextId } from '../flows/flowStateUtils'
import { updateProgress } from '$lib/tutorialUtils'
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: 'Welcome to the Windmil Flow editor',
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 = 'results.a'
}
}
})
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',
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)
})
}
}
}
]
}}
/>