Files
windmill/frontend/src/lib/components/flows/content/FlowModule.svelte
T
Faton Ramadani 381191442f fix(frontend): Support of suspend & stop expression + restore import/export menu (#580)
* feature(frontend): Various UI fix + restore removed features

* feature(frontend): WIP Prop picker panel

* feature(frontend): Advanced flow module tab

* feature(frontend): Add import/export flow menu

* feature(frontend): Remove summary edition + add a enable/disable button for suspend
2022-09-16 14:00:02 +02:00

189 lines
5.8 KiB
Svelte

<script lang="ts">
import { VSplitPane } from 'svelte-split-pane'
import type { Schema } from '$lib/common'
import Tab from '$lib/components/common/tabs/Tab.svelte'
import TabContent from '$lib/components/common/tabs/TabContent.svelte'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
import Editor from '$lib/components/Editor.svelte'
import EditorBar from '$lib/components/EditorBar.svelte'
import FlowPreview from '$lib/components/FlowPreview.svelte'
import FlowInputs from './FlowInputs.svelte'
import {
createInlineScriptModule,
createLoop,
createScriptFromInlineScript,
fork,
getStepPropPicker,
isEmptyFlowModule,
loadFlowModuleSchema,
pickScript
} from '$lib/components/flows/flowStateUtils'
import { flowStore } from '$lib/components/flows/flowStore'
import SchemaForm from '$lib/components/SchemaForm.svelte'
import { RawScript, type FlowModule } from '$lib/gen'
import FlowCard from '../common/FlowCard.svelte'
import FlowModuleHeader from './FlowModuleHeader.svelte'
import { flowStateStore, type FlowModuleSchema } from '../flowState'
import { scriptLangToEditorLang } from '$lib/utils'
import { getContext } from 'svelte'
import type { FlowEditorContext } from '../types'
import Toggle from '$lib/components/Toggle.svelte'
import FlowModuleAdvancedSettings from './FlowModuleAdvancedSettings.svelte'
export let indexes: string
export let flowModule: FlowModule
export let args: Record<string, any> = {}
export let schema: Schema
export let childFlowModules: FlowModuleSchema[] | undefined = undefined
const [parentIndex] = indexes.split('-').map(Number)
let editor: Editor
let websocketAlive = { pyright: false, black: false, deno: false }
$: shouldPick = isEmptyFlowModule(flowModule)
$: stepPropPicker = getStepPropPicker(
indexes.split('-').map(Number),
$flowStore.schema,
$flowStateStore,
args
)
async function apply<T>(fn: (arg: T) => Promise<FlowModuleSchema>, arg: T) {
const flowModuleSchema = await fn(arg)
flowModule = flowModuleSchema.flowModule
schema = flowModuleSchema.schema
if (flowModuleSchema.childFlowModules) {
childFlowModules = flowModuleSchema.childFlowModules
}
}
async function reload(flowModule: FlowModule) {
apply(loadFlowModuleSchema, flowModule)
}
async function applyCreateLoop() {
await apply(createLoop, null)
}
const { selectedId, select } = getContext<FlowEditorContext>('FlowEditorContext')
</script>
<div class="flex flex-col h-full ">
<FlowCard {flowModule}>
<svelte:fragment slot="header">
<div class="flex-shrink-0">
<FlowModuleHeader
bind:module={flowModule}
on:delete
on:fork={() => apply(fork, flowModule)}
on:createScriptFromInlineScript={() => {
apply(createScriptFromInlineScript, {
flowModule: flowModule,
suffix: indexes,
schema
})
}}
/>
</div>
</svelte:fragment>
{#if shouldPick}
<FlowInputs
shouldDisableTriggerScripts={parentIndex != 0}
shouldDisableLoopCreation={indexes.length > 1 || parentIndex == 0}
on:loop={() => {
applyCreateLoop()
select(['loop', $selectedId].join('-'))
}}
on:pick={(e) => apply(pickScript, e.detail.path)}
on:new={(e) =>
apply(createInlineScriptModule, {
language: e.detail.language,
kind: e.detail.kind,
subkind: e.detail.subkind
})}
/>
{:else}
{#if flowModule.value.type === 'rawscript'}
<div class="flex-shrink-0 border-b p-1">
<EditorBar {editor} lang={flowModule.value['language'] ?? 'deno'} {websocketAlive} />
</div>
{/if}
<div class="overflow-hidden flex-grow">
<VSplitPane
topPanelSize={flowModule.value.type === 'rawscript' ? '50%' : '0%'}
downPanelSize={flowModule.value.type === 'rawscript' ? '50%' : '100%'}
>
<top slot="top">
{#if flowModule.value.type === 'rawscript'}
<div on:mouseleave={() => reload(flowModule)} class="h-full overflow-auto">
<Editor
bind:websocketAlive
bind:this={editor}
class="h-full px-2"
bind:code={flowModule.value.content}
deno={flowModule.value.language === RawScript.language.DENO}
lang={scriptLangToEditorLang(flowModule.value.language)}
automaticLayout={true}
formatAction={() => reload(flowModule)}
/>
</div>
{/if}
</top>
<down slot="down">
<Tabs selected="inputs">
<Tab value="inputs">Inputs</Tab>
<Tab value="preview">Test</Tab>
<Tab value="advanced">Advanced</Tab>
<svelte:fragment slot="content">
<div class="h-full pb-16 overflow-y-scroll bg-white">
<div class="p-4 overflow-hidden">
<TabContent value="inputs">
<div class="w-11/12">
<SchemaForm
{schema}
inputTransform={true}
importPath={indexes}
bind:pickableProperties={stepPropPicker.pickableProperties}
bind:args={flowModule.input_transforms}
bind:extraLib={stepPropPicker.extraLib}
/>
</div>
</TabContent>
<TabContent value="preview">
<FlowPreview flow={$flowStore} {indexes} {schema} />
</TabContent>
<TabContent value="settings">
{#if ('path' in flowModule.value && flowModule.value.path) || ('language' in flowModule.value && flowModule.value.language)}
<input
on:click|stopPropagation={() => undefined}
class="overflow-x-auto"
type="text"
bind:value={flowModule.summary}
placeholder="Summary"
/>
{/if}
</TabContent>
<TabContent value="advanced">
<FlowModuleAdvancedSettings bind:flowModule />
</TabContent>
</div>
</div>
</svelte:fragment>
</Tabs>
</down>
</VSplitPane>
</div>
{/if}
</FlowCard>
</div>