mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 00:02:19 +00:00
UX improvements
This commit is contained in:
@@ -818,7 +818,11 @@ async fn push_next_flow_job(
|
||||
InputTransform::Static { value } => value,
|
||||
InputTransform::Javascript { expr } => eval_timeout(
|
||||
expr.to_string(),
|
||||
[("result".to_string(), last_result.clone())].into(),
|
||||
[
|
||||
("flow_input".to_string(), flow_input),
|
||||
("result".to_string(), last_result.clone()),
|
||||
]
|
||||
.into(),
|
||||
None,
|
||||
None,
|
||||
"".to_string(),
|
||||
@@ -835,7 +839,7 @@ async fn push_next_flow_job(
|
||||
n.as_u64().map(|x| from_now(Duration::from_secs(x)))
|
||||
}
|
||||
_ => Err(Error::ExecutionErr(format!(
|
||||
"Expected an array value, found: {json_value}"
|
||||
"Expected a number value, found: {json_value}"
|
||||
)))?,
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -165,50 +165,52 @@
|
||||
</div>
|
||||
</Pane>
|
||||
<Pane size={40} minSize={10}>
|
||||
<Splitpanes horizontal>
|
||||
<Pane size={33}>
|
||||
<div class="w-full border-b p-2 text-xs font-bold">Preview</div>
|
||||
<div class="px-2">
|
||||
<div class="break-words relative font-sans">
|
||||
<SchemaForm compact {schema} bind:args bind:isValid />
|
||||
<div class="flex flex-col h-full">
|
||||
<div class="px-2 w-full border-b py-1">
|
||||
{#if testIsLoading}
|
||||
<Button on:click={testJobLoader?.cancelJob} btnClasses="w-full" color="red" size="xs">
|
||||
<WindmillIcon
|
||||
white={true}
|
||||
class="animate-[spin_5s_linear_infinite] mr-2 text-white"
|
||||
height="20px"
|
||||
width="20px"
|
||||
/>
|
||||
Cancel
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
on:click={runTest}
|
||||
btnClasses="w-full"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: faPlay,
|
||||
classes: 'animate-none'
|
||||
}}
|
||||
>
|
||||
{#if testIsLoading}Running{:else}Test <Kbd class="ml-4 text-5xs -my-0.5">Ctrl+Enter</Kbd
|
||||
>{/if}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<Splitpanes horizontal>
|
||||
<Pane size={33}>
|
||||
<div class="px-2">
|
||||
<div class="break-words relative font-sans">
|
||||
<SchemaForm compact {schema} bind:args bind:isValid />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Pane>
|
||||
<Pane size={67}>
|
||||
<div class="px-2 py-1 w-full">
|
||||
{#if testIsLoading}
|
||||
<Button on:click={testJobLoader?.cancelJob} btnClasses="w-full" color="red" size="xs">
|
||||
<WindmillIcon
|
||||
white={true}
|
||||
class="animate-[spin_5s_linear_infinite] mr-2 text-white"
|
||||
height="20px"
|
||||
width="20px"
|
||||
/>
|
||||
Cancel
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
on:click={runTest}
|
||||
btnClasses="w-full"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: faPlay,
|
||||
classes: 'animate-none'
|
||||
}}
|
||||
>
|
||||
{#if testIsLoading}Running{:else}Test <Kbd class="ml-4 text-5xs">Ctrl+Enter</Kbd>{/if}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
<LogPanel
|
||||
{path}
|
||||
{lang}
|
||||
previewJob={testJob}
|
||||
{pastPreviews}
|
||||
previewIsLoading={testIsLoading}
|
||||
bind:lastSave
|
||||
/>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</Pane>
|
||||
<Pane size={67}>
|
||||
<LogPanel
|
||||
{path}
|
||||
{lang}
|
||||
previewJob={testJob}
|
||||
{pastPreviews}
|
||||
previewIsLoading={testIsLoading}
|
||||
bind:lastSave
|
||||
/>
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</div>
|
||||
</Pane>
|
||||
</SplitPanesWrapper>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import FlowCard from '../common/FlowCard.svelte'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
import FlowModuleEarlyStop from './FlowModuleEarlyStop.svelte'
|
||||
import FlowModuleSleep from './FlowModuleSleep.svelte'
|
||||
import FlowModuleSuspend from './FlowModuleSuspend.svelte'
|
||||
// import FlowRetries from './FlowRetries.svelte'
|
||||
|
||||
@@ -117,7 +118,8 @@
|
||||
<Tabs bind:selected>
|
||||
<!-- <Tab value="retries">Retries</Tab> -->
|
||||
<Tab value="early-stop">Early Stop</Tab>
|
||||
<Tab value="suspend">Sleep/Suspend</Tab>
|
||||
<Tab value="suspend">Suspend</Tab>
|
||||
<Tab value="sleep">Sleep</Tab>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<div class="overflow-hidden bg-white">
|
||||
@@ -135,7 +137,12 @@
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend previousModuleId={previousModule?.id} bind:flowModule />
|
||||
<FlowModuleSuspend bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
<TabContent value="sleep" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSleep previousModuleId={previousModule?.id} bind:flowModule />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import { getStepPropPicker } from '../previousResults'
|
||||
import { flowStateStore } from '../flowState'
|
||||
import { flowStore } from '../flowStore'
|
||||
import FlowModuleSleep from './FlowModuleSleep.svelte'
|
||||
|
||||
const { previewArgs } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
@@ -98,7 +99,8 @@
|
||||
<Tabs bind:selected>
|
||||
<!-- <Tab value="retries">Retries</Tab> -->
|
||||
<Tab value="early-stop">Early Stop</Tab>
|
||||
<Tab value="suspend">Sleep/Suspend</Tab>
|
||||
<Tab value="suspend">Suspend</Tab>
|
||||
<Tab value="sleep">Sleep</Tab>
|
||||
|
||||
<svelte:fragment slot="content">
|
||||
<div class="overflow-hidden bg-white" style="height:calc(100% - 32px);">
|
||||
@@ -116,7 +118,12 @@
|
||||
|
||||
<TabContent value="suspend" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSuspend previousModuleId={previousModule?.id} bind:flowModule={mod} />
|
||||
<FlowModuleSuspend bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
<TabContent value="sleep" class="flex flex-col flex-1 h-full">
|
||||
<div class="p-4 overflow-y-auto">
|
||||
<FlowModuleSleep previousModuleId={previousModule?.id} bind:flowModule={mod} />
|
||||
</div>
|
||||
</TabContent>
|
||||
</div>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import Alert from '$lib/components/common/alert/Alert.svelte'
|
||||
import FlowModuleSleep from './FlowModuleSleep.svelte'
|
||||
|
||||
const { selectedId, previewArgs } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
@@ -56,7 +57,7 @@
|
||||
$: stepPropPicker = failureModule
|
||||
? {
|
||||
pickableProperties: {
|
||||
flow_input: $flowStateStore.previewArgs,
|
||||
flow_input: $previewArgs,
|
||||
priorIds: {},
|
||||
previousId: undefined
|
||||
},
|
||||
@@ -221,7 +222,8 @@
|
||||
<Tab value="advanced-retries">Retries</Tab>
|
||||
{#if !$selectedId.includes('failure')}
|
||||
<Tab value="advanced-early-stop">Early Stop</Tab>
|
||||
<Tab value="advanced-suspend">Sleep/Suspend</Tab>
|
||||
<Tab value="advanced-suspend">Suspend</Tab>
|
||||
<Tab value="advanced-sleep">Sleep</Tab>
|
||||
<Tab value="advanced-same_worker">Same Worker/Shared dir</Tab>
|
||||
{/if}
|
||||
</Tabs>
|
||||
@@ -231,7 +233,11 @@
|
||||
<FlowModuleEarlyStop bind:flowModule class="px-4 pb-4 h-full overflow-auto" />
|
||||
{:else if selected === 'advanced-suspend'}
|
||||
<div class="px-4 pb-4 h-full overflow-auto">
|
||||
<FlowModuleSuspend previousModuleId={previousModule?.id} bind:flowModule />
|
||||
<FlowModuleSuspend bind:flowModule />
|
||||
</div>
|
||||
{:else if selected === 'advanced-sleep'}
|
||||
<div class="px-4 pb-4 h-full overflow-auto">
|
||||
<FlowModuleSleep previousModuleId={previousModule?.id} bind:flowModule />
|
||||
</div>
|
||||
{:else if selected === 'advanced-same_worker'}
|
||||
<div class="p-4 h-full overflow-auto">
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
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'
|
||||
import { getContext } from 'svelte'
|
||||
import { flowStateStore } from '../flowState'
|
||||
import PropPickerWrapper from '../propPicker/PropPickerWrapper.svelte'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
|
||||
export let flowModule: FlowModule
|
||||
export let previousModuleId: string | undefined
|
||||
|
||||
const { selectedId } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
let schema = emptySchema()
|
||||
schema.properties['sleep'] = {
|
||||
type: 'number',
|
||||
description: 'Sleep time in seconds'
|
||||
}
|
||||
|
||||
let editor: SimpleEditor | undefined = undefined
|
||||
|
||||
const result = $flowStateStore[$selectedId]?.previewResult ?? {}
|
||||
|
||||
$: isSleepEnabled = Boolean(flowModule.sleep)
|
||||
</script>
|
||||
|
||||
<h2 class="mt-2"
|
||||
>Sleep<Tooltip>
|
||||
If defined, at the end of the step, the flow will sleep for a number of seconds before
|
||||
scheduling the next job (if any, no effect if the step is the last one). Sleeping is passive and
|
||||
does not consume any resources.</Tooltip
|
||||
></h2
|
||||
>
|
||||
<Toggle
|
||||
checked={isSleepEnabled}
|
||||
on:change={() => {
|
||||
if (isSleepEnabled && flowModule.sleep != undefined) {
|
||||
flowModule.sleep = undefined
|
||||
} else {
|
||||
flowModule.sleep = {
|
||||
type: 'static',
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: 'Sleep after module successful execution'
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<span class="text-xs font-bold">Sleep for duration (seconds)</span>
|
||||
|
||||
{#if flowModule.sleep && schema.properties['sleep']}
|
||||
<div class="border">
|
||||
<PropPickerWrapper
|
||||
notSelectable
|
||||
{result}
|
||||
displayContext={false}
|
||||
pickableProperties={undefined}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
}}
|
||||
>
|
||||
<InputTransformForm
|
||||
bind:arg={flowModule.sleep}
|
||||
argName="sleep"
|
||||
{schema}
|
||||
{previousModuleId}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
<input type="number" disabled />
|
||||
{/if}
|
||||
</div>
|
||||
@@ -1,20 +1,11 @@
|
||||
<script lang="ts">
|
||||
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'
|
||||
import { getContext } from 'svelte'
|
||||
import { flowStateStore } from '../flowState'
|
||||
import PropPickerWrapper from '../propPicker/PropPickerWrapper.svelte'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
|
||||
export let flowModule: FlowModule
|
||||
export let previousModuleId: string | undefined
|
||||
|
||||
const { selectedId } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
let schema = emptySchema()
|
||||
schema.properties['sleep'] = {
|
||||
@@ -22,19 +13,15 @@
|
||||
description: 'Sleep time in seconds'
|
||||
}
|
||||
|
||||
let editor: SimpleEditor | undefined = undefined
|
||||
|
||||
const result = $flowStateStore[$selectedId]?.previewResult ?? {}
|
||||
|
||||
$: isSuspendEnabled = Boolean(flowModule.suspend)
|
||||
$: 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
|
||||
used flexibly for other purpose. To get the resume urls, use `wmill.getResumeUrls()` in
|
||||
Typescript, or `wmill.get_resume_urls()` in Python.</Tooltip
|
||||
></h2
|
||||
>
|
||||
<Toggle
|
||||
@@ -50,11 +37,11 @@
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: 'Suspend flow execution until approvals received'
|
||||
right: 'Suspend flow execution until events/approvals received'
|
||||
}}
|
||||
/>
|
||||
<div class="mb-4">
|
||||
<span class="text-xs font-bold">Number of approvals required for resuming flow</span>
|
||||
<span class="text-xs font-bold">Number of approvals/events required for resuming flow</span>
|
||||
|
||||
{#if flowModule.suspend}
|
||||
<input bind:value={flowModule.suspend.required_events} type="number" min="1" placeholder="1" />
|
||||
@@ -70,53 +57,3 @@
|
||||
<input type="number" disabled />
|
||||
{/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
|
||||
scheduling the next job (if any, no effect if the step is the last one). Sleeping is passive and
|
||||
does not consume any resources.</Tooltip
|
||||
></h2
|
||||
>
|
||||
<Toggle
|
||||
checked={isSleepEnabled}
|
||||
on:change={() => {
|
||||
if (isSleepEnabled && flowModule.sleep != undefined) {
|
||||
flowModule.sleep = undefined
|
||||
} else {
|
||||
flowModule.sleep = {
|
||||
type: 'static',
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: 'Sleep after module successful execution'
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<span class="text-xs font-bold">Sleep for duration (seconds)</span>
|
||||
|
||||
{#if flowModule.sleep && schema.properties['sleep']}
|
||||
<div class="border">
|
||||
<PropPickerWrapper
|
||||
notSelectable
|
||||
{result}
|
||||
displayContext={false}
|
||||
pickableProperties={undefined}
|
||||
on:select={({ detail }) => {
|
||||
editor?.insertAtCursor(detail)
|
||||
}}
|
||||
>
|
||||
<InputTransformForm
|
||||
bind:arg={flowModule.sleep}
|
||||
argName="sleep"
|
||||
{schema}
|
||||
{previousModuleId}
|
||||
/>
|
||||
</PropPickerWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
<input type="number" disabled />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
onSelect: SelectCallback
|
||||
}
|
||||
|
||||
writable
|
||||
export type PropPickerWrapperContext = {
|
||||
propPickerConfig: Writable<PropPickerConfig | undefined>
|
||||
focusProp: (propName: string, insertionMode: InsertionMode, onSelect: SelectCallback) => void
|
||||
@@ -55,7 +54,15 @@
|
||||
</Pane>
|
||||
<Pane minSize={20} size={40} class="py-2 relative !transition-none">
|
||||
{#if result}
|
||||
<PropPickerResult {result} />
|
||||
<PropPickerResult
|
||||
{result}
|
||||
on:select={({ detail }) => {
|
||||
dispatch('select', detail)
|
||||
if ($propPickerConfig?.onSelect(detail)) {
|
||||
propPickerConfig.set(undefined)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{:else if pickableProperties}
|
||||
<PropPicker
|
||||
{displayContext}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import ObjectViewer from './ObjectViewer.svelte'
|
||||
|
||||
export let result: any
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
<div class="w-full px-2">
|
||||
<span class="font-bold text-sm">Result</span>
|
||||
<div class="overflow-y-auto mb-2 w-full">
|
||||
<ObjectViewer json={{ result }} on:select />
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
<CenteredPage>
|
||||
{#if $workspaceStore == 'demo'}
|
||||
<div class="my-4" />
|
||||
<Alert title="Demo workspace">All uers get an invitation to this workspace.</Alert>
|
||||
<Alert title="Demo workspace">All users get an invitation to this workspace.</Alert>
|
||||
{:else if $workspaceStore == 'starter'}
|
||||
<div class="my-4" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user