From 6adc87561070d8aceaba1838008cd7e6be2e2660 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 28 Feb 2023 15:51:56 +0100 Subject: [PATCH] feat(frontend): drawer for editing workspace scripts in flows --- .../src/lib/components/DisplayResult.svelte | 35 ++++-- .../src/lib/components/FlowBuilder.svelte | 6 +- .../lib/components/FlowPreviewContent.svelte | 2 +- .../lib/components/FlowStatusViewer.svelte | 12 +- .../src/lib/components/SimpleEditor.svelte | 4 + .../InlineScriptEditor.svelte | 3 +- .../content/BranchPredicateEditor.svelte | 4 +- .../components/flows/content/FlowLoop.svelte | 4 +- .../flows/content/FlowModuleComponent.svelte | 26 +++- .../flows/content/FlowModuleEarlyStop.svelte | 1 + .../flows/content/FlowModuleHeader.svelte | 28 ++++- .../flows/content/FlowModuleSleep.svelte | 1 + .../flows/content/ScriptEditorDrawer.svelte | 117 ++++++++++++++++++ .../pickers/WorkspaceScriptPicker.svelte | 2 +- .../lib/components/flows/previousResults.ts | 1 - frontend/src/lib/components/flows/types.ts | 2 + frontend/src/lib/components/flows/utils.ts | 2 +- frontend/src/lib/components/graph/model.ts | 1 + frontend/src/lib/scripts.ts | 8 +- frontend/src/lib/utils.ts | 8 ++ frontend/src/routes/(root)/+layout.svelte | 2 +- 21 files changed, 240 insertions(+), 29 deletions(-) create mode 100644 frontend/src/lib/components/flows/content/ScriptEditorDrawer.svelte diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte index eeb8b40aca..b35e294601 100644 --- a/frontend/src/lib/components/DisplayResult.svelte +++ b/frontend/src/lib/components/DisplayResult.svelte @@ -2,9 +2,10 @@ import { Highlight } from 'svelte-highlight' import { json } from 'svelte-highlight/languages' import TableCustom from './TableCustom.svelte' - import { truncate } from '$lib/utils' - import { Button } from './common' + import { copyToClipboard, truncate } from '$lib/utils' + import { Button, Drawer, DrawerContent } from './common' import autosize from 'svelte-autosize' + import { ClipboardCopy } from 'lucide-svelte' export let result: any export let requireHtmlApproval = false @@ -86,16 +87,36 @@ return 'json' } let payload = '' + + let jsonViewer: Drawer + + + + + + + + +
{#if result != undefined} {#if resultKind && resultKind != 'json'}
as JSON 
{/if}{#if typeof result == 'object' && Object.keys(result).length > 0}
The result keys are: {truncate(Object.keys(result).join(', '), 50)}
The result keys are: {truncate(Object.keys(result).join(', '), 50)} +
+ +
{/if}{#if !forceJson && resultKind == 'table-col'}
@@ -223,10 +244,8 @@ >Approval Page
- {:else} + {:else} + {/if} {:else}
No result
diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 1fbc8f36b7..4b6f5bb7fc 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -13,6 +13,7 @@ import UnsavedConfirmationModal from './common/confirmationModal/UnsavedConfirmationModal.svelte' import { OFFSET } from './CronInput.svelte' import FlowGraphViewer from './FlowGraphViewer.svelte' + import ScriptEditorDrawer from './flows/content/ScriptEditorDrawer.svelte' import FlowEditor from './flows/FlowEditor.svelte' import { flowStateStore } from './flows/flowState' import { flowStore } from './flows/flowStore' @@ -145,6 +146,7 @@ const scheduleStore = writable({ args: {}, cron: '', enabled: false }) const previewArgsStore = writable>(initialArgs) + const scriptEditorDrawer = writable(undefined) function select(selectedId: string) { selectedIdStore.set(selectedId) @@ -154,7 +156,8 @@ selectedId: selectedIdStore, schedule: scheduleStore, select, - previewArgs: previewArgsStore + previewArgs: previewArgsStore, + scriptEditorDrawer }) async function loadSchedule() { @@ -181,6 +184,7 @@ {#if !$userStore?.operator} + diff --git a/frontend/src/lib/components/FlowPreviewContent.svelte b/frontend/src/lib/components/FlowPreviewContent.svelte index ebf9561094..0898f34ad1 100644 --- a/frontend/src/lib/components/FlowPreviewContent.svelte +++ b/frontend/src/lib/components/FlowPreviewContent.svelte @@ -149,7 +149,7 @@ -
+
{/if}
+
+ +
import Button from '$lib/components/common/button/Button.svelte' import type { Preview } from '$lib/gen' - import { faTrash } from '@fortawesome/free-solid-svg-icons' import { createEventDispatcher, getContext, onMount } from 'svelte' import type { AppEditorContext, InlineScript } from '../../types' - import { CheckCircle, Code2, Maximize2, Trash2, X } from 'lucide-svelte' + import { CheckCircle, Maximize2, Trash2, X } from 'lucide-svelte' import InlineScriptEditorDrawer from './InlineScriptEditorDrawer.svelte' import { inferArgs } from '$lib/infer' import type { Schema } from '$lib/common' diff --git a/frontend/src/lib/components/flows/content/BranchPredicateEditor.svelte b/frontend/src/lib/components/flows/content/BranchPredicateEditor.svelte index dc583c6388..796e84c61f 100644 --- a/frontend/src/lib/components/flows/content/BranchPredicateEditor.svelte +++ b/frontend/src/lib/components/flows/content/BranchPredicateEditor.svelte @@ -27,8 +27,7 @@ parentModule.id, $flowStore, $previewArgs, - false, - true + false ) @@ -37,6 +36,7 @@ pickableProperties={stepPropPicker.pickableProperties} on:select={({ detail }) => { editor?.insertAtCursor(detail) + editor?.focus() }} >
diff --git a/frontend/src/lib/components/flows/content/FlowLoop.svelte b/frontend/src/lib/components/flows/content/FlowLoop.svelte index 878ba21d04..1691ad56a7 100644 --- a/frontend/src/lib/components/flows/content/FlowLoop.svelte +++ b/frontend/src/lib/components/flows/content/FlowLoop.svelte @@ -33,8 +33,7 @@ mod.id, $flowStore, $previewArgs, - false, - true + false ) @@ -60,6 +59,7 @@ pickableProperties={stepPropPicker.pickableProperties} on:select={({ detail }) => { editor?.insertAtCursor(detail) + editor?.focus() }} > @@ -135,6 +141,16 @@ flowModule = module $flowStateStore[module.id] = state }} + on:reload={async () => { + if (flowModule.value.type == 'script') { + console.log('reload') + if (flowModule.value.hash != undefined) { + flowModule.value.hash = await getLatestHashForScript(flowModule.value.path) + } + forceReload++ + await reload(flowModule) + } + }} on:createScriptFromInlineScript={async () => { const [module, state] = await createScriptFromInlineScript( flowModule, @@ -194,7 +210,9 @@ />
{:else if value.type === 'script'} - + {#key forceReload} + + {/key} {:else if value.type === 'flow'} {/if} diff --git a/frontend/src/lib/components/flows/content/FlowModuleEarlyStop.svelte b/frontend/src/lib/components/flows/content/FlowModuleEarlyStop.svelte index c09f98b469..2490f7d27b 100644 --- a/frontend/src/lib/components/flows/content/FlowModuleEarlyStop.svelte +++ b/frontend/src/lib/components/flows/content/FlowModuleEarlyStop.svelte @@ -57,6 +57,7 @@ pickableProperties={undefined} on:select={({ detail }) => { editor?.insertAtCursor(detail) + editor?.focus() }} > import Button from '$lib/components/common/button/Button.svelte' import type { FlowModule } from '$lib/gen' - import { faCodeBranch, faSave } from '@fortawesome/free-solid-svg-icons' - import { createEventDispatcher } from 'svelte' + import { faCodeBranch, faPen, faSave } from '@fortawesome/free-solid-svg-icons' + import { createEventDispatcher, getContext } from 'svelte' import { Bed, PhoneIncoming, Repeat, Square } from 'lucide-svelte' import Popover from '../../Popover.svelte' + import type { FlowEditorContext } from '../types' + import { getLatestHashForScript, sendUserToast } from '$lib/utils' export let module: FlowModule + const { scriptEditorDrawer } = getContext('FlowEditorContext') const dispatch = createEventDispatcher() @@ -62,6 +65,27 @@ {/if} {#if module.value.type === 'script'}
+ {#if !module.value.path.startsWith('hub/')} + + {/if} + + + diff --git a/frontend/src/lib/components/flows/pickers/WorkspaceScriptPicker.svelte b/frontend/src/lib/components/flows/pickers/WorkspaceScriptPicker.svelte index 612f56f418..b8c731abcc 100644 --- a/frontend/src/lib/components/flows/pickers/WorkspaceScriptPicker.svelte +++ b/frontend/src/lib/components/flows/pickers/WorkspaceScriptPicker.svelte @@ -85,7 +85,7 @@
{/if} {#if displayLock} -
+
void schedule: Writable, previewArgs: Writable>, + scriptEditorDrawer: Writable } diff --git a/frontend/src/lib/components/flows/utils.ts b/frontend/src/lib/components/flows/utils.ts index defbbb22bd..8cca7fd03a 100644 --- a/frontend/src/lib/components/flows/utils.ts +++ b/frontend/src/lib/components/flows/utils.ts @@ -73,7 +73,7 @@ export async function loadSchemaFromModule(module: FlowModule): Promise<{ schema = emptySchema() await inferArgs(mod.language!, mod.content ?? '', schema) } else if (mod.type == 'script' && mod.path && mod.path != '') { - schema = await loadSchema(mod.path!) + schema = await loadSchema(mod.path!, mod.hash) } else if (mod.type == 'flow' && mod.path && mod.path != '') { schema = await loadSchemaFlow(mod.path!) } else { diff --git a/frontend/src/lib/components/graph/model.ts b/frontend/src/lib/components/graph/model.ts index 16da026152..1d0ea87b97 100644 --- a/frontend/src/lib/components/graph/model.ts +++ b/frontend/src/lib/components/graph/model.ts @@ -51,6 +51,7 @@ export type GraphItem = Node | Loop | Branch export type GraphModuleState = { type: FlowStatusModule.type + args: any logs?: string result?: any scheduled_for?: string diff --git a/frontend/src/lib/scripts.ts b/frontend/src/lib/scripts.ts index 6fc08c622d..41c152ca18 100644 --- a/frontend/src/lib/scripts.ts +++ b/frontend/src/lib/scripts.ts @@ -5,7 +5,7 @@ import { inferArgs } from './infer' import { workspaceStore } from './stores' import { emptySchema } from './utils' -export async function loadSchema(path: string): Promise { +export async function loadSchema(path: string, hash?: string): Promise { if (path.startsWith('hub/')) { const { content, language, schema } = await ScriptService.getHubScriptByPath({ path }) if (language == 'deno') { @@ -15,6 +15,12 @@ export async function loadSchema(path: string): Promise { } else { return schema ?? emptySchema() } + } else if (hash) { + const script = await ScriptService.getScriptByHash({ + workspace: get(workspaceStore)!, + hash + }) + return script.schema } else { const script = await ScriptService.getScriptByPath({ workspace: get(workspaceStore)!, diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 690d1c7efb..a51fa3708c 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -511,6 +511,14 @@ export async function getScriptByPath(path: string): Promise<{ } } +export async function getLatestHashForScript(path: string): Promise { + const script = await ScriptService.getScriptByPath({ + workspace: get(workspaceStore)!, + path: path ?? '' + }) + return script.hash +} + export async function loadHubScripts() { try { const scripts = (await ScriptService.listHubScripts()).asks ?? [] diff --git a/frontend/src/routes/(root)/+layout.svelte b/frontend/src/routes/(root)/+layout.svelte index f6780d30bc..8b7c1d0366 100644 --- a/frontend/src/routes/(root)/+layout.svelte +++ b/frontend/src/routes/(root)/+layout.svelte @@ -103,7 +103,7 @@ } } } else { - console.log('Caught unhandled promise rejection without message', event) + console.error('Caught unhandled promise rejection without message', event.reason, event) } } loadUser()