mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-08 08:04:25 +00:00
* Fix tutorial basic * fix other tutorials * nit fix bug with button shrinking * tutorial works backwards * nit delete field on prev
292 lines
7.3 KiB
Svelte
292 lines
7.3 KiB
Svelte
<script lang="ts">
|
||
import { createEventDispatcher, getContext, tick } from 'svelte'
|
||
import type { FlowEditorContext } from '../flows/types'
|
||
import { updateProgress } from '$lib/tutorialUtils'
|
||
import {
|
||
clickButtonBySelector,
|
||
isFlowTainted,
|
||
setInputBySelector,
|
||
triggerPointerDown,
|
||
waitForElementLoading
|
||
} from './utils'
|
||
import Tutorial from './Tutorial.svelte'
|
||
import { refreshStateStore } from '$lib/svelte5Utils.svelte'
|
||
import { wait } from '$lib/utils'
|
||
|
||
const { flowStore } = getContext<FlowEditorContext>('FlowEditorContext')
|
||
const dispatch = createEventDispatcher()
|
||
|
||
let tutorial: Tutorial | undefined = undefined
|
||
|
||
export function runTutorial() {
|
||
tutorial?.runTutorial()
|
||
}
|
||
</script>
|
||
|
||
<Tutorial
|
||
bind:this={tutorial}
|
||
index={0}
|
||
name="action"
|
||
tainted={isFlowTainted(flowStore.val)}
|
||
on:error
|
||
on:skipAll
|
||
getSteps={(driver) => [
|
||
{
|
||
popover: {
|
||
title: 'Flow builder tutorial',
|
||
description:
|
||
'Learn how to build powerful flows in a few steps. You can use arrow keys to navigate.'
|
||
}
|
||
},
|
||
{
|
||
popover: {
|
||
title: 'Flows inputs',
|
||
description: 'Flows have inputs that can be used in the flow',
|
||
onNextClick: async () => {
|
||
triggerPointerDown('#flow-editor-virtual-Input')
|
||
await wait(20)
|
||
clickButtonBySelector('#add-flow-input-btn')
|
||
await wait(0)
|
||
setInputBySelector('input[placeholder="Field name"]', 'firstname')
|
||
setTimeout(() => driver.moveNext())
|
||
}
|
||
},
|
||
element: '#flow-editor-virtual-Input'
|
||
},
|
||
{
|
||
element: 'input[placeholder="Field name"]',
|
||
popover: {
|
||
title: 'Name your property',
|
||
description: 'Give a name to your property. Here we will call it firstname',
|
||
onNextClick: () => {
|
||
setTimeout(() => {
|
||
driver.moveNext()
|
||
})
|
||
},
|
||
onPrevClick: () => {
|
||
clickButtonBySelector('#add-flow-input-btn') // Close the input drawer
|
||
setTimeout(() => driver.movePrevious())
|
||
}
|
||
}
|
||
},
|
||
{
|
||
element: '*:has(> #flow-editor-add-property)',
|
||
popover: {
|
||
title: 'Add your property',
|
||
description: 'Click here to save your property',
|
||
onNextClick: () => {
|
||
clickButtonBySelector('#flow-editor-add-property')
|
||
setTimeout(() => {
|
||
driver.moveNext()
|
||
})
|
||
}
|
||
}
|
||
},
|
||
{
|
||
element: '#flow-editor-add-step-0',
|
||
popover: {
|
||
title: 'Add a step',
|
||
description: 'Click here to add a step to your flow',
|
||
onNextClick: () => {
|
||
triggerPointerDown(`#flow-editor-add-step-0`)
|
||
setTimeout(() => driver.moveNext())
|
||
},
|
||
onPrevClick: async () => {
|
||
clickButtonBySelector('.delete-schema-field-button')
|
||
await wait(0)
|
||
clickButtonBySelector('#add-flow-input-btn')
|
||
await wait(0)
|
||
setInputBySelector('input[placeholder="Field name"]', 'firstname')
|
||
setTimeout(() => driver.movePrevious())
|
||
}
|
||
}
|
||
},
|
||
{
|
||
popover: {
|
||
title: 'Steps kind',
|
||
description: "Choose the kind of step you want to add. Let's start with a simple action",
|
||
onPrevClick: () => {
|
||
triggerPointerDown(`#flow-editor-add-step-0`)
|
||
setTimeout(() => driver.movePrevious())
|
||
}
|
||
},
|
||
element: '#flow-editor-insert-module'
|
||
},
|
||
{
|
||
popover: {
|
||
title: 'Pick an action',
|
||
description: 'Let’s pick an action to add to your flow',
|
||
onNextClick: () => {
|
||
triggerPointerDown('#flow-editor-insert-module > div > div > button:nth-child(1)')
|
||
|
||
setTimeout(() => {
|
||
driver.moveNext()
|
||
})
|
||
}
|
||
},
|
||
element: '#flow-editor-insert-module > div > div > button:nth-child(1)'
|
||
},
|
||
{
|
||
element: '#flow-editor-flow-providers',
|
||
popover: {
|
||
title: 'Action configuration',
|
||
description: 'An action can be inlined, imported from your workspace or the Hub.'
|
||
}
|
||
},
|
||
{
|
||
element: '#flow-editor-flow-atoms',
|
||
popover: {
|
||
title: 'Supported languages',
|
||
description: 'Windmill support the following languages/runtimes.'
|
||
}
|
||
},
|
||
{
|
||
element: '#flow-editor-new-bun',
|
||
popover: {
|
||
title: 'Typescript',
|
||
description: "Let's write a script for your flow",
|
||
onNextClick: () => {
|
||
clickButtonBySelector('#flow-editor-new-bun')
|
||
tick().then(() =>
|
||
waitForElementLoading('#flow-editor-editor', () => {
|
||
driver.moveNext()
|
||
})
|
||
)
|
||
}
|
||
}
|
||
},
|
||
{
|
||
element: '#flow-editor-editor',
|
||
popover: {
|
||
title: 'Action editor',
|
||
description: 'Windmill provides a full code editor to write your actions',
|
||
onPrevClick: () => {
|
||
triggerPointerDown(`#flow-editor-virtual-Input`)
|
||
triggerPointerDown(`#flow-editor-add-step-0`)
|
||
setTimeout(() => {
|
||
driver.movePrevious()
|
||
})
|
||
}
|
||
}
|
||
},
|
||
{
|
||
element: '#flow-editor-step-input',
|
||
onHighlighted: () => {
|
||
document.querySelector('#flow-editor-plug')?.parentElement?.classList.remove('opacity-0')
|
||
},
|
||
popover: {
|
||
title: 'Autogenerated schema',
|
||
description: 'The schema and the UI is autogenerated from your code'
|
||
}
|
||
},
|
||
{
|
||
element: '#flow-editor-plug',
|
||
onHighlighted: () => {
|
||
document.querySelector('#flow-editor-plug')?.parentElement?.classList.remove('opacity-0')
|
||
},
|
||
popover: {
|
||
title: 'Connect',
|
||
description:
|
||
'You can provide static values or connect to other nodes result. Here we will connect to the firstname input',
|
||
|
||
onNextClick: () => {
|
||
clickButtonBySelector('#flow-editor-plug')
|
||
setTimeout(() => {
|
||
driver.moveNext()
|
||
})
|
||
}
|
||
}
|
||
},
|
||
{
|
||
element: '#flow-editor-step-input .prop-picker-inputs',
|
||
popover: {
|
||
title: 'Connection mode',
|
||
description: 'Once you pressed the connect button, you can choose what to connect to.',
|
||
onNextClick: () => {
|
||
if (flowStore.val.value.modules[0].value.type === 'rawscript') {
|
||
flowStore.val.value.modules[0].value.input_transforms = {
|
||
x: {
|
||
type: 'javascript',
|
||
expr: 'flow_input.firstname'
|
||
}
|
||
}
|
||
}
|
||
|
||
refreshStateStore(flowStore)
|
||
dispatch('reload')
|
||
|
||
setTimeout(() => {
|
||
driver.moveNext()
|
||
})
|
||
},
|
||
onPrevClick: () => {
|
||
clickButtonBySelector('#flow-editor-plug')
|
||
setTimeout(() => driver.movePrevious())
|
||
}
|
||
}
|
||
},
|
||
|
||
{
|
||
element: '#flow-editor-step-input',
|
||
popover: {
|
||
title: 'Input connected!',
|
||
description: 'The input is now connected to the firstname input',
|
||
onPrevClick: () => {
|
||
clickButtonBySelector('#flow-editor-plug')
|
||
setTimeout(() => driver.movePrevious())
|
||
}
|
||
}
|
||
},
|
||
|
||
{
|
||
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: 'textarea.w-full',
|
||
popover: {
|
||
title: 'Flow input',
|
||
description: 'Let’s provide an input to our flow',
|
||
onNextClick: () => {
|
||
setInputBySelector('textarea.w-full', 'Hello World!')
|
||
|
||
setTimeout(() => {
|
||
driver.moveNext()
|
||
})
|
||
},
|
||
onPrevClick: () => {
|
||
clickButtonBySelector('#flow-editor-test-flow') // Close the test drawer
|
||
setTimeout(() => driver.movePrevious())
|
||
}
|
||
}
|
||
},
|
||
{
|
||
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)
|
||
})
|
||
}
|
||
}
|
||
}
|
||
]}
|
||
/>
|