Fix flow tutorials (#6722)

* Fix tutorial basic

* fix other tutorials

* nit fix bug with button shrinking

* tutorial works backwards

* nit delete field on prev
This commit is contained in:
Diego Imbert
2025-10-01 18:00:46 +02:00
committed by GitHub
parent e2e3ae9f02
commit 8eb6c13c19
9 changed files with 81 additions and 30 deletions

View File

@@ -643,7 +643,8 @@
{#if !uiOnly}
<button
class="rounded-full p-1 text-gray-500 bg-white
class="delete-schema-field-button
rounded-full p-1 text-gray-500 bg-white
duration-200 hover:bg-gray-600 focus:bg-gray-600 hover:text-white dark:bg-gray-700 dark:text-white dark:hover:bg-gray-800"
aria-label="Clear"
onclick={() => {

View File

@@ -49,6 +49,11 @@
use:clickOutside={{
eventToListenName: 'pointerdown',
stopPropagation: true,
exclude: async () => {
const tutorial = document.querySelector('#driver-popover-content') as HTMLElement | null
if (tutorial) return [tutorial]
return []
},
onClickOutside: () => (open = false)
}}
>

View File

@@ -109,8 +109,9 @@
{/if}
</div>
{:else}
<!-- Index 0 is used by the tutorial to identify the first "Add step" -->
<InsertModuleButton
index={0}
index="error-handler-button"
placement={'bottom-center'}
on:new={(e) => {
insertFailureModule(e.detail.inlineScript)

View File

@@ -15,7 +15,7 @@
type Placement = `${Side}-${Alignment}`
interface Props {
index?: number
index?: number | 'error-handler-button'
funcDesc?: string
kind?: 'script' | 'trigger' | 'preprocessor' | 'failure'
iconSize?: number

View File

@@ -51,14 +51,14 @@
}
},
{
element: '#flow-editor-error-handler',
element: '#flow-editor-add-step-error-handler-button',
popover: {
title: 'Error handler',
description:
'You can add an error handler to your flow. It will be executed if any of the steps in the flow fails.',
onNextClick: () => {
triggerPointerDown('#flow-editor-error-handler button')
triggerPointerDown('#flow-editor-add-step-error-handler-button')
setTimeout(() => {
driver.moveNext()
})

View File

@@ -178,6 +178,9 @@
{
element: '#flow-editor-step-input',
onHighlighted: () => {
document.querySelector('#flow-editor-plug')?.parentElement?.classList.remove('opacity-0')
},
popover: {
title: 'Flow inputs',
description: 'UI is autogenerated from your code.'

View File

@@ -11,6 +11,7 @@
} 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()
@@ -41,16 +42,13 @@
popover: {
title: 'Flows inputs',
description: 'Flows have inputs that can be used in the flow',
onNextClick: () => {
clickButtonBySelector('#flow-editor-virtual-Input')
tick()
.then(() => clickButtonBySelector('#add-flow-input-btn'))
.then(tick)
.then(() => setInputBySelector('input[placeholder="Field name"]', 'firstname'))
setTimeout(() => {
driver.moveNext()
})
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'
@@ -64,11 +62,15 @@
setTimeout(() => {
driver.moveNext()
})
},
onPrevClick: () => {
clickButtonBySelector('#add-flow-input-btn') // Close the input drawer
setTimeout(() => driver.movePrevious())
}
}
},
{
element: '#flow-editor-add-property',
element: '*:has(> #flow-editor-add-property)',
popover: {
title: 'Add your property',
description: 'Click here to save your property',
@@ -87,16 +89,26 @@
description: 'Click here to add a step to your flow',
onNextClick: () => {
triggerPointerDown(`#flow-editor-add-step-0`)
setTimeout(() => {
driver.moveNext()
})
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"
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'
},
@@ -149,6 +161,7 @@
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()
@@ -158,6 +171,9 @@
},
{
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'
@@ -165,10 +181,14 @@
},
{
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(() => {
@@ -198,6 +218,10 @@
setTimeout(() => {
driver.moveNext()
})
},
onPrevClick: () => {
clickButtonBySelector('#flow-editor-plug')
setTimeout(() => driver.movePrevious())
}
}
},
@@ -206,7 +230,11 @@
element: '#flow-editor-step-input',
popover: {
title: 'Input connected!',
description: 'The input is now connected to the firstname input'
description: 'The input is now connected to the firstname input',
onPrevClick: () => {
clickButtonBySelector('#flow-editor-plug')
setTimeout(() => driver.movePrevious())
}
}
},
@@ -226,7 +254,7 @@
},
{
element: '#flow-preview-content',
element: 'textarea.w-full',
popover: {
title: 'Flow input',
description: 'Lets provide an input to our flow',
@@ -236,6 +264,10 @@
setTimeout(() => {
driver.moveNext()
})
},
onPrevClick: () => {
clickButtonBySelector('#flow-editor-test-flow') // Close the test drawer
setTimeout(() => driver.movePrevious())
}
}
},

View File

@@ -24,6 +24,11 @@
// Render controls needs to be exposed so steps that have a custom render can call it
export function renderControls({ config, state }) {
const popoverContent = document.querySelector('#driver-popover-content')
popoverContent?.addEventListener('pointerdown', (event) => {
event.stopPropagation()
})
const popoverDescription = document.querySelector('#driver-popover-description')
if (!tutorial) {

View File

@@ -172,9 +172,9 @@ export function displayDate(
}
const dateChoices: Intl.DateTimeFormatOptions = displayDate
? {
day: 'numeric',
month: 'numeric'
}
day: 'numeric',
month: 'numeric'
}
: {}
return date.toLocaleString(undefined, {
...timeChoices,
@@ -1065,7 +1065,7 @@ export async function tryEvery({
try {
await tryCode()
break
} catch (err) { }
} catch (err) {}
i++
}
if (i >= times) {
@@ -1331,7 +1331,7 @@ export function conditionalMelt(node: HTMLElement, meltItem: AnyMeltElement | un
if (meltItem) {
return meltItem(node)
}
return { destroy: () => { } }
return { destroy: () => {} }
}
export type Item = {
@@ -1537,9 +1537,9 @@ export type S3Uri = `s3://${string}/${string}`
export type S3Object =
| S3Uri
| {
s3: string
storage?: string
}
s3: string
storage?: string
}
export function parseS3Object(s3Object: S3Object): { s3: string; storage?: string } {
if (typeof s3Object === 'object') return s3Object
@@ -1620,3 +1620,7 @@ export function createCache<Keys extends Record<string, any>, T, InitialKeys ext
return cache.get(key)!.value
}
}
export async function wait(ms: number) {
return new Promise((resolve) => setTimeout(() => resolve(undefined), ms))
}