From f44917feabb61fe5a22fd8b1435e7b930e8e2e80 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 11 Feb 2025 18:05:24 +0100 Subject: [PATCH] feat: improve large apps performances (#5265) --- .../components/buttons/AppFormButton.svelte | 144 +-- .../display/AppAccordionList.svelte | 85 +- .../components/display/AppCarouselList.svelte | 223 ++-- .../display/AppCustomComponent.svelte | 2 + .../apps/components/display/AppHtml.svelte | 46 +- .../components/display/AppMarkdown.svelte | 60 +- .../apps/components/display/AppText.svelte | 6 +- .../apps/components/display/PlotlyHtml.svelte | 28 +- .../components/display/PlotlyHtmlV2.svelte | 28 +- .../components/display/VegaLiteHtml.svelte | 14 +- .../display/dbtable/AppDbExplorer.svelte | 1 + .../helpers/NonRunnableComponent.svelte | 2 - .../layout/AppConditionalWrapper.svelte | 49 +- .../components/layout/AppContainer.svelte | 49 +- .../components/layout/AppDecisionTree.svelte | 109 +- .../apps/components/layout/AppDrawer.svelte | 188 ++-- .../apps/components/layout/AppList.svelte | 261 ++--- .../apps/components/layout/AppModal.svelte | 165 +-- .../components/layout/AppSplitpanes.svelte | 96 +- .../apps/components/layout/AppStepper.svelte | 191 ++-- .../apps/components/layout/AppTabs.svelte | 222 ++-- .../components/apps/editor/AppPreview.svelte | 4 - .../components/apps/editor/GridEditor.svelte | 5 +- .../components/apps/editor/GridViewer.svelte | 36 +- .../apps/editor/SubGridEditor.svelte | 296 +++--- .../apps/editor/component/Component.svelte | 976 +----------------- .../editor/component/ComponentInner.svelte | 778 ++++++++++++++ .../editor/component/ComponentRendered.svelte | 219 ++++ .../components/apps/svelte-grid/Grid.svelte | 232 +++-- .../apps/svelte-grid/MoveResize.svelte | 3 +- 30 files changed, 2374 insertions(+), 2144 deletions(-) create mode 100644 frontend/src/lib/components/apps/editor/component/ComponentInner.svelte create mode 100644 frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte diff --git a/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte b/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte index 68b52e515c..453d964d45 100644 --- a/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte +++ b/frontend/src/lib/components/apps/components/buttons/AppFormButton.svelte @@ -89,75 +89,79 @@ configuration={configuration[key]} /> {/each} - -
- - {#if noInputs} -
- Run forms are associated with a runnable that has user inputs. -
- Once a script or flow is chosen, set some Runnable Inputs to - - User Input - - +{#if render} + +
+ + {#if noInputs} +
+ Run forms are associated with a runnable that has user inputs. +
+ Once a script or flow is chosen, set some Runnable Inputs to + + User Input + + +
+ {/if} +
+
- {/if} -
- -
-
-
-
+ +
+ - - {#if errorsMessage} -
{errorsMessage}
- {/if} - -
+ + {#if errorsMessage} +
{errorsMessage}
+ {/if} + +
+{:else} + +{/if} diff --git a/frontend/src/lib/components/apps/components/display/AppAccordionList.svelte b/frontend/src/lib/components/apps/components/display/AppAccordionList.svelte index 2966cf418d..e322e9e783 100644 --- a/frontend/src/lib/components/apps/components/display/AppAccordionList.svelte +++ b/frontend/src/lib/components/apps/components/display/AppAccordionList.svelte @@ -18,17 +18,21 @@ export let initializing: boolean | undefined export let componentContainerHeight: number - type AccordionListValue = { header: string; [key: string]: any }; + type AccordionListValue = { header: string; [key: string]: any } type InternalAccordionListInput = AppInput & { - value: AccordionListValue[]; - }; + value: AccordionListValue[] + } - $: accordionInput = componentInput as InternalAccordionListInput; + $: accordionInput = componentInput as InternalAccordionListInput const { app, focusedGrid, selectedComponent, worldStore, connectingInput } = getContext('AppViewerContext') + let everRender = render + + $: render && !everRender && (everRender = true) + let activeIndex: number = 0 const outputs = initOutput($worldStore, id, { @@ -61,7 +65,6 @@ activeIndex = activeIndex === index ? -1 : index outputs.activeIndex.set(activeIndex) } - {#each Object.keys(css ?? {}) as key (key)} @@ -85,27 +88,27 @@ bind:initializing bind:result > -
- {#if $app.subgrids?.[`${id}-0`]} - {#if Array.isArray(result) && result.length > 0} - {#each result ?? [] as value, index} -
- - {#if activeIndex === index} -
+ {#if everRender} +
+ {#if $app.subgrids?.[`${id}-0`]} + {#if Array.isArray(result) && result.length > 0} + {#each result ?? [] as value, index} +
+ +
{ if (!inputs[id]) { @@ -133,8 +136,8 @@ >
- {/if} -
- {/each} - {:else} - - - - {#if !Array.isArray(result)} -
Input data is not an array
+
+ {/each} + {:else} + + + + {#if !Array.isArray(result)} +
Input data is not an array
+ {/if} {/if} {/if} - {/if} -
+
+ {:else if $app.subgrids} + + + + {/if} diff --git a/frontend/src/lib/components/apps/components/display/AppCarouselList.svelte b/frontend/src/lib/components/apps/components/display/AppCarouselList.svelte index 8ce89208dd..a8a2dce0e9 100644 --- a/frontend/src/lib/components/apps/components/display/AppCarouselList.svelte +++ b/frontend/src/lib/components/apps/components/display/AppCarouselList.svelte @@ -27,6 +27,9 @@ const { app, focusedGrid, selectedComponent, worldStore, connectingInput } = getContext('AppViewerContext') + let everRender = render + $: render && !everRender && (everRender = true) + const outputs = initOutput($worldStore, id, { result: undefined, loading: false, @@ -90,117 +93,123 @@ bind:initializing bind:result > -
- {#if $app.subgrids?.[`${id}-0`]} - {#if Array.isArray(result) && result.length > 0} - {#key result} - { - currentPageIndex = event.detail - $focusedGrid = { - parentComponentId: id, - subGridIndex: event.detail - } - }} - > -
-
- -
-
-
-
- -
-
- {#each result ?? [] as value, index} -
- { - if (!inputs[id]) { - inputs[id] = { [index]: value } - } else { - inputs[id] = { ...inputs[id], [index]: value } - } - outputs?.inputs.set(inputs, true) - }} - onRemove={(id) => { - if (inputs?.[id] == undefined) { - return - } - if (index == 0) { - delete inputs[id] - inputs = { ...inputs } - } else { - delete inputs[id][index] - inputs[id] = { ...inputs[id] } - } - outputs?.inputs.set(inputs, true) - }} - {value} - {index} - > - { - if (!$connectingInput.opened) { - $selectedComponent = [id] + if (currentPageIndex > 0) { + carousel.goTo(currentPageIndex - 1) + } else { + carousel.goTo(pagesCount - 1) } - onFocus() }} - /> - + > + + +
- {/each} - - {/key} - {:else} - - - - {#if !Array.isArray(result)} -
Input data is not an array
+
+
+ +
+
+ {#each result ?? [] as value, index} +
+ { + if (!inputs[id]) { + inputs[id] = { [index]: value } + } else { + inputs[id] = { ...inputs[id], [index]: value } + } + outputs?.inputs.set(inputs, true) + }} + onRemove={(id) => { + if (inputs?.[id] == undefined) { + return + } + if (index == 0) { + delete inputs[id] + inputs = { ...inputs } + } else { + delete inputs[id][index] + inputs[id] = { ...inputs[id] } + } + outputs?.inputs.set(inputs, true) + }} + {value} + {index} + > + { + if (!$connectingInput.opened) { + $selectedComponent = [id] + } + onFocus() + }} + /> + +
+ {/each} + + {/key} + {:else} + + + + {#if !Array.isArray(result)} +
Input data is not an array
+ {/if} {/if} {/if} - {/if} -
+
+ {:else if $app.subgrids} + + + + {/if} diff --git a/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte b/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte index d481de1a1b..192cf569ef 100644 --- a/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte +++ b/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte @@ -119,4 +119,6 @@
+{:else} + {/if} diff --git a/frontend/src/lib/components/apps/components/display/AppHtml.svelte b/frontend/src/lib/components/apps/components/display/AppHtml.svelte index 7d0b4e873c..7a79efc6f2 100644 --- a/frontend/src/lib/components/apps/components/display/AppHtml.svelte +++ b/frontend/src/lib/components/apps/components/display/AppHtml.svelte @@ -35,25 +35,29 @@ /> {/each} -
{ - e?.preventDefault() - }} - class="h-full w-full" -> - { + e?.preventDefault() + }} + class="h-full w-full" > -
- {#key result} - {@html result} - {/key} -
-
-
+ +
+ {#key result} + {@html result} + {/key} +
+
+ +{:else} + +{/if} diff --git a/frontend/src/lib/components/apps/components/display/AppMarkdown.svelte b/frontend/src/lib/components/apps/components/display/AppMarkdown.svelte index 8ff485a4ae..bdd6fc1658 100644 --- a/frontend/src/lib/components/apps/components/display/AppMarkdown.svelte +++ b/frontend/src/lib/components/apps/components/display/AppMarkdown.svelte @@ -62,32 +62,36 @@ /> {/each} -
{ - e?.preventDefault() - }} - class={classNames( - 'h-full w-full overflow-y-auto prose max-w-full', - resolvedConfig?.size ? proseMapping[resolvedConfig.size] : '', - css?.container?.class, - ' dark:prose-invert', - 'wm-markdown' - )} - style={css?.container?.style} -> - { + e?.preventDefault() + }} + class={classNames( + 'h-full w-full overflow-y-auto prose max-w-full', + resolvedConfig?.size ? proseMapping[resolvedConfig.size] : '', + css?.container?.class, + ' dark:prose-invert', + 'wm-markdown' + )} + style={css?.container?.style} > - {#if result} - {#key result} - - {/key} - {/if} - -
+ + {#if result} + {#key result} + + {/key} + {/if} + + +{:else} + +{/if} diff --git a/frontend/src/lib/components/apps/components/display/AppText.svelte b/frontend/src/lib/components/apps/components/display/AppText.svelte index 78e10402b6..f83b5ab6a8 100644 --- a/frontend/src/lib/components/apps/components/display/AppText.svelte +++ b/frontend/src/lib/components/apps/components/display/AppText.svelte @@ -217,7 +217,7 @@ {:else}
{#if resolvedConfig.copyButton && result} -
+
+ {/if} + +
{/if} - {#if getFirstNode(nodes)?.id !== currentNodeId} - - {/if} - -
+{:else if $app.subgrids} + {#each Object.values(nodes) ?? [] as _node, i} + + {/each} +{/if} diff --git a/frontend/src/lib/components/apps/components/layout/AppDrawer.svelte b/frontend/src/lib/components/apps/components/layout/AppDrawer.svelte index e5e73536d0..9504399bc7 100644 --- a/frontend/src/lib/components/apps/components/layout/AppDrawer.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppDrawer.svelte @@ -24,6 +24,9 @@ export let onOpenRecomputeIds: string[] | undefined = undefined export let onCloseRecomputeIds: string[] | undefined = undefined + let everRender = render + $: render && !everRender && (everRender = true) + const { app, focusedGrid, @@ -77,98 +80,103 @@ {/each} - -
- - - -
- - - { - outputs?.open.set(true) - onOpenRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) - }} - on:close={() => { - outputs?.open.set(false) - onCloseRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) - }} - > - { - appDrawer?.toggleDrawer() - $focusedGrid = undefined - }} - fullScreen={$mode !== 'dnd'} - > -
+ +
-
-
-
+ + +
+{/if} + +{#if everRender} + + { + outputs?.open.set(true) + onOpenRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) + }} + on:close={() => { + outputs?.open.set(false) + onCloseRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) + }} + > + { + appDrawer?.toggleDrawer() + $focusedGrid = undefined + }} + fullScreen={$mode !== 'dnd'} + > +
{ + e?.stopPropagation() + if (!$connectingInput.opened) { + $selectedComponent = [id] + $focusedGrid = { + parentComponentId: id, + subGridIndex: 0 + } + } + }} + > + {#if $app.subgrids?.[`${id}-0`]} + { + if (!$connectingInput.opened) { + $selectedComponent = [id] + $focusedGrid = { + parentComponentId: id, + subGridIndex: 0 + } + } + }} + /> + {/if} +
+
+
+
+{:else if $app.subgrids?.[`${id}-0`]} + +{/if} diff --git a/frontend/src/lib/components/apps/components/layout/AppList.svelte b/frontend/src/lib/components/apps/components/layout/AppList.svelte index a0e708670c..44e0a56509 100644 --- a/frontend/src/lib/components/apps/components/layout/AppList.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppList.svelte @@ -26,6 +26,9 @@ getContext('AppViewerContext') let page = 0 + let everRender = render + $: render && !everRender && (everRender = true) + const outputs = initOutput($worldStore, id, { result: undefined, loading: false, @@ -72,8 +75,8 @@ const l = initialData ? initialData.length : 0 if (mode === 'auto') { const pageSize: number = configuration.auto.pageSize ?? 0 - const shouldDisplayPagination = pageSize < l ?? false - const total = Math.ceil(l / pageSize ?? 0) + const shouldDisplayPagination = (pageSize ?? 0) < l + const total = Math.ceil(l / (pageSize ?? 0)) return { shouldDisplayPagination, @@ -136,136 +139,144 @@ bind:result bind:loading > -
+ {#if everRender}
- {#if $app.subgrids?.[`${id}-0`]} - {#if Array.isArray(result) && result.length > 0} - {#each result ?? [] as value, index (index)} - {@const inRange = index <= pagination.maxIndex && index >= pagination.indexOffset} -
- { - if (!inputs[id]) { - inputs[id] = { [index]: value } - } else { - inputs[id] = { ...inputs[id], [index]: value } - } - outputs?.inputs.set(inputs, true) - }} - onRemove={(id) => { - if (inputs?.[id] == undefined) { - return - } - if (index == 0) { - delete inputs[id] - inputs = { ...inputs } - } else { - delete inputs[id][index] - inputs[id] = { ...inputs[id] } - } - outputs?.inputs.set(inputs, true) - }} - {value} - {index} +
+ {#if $app.subgrids?.[`${id}-0`]} + {#if Array.isArray(result) && result.length > 0} + {#each result ?? [] as value, index (index)} + {@const inRange = index <= pagination.maxIndex && index >= pagination.indexOffset} +
- { - if (!$connectingInput.opened) { - $selectedComponent = [id] + { + if (!inputs[id]) { + inputs[id] = { [index]: value } + } else { + inputs[id] = { ...inputs[id], [index]: value } } - onFocus() + outputs?.inputs.set(inputs, true) }} - /> - -
- {/each} - {:else} - - - - {#if !Array.isArray(result)} -
Input data is not an array
+ onRemove={(id) => { + if (inputs?.[id] == undefined) { + return + } + if (index == 0) { + delete inputs[id] + inputs = { ...inputs } + } else { + delete inputs[id][index] + inputs[id] = { ...inputs[id] } + } + outputs?.inputs.set(inputs, true) + }} + {value} + {index} + > + { + if (!$connectingInput.opened) { + $selectedComponent = [id] + } + onFocus() + }} + /> + +
+ {/each} + {:else} + + + + {#if !Array.isArray(result)} +
Input data is not an array
+ {/if} {/if} {/if} +
+ {#if pagination.shouldDisplayPagination} +
+ + +
{page + 1} {pagination.total > 0 ? `of ${pagination.total}` : ''}
+
{/if}
- {#if pagination.shouldDisplayPagination} -
- - -
{page + 1} {pagination.total > 0 ? `of ${pagination.total}` : ''}
-
- {/if} -
+ {:else if $app.subgrids} + + + + {/if}
diff --git a/frontend/src/lib/components/apps/components/layout/AppModal.svelte b/frontend/src/lib/components/apps/components/layout/AppModal.svelte index 1a4bd62cce..ccb25145a6 100644 --- a/frontend/src/lib/components/apps/components/layout/AppModal.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppModal.svelte @@ -40,6 +40,9 @@ breakpoint } = getContext('AppViewerContext') + let everRender = render + $: render && !everRender && (everRender = true) + //used so that we can count number of outputs setup for first refresh const outputs = initOutput($worldStore, id, { open: false @@ -110,7 +113,7 @@ /> {/each} -{#if render} +{#if everRender}
-{/if} - - { - outputs?.open.set(true) - onOpenRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) - }} - on:close={() => { - outputs?.open.set(false) - onCloseRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) - }} - > -
+ { + outputs?.open.set(true) + onOpenRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) + }} + on:close={() => { + outputs?.open.set(false) + onCloseRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.())) + }} >
{ - if ($mode !== 'dnd' && !unclickableOutside) { - handleClickAway(e) - } - }} + class={twMerge( + `${ + $mode == 'dnd' ? 'absolute' : 'fixed' + } top-0 bottom-0 left-0 right-0 transition-all duration-50`, + open ? ' bg-black bg-opacity-60' : 'h-0 overflow-hidden invisible' + )} + style="z-index: {zIndex}" + bind:clientHeight={wrapperHeight} >
-
{resolvedConfig.modalTitle}
-
- -
-
- -
{ - e?.stopPropagation() - if (!$connectingInput.opened) { - $selectedComponent = [id] - $focusedGrid = { - parentComponentId: id, - subGridIndex: 0 - } + style={css?.popup?.style} + class={twMerge('mx-24 mt-8 bg-surface rounded-lg relative', css?.popup?.class)} + use:clickOutside={false} + on:click_outside={(e) => { + if ($mode !== 'dnd' && !unclickableOutside) { + handleClickAway(e) } }} > - {#if $app.subgrids?.[`${id}-0`]} - { - if (!$connectingInput.opened) { - $selectedComponent = [id] - $focusedGrid = { - parentComponentId: id, - subGridIndex: 0 - } +
+
{resolvedConfig.modalTitle}
+
+ +
+
+ +
{ + e?.stopPropagation() + if (!$connectingInput.opened) { + $selectedComponent = [id] + $focusedGrid = { + parentComponentId: id, + subGridIndex: 0 } - }} - /> - {/if} + } + }} + > + {#if $app.subgrids?.[`${id}-0`]} + { + if (!$connectingInput.opened) { + $selectedComponent = [id] + $focusedGrid = { + parentComponentId: id, + subGridIndex: 0 + } + } + }} + /> + {/if} +
-
-
-
+ + +{:else if $app.subgrids?.[`${id}-0`]} + +{/if} diff --git a/frontend/src/lib/components/apps/components/layout/AppSplitpanes.svelte b/frontend/src/lib/components/apps/components/layout/AppSplitpanes.svelte index 384000a06b..90dbf14618 100644 --- a/frontend/src/lib/components/apps/components/layout/AppSplitpanes.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppSplitpanes.svelte @@ -25,6 +25,10 @@ //used so that we can count number of outputs setup for first refresh initOutput($worldStore, id, {}) + let everRender = render + + $: render && !everRender && (everRender = true) + function onFocus() { $focusedGrid = { parentComponentId: id, @@ -82,47 +86,53 @@ -
- {#key sumedup} - - {#each sumedup as paneSize, index (index)} - -
{ - $selectedComponent = [id] - $focusedGrid = { - parentComponentId: id, - subGridIndex: index - } - }} - > - {#if $app.subgrids?.[`${id}-${index}`]} - { - if (!$connectingInput.opened) { - $selectedComponent = [id] - $focusedGrid = { - parentComponentId: id, - subGridIndex: index +{#if everRender} +
+ {#key sumedup} + + {#each sumedup as paneSize, index (index)} + +
{ + $selectedComponent = [id] + $focusedGrid = { + parentComponentId: id, + subGridIndex: index + } + }} + > + {#if $app.subgrids?.[`${id}-${index}`]} + { + if (!$connectingInput.opened) { + $selectedComponent = [id] + $focusedGrid = { + parentComponentId: id, + subGridIndex: index + } } - } - }} - /> - {/if} -
-
- {/each} -
- {/key} -
+ }} + /> + {/if} +
+
+ {/each} +
+ {/key} +
+{:else} + {#each sumedup as _paneSize, index (index)} + + {/each} +{/if} diff --git a/frontend/src/lib/components/apps/components/layout/AppStepper.svelte b/frontend/src/lib/components/apps/components/layout/AppStepper.svelte index 9a15955ec6..eb47b3e928 100644 --- a/frontend/src/lib/components/apps/components/layout/AppStepper.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppStepper.svelte @@ -36,6 +36,9 @@ runnableComponents } = getContext('AppViewerContext') + let everRender = render + $: render && !everRender && (everRender = true) + let selected = tabs[0] let tabHeight: number = 0 let footerHeight: number = 0 @@ -155,97 +158,109 @@ bind:result errorHandledByComponent={true} > -
-
- { - const index = e.detail.index - if (index <= maxReachedIndex || $mode === 'dnd') { - runStep(index) - } - }} - {tabs} - {selectedIndex} - {maxReachedIndex} - {statusByStep} - hasValidations={Boolean(runnableComponent)} - /> -
- -
- {#if $app.subgrids} - {#each tabs ?? [] as _res, i} - { - if (!$connectingInput.opened) { - $selectedComponent = [id] - handleTabSelection() + {#if everRender} +
+ {#if render} +
+ { + const index = e.detail.index + if (index <= maxReachedIndex || $mode === 'dnd') { + runStep(index) } }} + {tabs} + {selectedIndex} + {maxReachedIndex} + {statusByStep} + hasValidations={Boolean(runnableComponent)} /> - {/each} +
+ {/if} + +
+ {#if $app.subgrids} + {#each tabs ?? [] as _res, i} + { + if (!$connectingInput.opened) { + $selectedComponent = [id] + handleTabSelection() + } + }} + /> + {/each} + {/if} +
+ + {#if render} +
+
+
+ + Step {selectedIndex + 1} of {tabs.length} + +
+
+ + + +
+
+
{/if}
- -
-
-
- - Step {selectedIndex + 1} of {tabs.length} - -
-
- - - -
-
-
-
+ {:else if $app.subgrids} + {#each tabs ?? [] as _res, i} + + {/each} + {/if} diff --git a/frontend/src/lib/components/apps/components/layout/AppTabs.svelte b/frontend/src/lib/components/apps/components/layout/AppTabs.svelte index 553e6db4f1..f57d7c46f0 100644 --- a/frontend/src/lib/components/apps/components/layout/AppTabs.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppTabs.svelte @@ -29,6 +29,8 @@ components['tabscomponent'].initialData.configuration, configuration ) + let everRender = render + $: render && !everRender && (everRender = true) const { app, @@ -117,128 +119,134 @@ /> {/each} -
- {#if !resolvedConfig.tabsKind || resolvedConfig.tabsKind == 'tabs' || (resolvedConfig.tabsKind == 'invisibleOnView' && $mode == 'dnd')} -
- + {#if !resolvedConfig.tabsKind || resolvedConfig.tabsKind == 'tabs' || (resolvedConfig.tabsKind == 'invisibleOnView' && $mode == 'dnd')} +
+ + {#each tabs ?? [] as res, index} + + {res} + + {/each} + +
+ {:else if resolvedConfig.tabsKind == 'sidebar'} +
- {#each tabs ?? [] as res, index} - - {res} - - {/each} - -
- {:else if resolvedConfig.tabsKind == 'sidebar'} -
- {#each tabs ?? [] as res} - - {/each} -
- {/if} - {#if resolvedConfig.tabsKind == 'accordion'} -
- {#each tabs ?? [] as res, index} -
+ {#each tabs ?? [] as res} - {#if selected == res} -
- { - if (!$connectingInput.opened) { - $selectedComponent = [id] - handleTabSelection() - } - }} - /> -
- {/if} -
- {/each} -
- {:else} -
- {#if $app.subgrids} - {#each tabs ?? [] as _res, i} - { - if (!$connectingInput.opened) { - $selectedComponent = [id] - handleTabSelection() - } - }} - /> {/each} - {/if} -
- {/if} -
+
+ {/if} + {#if resolvedConfig.tabsKind == 'accordion'} +
+ {#each tabs ?? [] as res, index} +
+ + {#if selected == res} +
+ { + if (!$connectingInput.opened) { + $selectedComponent = [id] + handleTabSelection() + } + }} + /> +
+ {/if} +
+ {/each} +
+ {:else} +
+ {#if $app.subgrids} + {#each tabs ?? [] as _res, i} + { + if (!$connectingInput.opened) { + $selectedComponent = [id] + handleTabSelection() + } + }} + /> + {/each} + {/if} +
+ {/if} +
+{:else if $app.subgrids} + {#each tabs ?? [] as _res, i} + + {/each} +{/if} diff --git a/frontend/src/lib/components/apps/editor/AppPreview.svelte b/frontend/src/lib/components/apps/editor/AppPreview.svelte index e286988b42..ca1841c7b2 100644 --- a/frontend/src/lib/components/apps/editor/AppPreview.svelte +++ b/frontend/src/lib/components/apps/editor/AppPreview.svelte @@ -15,7 +15,6 @@ import GridViewer from './GridViewer.svelte' import Component from './component/Component.svelte' import { twMerge } from 'tailwind-merge' - import { columnConfiguration } from '../gridUtils' import { deepEqual } from 'fast-equals' import { dfs, maxHeight } from './appUtils' import { BG_PREFIX, migrateApp } from '../utils' @@ -292,8 +291,6 @@ allIdsInPath={$allIdsInPath} items={app.grid} let:dataItem - let:hidden - cols={columnConfiguration} {maxRow} breakpoint={$breakpoint} > @@ -308,7 +305,6 @@ selected={false} locked={true} fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight} - {hidden} /> diff --git a/frontend/src/lib/components/apps/editor/GridEditor.svelte b/frontend/src/lib/components/apps/editor/GridEditor.svelte index 5460f92cdc..9407e8714a 100644 --- a/frontend/src/lib/components/apps/editor/GridEditor.svelte +++ b/frontend/src/lib/components/apps/editor/GridEditor.svelte @@ -1,7 +1,7 @@
- {#if xPerPx} + {#if xPerPx && getComputedCols} {#each items as item (item.id)} {@const onTop = allIdsInPath?.includes(item.id)} {@const width = @@ -103,10 +117,14 @@ : ''} top: {top}px; left: {left}px;" > {#if item[getComputedCols]} -
{/each} + {:else if showSkeleton} +
{/if}
diff --git a/frontend/src/lib/components/apps/editor/SubGridEditor.svelte b/frontend/src/lib/components/apps/editor/SubGridEditor.svelte index 76cd8167eb..96b4b6cbb8 100644 --- a/frontend/src/lib/components/apps/editor/SubGridEditor.svelte +++ b/frontend/src/lib/components/apps/editor/SubGridEditor.svelte @@ -3,7 +3,7 @@ import { classNames } from '$lib/utils' import { createEventDispatcher, getContext, onDestroy } from 'svelte' import { twMerge } from 'tailwind-merge' - import { columnConfiguration, gridColumns, isFixed, toggleFixed } from '../gridUtils' + import { gridColumns, isFixed, toggleFixed } from '../gridUtils' import Grid from '../svelte-grid/Grid.svelte' import type { AppEditorContext, AppViewerContext, GridItem } from '../types' import { @@ -53,6 +53,10 @@ let isActive = false let sber = editorContext?.componentActive?.subscribe((x) => (isActive = x)) + let everVisible = visible + + $: visible && !everVisible && (everVisible = true) + onDestroy(() => { sber?.() }) @@ -173,160 +177,156 @@ } - - +{/if} diff --git a/frontend/src/lib/components/apps/editor/component/Component.svelte b/frontend/src/lib/components/apps/editor/component/Component.svelte index 6d4d0a396e..51d1891cd1 100644 --- a/frontend/src/lib/components/apps/editor/component/Component.svelte +++ b/frontend/src/lib/components/apps/editor/component/Component.svelte @@ -1,969 +1,39 @@ - - - - -
{ - outTimeout && clearTimeout(outTimeout) - if (component.id !== $hoverStore) { - $hoverStore = component.id - } - }} - on:mouseout|stopPropagation={mouseOut} - class={twMerge( - 'h-full flex flex-col w-full component relative', - initializing ? 'overflow-hidden h-0' : '', - hidden && $mode === 'preview' ? 'hidden' : '' - )} - data-connection-button -> - {#if locked && componentActive && $componentActive && moveMode === 'move' && componentDraggedId && componentDraggedId !== component.id && cachedAreOnTheSameSubgrid} -
-
- -
Anchored: The component cannot be moved.
-
-
- {:else if moveMode === 'insert' && isContainer(component.type) && componentDraggedId && componentDraggedId !== component.id && cachedComponentDraggedIsNotChild} -
- {/if} - {#if $mode !== 'preview'} - { - outTimeout && clearTimeout(outTimeout) - - if (component.id !== $hoverStore) { - $hoverStore = component.id - } - }} - hover={$hoverStore === component.id} - {component} - {selected} - {fullHeight} - connecting={$connectingInput.opened} - on:lock - on:expand - on:fillHeight - {locked} - {inlineEditorOpened} - hasInlineEditor={component.type === 'textcomponent' && - component.componentInput && - component.componentInput.type !== 'connected'} - on:triggerInlineEditor={() => { - inlineEditorOpened = !inlineEditorOpened - }} - {errorHandledByComponent} - {componentContainerWidth} - /> - {/if} - - {#if ismoving} -
- -
- {/if} -
- {#if component.type === 'displaycomponent'} - - {:else if component.type === 'logcomponent'} - - {:else if component.type === 'jobidlogcomponent'} - - {:else if component.type === 'flowstatuscomponent'} - - {:else if component.type === 'jobidflowstatuscomponent'} - - {:else if component.type === 'barchartcomponent'} - - {:else if component.type === 'timeseriescomponent'} - - {:else if component.type === 'htmlcomponent'} - - {:else if component.type === 'customcomponent'} - - {:else if component.type === 'mardowncomponent'} - - {:else if component.type === 'vegalitecomponent'} - - {:else if component.type === 'plotlycomponent'} - - {:else if component.type === 'plotlycomponentv2'} - - {:else if component.type === 'scatterchartcomponent'} - - {:else if component.type === 'piechartcomponent'} - - {:else if component.type === 'agchartscomponent'} - - {:else if component.type === 'agchartscomponentee'} - - {:else if component.type === 'tablecomponent'} - - {:else if component.type === 'dbexplorercomponent'} - - {:else if component.type === 'aggridcomponent'} - - {:else if component.type === 'aggridcomponentee'} - - {:else if component.type === 'aggridinfinitecomponent'} - - {:else if component.type === 'aggridinfinitecomponentee'} - - {:else if component.type === 'textcomponent'} - - {:else if component.type === 'buttoncomponent'} - - {:else if component.type === 'downloadcomponent'} - - {:else if component.type === 'selectcomponent' || component.type === 'resourceselectcomponent'} - - {:else if component.type === 'userresourcecomponent'} - - {:else if component.type === 'multiselectcomponent'} - - {:else if component.type === 'multiselectcomponentv2'} - - {:else if component.type === 'formcomponent'} - - {:else if component.type === 'formbuttoncomponent'} - - {:else if component.type === 'checkboxcomponent'} - - {:else if component.type === 'textinputcomponent'} - - {:else if component.type === 'quillcomponent'} - - {:else if component.type === 'textareainputcomponent'} - - {:else if component.type === 'emailinputcomponent'} - - {:else if component.type === 'passwordinputcomponent'} - - {:else if component.type === 'dateinputcomponent'} - - {:else if component.type === 'timeinputcomponent'} - - {:else if component.type === 'datetimeinputcomponent'} - - {:else if component.type === 'numberinputcomponent'} - - {:else if component.type === 'currencycomponent'} - - {:else if component.type === 'slidercomponent'} - - {:else if component.type === 'dateslidercomponent'} - - {:else if component.type === 'horizontaldividercomponent'} - - {:else if component.type === 'verticaldividercomponent'} - - {:else if component.type === 'rangecomponent'} - - {:else if component.type === 'tabscomponent' && component.tabs} - - {:else if component.type === 'steppercomponent' && component.tabs} - - {:else if component.type === 'conditionalwrapper' && component.conditions} - - {:else if component.type === 'containercomponent'} - - {:else if component.type === 'listcomponent'} - - {:else if component.type === 'verticalsplitpanescomponent'} - - {:else if component.type === 'horizontalsplitpanescomponent'} - - {:else if component.type === 'iconcomponent'} - - {:else if component.type === 'fileinputcomponent'} - - {:else if component.type === 's3fileinputcomponent'} - - {:else if component.type === 'imagecomponent'} - - {:else if component.type === 'drawercomponent'} - - {:else if component.type === 'mapcomponent'} - - {:else if component.type === 'pdfcomponent'} - - {:else if component.type === 'modalcomponent'} - - {:else if component.type === 'schemaformcomponent'} - - {:else if component.type === 'selecttabcomponent'} - - {:else if component.type === 'selectstepcomponent'} - - {:else if component.type === 'chartjscomponent'} - - {:else if component.type === 'chartjscomponentv2'} - - {:else if component.type === 'carousellistcomponent'} - - {:else if component.type === 'accordionlistcomponent'} - - {:else if component.type === 'statcomponent'} - - {:else if component.type === 'menucomponent'} - - {:else if component.type === 'decisiontreecomponent' && component.nodes} - - {:else if component.type === 'alertcomponent'} - - {:else if component.type === 'navbarcomponent'} - - {:else if component.type === 'dateselectcomponent'} - - {:else if component.type === 'jobiddisplaycomponent'} - - {:else if component.type === 'recomputeallcomponent'} - - {/if} -
-
-{#if initializing} - - -
{ - if (component.id !== $hoverStore) { - $hoverStore = component.id - } - }} - on:mouseout|stopPropagation={() => { - if ($hoverStore !== undefined) { - $hoverStore = undefined - } - }} - class="absolute inset-0 center-center flex-col bg- border animate-skeleton" +{#if everRender} + +{:else} + {/if} diff --git a/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte b/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte new file mode 100644 index 0000000000..9973ebbcbf --- /dev/null +++ b/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte @@ -0,0 +1,778 @@ + + +{#if component.type === 'displaycomponent'} + +{:else if component.type === 'logcomponent'} + +{:else if component.type === 'jobidlogcomponent'} + +{:else if component.type === 'flowstatuscomponent'} + +{:else if component.type === 'jobidflowstatuscomponent'} + +{:else if component.type === 'barchartcomponent'} + +{:else if component.type === 'timeseriescomponent'} + +{:else if component.type === 'htmlcomponent'} + +{:else if component.type === 'customcomponent'} + +{:else if component.type === 'mardowncomponent'} + +{:else if component.type === 'vegalitecomponent'} + +{:else if component.type === 'plotlycomponent'} + +{:else if component.type === 'plotlycomponentv2'} + +{:else if component.type === 'scatterchartcomponent'} + +{:else if component.type === 'piechartcomponent'} + +{:else if component.type === 'agchartscomponent'} + +{:else if component.type === 'agchartscomponentee'} + +{:else if component.type === 'tablecomponent'} + +{:else if component.type === 'dbexplorercomponent'} + +{:else if component.type === 'aggridcomponent'} + +{:else if component.type === 'aggridcomponentee'} + +{:else if component.type === 'aggridinfinitecomponent'} + +{:else if component.type === 'aggridinfinitecomponentee'} + +{:else if component.type === 'textcomponent'} + +{:else if component.type === 'buttoncomponent'} + +{:else if component.type === 'downloadcomponent'} + +{:else if component.type === 'selectcomponent' || component.type === 'resourceselectcomponent'} + +{:else if component.type === 'userresourcecomponent'} + +{:else if component.type === 'multiselectcomponent'} + +{:else if component.type === 'multiselectcomponentv2'} + +{:else if component.type === 'formcomponent'} + +{:else if component.type === 'formbuttoncomponent'} + +{:else if component.type === 'checkboxcomponent'} + +{:else if component.type === 'textinputcomponent'} + +{:else if component.type === 'quillcomponent'} + +{:else if component.type === 'textareainputcomponent'} + +{:else if component.type === 'emailinputcomponent'} + +{:else if component.type === 'passwordinputcomponent'} + +{:else if component.type === 'dateinputcomponent'} + +{:else if component.type === 'timeinputcomponent'} + +{:else if component.type === 'datetimeinputcomponent'} + +{:else if component.type === 'numberinputcomponent'} + +{:else if component.type === 'currencycomponent'} + +{:else if component.type === 'slidercomponent'} + +{:else if component.type === 'dateslidercomponent'} + +{:else if component.type === 'horizontaldividercomponent'} + +{:else if component.type === 'verticaldividercomponent'} + +{:else if component.type === 'rangecomponent'} + +{:else if component.type === 'tabscomponent' && component.tabs} + +{:else if component.type === 'steppercomponent' && component.tabs} + +{:else if component.type === 'conditionalwrapper' && component.conditions} + +{:else if component.type === 'containercomponent'} + +{:else if component.type === 'listcomponent'} + +{:else if component.type === 'verticalsplitpanescomponent'} + +{:else if component.type === 'horizontalsplitpanescomponent'} + +{:else if component.type === 'iconcomponent'} + +{:else if component.type === 'fileinputcomponent'} + +{:else if component.type === 's3fileinputcomponent'} + +{:else if component.type === 'imagecomponent'} + +{:else if component.type === 'drawercomponent'} + +{:else if component.type === 'mapcomponent'} + +{:else if component.type === 'pdfcomponent'} + +{:else if component.type === 'modalcomponent'} + +{:else if component.type === 'schemaformcomponent'} + +{:else if component.type === 'selecttabcomponent'} + +{:else if component.type === 'selectstepcomponent'} + +{:else if component.type === 'chartjscomponent'} + +{:else if component.type === 'chartjscomponentv2'} + +{:else if component.type === 'carousellistcomponent'} + +{:else if component.type === 'accordionlistcomponent'} + +{:else if component.type === 'statcomponent'} + +{:else if component.type === 'menucomponent'} + +{:else if component.type === 'decisiontreecomponent' && component.nodes} + +{:else if component.type === 'alertcomponent'} + +{:else if component.type === 'navbarcomponent'} + +{:else if component.type === 'dateselectcomponent'} + +{:else if component.type === 'jobiddisplaycomponent'} + +{:else if component.type === 'recomputeallcomponent'} + +{/if} diff --git a/frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte b/frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte new file mode 100644 index 0000000000..0a7c79fd1b --- /dev/null +++ b/frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte @@ -0,0 +1,219 @@ + + + + + + +
{ + outTimeout && clearTimeout(outTimeout) + if (component.id !== $hoverStore) { + $hoverStore = component.id + } + }} + on:mouseout|stopPropagation={mouseOut} + class={twMerge( + 'h-full flex flex-col w-full component relative', + initializing ? 'overflow-hidden h-0' : '' + )} + data-connection-button +> + {#if render} + {#if locked && componentActive && $componentActive && moveMode === 'move' && componentDraggedId && componentDraggedId !== component.id && cachedAreOnTheSameSubgrid} +
+
+ +
Anchored: The component cannot be moved.
+
+
+ {:else if moveMode === 'insert' && isContainer(component.type) && componentDraggedId && componentDraggedId !== component.id && cachedComponentDraggedIsNotChild} +
+ {/if} + {#if $mode !== 'preview'} + { + outTimeout && clearTimeout(outTimeout) + + if (component.id !== $hoverStore) { + $hoverStore = component.id + } + }} + hover={$hoverStore === component.id} + {component} + {selected} + {fullHeight} + connecting={$connectingInput.opened} + on:lock + on:expand + on:fillHeight + {locked} + {inlineEditorOpened} + hasInlineEditor={component.type === 'textcomponent' && + component.componentInput && + component.componentInput.type !== 'connected'} + on:triggerInlineEditor={() => { + inlineEditorOpened = !inlineEditorOpened + }} + {errorHandledByComponent} + {componentContainerWidth} + /> + {/if} + + {#if ismoving} +
+ +
+ {/if} + {/if} +
+ +
+
+{#if initializing && render && showSkeleton} + + +
{ + if (component.id !== $hoverStore) { + $hoverStore = component.id + } + }} + on:mouseout|stopPropagation={() => { + if ($hoverStore !== undefined) { + $hoverStore = undefined + } + }} + class="absolute inset-0 center-center flex-col border animate-skeleton dark:bg-frost-900/50 [animation-delay:1000ms]" + /> +{/if} diff --git a/frontend/src/lib/components/apps/svelte-grid/Grid.svelte b/frontend/src/lib/components/apps/svelte-grid/Grid.svelte index 6a4d0da8d1..fa74b33d9a 100644 --- a/frontend/src/lib/components/apps/svelte-grid/Grid.svelte +++ b/frontend/src/lib/components/apps/svelte-grid/Grid.svelte @@ -9,6 +9,8 @@