feat: add yaml editor in flow builder

This commit is contained in:
Ruben Fiszel
2024-09-02 15:13:51 +02:00
parent a5dde31304
commit 71470d7da9
7 changed files with 108 additions and 20 deletions
@@ -81,6 +81,7 @@
import CustomPopover from './CustomPopover.svelte'
import Summary from './Summary.svelte'
import type { FlowBuilderWhitelabelCustomUi } from './custom_ui'
import FlowYamlEditor from './flows/header/FlowYamlEditor.svelte'
export let initialPath: string = ''
export let pathStoreInit: string | undefined = undefined
@@ -1007,6 +1008,7 @@
let flowTutorials: FlowTutorials | undefined = undefined
let jsonViewerDrawer: Drawer | undefined = undefined
let yamlEditorDrawer: Drawer | undefined = undefined
let flowHistory: FlowHistory | undefined = undefined
export function triggerTutorial() {
@@ -1049,6 +1051,11 @@
displayName: 'Export',
icon: FileJson,
action: () => jsonViewerDrawer?.openDrawer()
},
{
displayName: 'Edit in YAML',
icon: FileJson,
action: () => yamlEditorDrawer?.openDrawer()
}
]
: [])
@@ -1069,6 +1076,7 @@
{#if $pathStore}
<FlowHistory bind:this={flowHistory} path={$pathStore} on:historyRestore />
{/if}
<FlowYamlEditor bind:drawer={yamlEditorDrawer} />
<FlowImportExportMenu bind:drawer={jsonViewerDrawer} />
<FlowCopilotInputsModal
on:confirmed={async () => {
@@ -9,6 +9,7 @@
import YAML from 'yaml'
import { yaml } from 'svelte-highlight/languages'
import HighlightTheme from './HighlightTheme.svelte'
import { filteredContentForExport } from './flows/utils'
export let flow: {
summary: string
@@ -17,12 +18,7 @@
schema?: any
}
$: flowFiltered = {
summary: flow.summary,
description: flow.description,
value: flow.value,
schema: flow.schema
}
$: flowFiltered = filteredContentForExport(flow)
let rawType: 'json' | 'yaml' = 'yaml'
@@ -18,7 +18,7 @@
<div class="flex gap-2 items-center">
<div class="max-w-sm grow">
{#if workerTags}
{#if $workerTags}
{#if $workerTags?.length ?? 0 > 0}
<select
value={tag}
@@ -35,6 +35,9 @@
{:else}
<option value="" disabled selected>Worker Group Tag</option>
{/if}
{#if tag && tag != '' && !($workerTags ?? []).includes(tag)}
<option value={tag} selected>{tag}</option>
{/if}
{#each $workerTags ?? [] as tag (tag)}
<option value={tag}>{tag}</option>
{/each}
@@ -13,7 +13,7 @@
import { getContext } from 'svelte'
import type { FlowEditorContext } from '../types'
import Slider from '$lib/components/Slider.svelte'
import { enterpriseLicense, workerTags, workspaceStore } from '$lib/stores'
import { enterpriseLicense, workspaceStore } from '$lib/stores'
import { isCloudHosted } from '$lib/cloud'
import { copyToClipboard } from '$lib/utils'
import Tooltip from '$lib/components/Tooltip.svelte'
@@ -36,10 +36,6 @@
$: url = `${hostname}/api/w/${$workspaceStore}/jobs/run/f/${$pathStore}`
$: syncedUrl = `${hostname}/api/w/${$workspaceStore}/jobs/run_wait_result/f/${$pathStore}`
$: if ($selectedId == 'settings-worker-group') {
$workerTags = undefined
}
function asSchema(x: any) {
return x as Schema
}
@@ -0,0 +1,62 @@
<script lang="ts">
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
import DrawerContent from '$lib/components/common/drawer/DrawerContent.svelte'
import { getContext } from 'svelte'
import type { FlowEditorContext } from '../types'
import { filteredContentForExport } from '../utils'
import YAML from 'yaml'
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
import { Button } from '$lib/components/common'
import { sendUserToast } from '$lib/toast'
const { flowStore } = getContext<FlowEditorContext>('FlowEditorContext')
export let drawer: Drawer | undefined
let code = ''
function reload() {
code = YAML.stringify(filteredContentForExport($flowStore))
}
function apply() {
try {
const parsed = YAML.parse(code)
if (parsed.summary && typeof parsed.summary === 'string') {
$flowStore.summary = parsed.summary
}
if (parsed.description && typeof parsed.description === 'string') {
$flowStore.description = parsed.description
}
if (parsed['ws_error_handler_muted'] !== undefined) {
$flowStore.ws_error_handler_muted = parsed['ws_error_handler_muted']
}
if (parsed['dedicated_worker'] !== undefined) {
$flowStore.dedicated_worker = parsed['dedicated_worker']
}
if (parsed['visible_to_runner_only'] !== undefined) {
$flowStore.visible_to_runner_only = parsed['visible_to_runner_only']
}
$flowStore.value = parsed.value
$flowStore.schema = parsed.schema
$flowStore.tag = parsed.tag
$flowStore = $flowStore
} catch (e) {
sendUserToast('Error parsing yaml: ' + e), true
}
}
</script>
<Drawer on:open={reload} bind:this={drawer} size="800px">
<DrawerContent title="OpenFlow" on:close={() => drawer?.toggleDrawer()}>
<svelte:fragment slot="actions">
<Button color="dark" size="sm" on:click={reload}>Reset code</Button>
<Button color="dark" size="sm" on:click={apply}>Apply changes</Button>
</svelte:fragment>
{#if $flowStore}
<SimpleEditor autoHeight bind:code lang="yaml" />
{/if}
</DrawerContent>
</Drawer>
+8 -8
View File
@@ -19,6 +19,13 @@ export type FlowInput = Record<
}
>
export type ExtendedOpenFlow = OpenFlow & {
tag?: string
ws_error_handler_muted?: boolean
dedicated_worker?: boolean
visible_to_runner_only?: boolean
}
export type FlowEditorContext = {
selectedId: Writable<string>
moving: Writable<{ module: FlowModule; modules: FlowModule[] } | undefined>
@@ -27,14 +34,7 @@ export type FlowEditorContext = {
scriptEditorDrawer: Writable<ScriptEditorDrawer | undefined>
history: History<OpenFlow>
pathStore: Writable<string>
flowStore: Writable<
OpenFlow & {
tag?: string
ws_error_handler_muted?: boolean
dedicated_worker?: boolean
visible_to_runner_only?: boolean
}
>
flowStore: Writable<ExtendedOpenFlow>
flowStateStore: Writable<FlowState>
testStepStore: Writable<Record<string, any>>
saveDraft: () => void
@@ -17,6 +17,7 @@ import { NEVER_TESTED_THIS_FAR } from './models'
import { sendUserToast } from '$lib/toast'
import type { Schema } from '$lib/common'
import { parseOutputs } from '$lib/infer'
import type { ExtendedOpenFlow } from './types'
function create_context_function_template(eval_string: string, context: Record<string, any>) {
return `
@@ -71,6 +72,28 @@ export function evalValue(
return v
}
export function filteredContentForExport(flow: ExtendedOpenFlow) {
let o = {
summary: flow.summary,
description: flow.description,
value: flow.value,
schema: flow.schema
}
if (flow.dedicated_worker) {
o['dedicated_worker'] = flow.dedicated_worker
}
if (flow.visible_to_runner_only) {
o['visible_to_runner_only'] = flow.visible_to_runner_only
}
if (flow.ws_error_handler_muted) {
o['ws_error_handler_muted'] = flow.ws_error_handler_muted
}
if (flow.tag) {
o['tag'] = flow.tag
}
return o
}
export function cleanInputs(flow: OpenFlow | any): OpenFlow & {
tag?: string
ws_error_handler_muted?: boolean