Files
windmill/frontend/src/lib/components/ModuleStep.svelte
T
Faton RamadaniandRuben Fiszel 080860fad8 improve Flow UI (#297)
* Improve flow ui

* Finish reworking

* Fix formating

* Fix naviation

* Fix navigaion + adjust icon sizes

* Remove duplicate code

Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-08-01 15:07:29 +02:00

181 lines
5.1 KiB
Svelte

<script lang="ts">
import { RawScript, type FlowModule } from '$lib/gen'
import { previewResults } from '$lib/stores'
import { buildExtraLib, objectToTsType, schemaToTsType } from '$lib/utils'
import { faChevronDown, faChevronUp, faPlus } from '@fortawesome/free-solid-svg-icons'
import Icon from 'svelte-awesome'
import Editor from './Editor.svelte'
import EditorBar from './EditorBar.svelte'
import FlowPreview from './FlowPreview.svelte'
import FlowBox from './flows/FlowBox.svelte'
import FlowInputs from './flows/FlowInputs.svelte'
import FlowModuleHeader from './flows/FlowModuleHeader.svelte'
import {
addModule,
createInlineScriptModule,
flowStore,
loadSchema,
pickScript,
schemasStore,
type FlowMode
} from './flows/flowStore'
import { getPickableProperties } from './flows/utils'
import SchemaForm from './SchemaForm.svelte'
import Tooltip from './Tooltip.svelte'
export let open: number
export let mode: FlowMode
export let i: number
export let mod: FlowModule
export let args: Record<string, any> = {}
let editor: Editor
let websocketAlive = { pyright: false, black: false, deno: false }
let pickableProperties: Object | undefined = undefined
let bigEditor = false
$: schema = $schemasStore[i]
$: shouldPick = 'path' in mod.value && mod.value.path === '' && !('language' in mod.value)
$: pickableProperties = getPickableProperties($flowStore?.schema, args, $previewResults, mode, i)
$: extraLib = buildExtraLib(
schemaToTsType($flowStore?.schema),
i === 0 ? schemaToTsType($flowStore?.schema) : objectToTsType($previewResults[i])
)
function toResults(jobs: any) {
return jobs.map((job) => {
if (job.result) {
return job.result
} else if (Array.isArray(job)) {
return toResults(job)
}
})
}
const isTrigger = mode === 'pull' && i === 0
</script>
<button
class="rounded-full h-10 w-10 bg-white border-2 border-gray-400"
on:click={() => {
addModule(i)
open = i
}}
>
<Icon class="text-gray-400 mb-1" data={faPlus} />
</button>
<FlowBox>
<div id="module-{i}">
<FlowModuleHeader bind:open {mod} {i} {shouldPick}>
<div>
<h3 class="text-lg font-bold text-gray-900">Step {i + 1}</h3>
{#if isTrigger}
<h3 class="font-bold">
Trigger Script
<Tooltip>
When a flow is 'Pull', the first step is a trigger script. Trigger scripts are scripts
that must return a list which are the new items to be treated one by one by the rest
of the flow, usually the list of new items since last time the flow was run. One can
retrieve the item in the next step using `previous_result._value`. To easily compute
the diff, windmill provides some helpers under the form of `getInternalState` and
`setInternalState`.
</Tooltip>
</h3>
{/if}
<p>
{#if 'path' in mod.value && mod.value.path}
{mod.value.path}
{/if}
{#if 'language' in mod.value && mod.value.language}
Inline {mod.value.language}
{/if}
{#if !('path' in mod.value) && !('language' in mod.value)}
Select a script
{/if}
</p>
</div>
</FlowModuleHeader>
{#if open == i}
<div class="p-6">
{#if shouldPick}
<FlowInputs
{isTrigger}
on:pick={(e) => pickScript(e.detail.path, i)}
on:new={(e) => createInlineScriptModule(e.detail.language, i, mode)}
/>
{/if}
{#if mod.value.type === 'rawscript'}
<div class="mb-2 overflow-hidden">
<EditorBar {editor} {websocketAlive} lang={mod.value.language ?? 'deno'} />
</div>
<div>
<Editor
bind:websocketAlive
bind:this={editor}
class="{bigEditor ? 'h-2/3' : 'h-80'} border p-2 rounded"
bind:code={mod.value.content}
deno={mod.value.language === RawScript.language.DENO}
automaticLayout={true}
on:blur={() => loadSchema(i)}
formatAction={() => loadSchema(i)}
/>
<button
class="w-full text-center"
on:click={() => {
bigEditor = !bigEditor
}}><Icon data={bigEditor ? faChevronUp : faChevronDown} scale={1.0} /></button
>
</div>
<div class="mt-2 mb-8">
<p class="text-gray-500 italic">
Move the focus outside of the text editor to recompute the input schema or press
Ctrl/Cmd+S
</p>
</div>
{/if}
{#if !shouldPick}
<p class="text-lg font-bold text-gray-900 mb-2">Step inputs</p>
<SchemaForm
inputTransform={true}
{schema}
{extraLib}
{i}
bind:pickableProperties
bind:args={mod.input_transform}
/>
{/if}
</div>
{#if !shouldPick}
<div class="border-b border-gray-200" />
<div class="p-3">
<FlowPreview
bind:args
flow={$flowStore}
{i}
{mode}
schemas={$schemasStore}
on:change={(e) => {
previewResults.set(toResults(e.detail))
}}
/>
</div>
{/if}
{/if}
{#if open == i}
<div>
<button class="w-full h-full" on:click={() => (open = -1)}>
<Icon data={faChevronUp} scale={1.0} />
</button>
</div>
{:else}
<div>
<button class="w-full h-full" on:click={() => (open = i)}>
<Icon data={faChevronDown} scale={1.0} />
</button>
</div>
{/if}
</div>
</FlowBox>