mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-08 00:03:07 +00:00
fix(frontend): fix flow tutorials (#2383)
* fix(frontend): fix flow tutorials * fix(frontend): restore tainted * fix(frontend): add guide about key arrows * fix(frontend): add how first tutorial is started * fix(frontend): add how first tutorial is started * fix(frontend): remove debugger * fix(frontend): fix deployement issues
This commit is contained in:
@@ -11,58 +11,72 @@
|
||||
import { classNames } from '$lib/utils'
|
||||
import { resetAllTodos, skipAllTodos } from '$lib/tutorialUtils'
|
||||
import { tutorialsToDo } from '$lib/stores'
|
||||
import { clickButtonBySelector } from './tutorials/utils'
|
||||
import { getContext } from 'svelte'
|
||||
import type { FlowEditorContext } from './flows/types'
|
||||
|
||||
let buttonDropdown: ButtonDropdown | undefined = undefined
|
||||
const { flowStore } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
$: {
|
||||
if (buttonDropdown && $tutorialsToDo.includes(0)) {
|
||||
clickButtonBySelector('#tutorials-button')
|
||||
}
|
||||
let flowBuilderTutorialSimpleFlow: FlowBuilderTutorialSimpleFlow | undefined = undefined
|
||||
|
||||
$: tainted =
|
||||
$flowStore.value.modules.length > 0 || Object.keys($flowStore?.schema?.properties).length > 0
|
||||
|
||||
let automaticallyRan: boolean = false
|
||||
|
||||
$: if (!automaticallyRan && $tutorialsToDo.includes(0)) {
|
||||
automaticallyRan = true
|
||||
flowBuilderTutorialSimpleFlow?.runTutorial()
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:pointerdown|stopPropagation>
|
||||
<ButtonDropdown hasPadding={false} bind:this={buttonDropdown}>
|
||||
<svelte:fragment slot="buttonReplacement">
|
||||
<Button nonCaptureEvent size="xs" color="light" variant="border" id="tutorials-button">
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<BookOpen size={16} />
|
||||
Tutorials
|
||||
</div>
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="items">
|
||||
<FlowBuilderTutorialSimpleFlow on:reload on:skipAll={skipAllTodos} />
|
||||
<FlowBuilderTutorialsForLoop on:reload on:skipAll={skipAllTodos} />
|
||||
<FlowBranchOne on:reload on:skipAll={skipAllTodos} />
|
||||
<FlowBranchAll on:reload on:skipAll={skipAllTodos} />
|
||||
<div class="border-t border-surface-hover" />
|
||||
<MenuItem
|
||||
on:click={() => {
|
||||
resetAllTodos()
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class={classNames(
|
||||
'text-primary flex flex-row items-center text-left gap-2 cursor-pointer hover:bg-surface-hover !text-xs font-semibold'
|
||||
)}
|
||||
{#if !tainted}
|
||||
<button on:pointerdown|stopPropagation>
|
||||
<ButtonDropdown hasPadding={false}>
|
||||
<svelte:fragment slot="buttonReplacement">
|
||||
<Button nonCaptureEvent size="xs" color="light" variant="border" id="tutorials-button">
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<BookOpen size={16} />
|
||||
Tutorials
|
||||
</div>
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="items">
|
||||
<FlowBuilderTutorialSimpleFlow on:reload on:skipAll={skipAllTodos} />
|
||||
<FlowBuilderTutorialsForLoop on:reload on:skipAll={skipAllTodos} />
|
||||
<FlowBranchOne on:reload on:skipAll={skipAllTodos} />
|
||||
<FlowBranchAll on:reload on:skipAll={skipAllTodos} />
|
||||
<div class="border-t border-surface-hover" />
|
||||
<MenuItem
|
||||
on:click={() => {
|
||||
resetAllTodos()
|
||||
}}
|
||||
>
|
||||
Reset tutorials
|
||||
</div>
|
||||
</MenuItem>
|
||||
<MenuItem on:click={() => skipAllTodos()}>
|
||||
<div
|
||||
class={classNames(
|
||||
'text-primary flex flex-row items-center text-left gap-2 cursor-pointer hover:bg-surface-hover !text-xs font-semibold'
|
||||
)}
|
||||
>
|
||||
Skip tutorials
|
||||
</div>
|
||||
</MenuItem>
|
||||
</svelte:fragment>
|
||||
</ButtonDropdown>
|
||||
</button>
|
||||
<div
|
||||
class={classNames(
|
||||
'text-primary flex flex-row items-center text-left gap-2 cursor-pointer hover:bg-surface-hover !text-xs font-semibold'
|
||||
)}
|
||||
>
|
||||
Reset tutorials
|
||||
</div>
|
||||
</MenuItem>
|
||||
<MenuItem on:click={() => skipAllTodos()}>
|
||||
<div
|
||||
class={classNames(
|
||||
'text-primary flex flex-row items-center text-left gap-2 cursor-pointer hover:bg-surface-hover !text-xs font-semibold'
|
||||
)}
|
||||
>
|
||||
Skip tutorials
|
||||
</div>
|
||||
</MenuItem>
|
||||
</svelte:fragment>
|
||||
</ButtonDropdown>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<FlowBuilderTutorialSimpleFlow
|
||||
bind:this={flowBuilderTutorialSimpleFlow}
|
||||
shouldRenderButton={false}
|
||||
/>
|
||||
|
||||
<style global>
|
||||
.driver-popover-title {
|
||||
@@ -74,6 +88,6 @@
|
||||
}
|
||||
|
||||
.driver-popover {
|
||||
@apply p-6;
|
||||
@apply p-6 bg-surface;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { driver } from 'driver.js'
|
||||
import 'driver.js/dist/driver.css'
|
||||
import { createEventDispatcher, getContext, tick } from 'svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import type { FlowEditorContext } from '../flows/types'
|
||||
import TutorialItem from './TutorialItem.svelte'
|
||||
import { clickButtonBySelector, triggerAddFlowStep, selectFlowStepKind } from './utils'
|
||||
@@ -21,7 +21,7 @@
|
||||
onPopoverRender: (popover, { config, state }) => {
|
||||
if (state.activeIndex == 0) {
|
||||
const skipThisButton = document.createElement('button')
|
||||
skipThisButton.innerText = 'Skip this'
|
||||
skipThisButton.innerText = 'Skip this tutorial'
|
||||
skipThisButton.addEventListener('click', () => {
|
||||
updateProgress(3)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
)
|
||||
|
||||
const skipAllButton = document.createElement('button')
|
||||
skipAllButton.innerText = 'Skip all'
|
||||
skipAllButton.innerText = 'Skip all tutorials'
|
||||
skipAllButton.addEventListener('click', () => {
|
||||
dispatch('skipAll')
|
||||
branchAllTutorial.destroy()
|
||||
@@ -48,12 +48,13 @@
|
||||
|
||||
const div = document.createElement('div')
|
||||
|
||||
div.setAttribute('class', 'flex flex-row gap-2')
|
||||
div.setAttribute('class', 'flex flex-row gap-2 justify-between w-full pt-2')
|
||||
|
||||
if (popoverDescription) {
|
||||
div.appendChild(skipThisButton)
|
||||
div.appendChild(skipAllButton)
|
||||
|
||||
div.appendChild(skipThisButton)
|
||||
|
||||
popoverDescription.appendChild(div)
|
||||
}
|
||||
}
|
||||
@@ -61,8 +62,9 @@
|
||||
steps: [
|
||||
{
|
||||
popover: {
|
||||
title: 'Welcome in the Windmil Flow editor',
|
||||
description: 'Learn how to build our first branch to be executed on a condition'
|
||||
title: 'Welcome to the Windmil Flow editor',
|
||||
description:
|
||||
'Learn how to build our first branch to be executed on a condition. You can use arrow keys to navigate'
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -172,7 +174,7 @@
|
||||
$flowStore = $flowStore
|
||||
dispatch('reload')
|
||||
|
||||
tick().then(() => {
|
||||
setTimeout(() => {
|
||||
branchAllTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { driver } from 'driver.js'
|
||||
import 'driver.js/dist/driver.css'
|
||||
import { createEventDispatcher, getContext, tick } from 'svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import type { FlowEditorContext } from '../flows/types'
|
||||
import TutorialItem from './TutorialItem.svelte'
|
||||
import {
|
||||
@@ -25,7 +25,7 @@
|
||||
onPopoverRender: (popover, { config, state }) => {
|
||||
if (state.activeIndex == 0) {
|
||||
const skipThisButton = document.createElement('button')
|
||||
skipThisButton.innerText = 'Skip this'
|
||||
skipThisButton.innerText = 'Skip this tutorials'
|
||||
skipThisButton.addEventListener('click', () => {
|
||||
updateProgress(2)
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
)
|
||||
|
||||
const skipAllButton = document.createElement('button')
|
||||
skipAllButton.innerText = 'Skip all'
|
||||
skipAllButton.innerText = 'Skip all tutorials'
|
||||
skipAllButton.addEventListener('click', () => {
|
||||
dispatch('skipAll')
|
||||
branchOneTutorial.destroy()
|
||||
@@ -52,11 +52,11 @@
|
||||
|
||||
const div = document.createElement('div')
|
||||
|
||||
div.setAttribute('class', 'flex flex-row gap-2')
|
||||
div.setAttribute('class', 'flex flex-row gap-2 justify-between w-full pt-2')
|
||||
|
||||
if (popoverDescription) {
|
||||
div.appendChild(skipThisButton)
|
||||
div.appendChild(skipAllButton)
|
||||
div.appendChild(skipThisButton)
|
||||
|
||||
popoverDescription.appendChild(div)
|
||||
}
|
||||
@@ -65,8 +65,9 @@
|
||||
steps: [
|
||||
{
|
||||
popover: {
|
||||
title: 'Welcome in the Windmil Flow editor',
|
||||
description: 'Learn how to build our first branch to be executed on a condition'
|
||||
title: 'Welcome to the Windmil Flow editor',
|
||||
description:
|
||||
'Learn how to build our first branch to be executed on a condition. You can use arrow keys to navigate'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -213,7 +214,7 @@
|
||||
$flowStore = $flowStore
|
||||
dispatch('reload')
|
||||
|
||||
tick().then(() => {
|
||||
setTimeout(() => {
|
||||
branchOneTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
@@ -265,7 +266,7 @@
|
||||
$flowStore = $flowStore
|
||||
dispatch('reload')
|
||||
|
||||
tick().then(() => {
|
||||
setTimeout(() => {
|
||||
branchOneTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,307 +11,313 @@
|
||||
setInputBySelector,
|
||||
triggerAddFlowStep
|
||||
} from './utils'
|
||||
import { tutorialsToDo } from '$lib/stores'
|
||||
|
||||
export let shouldRenderButton: boolean = true
|
||||
|
||||
const { flowStore } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const queue: string[] = []
|
||||
|
||||
const simpleFlowTutorial = driver({
|
||||
showProgress: true,
|
||||
allowClose: true,
|
||||
onPopoverRender: (popover, { config, state }) => {
|
||||
if (state.activeIndex == 0) {
|
||||
const skipThisButton = document.createElement('button')
|
||||
skipThisButton.innerText = 'Skip this'
|
||||
skipThisButton.addEventListener('click', () => {
|
||||
updateProgress(0)
|
||||
simpleFlowTutorial.destroy()
|
||||
})
|
||||
skipThisButton.setAttribute(
|
||||
'class',
|
||||
'border px-2 py-1 !text-xs font-normal rounded-md hover:bg-surface-hover transition-all flex items-center'
|
||||
)
|
||||
export function runTutorial() {
|
||||
const simpleFlowTutorial = driver({
|
||||
showProgress: true,
|
||||
allowClose: true,
|
||||
onPopoverRender: (popover, { config, state }) => {
|
||||
if (state.activeIndex == 0) {
|
||||
const skipThisButton = document.createElement('button')
|
||||
skipThisButton.innerText = 'Skip this tutorials'
|
||||
skipThisButton.addEventListener('click', () => {
|
||||
updateProgress(0)
|
||||
simpleFlowTutorial.destroy()
|
||||
})
|
||||
skipThisButton.setAttribute(
|
||||
'class',
|
||||
'border px-2 py-1 !text-xs font-normal rounded-md hover:bg-surface-hover transition-all flex items-center'
|
||||
)
|
||||
|
||||
const skipAllButton = document.createElement('button')
|
||||
skipAllButton.innerText = 'Skip all'
|
||||
skipAllButton.addEventListener('click', () => {
|
||||
dispatch('skipAll')
|
||||
simpleFlowTutorial.destroy()
|
||||
})
|
||||
const skipAllButton = document.createElement('button')
|
||||
skipAllButton.innerText = 'Skip all tutorials'
|
||||
skipAllButton.addEventListener('click', () => {
|
||||
dispatch('skipAll')
|
||||
simpleFlowTutorial.destroy()
|
||||
})
|
||||
|
||||
skipAllButton.setAttribute(
|
||||
'class',
|
||||
'border px-2 py-1 !text-xs font-normal rounded-md hover:bg-surface-hover transition-all flex items-center'
|
||||
)
|
||||
skipAllButton.setAttribute(
|
||||
'class',
|
||||
'border px-2 py-1 !text-xs font-normal rounded-md hover:bg-surface-hover transition-all flex items-center'
|
||||
)
|
||||
|
||||
const popoverDescription = document.querySelector('#driver-popover-description')
|
||||
const popoverDescription = document.querySelector('#driver-popover-description')
|
||||
|
||||
const div = document.createElement('div')
|
||||
const div = document.createElement('div')
|
||||
|
||||
div.setAttribute('class', 'flex flex-row gap-2')
|
||||
div.setAttribute('class', 'flex flex-row gap-2 justify-between w-full pt-2')
|
||||
|
||||
if (popoverDescription) {
|
||||
div.appendChild(skipThisButton)
|
||||
div.appendChild(skipAllButton)
|
||||
if (popoverDescription) {
|
||||
div.appendChild(skipAllButton)
|
||||
div.appendChild(skipThisButton)
|
||||
|
||||
popoverDescription.appendChild(div)
|
||||
}
|
||||
}
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
popover: {
|
||||
title: 'Welcome in the Windmil Flow editor',
|
||||
description: 'Learn how to build powerful flows in a few steps'
|
||||
popoverDescription.appendChild(div)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
popover: {
|
||||
title: 'Flows inputs',
|
||||
description: 'Flows have inputs that can be used in the flow',
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector('#flow-editor-virtual-Input')
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
steps: [
|
||||
{
|
||||
popover: {
|
||||
title: 'Welcome to the Windmil Flow editor',
|
||||
description:
|
||||
'Learn how to build powerful flows in a few steps. You can use arrow keys to navigate.'
|
||||
}
|
||||
},
|
||||
element: '#svelvet-Input'
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-add-property',
|
||||
popover: {
|
||||
title: 'Add a property',
|
||||
description: 'Click here to add a property to your schema',
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector('#flow-editor-add-property')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '#schema-modal-name',
|
||||
popover: {
|
||||
title: 'Name your property',
|
||||
description: 'Give a name to your property. Here we will call it firstname',
|
||||
onNextClick: () => {
|
||||
setInputBySelector('#schema-modal-name', 'firstname')
|
||||
|
||||
simpleFlowTutorial.moveNext()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '#schema-modal-save',
|
||||
popover: {
|
||||
title: 'Save your property',
|
||||
description: 'Click here to save your property',
|
||||
onNextClick: () => {
|
||||
queue.push(JSON.stringify($flowStore))
|
||||
|
||||
clickButtonBySelector('#schema-modal-save')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-add-step-0',
|
||||
popover: {
|
||||
title: 'Add a step',
|
||||
description: 'Click here to add a step to your flow',
|
||||
onNextClick: () => {
|
||||
triggerAddFlowStep(0)
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
{
|
||||
popover: {
|
||||
title: 'Flows inputs',
|
||||
description: 'Flows have inputs that can be used in the flow',
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector('#flow-editor-virtual-Input')
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onPrevClick: () => {
|
||||
simpleFlowTutorial.moveTo(1)
|
||||
debugger
|
||||
$flowStore = JSON.parse(queue.pop() || '{}')
|
||||
dispatch('reload')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
popover: {
|
||||
title: 'Steps kind',
|
||||
description: "Choose the kind of step you want to add. Let's start with a simple action"
|
||||
element: '#svelvet-Input'
|
||||
},
|
||||
element: '#flow-editor-insert-module'
|
||||
},
|
||||
{
|
||||
popover: {
|
||||
title: 'Pick an action',
|
||||
description: 'Let’s pick an action to add to your flow',
|
||||
onNextClick: () => {
|
||||
selectFlowStepKind(1)
|
||||
{
|
||||
element: '#flow-editor-add-property',
|
||||
popover: {
|
||||
title: 'Add a property',
|
||||
description: 'Click here to add a property to your schema',
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector('#flow-editor-add-property')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
element: '#flow-editor-insert-module > div > button:nth-child(1)'
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-flow-inputs',
|
||||
popover: {
|
||||
title: 'Action configuration',
|
||||
description: 'An action can be inlined, imported from your workspace or the Hub.'
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-action-script',
|
||||
popover: {
|
||||
title: 'Supported languages',
|
||||
description: 'Windmill support the following languages/runtimes.'
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-action-script > button:nth-child(1)',
|
||||
popover: {
|
||||
title: 'Typescript',
|
||||
description: "Let's pick an action to add to your flow",
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector('#flow-editor-action-script > button > div > button:nth-child(1)')
|
||||
{
|
||||
element: '#schema-modal-name',
|
||||
popover: {
|
||||
title: 'Name your property',
|
||||
description: 'Give a name to your property. Here we will call it firstname',
|
||||
onNextClick: () => {
|
||||
setInputBySelector('#schema-modal-name', 'firstname')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
element: '#schema-modal-save',
|
||||
popover: {
|
||||
title: 'Save your property',
|
||||
description: 'Click here to save your property',
|
||||
onNextClick: () => {
|
||||
queue.push(JSON.stringify($flowStore))
|
||||
|
||||
{
|
||||
element: '#flow-editor-editor',
|
||||
popover: {
|
||||
title: 'Action editor',
|
||||
description: 'Windmill provides a full code editor to write your actions'
|
||||
}
|
||||
},
|
||||
clickButtonBySelector('#schema-modal-save')
|
||||
|
||||
{
|
||||
element: '#flow-editor-step-input',
|
||||
popover: {
|
||||
title: 'Autogenerated schema',
|
||||
description: 'The schema and the UI is autogenerated from your code'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-editor-plug',
|
||||
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(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '.key',
|
||||
popover: {
|
||||
title: 'Connection mode',
|
||||
description: 'Once you pressed the connect button, you can choose what to connect to.',
|
||||
onNextClick: () => {
|
||||
if ($flowStore.value.modules[0].value.type === 'rawscript') {
|
||||
$flowStore.value.modules[0].value.input_transforms = {
|
||||
x: {
|
||||
type: 'javascript',
|
||||
expr: 'flow_input.firstname'
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-add-step-0',
|
||||
popover: {
|
||||
title: 'Add a step',
|
||||
description: 'Click here to add a step to your flow',
|
||||
onNextClick: () => {
|
||||
triggerAddFlowStep(0)
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
},
|
||||
|
||||
onPrevClick: () => {
|
||||
simpleFlowTutorial.moveTo(1)
|
||||
$flowStore = JSON.parse(queue.pop() || '{}')
|
||||
dispatch('reload')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
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: 'Pick an action',
|
||||
description: 'Let’s pick an action to add to your flow',
|
||||
onNextClick: () => {
|
||||
selectFlowStepKind(1)
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
},
|
||||
element: '#flow-editor-insert-module > div > button:nth-child(1)'
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-flow-inputs',
|
||||
popover: {
|
||||
title: 'Action configuration',
|
||||
description: 'An action can be inlined, imported from your workspace or the Hub.'
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-action-script',
|
||||
popover: {
|
||||
title: 'Supported languages',
|
||||
description: 'Windmill support the following languages/runtimes.'
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '#flow-editor-action-script > button:nth-child(1)',
|
||||
popover: {
|
||||
title: 'Typescript',
|
||||
description: "Let's pick an action to add to your flow",
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector(
|
||||
'#flow-editor-action-script > button > div > button:nth-child(1)'
|
||||
)
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-editor-editor',
|
||||
popover: {
|
||||
title: 'Action editor',
|
||||
description: 'Windmill provides a full code editor to write your actions'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-editor-step-input',
|
||||
popover: {
|
||||
title: 'Autogenerated schema',
|
||||
description: 'The schema and the UI is autogenerated from your code'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-editor-plug',
|
||||
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(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
element: '.key',
|
||||
popover: {
|
||||
title: 'Connection mode',
|
||||
description: 'Once you pressed the connect button, you can choose what to connect to.',
|
||||
onNextClick: () => {
|
||||
if ($flowStore.value.modules[0].value.type === 'rawscript') {
|
||||
$flowStore.value.modules[0].value.input_transforms = {
|
||||
x: {
|
||||
type: 'javascript',
|
||||
expr: 'flow_input.firstname'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$flowStore = $flowStore
|
||||
dispatch('reload')
|
||||
|
||||
tick().then(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
$flowStore = $flowStore
|
||||
dispatch('reload')
|
||||
{
|
||||
element: '#flow-editor-step-input',
|
||||
popover: {
|
||||
title: 'Input connected!',
|
||||
description: 'The input is now connected to the firstname input'
|
||||
}
|
||||
},
|
||||
|
||||
tick().then(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
{
|
||||
element: '#flow-editor-test-flow',
|
||||
popover: {
|
||||
title: 'Test your flow',
|
||||
description: 'We can now test our flow',
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector('#flow-editor-test-flow')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-preview-content',
|
||||
popover: {
|
||||
title: 'Flow input',
|
||||
description: 'Let’s provide an input to our flow',
|
||||
onNextClick: () => {
|
||||
setInputBySelector('textarea.w-full', 'Hello World!')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.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(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
|
||||
updateProgress(0)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-editor-step-input',
|
||||
popover: {
|
||||
title: 'Input connected!',
|
||||
description: 'The input is now connected to the firstname input'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-editor-test-flow',
|
||||
popover: {
|
||||
title: 'Test your flow',
|
||||
description: 'We can now test our flow',
|
||||
onNextClick: () => {
|
||||
clickButtonBySelector('#flow-editor-test-flow')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
element: '#flow-preview-content',
|
||||
popover: {
|
||||
title: 'Flow input',
|
||||
description: 'Let’s provide an input to our flow',
|
||||
onNextClick: () => {
|
||||
setInputBySelector('textarea.w-full', 'Hello World!')
|
||||
|
||||
setTimeout(() => {
|
||||
simpleFlowTutorial.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(() => {
|
||||
simpleFlowTutorial.moveNext()
|
||||
|
||||
updateProgress(0)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
$: $tutorialsToDo.includes(0) && simpleFlowTutorial.drive()
|
||||
]
|
||||
})
|
||||
simpleFlowTutorial.drive()
|
||||
}
|
||||
</script>
|
||||
|
||||
<TutorialItem
|
||||
on:click={() => simpleFlowTutorial.drive()}
|
||||
label="Simple flow tutorial"
|
||||
index={0}
|
||||
id="flow-builder-tutorial-action"
|
||||
/>
|
||||
{#if shouldRenderButton}
|
||||
<TutorialItem
|
||||
on:click={() => runTutorial()}
|
||||
label="Simple flow tutorial"
|
||||
index={0}
|
||||
id="flow-builder-tutorial-action"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { driver } from 'driver.js'
|
||||
import 'driver.js/dist/driver.css'
|
||||
import { createEventDispatcher, getContext, tick } from 'svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import type { FlowEditorContext } from '../flows/types'
|
||||
import TutorialItem from './TutorialItem.svelte'
|
||||
import { emptyFlowModuleState } from '../flows/utils'
|
||||
@@ -28,7 +28,7 @@
|
||||
onPopoverRender: (popover, { config, state }) => {
|
||||
if (state.activeIndex == 0) {
|
||||
const skipThisButton = document.createElement('button')
|
||||
skipThisButton.innerText = 'Skip this'
|
||||
skipThisButton.innerText = 'Skip this tutorials'
|
||||
skipThisButton.addEventListener('click', () => {
|
||||
updateProgress(1)
|
||||
forloopTutorial.destroy()
|
||||
@@ -39,7 +39,7 @@
|
||||
)
|
||||
|
||||
const skipAllButton = document.createElement('button')
|
||||
skipAllButton.innerText = 'Skip all'
|
||||
skipAllButton.innerText = 'Skip all tutorials'
|
||||
skipAllButton.addEventListener('click', () => {
|
||||
dispatch('skipAll')
|
||||
forloopTutorial.destroy()
|
||||
@@ -54,11 +54,11 @@
|
||||
|
||||
const div = document.createElement('div')
|
||||
|
||||
div.setAttribute('class', 'flex flex-row gap-2')
|
||||
div.setAttribute('class', 'flex flex-row gap-2 justify-between w-full pt-2')
|
||||
|
||||
if (popoverDescription) {
|
||||
div.appendChild(skipThisButton)
|
||||
div.appendChild(skipAllButton)
|
||||
div.appendChild(skipThisButton)
|
||||
|
||||
popoverDescription.appendChild(div)
|
||||
}
|
||||
@@ -67,8 +67,9 @@
|
||||
steps: [
|
||||
{
|
||||
popover: {
|
||||
title: 'Welcome in the Windmil Flow editor',
|
||||
description: 'Learn how to build our first for loop to iterate on'
|
||||
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.'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -201,7 +202,7 @@
|
||||
|
||||
dispatch('reload')
|
||||
|
||||
tick().then(() => {
|
||||
setTimeout(() => {
|
||||
forloopTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
@@ -251,7 +252,7 @@
|
||||
|
||||
dispatch('reload')
|
||||
|
||||
tick().then(() => {
|
||||
setTimeout(() => {
|
||||
forloopTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
@@ -267,7 +268,7 @@
|
||||
$flowStore = $flowStore
|
||||
|
||||
dispatch('reload')
|
||||
tick().then(() => {
|
||||
setTimeout(() => {
|
||||
forloopTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
@@ -326,7 +327,7 @@
|
||||
$flowStore = $flowStore
|
||||
dispatch('reload')
|
||||
|
||||
tick().then(() => {
|
||||
setTimeout(() => {
|
||||
forloopTutorial.moveNext()
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user