mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 00:02:03 +00:00
flow UX improvements
This commit is contained in:
@@ -12,7 +12,6 @@
|
||||
} from '$lib/utils'
|
||||
import { faGlobe, faPen } from '@fortawesome/free-solid-svg-icons'
|
||||
import { setContext } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { writable } from 'svelte/store'
|
||||
import CenteredPage from './CenteredPage.svelte'
|
||||
import { Button } from './common'
|
||||
@@ -23,6 +22,7 @@
|
||||
import { flowStateStore } from './flows/flowState'
|
||||
import { flowStore } from './flows/flowStore'
|
||||
import FlowImportExportMenu from './flows/header/FlowImportExportMenu.svelte'
|
||||
import FlowPreviewButtons from './flows/header/FlowPreviewButtons.svelte'
|
||||
import { loadFlowSchedule, type Schedule } from './flows/scheduleUtils'
|
||||
import type { FlowEditorContext } from './flows/types'
|
||||
import { cleanInputs } from './flows/utils'
|
||||
@@ -162,41 +162,8 @@
|
||||
|
||||
<div class="flex flex-col flex-1 h-full">
|
||||
<!-- Nav between steps-->
|
||||
<div
|
||||
class="justify-between flex flex-row w-full my-2 px-4 space-x-4 h-10 overflow-x-auto scrollbar-hidden"
|
||||
>
|
||||
<div id="flow_title" class="flex justify-between items-center">
|
||||
<button class="flex flex-row items-center w-full h-full" on:click={() => select('settings')}>
|
||||
<span class="font-mono text-sm"> {$flowStore.path}</span>
|
||||
<Icon
|
||||
data={faPen}
|
||||
scale={0.8}
|
||||
class="text-gray-500 ml-2 flex justify-center items-center mb-0.5"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="shrink h-full">
|
||||
<button
|
||||
class="flex flex-row items-center w-full h-full"
|
||||
on:click={() => {
|
||||
select('settings')
|
||||
document.getElementById('flow-summary')?.focus()
|
||||
}}
|
||||
>
|
||||
<div class="overflow-x-auto flex items-center h-full text-sm text-left font-semibold">
|
||||
<div>
|
||||
{$flowStore.summary == '' || !$flowStore.summary ? 'No summary' : $flowStore.summary}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Icon data={faPen} scale={0.8} class="text-gray-500 ml-1" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-row-reverse ml-2 space-x-reverse space-x-2">
|
||||
<Button disabled={pathError != ''} color="blue" size="sm" on:click={saveFlow}>Save</Button>
|
||||
<FlowImportExportMenu />
|
||||
|
||||
<div class="justify-between flex flex-row w-full py-2 px-4 space-x-4">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<Button
|
||||
color="light"
|
||||
size="sm"
|
||||
@@ -212,10 +179,43 @@
|
||||
url.searchParams.append('flow', btoa(JSON.stringify(openFlow)))
|
||||
window.open(url, '_blank')?.focus()
|
||||
}}
|
||||
startIcon={{ icon: faGlobe }}
|
||||
>
|
||||
<Icon data={faGlobe} scale={0.8} class="inline mr-2" />
|
||||
Publish to Hub
|
||||
</Button>
|
||||
<FlowImportExportMenu />
|
||||
</div>
|
||||
<div class="gap-1 flex-row hidden md:flex shrink overflow-hidden">
|
||||
<Button
|
||||
btnClasses="hidden lg:inline-flex"
|
||||
startIcon={{ icon: faPen }}
|
||||
variant="contained"
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={async () => {
|
||||
select('settings')
|
||||
}}
|
||||
>
|
||||
{$flowStore.path}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={{ icon: faPen }}
|
||||
variant="contained"
|
||||
color="light"
|
||||
size="xs"
|
||||
on:click={async () => {
|
||||
select('settings')
|
||||
document.getElementById('flow-summary')?.focus()
|
||||
}}
|
||||
>
|
||||
<div class="max-w-[10em] !truncate">
|
||||
{$flowStore.summary == '' || !$flowStore.summary ? 'No summary' : $flowStore.summary}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex flex-row-reverse ml-2 space-x-reverse space-x-2">
|
||||
<Button disabled={pathError != ''} size="sm" on:click={saveFlow}>Save</Button>
|
||||
<FlowPreviewButtons />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -98,8 +98,9 @@
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
|
||||
<div class="gap-1 flex-row hidden md:flex">
|
||||
<div class="gap-1 flex-row hidden md:flex shrink overflow-hidden">
|
||||
<Button
|
||||
btnClasses="hidden lg:inline-flex"
|
||||
startIcon={{ icon: faPen }}
|
||||
variant="contained"
|
||||
color="light"
|
||||
|
||||
@@ -9,12 +9,10 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center space-x-1">
|
||||
<div class="flex items-center justify-center">
|
||||
{#each items as item, index}
|
||||
{#if index > 0}
|
||||
<div class="mx-1">
|
||||
<slot name="separator" />
|
||||
</div>
|
||||
<slot name="separator" />
|
||||
{/if}
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
export let endIcon: ButtonType.Icon | undefined = undefined
|
||||
export let element: ButtonType.Element | undefined = undefined
|
||||
export let id: string = ''
|
||||
export let nonCaptureEvent: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
// Order of classes: border, border modifier, bg, bg modifier, text, text modifier, everything else
|
||||
@@ -68,13 +69,15 @@
|
||||
}
|
||||
|
||||
function onClick(event: MouseEvent) {
|
||||
event.preventDefault()
|
||||
dispatch('click', event)
|
||||
if (href) {
|
||||
if (href.startsWith('http')) {
|
||||
window.open(href, target)
|
||||
} else {
|
||||
goto(href)
|
||||
if (!nonCaptureEvent) {
|
||||
event.preventDefault()
|
||||
dispatch('click', event)
|
||||
if (href) {
|
||||
if (href.startsWith('http')) {
|
||||
window.open(href, target)
|
||||
} else {
|
||||
goto(href)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +93,7 @@
|
||||
<svelte:element
|
||||
this={href ? 'a' : 'button'}
|
||||
bind:this={element}
|
||||
on:click|stopPropagation={onClick}
|
||||
on:click={onClick}
|
||||
on:focus
|
||||
on:blur
|
||||
{...buttonProps}
|
||||
|
||||
@@ -47,24 +47,20 @@
|
||||
</script>
|
||||
|
||||
<div class="relative" bind:this={menu}>
|
||||
<div>
|
||||
<div on:click={() => (show = !show)} on:click>
|
||||
<slot name="trigger" />
|
||||
</div>
|
||||
|
||||
{#if show}
|
||||
<div
|
||||
in:scale={{ duration: 100, start: 0.95 }}
|
||||
out:scale={{ duration: 75, start: 0.95 }}
|
||||
class={classNames(
|
||||
'z-50 absolute mt-2 w-60 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none',
|
||||
placementsClasses[placement]
|
||||
)}
|
||||
role="menu"
|
||||
tabindex="-1"
|
||||
>
|
||||
<slot {close} />
|
||||
</div>
|
||||
{/if}
|
||||
<div on:click={() => (show = !show)} on:click>
|
||||
<slot name="trigger" />
|
||||
</div>
|
||||
|
||||
{#if show}
|
||||
<div
|
||||
class={classNames(
|
||||
'z-50 absolute mt-2 w-60 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none',
|
||||
placementsClasses[placement]
|
||||
)}
|
||||
role="menu"
|
||||
tabindex="-1"
|
||||
>
|
||||
<slot {close} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -3,16 +3,14 @@
|
||||
import FlowEditorPanel from './content/FlowEditorPanel.svelte'
|
||||
import FlowModuleSchemaMap from './map/FlowModuleSchemaMap.svelte'
|
||||
import { flowStore } from './flowStore'
|
||||
import FlowPreviewButtons from './header/FlowPreviewButtons.svelte'
|
||||
|
||||
export let initialPath: string
|
||||
</script>
|
||||
|
||||
<div class="h-full overflow-hidden border-t">
|
||||
<Splitpanes>
|
||||
<Pane size={25} minSize={20} class="h-full flex flex-col">
|
||||
<FlowPreviewButtons />
|
||||
<div class="grow overflow-auto p-4 bg-gray-50">
|
||||
<Pane size={25} minSize={20} class="h-full">
|
||||
<div class="grow overflow-auto p-4 bg-gray h-full bg-gray-50 relative">
|
||||
{#if $flowStore.value.modules}
|
||||
<FlowModuleSchemaMap bind:modules={$flowStore.value.modules} root />
|
||||
{/if}
|
||||
|
||||
@@ -1,45 +1,82 @@
|
||||
<script lang="ts">
|
||||
import { Tab } from '$lib/components/common'
|
||||
import { Alert, Tab } from '$lib/components/common'
|
||||
import TabContent from '$lib/components/common/tabs/TabContent.svelte'
|
||||
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import FlowCard from '../common/FlowCard.svelte'
|
||||
import FlowModuleEarlyStop from './FlowModuleEarlyStop.svelte'
|
||||
import FlowModuleSuspend from './FlowModuleSuspend.svelte'
|
||||
import FlowRetries from './FlowRetries.svelte'
|
||||
|
||||
export let flowModule: FlowModule
|
||||
export let type: 'branchall' | 'branchone'
|
||||
export let parentModule: FlowModule | undefined
|
||||
export let previousModuleId: string | undefined
|
||||
|
||||
let selected: string = 'retries'
|
||||
</script>
|
||||
|
||||
{#if flowModule}
|
||||
<Tabs bind:selected>
|
||||
<Tab value="retries">Retries</Tab>
|
||||
<Tab value="early-stop">Early Stop</Tab>
|
||||
<Tab value="suspend">Sleep/Suspend</Tab>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<div class="overflow-hidden bg-white" style="height:calc(100% - 32px);">
|
||||
<TabContent value="retries" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowRetries bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="early-stop" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleEarlyStop {previousModuleId} bind:flowModule {parentModule} />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend {previousModuleId} bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
<div class="h-full flex flex-col">
|
||||
<FlowCard title={type == 'branchall' ? 'Run all branches' : 'Run one branch'}>
|
||||
<div class="flex flex-col h-full">
|
||||
<div class="border">
|
||||
{#if type == 'branchall'}
|
||||
<Alert type="info" title="All branches will be run in order">
|
||||
Branches run in sequence, every branch is run to the end one after the other.
|
||||
<br />
|
||||
<br />
|
||||
Configure branches to skip errors and to not result in that step itself failing.
|
||||
<br />
|
||||
<br />
|
||||
The result of this step is the list of the result of each branch.
|
||||
<br />
|
||||
<br />
|
||||
Since this is a step containing all branches as embedded flows, this step can be retried,
|
||||
stopped early, can be made to sleep or to suspend after execution.
|
||||
</Alert>
|
||||
{:else}
|
||||
<Alert type="info" title="Only one branch will be run">
|
||||
Only one branch is ran, the first one that match its predicate, if none do, the default
|
||||
branch is chosen.
|
||||
<br />
|
||||
<br />
|
||||
The result of this step is the result of the branch.
|
||||
<br />
|
||||
<br />
|
||||
Since this is a step containing all branches as embedded flows, this step can be retried,
|
||||
stopped early, can be made to sleep or to suspend after execution.
|
||||
</Alert>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
{/if}
|
||||
{#if flowModule}
|
||||
<Tabs bind:selected>
|
||||
<Tab value="retries">Retries</Tab>
|
||||
<Tab value="early-stop">Early Stop</Tab>
|
||||
<Tab value="suspend">Sleep/Suspend</Tab>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<div class="overflow-hidden bg-white">
|
||||
<TabContent value="retries" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowRetries bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="early-stop" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleEarlyStop {previousModuleId} bind:flowModule {parentModule} />
|
||||
</div>
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend {previousModuleId} bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
{/if}
|
||||
</div>
|
||||
</FlowCard>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import { getStepPropPicker } from '../previousResults'
|
||||
import { flowStateStore } from '../flowState'
|
||||
import { flowStore } from '../flowStore'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
|
||||
const { previewArgs } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
@@ -36,6 +37,13 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-start space-y-2 {$$props.class}">
|
||||
<h2 class="mt-2"
|
||||
>Early stop <Tooltip>
|
||||
If defined, at the end of the step, the predicate expression will be evaluated to decide if
|
||||
the flow should stop early. Skipped flows are just a label useful to not see them in the runs
|
||||
page.</Tooltip
|
||||
></h2
|
||||
>
|
||||
<Toggle
|
||||
checked={isStopAfterIfEnabled}
|
||||
on:change={() => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import InputTransformForm from '$lib/components/InputTransformForm.svelte'
|
||||
import type SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
@@ -31,6 +32,13 @@
|
||||
$: isSleepEnabled = Boolean(flowModule.sleep)
|
||||
</script>
|
||||
|
||||
<h2 class="mt-2"
|
||||
>Suspend<Tooltip>
|
||||
If defined, at the end of the step, the flow will be suspended until it receives external
|
||||
requests to be resumed or canceled. This is most useful to implement approval steps but can be
|
||||
used flexibly for other purpose. To get the resume urls, use `wmill.getResumeEndpoints`.</Tooltip
|
||||
></h2
|
||||
>
|
||||
<Toggle
|
||||
checked={isSuspendEnabled}
|
||||
on:change={() => {
|
||||
@@ -65,6 +73,12 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4"
|
||||
>Sleep<Tooltip>
|
||||
If defined, at the end of the step, the flow will sleep for a number of seconds before being
|
||||
resumed. Sleeping is passive and does not consume any resources.</Tooltip
|
||||
></h2
|
||||
>
|
||||
<Toggle
|
||||
checked={isSleepEnabled}
|
||||
on:change={() => {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
import FlowInputs from './FlowInputs.svelte'
|
||||
import { flowStateStore, type FlowModuleState } from '../flowState'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { Alert } from '$lib/components/common'
|
||||
|
||||
const { selectedId } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
@@ -34,10 +35,30 @@
|
||||
{#if flowModule.value.type === 'forloopflow'}
|
||||
<FlowLoop bind:mod={flowModule} {parentModule} {previousModuleId} />
|
||||
{:else if flowModule.value.type === 'branchone'}
|
||||
<FlowBranchesWrapper {previousModuleId} bind:flowModule {parentModule} />
|
||||
<FlowBranchesWrapper
|
||||
type={flowModule.value.type}
|
||||
{previousModuleId}
|
||||
bind:flowModule
|
||||
{parentModule}
|
||||
/>
|
||||
{:else if flowModule.value.type === 'branchall'}
|
||||
<FlowBranchesWrapper {previousModuleId} bind:flowModule {parentModule} />
|
||||
<FlowBranchesWrapper
|
||||
type={flowModule.value.type}
|
||||
{previousModuleId}
|
||||
bind:flowModule
|
||||
{parentModule}
|
||||
/>
|
||||
{:else if flowModule.value.type === 'identity'}
|
||||
{#if $selectedId == 'failure'}
|
||||
<Alert type="info" title="Error handlers are triggered upon non recovered errors">
|
||||
If defined, the error handler will take as input, the result of the step that errored (which
|
||||
has its error in the 'error field').
|
||||
<br />
|
||||
<br />
|
||||
Steps are retried until they succeed, or until the maximum number of retries defined for that
|
||||
spec is reached, at which point the error handler is called.
|
||||
</Alert>
|
||||
{/if}
|
||||
<h1 class="p-4"
|
||||
>Select a step kind <Tooltip
|
||||
>Until being defined, this step acts as an identify function, returning as result its input
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Alert } from '$lib/components/common'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
|
||||
export let flowModule: FlowModule
|
||||
@@ -30,6 +32,15 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col items-start space-y-1 {$$props.class}">
|
||||
<h2 class="mt-2"
|
||||
>Retries <Tooltip>
|
||||
If defined, upon error this step will be retried with a delay and a maximum number of attempts
|
||||
as defined below. If none of the retries succeed, the step job is a failure and the error will
|
||||
propagate up in the case of a branch, and the error handler will be called ultimately if not
|
||||
handled prior.</Tooltip
|
||||
></h2
|
||||
>
|
||||
|
||||
<Toggle
|
||||
checked={isConstantRetryEnabled}
|
||||
on:change={() => {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import FlowSchedules from './FlowSchedules.svelte'
|
||||
import SvelteMarkdown from 'svelte-markdown'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { Alert } from '$lib/components/common'
|
||||
|
||||
export let initialPath: string
|
||||
|
||||
@@ -71,12 +72,22 @@
|
||||
</div>
|
||||
</TabContent>
|
||||
<TabContent value="schedule" class="p-4">
|
||||
<Alert type="info" title="Primary Schedule">
|
||||
Flows can be triggered by any schedules, their webhooks or their UI but they only have
|
||||
only one primary schedules with which they share the same path. The primary schedule can
|
||||
be set here.
|
||||
</Alert>
|
||||
<div class="mt-4" />
|
||||
<FlowSchedules />
|
||||
</TabContent>
|
||||
|
||||
<TabContent value="same-worker" class="p-4 flex flex-col">
|
||||
<Alert type="info" title="Toggle Same Worker to have all steps be ran on the same worker">
|
||||
Steps will be run one after the other on the same worker, and will share a folder at
|
||||
`/shared` in which they can store heavier data and pass them to the next step. <br /><br
|
||||
/>Beware that the `/shared` folder is not preserved across suspends and sleeps.
|
||||
</Alert>
|
||||
<span class="my-2 text-sm font-bold">Same Worker</span>
|
||||
|
||||
<Toggle
|
||||
bind:checked={$flowStore.value.same_worker}
|
||||
options={{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import FlowViewer from '$lib/components/FlowViewer.svelte'
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
import { faFileExport, faFileImport } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faFileExport, faFileImport, faGlobe } from '@fortawesome/free-solid-svg-icons'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { Button } from '../../common'
|
||||
import { flowStore, initFlow } from '../flowStore'
|
||||
@@ -27,13 +27,10 @@
|
||||
</script>
|
||||
|
||||
<Menu placement="bottom-end">
|
||||
<button
|
||||
slot="trigger"
|
||||
class="flex items-center text-sm border focus:outline-none focus:ring-4 rounded-md
|
||||
text-gray-800 bg-white hover:bg-gray-100 focus:ring-gray-300 px-4 py-2"
|
||||
>
|
||||
Import/Export
|
||||
</button>
|
||||
<div slot="trigger">
|
||||
<Button nonCaptureEvent={true} color="light" size="sm" variant="border">Import/Export</Button>
|
||||
</div>
|
||||
|
||||
<div class="divide-y divide-gray-200">
|
||||
<MenuItem on:click={() => jsonSetterDrawer.toggleDrawer()}>
|
||||
<Icon data={faFileImport} scale={0.6} class="inline mr-2" />
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import { faPlay } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import { getContext } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
const { selectedId } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
let previewOpen = false
|
||||
@@ -22,23 +21,19 @@
|
||||
].includes($selectedId)
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex flex-row-reverse justify-between items-center flex-wrap gap-2 w-full py-1 px-4 bg-white border-b"
|
||||
>
|
||||
<div class="flex flex-row-reverse justify-between items-center gap-x-2">
|
||||
<Button
|
||||
btnClasses="grow"
|
||||
on:click={() => {
|
||||
previewMode = 'whole'
|
||||
previewOpen = !previewOpen
|
||||
}}
|
||||
size="sm"
|
||||
endIcon={{ icon: faPlay }}
|
||||
>
|
||||
Test flow
|
||||
<Icon data={faPlay} class="ml-2" scale={0.8} />
|
||||
</Button>
|
||||
{#if !upToDisabled}
|
||||
<Button
|
||||
btnClasses="grow"
|
||||
size="sm"
|
||||
disabled={upToDisabled}
|
||||
color="light"
|
||||
@@ -47,12 +42,12 @@
|
||||
previewMode = 'upTo'
|
||||
previewOpen = !previewOpen
|
||||
}}
|
||||
endIcon={{ icon: faPlay }}
|
||||
>
|
||||
Test up to step {$selectedId
|
||||
.split('-')
|
||||
.map((x) => (Number.isNaN(Number(x)) ? x : Number(x) + 1))
|
||||
.join(' ')}
|
||||
<Icon data={faPlay} class="ml-2" scale={0.8} />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
}
|
||||
}}
|
||||
class={classNames(
|
||||
'border rounded-md p-2 bg-white text-sm cursor-pointer mt-4 flex flex-col overflow-x-hidden',
|
||||
'border rounded-md p-2 bg-white text-sm cursor-pointer mt-4 flex flex-col overflow-x-hidden bottom-0 z-20 sticky',
|
||||
$selectedId.includes('failure') ? 'outline outline-offset-1 outline-2 outline-slate-900' : ''
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
{#if deletable}
|
||||
<Button
|
||||
on:click={(event) => dispatch('delete', event)}
|
||||
startIcon={{ icon: faTrashAlt }}
|
||||
startIcon={{ icon: faTrashAlt, classes: 'text-gray-500' }}
|
||||
iconOnly={true}
|
||||
color="light"
|
||||
variant="border"
|
||||
|
||||
@@ -99,10 +99,10 @@
|
||||
{/each}
|
||||
|
||||
<InsertModuleButton on:click={() => insertNewModuleAtIndex(modules.length)} />
|
||||
{#if root}
|
||||
<FlowErrorHandlerItem />
|
||||
{/if}
|
||||
</ul>
|
||||
{#if root}
|
||||
<FlowErrorHandlerItem />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<RemoveStepConfirmationModal
|
||||
|
||||
Reference in New Issue
Block a user