From b4e2735315fe24108cde8b88cdffa41d53fd6b89 Mon Sep 17 00:00:00 2001 From: Faton Ramadani Date: Mon, 19 Dec 2022 16:44:28 +0100 Subject: [PATCH] Inline script editor (#1029) * feat(frontend): WIP * feat(frontend): WI * feat(frontend): Fix inline scripts * feat(frontend): Fix inline scripts --- .../src/lib/components/ScriptBuilder.svelte | 1 - .../components/dataDisplay/AppText.svelte | 2 +- .../helpers/RunnableComponent.svelte | 20 +- .../components/helpers/RunnableWrapper.svelte | 17 +- .../apps/components/table/AppTable.svelte | 4 + .../apps/editor/ComponentHeader.svelte | 4 +- .../components/apps/editor/GridEditor.svelte | 9 +- .../componentsPanel/ComponentList.svelte | 28 +-- .../editor/contextPanel/ContextPanel.svelte | 40 ++-- .../InlineScriptEditor.svelte | 183 ++++++++++++++++ .../InlineScriptEditorDrawer.svelte | 62 +----- .../InlineScriptsPanel.svelte | 196 +----------------- .../InlineScriptsPanelList.svelte | 54 +++++ .../settingsPanel/AlignmentEditor.svelte | 51 +++++ .../ComponentInputTypeEditor.svelte | 35 ++++ .../settingsPanel/ComponentPanel.svelte | 155 ++------------ .../settingsPanel/InputsSpecEditor.svelte | 4 +- .../settingsPanel/SelectedRunnable.svelte | 54 +++++ .../editor/settingsPanel/SubTypeEditor.svelte | 2 +- .../ConnectedInputEditor.svelte | 5 +- .../inputEditor/RunnableInputEditor.svelte | 16 ++ .../StaticInputEditor.svelte | 6 +- .../mainInput/RunnableSelector.svelte | 74 ++++--- frontend/src/lib/components/apps/inputType.ts | 4 +- frontend/src/lib/components/apps/types.ts | 1 - frontend/src/lib/components/apps/utils.ts | 29 ++- 26 files changed, 593 insertions(+), 463 deletions(-) create mode 100644 frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte create mode 100644 frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelList.svelte create mode 100644 frontend/src/lib/components/apps/editor/settingsPanel/AlignmentEditor.svelte create mode 100644 frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputTypeEditor.svelte create mode 100644 frontend/src/lib/components/apps/editor/settingsPanel/SelectedRunnable.svelte rename frontend/src/lib/components/apps/editor/settingsPanel/{ => inputEditor}/ConnectedInputEditor.svelte (94%) create mode 100644 frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/RunnableInputEditor.svelte rename frontend/src/lib/components/apps/editor/settingsPanel/{ => inputEditor}/StaticInputEditor.svelte (87%) diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index 970cd93970..7f3d07c2b7 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -9,7 +9,6 @@ import { encodeState, sendUserToast, setQueryWithoutLoad } from '$lib/utils' import Path from './Path.svelte' import RadioButton from './RadioButton.svelte' - import Required from './Required.svelte' import ScriptEditor from './ScriptEditor.svelte' import ScriptSchema from './ScriptSchema.svelte' import CenteredPage from './CenteredPage.svelte' diff --git a/frontend/src/lib/components/apps/components/dataDisplay/AppText.svelte b/frontend/src/lib/components/apps/components/dataDisplay/AppText.svelte index 9043a2473f..78b9d9048f 100644 --- a/frontend/src/lib/components/apps/components/dataDisplay/AppText.svelte +++ b/frontend/src/lib/components/apps/components/dataDisplay/AppText.svelte @@ -14,7 +14,7 @@ let result: string = '' - + {#if result === ''}
diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte index 9bdc47ebf5..c4d5ba7854 100644 --- a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte +++ b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte @@ -22,7 +22,7 @@ export let result: any = undefined export let forceSchemaDisplay: boolean = false - const { app, worldStore, runnableComponents } = getContext('AppEditorContext') + const { worldStore, runnableComponents } = getContext('AppEditorContext') onMount(() => { $runnableComponents[id] = async () => { @@ -95,9 +95,11 @@ loadSchemaFromTriggerable($workspaceStore, path, runType) } else if (runnable?.type === 'runnableByName' && !schema) { - const { inlineScriptName } = runnable + const { inlineScript } = runnable // Inline scripts directly provide the schema - schema = $app.inlineScripts[inlineScriptName].schema + if (inlineScript) { + schema = inlineScript.schema + } } // When the schema is loaded, we need to update the inputs spec @@ -165,12 +167,14 @@ } if (runnable?.type === 'runnableByName') { - const { inlineScriptName } = runnable + const { inlineScript } = runnable - requestBody['raw_code'] = { - content: $app.inlineScripts[inlineScriptName].content, - language: $app.inlineScripts[inlineScriptName].language, - path: $app.inlineScripts[inlineScriptName].path + if (inlineScript) { + requestBody['raw_code'] = { + content: inlineScript.content, + language: inlineScript.language, + path: inlineScript.path + } } } else if (runnable?.type === 'runnableByPath') { const { path, runType } = runnable diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte index 0a0873e1c8..fd535c02d1 100644 --- a/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte +++ b/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte @@ -11,11 +11,26 @@ export let autoRefresh: boolean = true export let runnableComponent: RunnableComponent | undefined = undefined export let forceSchemaDisplay: boolean = false + + function isRunnableDefined() { + if (!componentInput) return false + if (componentInput.type !== 'runnable') return false + + if ( + (componentInput.runnable?.type === 'runnableByName' && + componentInput.runnable.inlineScript) || + (componentInput.runnable?.type === 'runnableByPath' && componentInput.runnable.path) + ) { + return true + } + + return false + } {#if componentInput === undefined} -{:else if componentInput.type === 'runnable'} +{:else if componentInput.type === 'runnable' && isRunnableDefined()} >) { + if (!Array.isArray(result)) { + return + } + const headers = Array.from(new Set(result.flatMap((row) => Object.keys(row)))) $options = { diff --git a/frontend/src/lib/components/apps/editor/ComponentHeader.svelte b/frontend/src/lib/components/apps/editor/ComponentHeader.svelte index 51e30fc7d0..af371c1d56 100644 --- a/frontend/src/lib/components/apps/editor/ComponentHeader.svelte +++ b/frontend/src/lib/components/apps/editor/ComponentHeader.svelte @@ -13,11 +13,11 @@ - {displayData[component.type].name} - {component.id} + {component.id} +
+ + + {getComponentNameById(componentId)} + +
($selectedComponent = componentId)} class={classNames( - 'w-full py-2 border', - $selectedComponent === componentId ? 'border border-blue-500' : 'cursor-pointer' + 'w-full py-2 border relative', + $selectedComponent === componentId ? 'border border-blue-500 ' : 'cursor-pointer' )} > + {#if $selectedComponent === componentId && $connectingInput?.opened} +
+ {/if} + import Button from '$lib/components/common/button/Button.svelte' + import { Preview, Script } from '$lib/gen' + import { initialCode } from '$lib/script_helpers' + import { emptySchema } from '$lib/utils' + import { faTrash } from '@fortawesome/free-solid-svg-icons' + import { getContext } from 'svelte' + import type { AppEditorContext } from '../../types' + import SimpleEditor from '$lib/components/SimpleEditor.svelte' + import { Check, CheckCheck, CheckCircle, Code2, X } from 'lucide-svelte' + import FlowScriptPicker from '$lib/components/flows/pickers/FlowScriptPicker.svelte' + import type { ResultAppInput } from '../../inputType' + import InlineScriptEditorDrawer from './InlineScriptEditorDrawer.svelte' + import { inferArgs } from '$lib/infer' + import type { Schema } from '$lib/common' + import Badge from '$lib/components/common/badge/Badge.svelte' + + let inlineScriptEditorDrawer: InlineScriptEditorDrawer + export let componentInput: ResultAppInput + export let selectedScriptName: string | undefined = undefined + + $: shouldDisplay = + componentInput.runnable?.type === 'runnableByName' && + componentInput.runnable?.name === selectedScriptName + const { appPath } = getContext('AppEditorContext') + + let validCode = false + + async function inferInlineScriptSchema( + language: Preview.language, + content: string, + schema: Schema + ): Promise { + try { + await inferArgs(language, content, schema) + validCode = true + } catch (e) { + console.error("Couldn't infer args", e) + validCode = false + } + + return schema + } + + async function createInlineScriptByLanguage( + language: Preview.language, + path: string, + subkind: 'pgsql' | 'mysql' | undefined = undefined + ) { + const fullPath = `${appPath}/inline-script/${path}` + + const content = initialCode(language, Script.kind.SCRIPT, subkind) + let schema: Schema = emptySchema() + + schema = await inferInlineScriptSchema(language, content, schema) + + const inlineScript = { + content, + language, + path: fullPath, + schema + } + if (componentInput?.runnable?.type === 'runnableByName') { + componentInput.runnable.inlineScript = inlineScript + } + } + + +{#if componentInput.runnable && componentInput.runnable.type === 'runnableByName' && componentInput.runnable.inlineScript} + +{/if} + +{#if shouldDisplay} + {#if componentInput?.runnable?.type === 'runnableByName' && componentInput?.runnable?.inlineScript} +
+
+ +
+ + {#if componentInput?.runnable?.type === 'runnableByName' && componentInput?.runnable?.inlineScript} +
+ { + if ( + componentInput?.runnable?.type === 'runnableByName' && + componentInput?.runnable?.inlineScript + ) { + let schema = await inferInlineScriptSchema( + componentInput?.runnable?.inlineScript?.language, + componentInput.runnable.inlineScript.content, + componentInput.runnable.inlineScript.schema + ) + + componentInput.runnable.inlineScript.schema = schema + + componentInput = componentInput + } + }} + /> +
+ {/if} +
+ {:else} +
+ Please choose a language: +
+ {#each Object.values(Script.language) as lang} + { + if (selectedScriptName) { + createInlineScriptByLanguage(lang, selectedScriptName) + } + }} + /> + {/each} + + { + if (selectedScriptName) { + createInlineScriptByLanguage(Script.language.DENO, selectedScriptName, 'pgsql') + } + }} + /> + { + if (selectedScriptName) { + createInlineScriptByLanguage(Script.language.DENO, selectedScriptName, 'mysql') + } + }} + /> +
+
+ {/if} +{/if} diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorDrawer.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorDrawer.svelte index 4e30ad8df4..edc4a3b553 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorDrawer.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorDrawer.svelte @@ -1,58 +1,14 @@ @@ -63,12 +19,12 @@ forceOverflowVisible on:close={scriptEditorDrawer.closeDrawer} > - {#if selectedScript} + {#if inlineScript} {/if} diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanel.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanel.svelte index 0bc13879a7..d2acdaf83f 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanel.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanel.svelte @@ -1,200 +1,26 @@ - - - -
- - e.key === 'Enter' && createScript()} - /> - -
- {#if isTakenPath && !ignorePathError} -
- This name is already used. -
- {/if} -
-
- - - - -
- {#if $app.inlineScripts && Object.keys($app.inlineScripts).length > 0} -
- {#each $app.inlineScripts ? Object.entries($app.inlineScripts) : [] as [key, value], index} - -
{ - selectedScript = value - selectedScriptName = key - }} - > - {key} - {#if scriptsUsedByComponents.get(key)} - {scriptsUsedByComponents.get(key)} - {:else} - Unused - {/if} -
- {/each} -
- {:else} -
No inline scripts
- {/if} -
-
+
- {#key selectedScript?.path} - {#if selectedScript} -
-
- -
- -
- -
-
- {/if} - {/key} + {#each $app.grid as gridComponent, index (index)} + + {/each}
diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelList.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelList.svelte new file mode 100644 index 0000000000..9a1911b0e8 --- /dev/null +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelList.svelte @@ -0,0 +1,54 @@ + + + +
+ {#if componentInlineScripts.length > 0} +
+ {#each componentInlineScripts as { name, id }, index (index)} + +
selectInlineScript(name)} + > + {name} + {id} +
+ {/each} +
+ {:else} +
No inline scripts
+ {/if} +
+
diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/AlignmentEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/AlignmentEditor.svelte new file mode 100644 index 0000000000..c0f5176230 --- /dev/null +++ b/frontend/src/lib/components/apps/editor/settingsPanel/AlignmentEditor.svelte @@ -0,0 +1,51 @@ + + +{#if component.verticalAlignment !== undefined} + +
Horizontal
+ +
+ + + + + + + + + + + +
+ {#if component.type !== 'formcomponent'} +
Vertical
+
+ + + + + + + + + + + +
+ {/if} +
+{/if} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputTypeEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputTypeEditor.svelte new file mode 100644 index 0000000000..dcbad25606 --- /dev/null +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputTypeEditor.svelte @@ -0,0 +1,35 @@ + + +{#if componentInput.fieldType !== 'any'} +
+ + + Static + + + Connected + + + Computed + + +
+{/if} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte index f4f7cfd0be..bf58df5cd9 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte @@ -1,45 +1,28 @@ {#if component} - -
{#if component.componentInput} {/if} - {#if component.componentInput.fieldType !== 'any'} -
- - - Static - - - Connected - - - Computed - - -
- {/if} + +
{#if component.componentInput.type === 'static'} {:else if component.componentInput.type === 'connected' && component.componentInput !== undefined} - {:else if component && component.componentInput?.type === 'runnable' && component.componentInput.runnable} -
- - {component.componentInput.runnable.type === 'runnableByName' - ? component.componentInput.runnable.inlineScriptName - : component.componentInput.runnable.path} - -
- - -
-
- {:else} - + {:else if component.componentInput?.type === 'runnable' && component.componentInput !== undefined} + {/if}
{#if component.componentInput?.type === 'runnable' && Object.keys(component.componentInput.fields ?? {}).length > 0} @@ -213,41 +116,7 @@ {/if} - {#if component.verticalAlignment !== undefined} - -
Horizontal
- -
- - - - - - - - - - - -
- {#if component.type !== 'formcomponent'} -
Vertical
-
- - - - - - - - - - - -
- {/if} -
- {/if} + {#if component.type === 'buttoncomponent' || component.type === 'formcomponent'} {/if} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecEditor.svelte index 3db14429c8..22fb9e4a01 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecEditor.svelte @@ -1,7 +1,7 @@ + +{#if appInput.runnable && appInput.runnable.type === 'runnableByName' && appInput.runnable.inlineScript} + +{/if} +
+ + {#if appInput.runnable?.type === 'runnableByName'} + {appInput.runnable.name} + {:else if appInput.runnable?.type === 'runnableByPath'} + {appInput.runnable.path} + {/if} + +
+ {#if appInput.runnable?.type === 'runnableByName' && appInput.runnable.inlineScript} + + {/if} + +
+
+{#if appInput.runnable?.type === 'runnableByName' && !appInput.runnable.inlineScript} + + Please configure the language in the inline script panel + +{/if} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/SubTypeEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/SubTypeEditor.svelte index c21f5077c3..85a9a04238 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/SubTypeEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/SubTypeEditor.svelte @@ -1,6 +1,6 @@ + +{#if isRunnableSelected} + +{:else} + +{/if} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/StaticInputEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/StaticInputEditor.svelte similarity index 87% rename from frontend/src/lib/components/apps/editor/settingsPanel/StaticInputEditor.svelte rename to frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/StaticInputEditor.svelte index 5fcf21b791..42de459585 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/StaticInputEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/StaticInputEditor.svelte @@ -1,9 +1,9 @@ @@ -85,7 +117,7 @@
{#if tab == 'inlinescripts'} - pickInlineScript(e.detail)} /> + pickInlineScript('', e.detail)} /> {:else if tab == 'workspacescripts'} pickScript(e.detail)} /> {:else if tab == 'workspaceflows'} @@ -100,17 +132,9 @@ - -
+