From 80c11aa3148c049de3bf9cbf4df7b13f2fc00ec6 Mon Sep 17 00:00:00 2001 From: Faton Ramadani Date: Mon, 21 Nov 2022 18:24:46 +0100 Subject: [PATCH] App editor inline editor (#917) * fix(frontend): add table * fix(frontend): Rework the context panel * fix(frontend): WIP * fix(frontend): hide script selector when selected * fix(frontend): Fix preview mode + remove errors * fix(frontend): Fix table search * fix(frontend): temporary fix --- .../apps/components/DisplayComponent.svelte | 12 +- .../apps/components/RunFormComponent.svelte | 36 ++- .../apps/components/TableComponent.svelte | 219 ++++++++++-------- .../charts/PieChartComponent.svelte | 66 ++++++ .../components/common/ButtonComponent.svelte | 36 +++ .../components/common/TextComponent.svelte | 22 +- .../{common => helpers}/AlignWrapper.svelte | 0 .../helpers/ComponentInputValue.svelte | 27 +++ .../components/helpers/DebouncedInput.svelte | 17 ++ .../helpers/RunnableComponent.svelte | 173 ++++++++++++++ .../components/apps/editor/AppEditor.svelte | 126 ++++------ .../apps/editor/ComponentEditor.svelte | 16 +- .../components/apps/editor/GridEditor.svelte | 12 +- .../componentsPanel/ComponentList.svelte | 10 +- .../apps/editor/componentsPanel/data.ts | 47 +++- .../contextPanel/ComponentOutputViewer.svelte | 23 ++ .../editor/contextPanel/ContextPanel.svelte | 173 ++++++++++++++ .../InlineScriptCreationPanel.svelte | 34 +++ .../ComponentInputsSpecsEditor.svelte | 4 +- .../settingsPanel/ComponentPanel.svelte | 24 +- .../settingsPanel/StaticInputEditor.svelte | 6 +- .../settingsPanel/common/PanelSection.svelte | 5 +- frontend/src/lib/components/apps/types.ts | 43 ++-- frontend/src/lib/components/apps/utils.ts | 4 + .../components/common/button/Button.svelte | 7 +- frontend/src/routes/apps.svelte | 3 +- .../src/routes/apps/edit/[...path].svelte | 2 +- 27 files changed, 905 insertions(+), 242 deletions(-) create mode 100644 frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte create mode 100644 frontend/src/lib/components/apps/components/common/ButtonComponent.svelte rename frontend/src/lib/components/apps/components/{common => helpers}/AlignWrapper.svelte (100%) create mode 100644 frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte create mode 100644 frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte create mode 100644 frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte create mode 100644 frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte create mode 100644 frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte create mode 100644 frontend/src/lib/components/apps/editor/contextPanel/InlineScriptCreationPanel.svelte diff --git a/frontend/src/lib/components/apps/components/DisplayComponent.svelte b/frontend/src/lib/components/apps/components/DisplayComponent.svelte index 0b76dec170..37fb1ac44c 100644 --- a/frontend/src/lib/components/apps/components/DisplayComponent.svelte +++ b/frontend/src/lib/components/apps/components/DisplayComponent.svelte @@ -13,10 +13,16 @@ componentInputs.result.name $: inputResult = hasConnection - ? $worldStore?.connect(componentInputs.result, (x) => { + ? $worldStore?.connect(componentInputs.result, () => { update() }) - : undefined + : { + peak: () => { + if (componentInputs.result.type === 'static') { + return componentInputs.result.value + } + } + } let result: any @@ -24,6 +30,8 @@ result = inputResult?.peak() } + $: !hasConnection && componentInputs.result && update() + export const staticOutputs: string[] = [] diff --git a/frontend/src/lib/components/apps/components/RunFormComponent.svelte b/frontend/src/lib/components/apps/components/RunFormComponent.svelte index 9699fd65bb..78ba339c72 100644 --- a/frontend/src/lib/components/apps/components/RunFormComponent.svelte +++ b/frontend/src/lib/components/apps/components/RunFormComponent.svelte @@ -18,9 +18,11 @@ export let inputs: InputsSpec export let path: string | undefined = undefined export let runType: 'script' | 'flow' | undefined = undefined + export let inlineScriptName: string | undefined = undefined + export const staticOutputs = ['loading', 'result'] - const { worldStore } = getContext('AppEditorContext') + const { worldStore, app } = getContext('AppEditorContext') let pagePath = $page.params.path $: outputs = $worldStore?.outputsById[id] as { @@ -42,6 +44,11 @@ loadSchemaFromTriggerable($workspaceStore, path, runType) } + $: if (inlineScriptName) { + schema = $app.inlineScripts[inlineScriptName].schema + reloadSchemaAndArgs() + } + $: if (inputs && schema !== undefined) { if (Object.keys(schema.properties).length !== Object.keys(inputs).length) { inputs = schemaToInputsSpec(schema) @@ -82,17 +89,28 @@ }, []) async function executeComponent() { - await testJobLoader?.abstractRun(() => - AppService.executeComponent({ + await testJobLoader?.abstractRun(() => { + const requestBody = { + args, + force_viewer_static_fields: {} + } + + if (inlineScriptName && $app.inlineScripts[inlineScriptName]) { + requestBody['raw_code'] = { + content: $app.inlineScripts[inlineScriptName].content, + language: $app.inlineScripts[inlineScriptName].language, + path: $app.inlineScripts[inlineScriptName].path + } + } else if (path && runType) { + requestBody['path'] = `${runType}/${path}` + } + + return AppService.executeComponent({ workspace: $workspaceStore!, path: pagePath, - requestBody: { - path: `${runType}/${path}`, - args, - force_viewer_static_fields: {} - } + requestBody }) - ) + }) outputs?.loading.set(true) } diff --git a/frontend/src/lib/components/apps/components/TableComponent.svelte b/frontend/src/lib/components/apps/components/TableComponent.svelte index 1d1d993a03..31df45cf07 100644 --- a/frontend/src/lib/components/apps/components/TableComponent.svelte +++ b/frontend/src/lib/components/apps/components/TableComponent.svelte @@ -1,108 +1,141 @@ -
-
-
-

{title}

- {#if description} -

- {description} -

- {/if} -
-
-
-
-
-
- - - - {#each headers as header} - - {/each} - - - - - {#each data as x} - - {#each headers as header} - - {/each} - - - {/each} - -
- {header} - - Edit -
- {x[header]} - - - Edit - , Lindsay Walton - -
+ + + + +
+ {#if searchEnabledValue} +
+
+
+ {/if} +
+ + {#if headers} + + + {#each headers as header} + + {/each} + + + + {/if} + + {#each result as row, rowIndex (rowIndex)} + toggleRow(row, rowIndex)} + > + {#each headers as header} + + {/each} + + + {/each} + +
+ {header.replace(/([A-Z]+)*([A-Z][a-z])/g, '$1 $2')} + + Edit +
+ {row[header]} + + {#if false} + + {/if} +
-
- -
+
+ {/if} +
+ diff --git a/frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte b/frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte new file mode 100644 index 0000000000..1a771079cf --- /dev/null +++ b/frontend/src/lib/components/apps/components/charts/PieChartComponent.svelte @@ -0,0 +1,66 @@ + + + +{#if data.datasets.length > 0} + +{:else} + No dataset +{/if} diff --git a/frontend/src/lib/components/apps/components/common/ButtonComponent.svelte b/frontend/src/lib/components/apps/components/common/ButtonComponent.svelte new file mode 100644 index 0000000000..6fae003a75 --- /dev/null +++ b/frontend/src/lib/components/apps/components/common/ButtonComponent.svelte @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/frontend/src/lib/components/apps/components/common/TextComponent.svelte b/frontend/src/lib/components/apps/components/common/TextComponent.svelte index bb9921e9dc..64becb5cd8 100644 --- a/frontend/src/lib/components/apps/components/common/TextComponent.svelte +++ b/frontend/src/lib/components/apps/components/common/TextComponent.svelte @@ -1,22 +1,20 @@ -{#if $worldStore && componentInputs?.content.type === 'static'} -
- - - -
-{/if} + + + + + diff --git a/frontend/src/lib/components/apps/components/common/AlignWrapper.svelte b/frontend/src/lib/components/apps/components/helpers/AlignWrapper.svelte similarity index 100% rename from frontend/src/lib/components/apps/components/common/AlignWrapper.svelte rename to frontend/src/lib/components/apps/components/helpers/AlignWrapper.svelte diff --git a/frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte b/frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte new file mode 100644 index 0000000000..fb51a823fb --- /dev/null +++ b/frontend/src/lib/components/apps/components/helpers/ComponentInputValue.svelte @@ -0,0 +1,27 @@ + diff --git a/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte b/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte new file mode 100644 index 0000000000..5f251e509e --- /dev/null +++ b/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte @@ -0,0 +1,17 @@ + + + diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte new file mode 100644 index 0000000000..ee65b99fa9 --- /dev/null +++ b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte @@ -0,0 +1,173 @@ + + + { + if (testJob) { + outputs.result.set(testJob?.result) + result = testJob?.result + } + }} + bind:isLoading={testIsLoading} + bind:job={testJob} + bind:this={testJobLoader} +/> + +{#if schemaClone !== undefined} + +{/if} + +{#if shouldTick === undefined} + +{/if} + diff --git a/frontend/src/lib/components/apps/editor/AppEditor.svelte b/frontend/src/lib/components/apps/editor/AppEditor.svelte index 1027fd6575..afb249973c 100644 --- a/frontend/src/lib/components/apps/editor/AppEditor.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditor.svelte @@ -17,14 +17,13 @@ import Icon from 'svelte-awesome' import { faPlus, faSliders } from '@fortawesome/free-solid-svg-icons' import ComponentPanel from './settingsPanel/ComponentPanel.svelte' - import PanelSection from './settingsPanel/common/PanelSection.svelte' - import Badge from '$lib/components/common/badge/Badge.svelte' - import Button from '$lib/components/common/button/Button.svelte' + import ContextPanel from './contextPanel/ContextPanel.svelte' + import { classNames } from '$lib/utils' export let app: App + export let path: string const appStore = writable(app) - const worldStore = writable(undefined) const staticOutputs = writable>({}) const selectedComponent = writable(undefined) @@ -56,14 +55,14 @@ let mounted = false onMount(() => { mounted = true - console.log($staticOutputs, $appStore.grid) }) - $: $mode && $selectedComponent && clearSelectionOnPreview() $: mounted && ($worldStore = buildWorld($staticOutputs)) + $: $mode && $selectedComponent && clearSelectionOnPreview() $: selectedTab = 'settings' + // If ever the the selected component changes, we need to update the selected tab selectedComponent.subscribe(() => { if (selectedTab === 'insert') { setTimeout(() => { @@ -71,90 +70,51 @@ }) } }) - - function connectInput(id: string, name: string) { - if ($connectingInput) { - $connectingInput = { - opened: false, - input: { - id, - name, - type: 'output', - defaultValue: undefined - } - } - } - } - {#if $mode !== 'preview'} - - - {#each Object.entries($staticOutputs) as [componentId, outputs], index} - {#if outputs.length > 0} - {componentId} - - {#each outputs as output} - - {/each} - {/if} - {/each} - - - Todo - - {/if} - -
+ + + + +
{#if $appStore.grid} {/if}
- {#if $mode !== 'preview'} - - - -
- - Insert -
-
- -
- - Settings -
-
- - - {#if $selectedComponent !== undefined} - {#each $appStore.grid as gridItem (gridItem.id)} - {#if gridItem.data.id === $selectedComponent} - - {/if} - {/each} - {/if} - {#if $selectedComponent === undefined} -
No component selected.
- {/if} -
- - - -
-
-
- {/if} + + + +
+ + Insert +
+
+ +
+ + Settings +
+
+ + + {#if $selectedComponent !== undefined} + {#each $appStore.grid as gridItem (gridItem.id)} + {#if gridItem.data.id === $selectedComponent} + + {/if} + {/each} + {/if} + {#if $selectedComponent === undefined} +
No component selected.
+ {/if} +
+ + + +
+
+
diff --git a/frontend/src/lib/components/apps/editor/ComponentEditor.svelte b/frontend/src/lib/components/apps/editor/ComponentEditor.svelte index fb93d68b11..1951f55ff3 100644 --- a/frontend/src/lib/components/apps/editor/ComponentEditor.svelte +++ b/frontend/src/lib/components/apps/editor/ComponentEditor.svelte @@ -8,6 +8,8 @@ import TextComponent from '../components/common/TextComponent.svelte' import type { AppComponent, AppEditorContext } from '../types' import { displayData } from '../utils' + import ButtonComponent from '../components/common/ButtonComponent.svelte' + import PieChartComponent from '../components/charts/PieChartComponent.svelte' export let component: AppComponent export let selected: boolean @@ -44,14 +46,26 @@ {:else if component.type === 'barchartcomponent'} + {:else if component.type === 'piechartcomponent'} + {:else if component.type === 'tablecomponent'} - + {:else if component.type === 'textcomponent'} + {:else if component.type === 'buttoncomponent'} + {/if}
diff --git a/frontend/src/lib/components/apps/editor/GridEditor.svelte b/frontend/src/lib/components/apps/editor/GridEditor.svelte index 62cd579db1..bfd40382d8 100644 --- a/frontend/src/lib/components/apps/editor/GridEditor.svelte +++ b/frontend/src/lib/components/apps/editor/GridEditor.svelte @@ -11,21 +11,21 @@ $: if ($mode === 'preview') { $app.grid.map((c) => { - c[6].customDragger = true - c[6].customResizer = true + c[COLS].customDragger = true + c[COLS].customResizer = true return c }) } else { $app.grid.map((c) => { - c[6].customDragger = false - c[6].customResizer = false + c[COLS].customDragger = false + c[COLS].customResizer = false return c }) } -
- +
+ {@const index = $app.grid.findIndex((c) => c.data.id === dataItem.data.id)}
gridItem.data.id)) @@ -58,12 +58,12 @@ {#each componentSets as componentSet, index (index)}
{componentSet.title}
-
+
{#each componentSet.components as item, componentIndex (componentIndex)}
add(item, { w: 2, h: 2 })} + class="border shadow-sm h-16 p-2 flex flex-col gap-2 items-center justify-center bg-white rounded-md scale-100 hover:scale-105 ease-in duration-75" + on:click={() => addComponent(item, { w: 2, h: 2 })} >
{displayData[item.type].name}
diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/data.ts b/frontend/src/lib/components/apps/editor/componentsPanel/data.ts index a886a92063..beb6b5dcbf 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/data.ts +++ b/frontend/src/lib/components/apps/editor/componentsPanel/data.ts @@ -45,7 +45,16 @@ const plainComponents = { { ...defaultProps, id: 'buttoncomponent', - type: 'buttoncomponent' + type: 'buttoncomponent', + componentInputs: { + label: { + type: 'static', + visible: true, + value: 'Lorem ipsum', + fieldType: 'textarea' + } + }, + runnable: true }, { ...defaultProps, @@ -81,7 +90,15 @@ const chartComponents = { { ...defaultProps, id: 'piechartcomponent', - type: 'piechartcomponent' + type: 'piechartcomponent', + componentInputs: { + dataset: { + type: 'static', + visible: true, + value: {}, + fieldType: 'textarea' + } + } }, { ...defaultProps, @@ -91,6 +108,30 @@ const chartComponents = { ] as AppComponent[] } -const componentSets = [windmillComponents, plainComponents, chartComponents] +const tableComponents = { + title: 'Table', + components: [ + { + ...defaultProps, + id: 'tablecomponent', + type: 'tablecomponent', + componentInputs: { + searchEnabled: { + type: 'static', + value: false, + fieldType: 'boolean' + }, + paginationEnabled: { + type: 'static', + value: false, + fieldType: 'boolean' + } + }, + runnable: true + } + ] as AppComponent[] +} + +const componentSets = [windmillComponents, plainComponents, chartComponents, tableComponents] export { componentSets } diff --git a/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte new file mode 100644 index 0000000000..d7906f8525 --- /dev/null +++ b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte @@ -0,0 +1,23 @@ + + + diff --git a/frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte b/frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte new file mode 100644 index 0000000000..aec50cb776 --- /dev/null +++ b/frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte @@ -0,0 +1,173 @@ + + + + { + scriptCreationDrawer.closeDrawer() + }} + > + + + + + + + { + scriptEditorDrawer.closeDrawer() + }} + > + {#if selectedScript} + + {/if} + + + + + + + + +
+ {#each $app.inlineScripts ? Object.entries($app.inlineScripts) : [] as [key, value], index} +
+ {key} +
+
+
+ {/each} +
+
+ + + {#each Object.entries($staticOutputs) as [componentId, outputs], index} + {#if outputs.length > 0} + Component: {componentId} + +
+ { + const [output] = detail.split('.') + connectInput(componentId, output) + }} + /> +
+ {/if} + {/each} +
diff --git a/frontend/src/lib/components/apps/editor/contextPanel/InlineScriptCreationPanel.svelte b/frontend/src/lib/components/apps/editor/contextPanel/InlineScriptCreationPanel.svelte new file mode 100644 index 0000000000..fa2d163c4c --- /dev/null +++ b/frontend/src/lib/components/apps/editor/contextPanel/InlineScriptCreationPanel.svelte @@ -0,0 +1,34 @@ + + + + diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputsSpecsEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputsSpecsEditor.svelte index 30bdc51c83..e5f303572f 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputsSpecsEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentInputsSpecsEditor.svelte @@ -11,13 +11,13 @@
- {#each Object.keys(componentInputSpecs) as inputSpecKey} - + {#each Object.keys(componentInputSpecs) as inputSpecKey, index (index)}
{ openedProp = inputSpecKey }} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte index 6c2f8bc377..b6c650be0d 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte @@ -21,9 +21,9 @@ const { app } = getContext('AppEditorContext') - function remove() { + function removeGridElement() { const COLS = 6 - const index = $app.grid.findIndex((c) => c.data.id === component?.id) + const index = $app.grid.findIndex((gridComponent) => gridComponent.data.id === component?.id) $app.grid.splice(index, 1) $app.grid = gridHelp.adjust($app.grid, COLS) } @@ -36,7 +36,7 @@ {/if} - {#if component.type === 'runformcomponent' && component.path === undefined} + {#if component.runnable && component['path'] === undefined && component['inlineScriptName'] === undefined} Select a script or a flow to continue {/if} + {#if component.runnable && component['path'] === undefined && component['inlineScriptName'] === undefined} + {#each Object.keys($app.inlineScripts ?? {}) as inlineScriptName} + + {/each} + {/if} + {#if component.componentInputs} {/if} @@ -98,7 +114,7 @@ color="red" variant="border" startIcon={{ icon: faTrashAlt }} - on:click={remove} + on:click={removeGridElement} > Delete component diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/StaticInputEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/StaticInputEditor.svelte index 148bf649d4..29b9199130 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/StaticInputEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/StaticInputEditor.svelte @@ -10,12 +10,12 @@ {/if} -{#if input.fieldType === 'text'} - -{:else if input.fieldType === 'number'} +{#if input.fieldType === 'number'} {:else if input.fieldType === 'textarea'}