diff --git a/frontend/src/lib/components/apps/components/GroupWrapper.svelte b/frontend/src/lib/components/apps/components/GroupWrapper.svelte index b41d20e654..e7e7555ca6 100644 --- a/frontend/src/lib/components/apps/components/GroupWrapper.svelte +++ b/frontend/src/lib/components/apps/components/GroupWrapper.svelte @@ -3,10 +3,15 @@ import type { Writable } from 'svelte/store' import type { GroupContext } from '../types' - export let context: Writable> - export let id: string + interface Props { + context: Writable> + id: string + children?: import('svelte').Snippet + } + + let { context, id, children }: Props = $props() setContext('GroupContext', { id, context }) - +{@render children?.()} diff --git a/frontend/src/lib/components/apps/components/display/AppBarChart.svelte b/frontend/src/lib/components/apps/components/display/AppBarChart.svelte index 621be96ef3..f873e149bb 100644 --- a/frontend/src/lib/components/apps/components/display/AppBarChart.svelte +++ b/frontend/src/lib/components/apps/components/display/AppBarChart.svelte @@ -22,18 +22,28 @@ import ResolveConfig from '../helpers/ResolveConfig.svelte' import { twMerge } from 'tailwind-merge' import ResolveStyle from '../helpers/ResolveStyle.svelte' - export let id: string - export let componentInput: AppInput | undefined - export let configuration: RichConfigurations - export let initializing: boolean | undefined = undefined - export let customCss: ComponentCustomCSS<'barchartcomponent'> | undefined = undefined - export let render: boolean + interface Props { + id: string + componentInput: AppInput | undefined + configuration: RichConfigurations + initializing?: boolean | undefined + customCss?: ComponentCustomCSS<'barchartcomponent'> | undefined + render: boolean + } + + let { + id, + componentInput, + configuration, + initializing = $bindable(undefined), + customCss = undefined, + render + }: Props = $props() const { app, worldStore } = getContext('AppViewerContext') - let resolvedConfig = initConfig( - components['barchartcomponent'].initialData.configuration, - configuration + let resolvedConfig = $state( + initConfig(components['barchartcomponent'].initialData.configuration, configuration) ) let outputs = initOutput($worldStore, id, { @@ -52,15 +62,17 @@ BarElement ) - let result: { data: number[]; labels?: string[] } | undefined = undefined + let result = $state(undefined) as { data: number[]; labels?: string[] } | undefined - $: backgroundColor = { - theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'], - // blue theme - theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'], - // red theme - theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e'] - }[resolvedConfig.theme ?? 'theme1'] + let backgroundColor = $derived( + { + theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'], + // blue theme + theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'], + // red theme + theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e'] + }[resolvedConfig.theme ?? 'theme1'] + ) const lineOptions: ChartOptions<'line'> = { responsive: true, @@ -84,7 +96,7 @@ } } - $: data = { + let data = $derived({ labels: result?.labels ?? [], datasets: [ @@ -105,9 +117,9 @@ } } } - } + }) - let css = initCss($app.css?.barchartcomponent, customCss) + let css = $state(initCss($app.css?.barchartcomponent, customCss)) {#each Object.keys(components['barchartcomponent'].initialData.configuration) as key (key)} diff --git a/frontend/src/lib/components/apps/components/display/AppChartJs.svelte b/frontend/src/lib/components/apps/components/display/AppChartJs.svelte index 4b88b5840a..7ac9cdb9b9 100644 --- a/frontend/src/lib/components/apps/components/display/AppChartJs.svelte +++ b/frontend/src/lib/components/apps/components/display/AppChartJs.svelte @@ -12,12 +12,23 @@ import { twMerge } from 'tailwind-merge' import ResolveStyle from '../helpers/ResolveStyle.svelte' - export let id: string - export let componentInput: AppInput | undefined - export let configuration: RichConfigurations - export let initializing: boolean | undefined = undefined - export let customCss: ComponentCustomCSS<'chartjscomponent'> | undefined = undefined - export let render: boolean + interface Props { + id: string + componentInput: AppInput | undefined + configuration: RichConfigurations + initializing?: boolean | undefined + customCss?: ComponentCustomCSS<'chartjscomponent'> | undefined + render: boolean + } + + let { + id, + componentInput, + configuration, + initializing = $bindable(undefined), + customCss = undefined, + render + }: Props = $props() const { app, worldStore } = getContext('AppViewerContext') @@ -28,20 +39,19 @@ ChartJS.register(...registerables) - let result: undefined = undefined + let result: undefined = $state(undefined) - const resolvedConfig = initConfig( - components['chartjscomponent'].initialData.configuration, - configuration + const resolvedConfig = $state( + initConfig(components['chartjscomponent'].initialData.configuration, configuration) ) - $: options = { + let options = $derived({ responsive: true, animation: false, maintainAspectRatio: false, ...(resolvedConfig.options ?? {}) - } as ChartOptions + } as ChartOptions) - let css = initCss($app.css?.chartjscomponent, customCss) + let css = $state(initCss($app.css?.chartjscomponent, customCss)) {#each Object.keys(components['chartjscomponent'].initialData.configuration) as key (key)} diff --git a/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte b/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte index 5c7b662a03..e6f748f3f1 100644 --- a/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte +++ b/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte @@ -1,5 +1,5 @@ diff --git a/frontend/src/lib/components/apps/components/display/AppNavbarItem.svelte b/frontend/src/lib/components/apps/components/display/AppNavbarItem.svelte index d06df2a9d8..c121d361cb 100644 --- a/frontend/src/lib/components/apps/components/display/AppNavbarItem.svelte +++ b/frontend/src/lib/components/apps/components/display/AppNavbarItem.svelte @@ -1,10 +1,10 @@ - diff --git a/frontend/src/lib/components/apps/components/display/AppPieChart.svelte b/frontend/src/lib/components/apps/components/display/AppPieChart.svelte index 808bca072b..d7fde24dc9 100644 --- a/frontend/src/lib/components/apps/components/display/AppPieChart.svelte +++ b/frontend/src/lib/components/apps/components/display/AppPieChart.svelte @@ -21,12 +21,23 @@ import { twMerge } from 'tailwind-merge' import ResolveStyle from '../helpers/ResolveStyle.svelte' - export let id: string - export let componentInput: AppInput | undefined - export let configuration: RichConfigurations - export let initializing: boolean | undefined = undefined - export let customCss: ComponentCustomCSS<'piechartcomponent'> | undefined = undefined - export let render: boolean + interface Props { + id: string + componentInput: AppInput | undefined + configuration: RichConfigurations + initializing?: boolean | undefined + customCss?: ComponentCustomCSS<'piechartcomponent'> | undefined + render: boolean + } + + let { + id, + componentInput, + configuration, + initializing = $bindable(undefined), + customCss = undefined, + render + }: Props = $props() const { app, worldStore } = getContext('AppViewerContext') @@ -46,17 +57,19 @@ ArcElement ) - let result: { data: number[]; labels?: string[] } | undefined = undefined - let theme: string = 'theme1' - let doughnut = false + let result = $state(undefined) as { data: number[]; labels?: string[] } | undefined + let theme: string = $state('theme1') + let doughnut = $state(false) - $: backgroundColor = { - theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'], - // blue theme - theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'], - // red theme - theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e'] - }[theme] + let backgroundColor = $derived( + { + theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'], + // blue theme + theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'], + // red theme + theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e'] + }[theme] + ) const options = { responsive: true, @@ -64,7 +77,7 @@ maintainAspectRatio: false } - $: data = { + let data = $derived({ labels: result?.labels ?? [], datasets: [ { @@ -72,9 +85,9 @@ backgroundColor: backgroundColor } ] - } + }) - let css = initCss($app.css?.piechartcomponent, customCss) + let css = $state(initCss($app.css?.piechartcomponent, customCss)) {#each Object.keys(css ?? {}) as key (key)} diff --git a/frontend/src/lib/components/apps/components/display/AppScatterChart.svelte b/frontend/src/lib/components/apps/components/display/AppScatterChart.svelte index 653adb1233..dd0d03e70a 100644 --- a/frontend/src/lib/components/apps/components/display/AppScatterChart.svelte +++ b/frontend/src/lib/components/apps/components/display/AppScatterChart.svelte @@ -24,15 +24,26 @@ import ResolveStyle from '../helpers/ResolveStyle.svelte' import { Scatter } from '$lib/components/chartjs-wrappers/chartJs' - export let id: string - export let componentInput: AppInput | undefined - export let configuration: RichConfigurations - export let initializing: boolean | undefined = undefined - export let customCss: ComponentCustomCSS<'scatterchartcomponent'> | undefined = undefined - export let render: boolean + interface Props { + id: string + componentInput: AppInput | undefined + configuration: RichConfigurations + initializing?: boolean | undefined + customCss?: ComponentCustomCSS<'scatterchartcomponent'> | undefined + render: boolean + } - let zoomable = false - let pannable = false + let { + id, + componentInput, + configuration, + initializing = $bindable(undefined), + customCss = undefined, + render + }: Props = $props() + + let zoomable = $state(false) + let pannable = $state(false) const { app, worldStore } = getContext('AppViewerContext') @@ -53,9 +64,9 @@ zoomPlugin ) - let result: { data: { x: any[]; y: string[] } } | undefined = undefined + let result: { data: { x: any[]; y: string[] } } | undefined = $state(undefined) - $: options = { + let options = $derived({ responsive: true, animation: false, maintainAspectRatio: false, @@ -74,13 +85,13 @@ } } } - } as ChartOptions<'scatter'> + } as ChartOptions<'scatter'>) - $: data = { + let data = $derived({ datasets: result ?? [] - } as ChartData<'scatter', (number | Point)[], unknown> + } as ChartData<'scatter', (number | Point)[], unknown>) - let css = initCss($app.css?.scatterchartcomponent, customCss) + let css = $state(initCss($app.css?.scatterchartcomponent, customCss)) {#each Object.keys(css ?? {}) as key (key)} diff --git a/frontend/src/lib/components/apps/components/display/AppTimeseries.svelte b/frontend/src/lib/components/apps/components/display/AppTimeseries.svelte index d0389eab0f..638d68d71e 100644 --- a/frontend/src/lib/components/apps/components/display/AppTimeseries.svelte +++ b/frontend/src/lib/components/apps/components/display/AppTimeseries.svelte @@ -27,12 +27,23 @@ import { twMerge } from 'tailwind-merge' import ResolveStyle from '../helpers/ResolveStyle.svelte' - export let id: string - export let componentInput: AppInput | undefined - export let configuration: RichConfigurations - export let initializing: boolean | undefined = undefined - export let customCss: ComponentCustomCSS<'timeseriescomponent'> | undefined = undefined - export let render: boolean + interface Props { + id: string + componentInput: AppInput | undefined + configuration: RichConfigurations + initializing?: boolean | undefined + customCss?: ComponentCustomCSS<'timeseriescomponent'> | undefined + render: boolean + } + + let { + id, + componentInput, + configuration, + initializing = $bindable(undefined), + customCss = undefined, + render + }: Props = $props() const { app, worldStore } = getContext('AppViewerContext') @@ -41,9 +52,9 @@ loading: false }) - let logarithmicScale = false - let zoomable = false - let pannable = false + let logarithmicScale = $state(false) + let zoomable = $state(false) + let pannable = $state(false) ChartJS.register( Title, @@ -59,9 +70,9 @@ LogarithmicScale ) - let result: { data: { x: any[]; y: string[] } } | undefined = undefined + let result: { data: { x: any[]; y: string[] } } | undefined = $state(undefined) - $: options = { + let options = $derived({ responsive: true, animation: false, maintainAspectRatio: false, @@ -88,13 +99,13 @@ type: logarithmicScale ? 'logarithmic' : 'linear' } } - } as ChartOptions<'scatter'> + } as ChartOptions<'scatter'>) - $: data = { + let data = $derived({ datasets: result ?? [] - } as ChartData<'scatter', (number | Point)[], unknown> + } as ChartData<'scatter', (number | Point)[], unknown>) - let css = initCss($app.css?.timeseriescomponent, customCss) + let css = $state(initCss($app.css?.timeseriescomponent, customCss)) {#each Object.keys(css ?? {}) as key (key)} diff --git a/frontend/src/lib/components/apps/components/display/PlotlyHtml.svelte b/frontend/src/lib/components/apps/components/display/PlotlyHtml.svelte index 3e00fd9f98..82cd9f805f 100644 --- a/frontend/src/lib/components/apps/components/display/PlotlyHtml.svelte +++ b/frontend/src/lib/components/apps/components/display/PlotlyHtml.svelte @@ -1,6 +1,9 @@ {#each Object.keys(components['plotlycomponent'].initialData.configuration) as key (key)} @@ -113,7 +125,7 @@ {/if} -
+
{:else} diff --git a/frontend/src/lib/components/apps/components/display/PlotlyHtmlV2.svelte b/frontend/src/lib/components/apps/components/display/PlotlyHtmlV2.svelte index e42391da02..f6ed334205 100644 --- a/frontend/src/lib/components/apps/components/display/PlotlyHtmlV2.svelte +++ b/frontend/src/lib/components/apps/components/display/PlotlyHtmlV2.svelte @@ -1,6 +1,9 @@ {#each Object.keys(components['plotlycomponentv2'].initialData.configuration) as key (key)} @@ -179,7 +207,7 @@ {/if} -
+
{:else} diff --git a/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte b/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte index 7897656ef4..e5307b4d15 100644 --- a/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte +++ b/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte @@ -3,20 +3,25 @@ import ResolveConfig from '../helpers/ResolveConfig.svelte' import { initConfig } from '../../editor/appUtils' - export let navbarItem: NavbarItem - export let id: string - export let index: number + interface Props { + navbarItem: NavbarItem + id: string + index: number + resolvedPath?: string | undefined + } - export let resolvedPath: string | undefined = undefined + let { navbarItem, id, index, resolvedPath = $bindable(undefined) }: Props = $props() - let resolvedConfig = initConfig({ path: navbarItem.path }, { path: navbarItem.path }) + let resolvedConfig = $state(initConfig({ path: navbarItem.path }, { path: navbarItem.path })) - $: resolvedPath = ( - resolvedConfig?.path?.selected === 'href' - ? resolvedConfig?.path?.configuration?.href?.href - : resolvedConfig?.path?.configuration?.app?.path + - (resolvedConfig?.path?.configuration?.app?.queryParamsOrHash ?? '') - ) as string | undefined + $effect.pre(() => { + resolvedPath = ( + resolvedConfig?.path?.selected === 'href' + ? resolvedConfig?.path?.configuration?.href?.href + : resolvedConfig?.path?.configuration?.app?.path + + (resolvedConfig?.path?.configuration?.app?.queryParamsOrHash ?? '') + ) as string | undefined + }) + import { createBubbler } from 'svelte/legacy' + + const bubble = createBubbler() import { getContext, onMount } from 'svelte' import { initOutput } from '../../editor/appUtils' import type { AppInput } from '../../inputType' @@ -6,14 +9,24 @@ import InputValue from '../helpers/InputValue.svelte' import RunnableWrapper from '../helpers/RunnableWrapper.svelte' - export let id: string - export let componentInput: AppInput | undefined - export let configuration: RichConfigurations - export let initializing: boolean | undefined = undefined - export let render: boolean + interface Props { + id: string + componentInput: AppInput | undefined + configuration: RichConfigurations + initializing?: boolean | undefined + render: boolean + } - let result: object | undefined = undefined - let divEl: HTMLDivElement | null = null + let { + id, + componentInput, + configuration, + initializing = $bindable(undefined), + render + }: Props = $props() + + let result: object | undefined = $state(undefined) + let divEl: HTMLDivElement | null = $state(null) const { worldStore } = getContext('AppViewerContext') @@ -22,7 +35,7 @@ loading: false }) - let vegaEmbed + let vegaEmbed = $state() as any onMount(async () => { //@ts-ignore await import(/* webpackIgnore: true */ 'https://cdn.jsdelivr.net/npm/vega@5.22.1') @@ -34,35 +47,37 @@ vegaEmbed = window['vegaEmbed'] }) - let h: number | undefined = undefined - let w: number | undefined = undefined - let canvas = false + let h: number | undefined = $state(undefined) + let w: number | undefined = $state(undefined) + let canvas = $state(false) - $: vegaEmbed && - result && - divEl && - h && - w && - vegaEmbed( - divEl, - { - ...result, - ...{ - width: w - 100, - config: { - legend: { orient: 'bottom', ...(result?.['config']?.['legend'] ?? {}) }, - ...(result?.['config'] ?? {}) + $effect(() => { + vegaEmbed && + result && + divEl && + h && + w && + vegaEmbed( + divEl, + { + ...result, + ...{ + width: w - 100, + config: { + legend: { orient: 'bottom', ...(result?.['config']?.['legend'] ?? {}) }, + ...(result?.['config'] ?? {}) + } } + }, + { + mode: 'vega-lite', + actions: false, + renderer: canvas ? 'canvas' : 'svg', + height: h - 75, + width: w - 100 } - }, - { - mode: 'vega-lite', - actions: false, - renderer: canvas ? 'canvas' : 'svg', - height: h - 75, - width: w - 100 - } - ) + ) + }) @@ -70,7 +85,7 @@ {#if render}
-
+
{:else} diff --git a/frontend/src/lib/components/apps/components/display/charts/AppAgCharts.svelte b/frontend/src/lib/components/apps/components/display/charts/AppAgCharts.svelte index 5597ab3d37..c37250fa95 100644 --- a/frontend/src/lib/components/apps/components/display/charts/AppAgCharts.svelte +++ b/frontend/src/lib/components/apps/components/display/charts/AppAgCharts.svelte @@ -1,12 +1,7 @@ ('AppViewerContext') @@ -19,9 +23,9 @@ jobId: undefined }) - let runnableComponent: RunnableComponent - let loading = false - let input: AppInput | undefined = undefined + let runnableComponent: RunnableComponent | undefined = $state(undefined) + let loading = $state(false) + let input: AppInput | undefined = $state(undefined) export async function triggerUpdate( resource: string, diff --git a/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte index e787c13f2b..a76821dfb7 100644 --- a/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte +++ b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte @@ -1,4 +1,4 @@ - { + onkeypress={(e) => { if (e.key === 'Enter') { saveEdit() } }} /> {:else} - -
+ +
{#if typeof value == 'object'} {JSON.stringify(value)} {:else} diff --git a/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte b/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte index c7ed674efb..e6fd477ddc 100644 --- a/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte +++ b/frontend/src/lib/components/apps/components/helpers/DebouncedInput.svelte @@ -1,18 +1,31 @@ diff --git a/frontend/src/lib/components/apps/components/helpers/InputValue.svelte b/frontend/src/lib/components/apps/components/helpers/InputValue.svelte index 3af552e162..62c68d0d60 100644 --- a/frontend/src/lib/components/apps/components/helpers/InputValue.svelte +++ b/frontend/src/lib/components/apps/components/helpers/InputValue.svelte @@ -347,6 +347,10 @@ ) && untrack(() => debounceTemplate()) }) + + // $effect(() => { + // console.log('handleConnection4', input) + // }) $effect(() => { input?.type == 'static' && input.value input && $worldStore && untrack(() => debounce(handleConnection)) diff --git a/frontend/src/lib/components/apps/components/helpers/Loader.svelte b/frontend/src/lib/components/apps/components/helpers/Loader.svelte index 67256f9333..e925a7943b 100644 --- a/frontend/src/lib/components/apps/components/helpers/Loader.svelte +++ b/frontend/src/lib/components/apps/components/helpers/Loader.svelte @@ -1,11 +1,16 @@ {#if !loading} - + {@render children?.()} {:else}
diff --git a/frontend/src/lib/components/apps/components/helpers/MissingConnectionWarning.svelte b/frontend/src/lib/components/apps/components/helpers/MissingConnectionWarning.svelte index 72c24c0ea4..01a4154d1d 100644 --- a/frontend/src/lib/components/apps/components/helpers/MissingConnectionWarning.svelte +++ b/frontend/src/lib/components/apps/components/helpers/MissingConnectionWarning.svelte @@ -1,7 +1,11 @@ {#if input.type === 'connected'} diff --git a/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte b/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte index b7f292807d..bd4e629a1e 100644 --- a/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte +++ b/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte @@ -10,6 +10,7 @@ resolvedConfig: any | { type: 'oneOf'; configuration: any; selected: string } configuration: RichConfiguration initialConfig?: RichConfiguration | undefined + debug?: boolean } let { @@ -18,15 +19,17 @@ key, resolvedConfig = $bindable(), configuration, - initialConfig = undefined + initialConfig = undefined, + debug = false }: Props = $props() function handleSelected(selected: string) { if (resolvedConfig?.selected != undefined && resolvedConfig?.selected != selected) { resolvedConfig.selected = selected } + // console.log('handleSelected', JSON.stringify({ resolvedConfig, configuration })) } - $effect(() => { + $effect.pre(() => { configuration?.type == 'oneOf' && configuration.selected && untrack(() => handleSelected(configuration.selected)) @@ -50,6 +53,13 @@ {/if} {/each} {:else} + {#if debug} +
+			key: {key} 
+			{JSON.stringify({ r: resolvedConfig })}
+			{JSON.stringify(configuration)}
+ {/if} | undefined + componentStyle?: Record | undefined + } - export let customCss: Record | undefined = undefined - export let componentStyle: Record | undefined = undefined + let { + css = $bindable(), + id, + key, + extraKey = '', + customCss = undefined, + componentStyle = undefined + }: Props = $props() - let evalClassValue: string | undefined = undefined - let evalClassValueGlobal: string | undefined = undefined + let evalClassValue: string | undefined = $state(undefined) + let evalClassValueGlobal: string | undefined = $state(undefined) function updateCss( componentStyle: Record | undefined, @@ -36,17 +47,24 @@ } // When any of the values change, update the css - $: updateCss(componentStyle, customCss, evalClassValue, evalClassValueGlobal) + $effect(() => { + ;[componentStyle, customCss, evalClassValue, evalClassValueGlobal] + untrack(() => updateCss(componentStyle, customCss, evalClassValue, evalClassValueGlobal)) + }) // We need to clear the evalClassValue if the user has disabled the evalClass - $: if (customCss?.[key]?.evalClass === undefined && evalClassValue !== undefined) { - evalClassValue = undefined - } + $effect(() => { + if (customCss?.[key]?.evalClass === undefined && evalClassValue !== undefined) { + evalClassValue = undefined + } + }) // We need to clear the evalClassValue if the user has disabled the evalClass - $: if (componentStyle?.[key]?.evalClass === undefined && evalClassValueGlobal !== undefined) { - evalClassValueGlobal = undefined - } + $effect(() => { + if (componentStyle?.[key]?.evalClass === undefined && evalClassValueGlobal !== undefined) { + evalClassValueGlobal = undefined + } + }) {#if customCss} diff --git a/frontend/src/lib/components/apps/components/inputs/AppDateInput.svelte b/frontend/src/lib/components/apps/components/inputs/AppDateInput.svelte index 0f6fe45391..164d210d32 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppDateInput.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppDateInput.svelte @@ -1,5 +1,8 @@ {#each Object.keys(components['dateinputcomponent'].initialData.configuration) as key (key)} @@ -104,11 +119,11 @@ {#if inputType === 'date'} { + onkeydown={(e) => { e.stopPropagation() }} - on:focus={() => ($selectedComponent = [id])} - on:pointerdown|stopPropagation + onfocus={() => ($selectedComponent = [id])} + onpointerdown={stopPropagation(bubble('pointerdown'))} type="date" bind:value disabled={resolvedConfig.disabled} diff --git a/frontend/src/lib/components/apps/components/inputs/AppDateSelect.svelte b/frontend/src/lib/components/apps/components/inputs/AppDateSelect.svelte index 74b6830e9d..d9a5c0697a 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppDateSelect.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppDateSelect.svelte @@ -1,5 +1,5 @@ {#each Object.keys(components['dateselectcomponent'].initialData.configuration) as key (key)} diff --git a/frontend/src/lib/components/apps/components/inputs/AppDateSliderInput.svelte b/frontend/src/lib/components/apps/components/inputs/AppDateSliderInput.svelte index 4e998ed739..42e9383ac3 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppDateSliderInput.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppDateSliderInput.svelte @@ -1,6 +1,8 @@ {#each Object.keys(components['dateslidercomponent'].initialData.configuration) as key (key)} @@ -169,7 +186,7 @@ resolvedConfig?.vertical ? 'h-full' : 'w-full' )} style={css?.bar?.style} - on:pointerdown|stopPropagation={() => ($selectedComponent = [id])} + onpointerdown={stopPropagation(() => ($selectedComponent = [id]))} > - import { getContext, onDestroy } from 'svelte' + import { getContext, onDestroy, untrack } from 'svelte' import { initConfig, initOutput } from '../../editor/appUtils' import type { AppViewerContext, @@ -19,22 +19,33 @@ import { twMerge } from 'tailwind-merge' import { parseISO, format as formatDateFns } from 'date-fns' - export let id: string - export let configuration: RichConfigurations - export let inputType: 'date' - export let verticalAlignment: VerticalAlignment | undefined = undefined - export let customCss: ComponentCustomCSS<'datetimeinputcomponent'> | undefined = undefined - export let render: boolean - export let onChange: string[] | undefined = undefined + interface Props { + id: string + configuration: RichConfigurations + inputType: 'date' + verticalAlignment?: VerticalAlignment | undefined + customCss?: ComponentCustomCSS<'datetimeinputcomponent'> | undefined + render: boolean + onChange?: string[] | undefined + } + + let { + id, + configuration, + inputType, + verticalAlignment = undefined, + customCss = undefined, + render, + onChange = undefined + }: Props = $props() const { app, worldStore, componentControl, selectedComponent, runnableComponents } = getContext('AppViewerContext') const iterContext = getContext('ListWrapperContext') const listInputs: ListInputs | undefined = getContext('ListInputs') - let resolvedConfig = initConfig( - components['datetimeinputcomponent'].initialData.configuration, - configuration + let resolvedConfig = $state( + initConfig(components['datetimeinputcomponent'].initialData.configuration, configuration) ) let outputs = initOutput($worldStore, id, { @@ -43,8 +54,9 @@ }) let initValue = outputs?.result.peak() - let value: string | undefined = + let value: string | undefined = $state( !iterContext && initValue != undefined ? initValue : resolvedConfig.defaultValue + ) $componentControl[id] = { setValue(nvalue: string) { @@ -59,8 +71,6 @@ let initialHandleDefault = true - $: handleDefault(resolvedConfig.defaultValue) - function formatDate(dateString: string, formatString: string = 'dd.MM.yyyy HH:mm') { if (formatString === '') { formatString = 'dd.MM.yyyy HH:mm' @@ -74,7 +84,28 @@ } } - $: { + function fireOnChange() { + if (onChange) { + onChange.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb())) + } + } + + function handleDefault(defaultValue: string | undefined) { + if (initialHandleDefault) { + initialHandleDefault = false + if (value != undefined) { + return + } + } + value = defaultValue + } + + let css = $state(initCss($app.css?.datetimeinputcomponent, customCss)) + $effect.pre(() => { + ;[resolvedConfig.defaultValue] + untrack(() => handleDefault(resolvedConfig.defaultValue)) + }) + $effect.pre(() => { if (value) { const r = formatDate(value, resolvedConfig.outputFormat) outputs?.result.set(r) @@ -120,25 +151,7 @@ } } fireOnChange() - } - - function fireOnChange() { - if (onChange) { - onChange.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb())) - } - } - - function handleDefault(defaultValue: string | undefined) { - if (initialHandleDefault) { - initialHandleDefault = false - if (value != undefined) { - return - } - } - value = defaultValue - } - - let css = initCss($app.css?.datetimeinputcomponent, customCss) + }) {#each Object.keys(components['datetimeinputcomponent'].initialData.configuration) as key (key)} diff --git a/frontend/src/lib/components/apps/components/inputs/AppFileInput.svelte b/frontend/src/lib/components/apps/components/inputs/AppFileInput.svelte index fa8e956709..8ef0460482 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppFileInput.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppFileInput.svelte @@ -1,5 +1,5 @@ {#each Object.keys(css ?? {}) as key (key)} diff --git a/frontend/src/lib/components/apps/components/inputs/AppMultiSelect.svelte b/frontend/src/lib/components/apps/components/inputs/AppMultiSelect.svelte index 800d00fde3..a34ce71f7a 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppMultiSelect.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppMultiSelect.svelte @@ -2,9 +2,13 @@ import AlignWrapper from '../helpers/AlignWrapper.svelte' import InitializeComponent from '../helpers/InitializeComponent.svelte' - export let id: string - export let render: boolean - export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined + interface Props { + id: string + render: boolean + verticalAlignment?: 'top' | 'center' | 'bottom' | undefined + } + + let { id, render, verticalAlignment = undefined }: Props = $props() diff --git a/frontend/src/lib/components/apps/components/inputs/AppNumberInput.svelte b/frontend/src/lib/components/apps/components/inputs/AppNumberInput.svelte index 0022fa0885..da95b05e30 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppNumberInput.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppNumberInput.svelte @@ -1,5 +1,7 @@ {#each Object.keys(components['numberinputcomponent'].initialData.configuration) as key (key)} @@ -106,8 +123,8 @@ ($selectedComponent = [id])} - on:focus={() => ($selectedComponent = [id])} + onpointerdown={stopPropagation(() => ($selectedComponent = [id]))} + onfocus={() => ($selectedComponent = [id])} class={twMerge( 'windmillapp w-full py-1.5 px-2 text-sm app-editor-input', css?.input?.class ?? '', diff --git a/frontend/src/lib/components/apps/components/inputs/AppQuillEditor.svelte b/frontend/src/lib/components/apps/components/inputs/AppQuillEditor.svelte index c9e8f57ef4..6e3f0f5789 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppQuillEditor.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppQuillEditor.svelte @@ -1,43 +1,45 @@ @@ -90,11 +104,11 @@ {#if render}
{ + onpointerdown={stopPropagation(() => { if (!$connectingInput.opened) { $selectedComponent = [id] } - }} + })} >
diff --git a/frontend/src/lib/components/apps/components/inputs/AppRangeInput.svelte b/frontend/src/lib/components/apps/components/inputs/AppRangeInput.svelte index 9177b9ae8b..1a0eee5338 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppRangeInput.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppRangeInput.svelte @@ -1,5 +1,8 @@ {#each Object.keys(components['rangecomponent'].initialData.configuration) as key (key)} @@ -108,7 +123,7 @@ class={twMerge('grow', 'wm-slider-bar')} style="--range-handle-focus: {'#7e9abd'}; --range-handle: {'#7e9abd'}; {css?.bar?.style ?? ''}" - on:pointerdown|stopPropagation + onpointerdown={stopPropagation(bubble('pointerdown'))} > | undefined = undefined - export let render: boolean - export let extraKey: string | undefined = undefined - export let onFileChange: string[] | undefined = undefined + interface Props { + id: string + configuration: RichConfigurations + customCss?: ComponentCustomCSS<'s3fileinputcomponent'> | undefined + render: boolean + extraKey?: string | undefined + onFileChange?: string[] | undefined + } - let resolvedConfig = initConfig( - components['s3fileinputcomponent'].initialData.configuration, - configuration + let { + id, + configuration, + customCss = undefined, + render, + extraKey = undefined, + onFileChange = undefined + }: Props = $props() + + let resolvedConfig = $state( + initConfig(components['s3fileinputcomponent'].initialData.configuration, configuration) ) let fileUploads: Writable = writable([]) @@ -38,16 +48,16 @@ } } - let value: { path: string; filename: string }[] | undefined = undefined + let value: { path: string; filename: string }[] | undefined = $state(undefined) const outputs = initOutput($worldStore, id, { result: value ?? ([] as { path: string; filename: string }[] | undefined), loading: false, jobId: undefined }) - $: resolvedConfigS3 = resolvedConfig.type.configuration.s3 + let resolvedConfigS3 = $derived(resolvedConfig.type.configuration.s3) - let css = initCss($app.css?.fileinputcomponent, customCss) + let css = $state(initCss($app.css?.fileinputcomponent, customCss)) /* {#if resolvedConfig.displayDirectLink && fileUpload.progress === 100} diff --git a/frontend/src/lib/components/apps/components/inputs/AppSliderInputs.svelte b/frontend/src/lib/components/apps/components/inputs/AppSliderInputs.svelte index 7d4adaa877..34432bc926 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppSliderInputs.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppSliderInputs.svelte @@ -1,6 +1,8 @@ {#each Object.keys(components['slidercomponent'].initialData.configuration) as key (key)} @@ -138,7 +156,7 @@ )} style="--range-handle-focus: {'#7e9abd'}; --range-handle: {'#7e9abd'}; {css?.bar?.style ?? ''}" - on:pointerdown|stopPropagation={() => ($selectedComponent = [id])} + onpointerdown={stopPropagation(() => ($selectedComponent = [id]))} > - import { getContext, onDestroy } from 'svelte' + import { stopPropagation, createBubbler } from 'svelte/legacy' + + const bubble = createBubbler() + import { getContext, onDestroy, untrack } from 'svelte' import { twMerge } from 'tailwind-merge' import { initConfig, initOutput, selectId } from '../../editor/appUtils' import type { @@ -17,18 +20,31 @@ import ResolveStyle from '../helpers/ResolveStyle.svelte' import { loadIcon } from '../icon' - export let id: string - export let configuration: RichConfigurations - export let inputType = 'text' - export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined - export let customCss: ComponentCustomCSS<'textinputcomponent'> | undefined = undefined - export let appCssKey: - | 'textinputcomponent' - | 'passwordinputcomponent' - | 'emailinputcomponent' - | 'textareainputcomponent' = 'textinputcomponent' - export let render: boolean - export let onChange: string[] | undefined = undefined + interface Props { + id: string + configuration: RichConfigurations + inputType?: string + verticalAlignment?: 'top' | 'center' | 'bottom' | undefined + customCss?: ComponentCustomCSS<'textinputcomponent'> | undefined + appCssKey?: + | 'textinputcomponent' + | 'passwordinputcomponent' + | 'emailinputcomponent' + | 'textareainputcomponent' + render: boolean + onChange?: string[] | undefined + } + + let { + id, + configuration, + inputType = 'text', + verticalAlignment = undefined, + customCss = undefined, + appCssKey = 'textinputcomponent', + render, + onChange = undefined + }: Props = $props() const { app, @@ -39,9 +55,8 @@ runnableComponents } = getContext('AppViewerContext') - let resolvedConfig = initConfig( - components['textinputcomponent'].initialData.configuration, - configuration + let resolvedConfig = $state( + initConfig(components['textinputcomponent'].initialData.configuration, configuration) ) const iterContext = getContext('ListWrapperContext') @@ -52,8 +67,9 @@ }) let initValue = outputs?.result.peak() - let value: string | undefined = + let value: string | undefined = $state( !iterContext && initValue && initValue != '' ? initValue : resolvedConfig.defaultValue + ) onDestroy(() => { listInputs?.remove(id) @@ -67,9 +83,6 @@ } let initialHandleDefault = true - $: handleDefault(resolvedConfig.defaultValue) - - $: value, onValueChange() function onValueChange() { let val = value ?? '' @@ -96,21 +109,10 @@ value = defaultValue } - let css = initCss($app.css?.[appCssKey], customCss) + let css = $state(initCss($app.css?.[appCssKey], customCss)) - $: classInput = twMerge( - 'windmillapp w-full py-1.5 px-2 text-sm', - 'app-editor-input', - css?.input?.class ?? '', - 'wm-input', - 'wm-text-input' - ) - - let beforeIconComponent: any - let afterIconComponent: any - - $: resolvedConfig.beforeIcon && beforeIconComponent && handleBeforeIcon() - $: resolvedConfig.afterIcon && afterIconComponent && handleAfterIcon() + let beforeIconComponent: any = $state() + let afterIconComponent: any = $state() async function handleBeforeIcon() { if (resolvedConfig.beforeIcon) { @@ -135,6 +137,29 @@ ) } } + $effect.pre(() => { + resolvedConfig.defaultValue + untrack(() => handleDefault(resolvedConfig.defaultValue)) + }) + $effect.pre(() => { + value + untrack(() => onValueChange()) + }) + let classInput = $derived( + twMerge( + 'windmillapp w-full py-1.5 px-2 text-sm', + 'app-editor-input', + css?.input?.class ?? '', + 'wm-input', + 'wm-text-input' + ) + ) + $effect.pre(() => { + resolvedConfig.beforeIcon && beforeIconComponent && untrack(() => handleBeforeIcon()) + }) + $effect.pre(() => { + resolvedConfig.afterIcon && afterIconComponent && untrack(() => handleAfterIcon()) + }) {#each Object.keys(components['textinputcomponent'].initialData.configuration) as key (key)} @@ -169,9 +194,11 @@ 'h-full' )} style="resize:none; {css?.input?.style ?? ''}" - on:pointerdown|stopPropagation={(e) => - !$connectingInput.opened && selectId(e, id, selectedComponent, $app)} - on:keydown|stopPropagation + onpointerdown={(e) => { + e.stopPropagation() + !$connectingInput.opened && selectId(e, id, selectedComponent, $app) + }} + onkeydown={stopPropagation(bubble('keydown'))} bind:value placeholder={resolvedConfig.placeholder} disabled={resolvedConfig.disabled} @@ -195,9 +222,11 @@ resolvedConfig.afterIcon ? '!pr-8' : '' )} style={css?.input?.style ?? ''} - on:pointerdown|stopPropagation={(e) => - !$connectingInput.opened && selectId(e, id, selectedComponent, $app)} - on:keydown|stopPropagation + onpointerdown={(e) => { + e.stopPropagation() + !$connectingInput.opened && selectId(e, id, selectedComponent, $app) + }} + onkeydown={stopPropagation(bubble('keydown'))} type="password" autocomplete="new-password" bind:value @@ -212,9 +241,11 @@ resolvedConfig.afterIcon ? '!pr-8' : '' )} style={css?.input?.style ?? ''} - on:pointerdown|stopPropagation={(e) => - !$connectingInput.opened && selectId(e, id, selectedComponent, $app)} - on:keydown|stopPropagation + onpointerdown={(e) => { + e.stopPropagation() + !$connectingInput.opened && selectId(e, id, selectedComponent, $app) + }} + onkeydown={stopPropagation(bubble('keydown'))} type="text" bind:value placeholder={resolvedConfig.placeholder} @@ -228,9 +259,11 @@ resolvedConfig.afterIcon ? '!pr-8' : '' )} style={css?.input?.style ?? ''} - on:pointerdown|stopPropagation={(e) => - !$connectingInput.opened && selectId(e, id, selectedComponent, $app)} - on:keydown|stopPropagation + onpointerdown={(e) => { + e.stopPropagation() + !$connectingInput.opened && selectId(e, id, selectedComponent, $app) + }} + onkeydown={stopPropagation(bubble('keydown'))} type="email" bind:value placeholder={resolvedConfig.placeholder} diff --git a/frontend/src/lib/components/apps/components/inputs/AppTimeInput.svelte b/frontend/src/lib/components/apps/components/inputs/AppTimeInput.svelte index cfee4a193c..e8b734dff9 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppTimeInput.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppTimeInput.svelte @@ -1,5 +1,7 @@ {#each Object.keys(components['timeinputcomponent'].initialData.configuration) as key (key)} @@ -117,8 +130,8 @@ ($selectedComponent = [id])} - on:pointerdown|stopPropagation={() => ($selectedComponent = [id])} + onfocus={() => ($selectedComponent = [id])} + onpointerdown={stopPropagation(() => ($selectedComponent = [id]))} type="time" bind:value min={resolvedConfig.minTime} diff --git a/frontend/src/lib/components/apps/components/inputs/currency/AppCurrencyInput.svelte b/frontend/src/lib/components/apps/components/inputs/currency/AppCurrencyInput.svelte index 4448cfa4d3..8241312078 100644 --- a/frontend/src/lib/components/apps/components/inputs/currency/AppCurrencyInput.svelte +++ b/frontend/src/lib/components/apps/components/inputs/currency/AppCurrencyInput.svelte @@ -1,6 +1,8 @@ {#each Object.keys(components['currencycomponent'].initialData.configuration) as key (key)} @@ -104,7 +119,7 @@ {#key resolvedConfig.isNegativeAllowed} {#key resolvedConfig.locale} {#key resolvedConfig.currency} -
($selectedComponent = [id])}> +
($selectedComponent = [id]))}> import DarkModeObserver from '$lib/components/DarkModeObserver.svelte' + import { untrack } from 'svelte' /* Forked from MIT LICENSE https://raw.githubusercontent.com/Canutin/svelte-currency-input/main/src/lib/CurrencyInput.svelte @@ -27,18 +28,35 @@ formattedZero?: string } - export let value: number = DEFAULT_VALUE - export let locale: string = DEFAULT_LOCALE - export let currency: string = DEFAULT_CURRENCY - export let name: string = DEFAULT_NAME - export let required: boolean = false - export let disabled: boolean = false - export let placeholder: number | null = DEFAULT_VALUE - export let isNegativeAllowed: boolean = true - export let fractionDigits: number = DEFAULT_FRACTION_DIGITS - export let inputClasses: InputClasses | null = null - export let noColor: boolean = false - export let style: string = '' + interface Props { + value?: number + locale?: string + currency?: string + name?: string + required?: boolean + disabled?: boolean + placeholder?: number | null + isNegativeAllowed?: boolean + fractionDigits?: number + inputClasses?: InputClasses | null + noColor?: boolean + style?: string + } + + let { + value = $bindable(DEFAULT_VALUE), + locale = DEFAULT_LOCALE, + currency = DEFAULT_CURRENCY, + name = DEFAULT_NAME, + required = false, + disabled = false, + placeholder = DEFAULT_VALUE, + isNegativeAllowed = true, + fractionDigits = DEFAULT_FRACTION_DIGITS, + inputClasses = null, + noColor = false, + style = '' + }: Props = $props() // Formats value as: e.g. $1,523.00 | -$1,523.00 const formatCurrency = ( @@ -158,14 +176,19 @@ }, 0.1) } - let formattedValue = '' + let formattedValue = $state('') let formattedPlaceholder = placeholder !== null ? formatCurrency(placeholder, fractionDigits, fractionDigits) : '' - $: isZero = value === 0 - $: isNegative = value < 0 - $: value, setFormattedValue() + let isZero = $derived(value === 0) + let isNegative = $derived(value < 0) + $effect(() => { + value + untrack(() => { + setFormattedValue() + }) + }) - let darkMode: boolean = false + let darkMode: boolean = $state(false) @@ -182,11 +205,11 @@ class=" {inputClasses?.formatted ?? DEFAULT_CLASS_FORMATTED} {isNegativeAllowed && !isZero && !isNegative - ? inputClasses?.formattedPositive ?? DEFAULT_CLASS_FORMATTED_POSITIVE + ? (inputClasses?.formattedPositive ?? DEFAULT_CLASS_FORMATTED_POSITIVE) : ''} - {isZero ? inputClasses?.formattedZero ?? DEFAULT_CLASS_FORMATTED_ZERO : ''} + {isZero ? (inputClasses?.formattedZero ?? DEFAULT_CLASS_FORMATTED_ZERO) : ''} {isNegativeAllowed && isNegative - ? inputClasses?.formattedNegative ?? DEFAULT_CLASS_FORMATTED_NEGATIVE + ? (inputClasses?.formattedNegative ?? DEFAULT_CLASS_FORMATTED_NEGATIVE) : ''} " style={style ? style : noColor ? (darkMode ? 'color: white;' : 'color: black;') : ''} @@ -197,8 +220,8 @@ placeholder={formattedPlaceholder} {disabled} bind:value={formattedValue} - on:keydown={handleKeyDown} - on:keyup={setUnformattedValue} + onkeydown={handleKeyDown} + onkeyup={setUnformattedValue} />
diff --git a/frontend/src/lib/components/apps/components/layout/AppDivider.svelte b/frontend/src/lib/components/apps/components/layout/AppDivider.svelte index ac218f3086..97a698dd60 100644 --- a/frontend/src/lib/components/apps/components/layout/AppDivider.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppDivider.svelte @@ -15,21 +15,33 @@ import InitializeComponent from '../helpers/InitializeComponent.svelte' import ResolveStyle from '../helpers/ResolveStyle.svelte' - export let id: string - export let configuration: RichConfigurations - export let horizontalAlignment: HorizontalAlignment | undefined = undefined - export let verticalAlignment: VerticalAlignment | undefined = undefined - export let customCss: - | ComponentCustomCSS<'verticaldividercomponent' | 'horizontaldividercomponent'> - | undefined = undefined - export let position: 'horizontal' | 'vertical' - export let render: boolean + interface Props { + id: string + configuration: RichConfigurations + horizontalAlignment?: HorizontalAlignment | undefined + verticalAlignment?: VerticalAlignment | undefined + customCss?: + | ComponentCustomCSS<'verticaldividercomponent' | 'horizontaldividercomponent'> + | undefined + position: 'horizontal' | 'vertical' + render: boolean + } + + let { + id, + configuration, + horizontalAlignment = undefined, + verticalAlignment = undefined, + customCss = undefined, + position, + render + }: Props = $props() const { app, worldStore } = getContext('AppViewerContext') - let size = 2 - let color = '#00000060' + let size = $state(2) + let color = $state('#00000060') - let css = initCss($app.css?.[position + 'dividercomponent'], customCss) + let css = $state(initCss($app.css?.[position + 'dividercomponent'], customCss)) //used so that we can count number of outputs setup for first refresh initOutput($worldStore, id, {}) diff --git a/frontend/src/lib/components/apps/components/layout/ListWrapper.svelte b/frontend/src/lib/components/apps/components/layout/ListWrapper.svelte index 0b6c6328d6..992bcd6952 100644 --- a/frontend/src/lib/components/apps/components/layout/ListWrapper.svelte +++ b/frontend/src/lib/components/apps/components/layout/ListWrapper.svelte @@ -3,14 +3,28 @@ import type { ListInputs, ListContext } from '../../types' import { writable } from 'svelte/store' - export let index: number - export let value: any - export let disabled = false - export let onSet: ((id: string, value: any) => void) | undefined = undefined - export let onRemove: ((id: string) => void) | undefined = undefined + interface Props { + index: number + value: any + disabled?: boolean + onSet?: ((id: string, value: any) => void) | undefined + onRemove?: ((id: string) => void) | undefined + children?: import('svelte').Snippet + } + + let { + index, + value, + disabled = false, + onSet = undefined, + onRemove = undefined, + children + }: Props = $props() const ctx = writable({ index, value, disabled }) - $: $ctx = { index, value, disabled } + $effect(() => { + $ctx = { index, value, disabled } + }) setContext('ListWrapperContext', ctx) setContext('ListInputs', { set: (id: string, value: any) => { @@ -22,4 +36,4 @@ }) - +{@render children?.()} diff --git a/frontend/src/lib/components/apps/components/layout/RowWrapper.svelte b/frontend/src/lib/components/apps/components/layout/RowWrapper.svelte index 105bce92c2..dd588b26e1 100644 --- a/frontend/src/lib/components/apps/components/layout/RowWrapper.svelte +++ b/frontend/src/lib/components/apps/components/layout/RowWrapper.svelte @@ -3,15 +3,22 @@ import type { ListInputs, ListContext } from '../../types' import { writable } from 'svelte/store' - export let index: number - export let value: any - export let disabled = false - export let onSet: (id: string, value: any) => void - export let onRemove: (id: string) => void + interface Props { + index: number + value: any + disabled?: boolean + onSet: (id: string, value: any) => void + onRemove: (id: string) => void + children?: import('svelte').Snippet + } + + let { index, value, disabled = false, onSet, onRemove, children }: Props = $props() const ctx = writable({ index, value, disabled }) - $: $ctx = { index, value, disabled } + $effect(() => { + $ctx = { index, value, disabled } + }) setContext('RowWrapperContext', ctx) setContext('RowInputs', { @@ -24,4 +31,4 @@ }) - +{@render children?.()} diff --git a/frontend/src/lib/components/apps/editor/AppComponentInput.svelte b/frontend/src/lib/components/apps/editor/AppComponentInput.svelte index daa81d2f0d..4d1487f737 100644 --- a/frontend/src/lib/components/apps/editor/AppComponentInput.svelte +++ b/frontend/src/lib/components/apps/editor/AppComponentInput.svelte @@ -2,8 +2,12 @@ import { components, type AppComponent } from './component' import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte' - export let component: AppComponent - export let resourceOnly = false + interface Props { + component: AppComponent + resourceOnly?: boolean + } + + let { component = $bindable(), resourceOnly = false }: Props = $props() {#if component?.componentInput?.type === 'runnable' && Object.keys(component?.componentInput?.fields ?? {}).length > 0} diff --git a/frontend/src/lib/components/apps/editor/AppDeploymentHistory.svelte b/frontend/src/lib/components/apps/editor/AppDeploymentHistory.svelte index a712b69087..6e73f97c19 100644 --- a/frontend/src/lib/components/apps/editor/AppDeploymentHistory.svelte +++ b/frontend/src/lib/components/apps/editor/AppDeploymentHistory.svelte @@ -5,8 +5,12 @@ import { sendUserToast } from '$lib/toast' import DeploymentHistory from './DeploymentHistory.svelte' - export let appPath: string | undefined = undefined - let historyBrowserDrawerOpen = false + interface Props { + appPath?: string | undefined + } + + let { appPath = undefined }: Props = $props() + let historyBrowserDrawerOpen = $state(false) export function open() { historyBrowserDrawerOpen = true diff --git a/frontend/src/lib/components/apps/editor/AppEditorBottomPanel.svelte b/frontend/src/lib/components/apps/editor/AppEditorBottomPanel.svelte index 5839a3e9be..890299f163 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorBottomPanel.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorBottomPanel.svelte @@ -1,15 +1,26 @@ {#if rightPanelSize !== 0} - -
+ +
diff --git a/frontend/src/lib/components/apps/editor/AppJobsDrawer.svelte b/frontend/src/lib/components/apps/editor/AppJobsDrawer.svelte index 9f6bdb8d19..e6a3965693 100644 --- a/frontend/src/lib/components/apps/editor/AppJobsDrawer.svelte +++ b/frontend/src/lib/components/apps/editor/AppJobsDrawer.svelte @@ -20,30 +20,47 @@ import TestJobLoader from '$lib/components/TestJobLoader.svelte' import type { Job } from '$lib/gen' import type { JobById } from '../types' - import { createEventDispatcher } from 'svelte' + import { createEventDispatcher, untrack } from 'svelte' - export let open = false - export let jobs: string[] - export let jobsById: Record + interface Props { + open?: boolean + jobs: string[] + jobsById: Record + hasErrors?: boolean + selectedJobId?: string | undefined + refreshComponents?: (() => void) | undefined + errorByComponent?: Record + } - export let hasErrors: boolean = false - export let selectedJobId: string | undefined = undefined - export let refreshComponents: (() => void) | undefined = undefined - export let errorByComponent: Record = {} + let { + open = $bindable(false), + jobs, + jobsById, + hasErrors = false, + selectedJobId = $bindable(undefined), + refreshComponents = undefined, + errorByComponent = {} + }: Props = $props() const dispatch = createEventDispatcher() - let testJobLoader: TestJobLoader - let job: Job | undefined = undefined - let testIsLoading = false + let testJobLoader: TestJobLoader | undefined = $state() + let job: Job | undefined = $state(undefined) + let testIsLoading = $state(false) - let rightColumnSelect: 'timeline' | 'detail' = 'timeline' + let rightColumnSelect: 'timeline' | 'detail' = $state('timeline') - $: selectedJobId && !selectedJobId?.includes('Frontend') && testJobLoader?.watchJob(selectedJobId) + $effect(() => { + selectedJobId && + !selectedJobId?.includes('Frontend') && + untrack(() => selectedJobId && testJobLoader?.watchJob(selectedJobId)) + }) - $: if (selectedJobId?.includes('Frontend') && selectedJobId) { - job = undefined - } + $effect(() => { + if (selectedJobId?.includes('Frontend') && selectedJobId) { + job = undefined + } + }) @@ -67,8 +84,8 @@ {#each jobs ?? [] as id} {@const selectedJob = jobsById[id]} {#if selectedJob} - - + +
{ + onclick={() => { selectedJobId = id rightColumnSelect = 'detail' }} diff --git a/frontend/src/lib/components/apps/editor/AppReportsDrawer.svelte b/frontend/src/lib/components/apps/editor/AppReportsDrawer.svelte index ddea337c63..1038afcf5c 100644 --- a/frontend/src/lib/components/apps/editor/AppReportsDrawer.svelte +++ b/frontend/src/lib/components/apps/editor/AppReportsDrawer.svelte @@ -2,8 +2,12 @@ import { Drawer } from '$lib/components/common' import AppReportsDrawerInner from './AppReportsDrawerInner.svelte' - export let appPath: string - export let open = false + interface Props { + appPath: string + open?: boolean + } + + let { appPath, open = $bindable(false) }: Props = $props() diff --git a/frontend/src/lib/components/apps/editor/AppTimeline.svelte b/frontend/src/lib/components/apps/editor/AppTimeline.svelte index db06d7b104..b3b7540ed2 100644 --- a/frontend/src/lib/components/apps/editor/AppTimeline.svelte +++ b/frontend/src/lib/components/apps/editor/AppTimeline.svelte @@ -1,24 +1,30 @@ {#if connecting} - - + +
- + {#snippet trigger()}
- - + {/snippet} + {#snippet content()} connectOutput(connectingInput, component.type, component.id, detail)} componentId={component.id} /> - + {/snippet}
{/if} {#if selected || hover} - - + +
{ + onmouseover={stopPropagation(() => { hoverHeader = true dispatch('mouseover') - }} - on:mouseleave|stopPropagation={() => { + })} + onmouseleave={stopPropagation(() => { hoverHeader = false - }} - on:mousedown|stopPropagation|capture + })} + onmousedowncapture={stopPropagation(bubble('mousedown'))} draggable="false" title={`Id: ${component.id}`} class={twMerge( @@ -144,8 +163,8 @@ ? 'bg-blue-300 text-blue-800' : 'text-white hover:bg-blue-400 hover:text-white' )} - on:click={() => dispatch('fillHeight')} - on:pointerdown|stopPropagation + onclick={() => dispatch('fillHeight')} + onpointerdown={stopPropagation(bubble('pointerdown'))} > @@ -156,8 +175,8 @@ 'px-1 py-0.5 text-2xs font-bold rounded cursor-pointer w-fit h-full', locked ? 'bg-blue-300 text-blue-800' : 'text-white hover:bg-blue-400 hover:text-white' )} - on:click={() => dispatch('lock')} - on:pointerdown|stopPropagation + onclick={() => dispatch('lock')} + onpointerdown={stopPropagation(bubble('pointerdown'))} > {#if locked} @@ -171,8 +190,8 @@ class={twMerge( 'px-1 py-0.5 text-2xs font-bold rounded cursor-pointer w-fit h-full text-white hover:bg-blue-400 hover:text-white' )} - on:click={() => dispatch('expand')} - on:pointerdown|stopPropagation + onclick={() => dispatch('expand')} + onpointerdown={stopPropagation(bubble('pointerdown'))} > @@ -198,8 +217,8 @@ ? 'bg-blue-300 text-blue-800' : 'text-blue-600 hover:bg-blue-300 hover:text-blue-800' )} - on:click={() => dispatch('triggerInlineEditor')} - on:pointerdown|stopPropagation + onclick={() => dispatch('triggerInlineEditor')} + onpointerdown={stopPropagation(bubble('pointerdown'))} > @@ -228,13 +247,13 @@ ? 'text-red-600 hover:bg-red-300 hover:text-red-800' : 'text-blue-600 hover:bg-blue-300 hover:text-blue-800' )} - on:click={() => { + onclick={() => { const element = document.getElementById(`decision-tree-graph-editor`) if (element) { element.click() } }} - on:pointerdown|stopPropagation + onpointerdown={stopPropagation(bubble('pointerdown'))} > @@ -264,7 +283,7 @@ {/if} --> - +
{/if}
@@ -279,14 +298,14 @@ )} > - + {#snippet trigger()} - - + {/snippet} + {#snippet content()}
{error ?? ''}	
-						
+
-
+ {/snippet}
{/if} diff --git a/frontend/src/lib/components/apps/editor/DeploymentHistory.svelte b/frontend/src/lib/components/apps/editor/DeploymentHistory.svelte index 6067e6b739..73113984fa 100644 --- a/frontend/src/lib/components/apps/editor/DeploymentHistory.svelte +++ b/frontend/src/lib/components/apps/editor/DeploymentHistory.svelte @@ -1,4 +1,7 @@ @@ -75,14 +86,14 @@ {#if versions.length > 0}
{#each versions ?? [] as version} - - + +
{ + onclick={() => { selectedVersion = version deploymentMsgUpdateMode = false deploymentMsgUpdate = undefined @@ -115,10 +126,11 @@ type="text" bind:value={deploymentMsgUpdate} class="!w-auto grow" - on:click|stopPropagation={() => {}} - on:keydown|stopPropagation - on:keypress|stopPropagation={({ key }) => { - if (key === 'Enter') + onclick={stopPropagation(() => {})} + onkeydown={stopPropagation(bubble('keydown'))} + onkeypress={(e) => { + e.stopPropagation() + if (e.key === 'Enter') updateDeploymentMsg(selected?.id, selectedVersion?.version) }} /> @@ -155,7 +167,7 @@ Deployed {displayDate(selected.created_at)} by {selected.created_by} {/if}
{/each} diff --git a/frontend/src/lib/components/apps/editor/RunnableJobPanel.svelte b/frontend/src/lib/components/apps/editor/RunnableJobPanel.svelte index f5e905f0c8..3746a94f39 100644 --- a/frontend/src/lib/components/apps/editor/RunnableJobPanel.svelte +++ b/frontend/src/lib/components/apps/editor/RunnableJobPanel.svelte @@ -1,26 +1,31 @@ {#if ($runnableJobEditorPanel.focused && $selectedComponentInEditor) || logDrawerOpen || resultDrawerOpen || !float} {@const frontendJob = $runnableJobEditorPanel?.frontendJobs[$selectedComponentInEditor ?? '']} - + {#if float}
diff --git a/frontend/src/lib/components/apps/editor/SettingsPanel.svelte b/frontend/src/lib/components/apps/editor/SettingsPanel.svelte index a76f3a2272..50df37150d 100644 --- a/frontend/src/lib/components/apps/editor/SettingsPanel.svelte +++ b/frontend/src/lib/components/apps/editor/SettingsPanel.svelte @@ -109,58 +109,37 @@ {#if gridItemWithLocation} - {#key gridItemWithLocation.item.id} - gridItemWithLocation, - (cs) => { - if (gridItemWithLocation?.location.type === 'grid') { - $app.grid[gridItemWithLocation.location.gridItemIndex] = cs.item - } else if ( - gridItemWithLocation?.location.type === 'subgrid' && - Array.isArray($app.subgrids?.[gridItemWithLocation.location.subgridKey]) - ) { - if ( - $app.subgrids[gridItemWithLocation.location.subgridKey][ - gridItemWithLocation.location.subgridItemIndex - ] - ) { - $app.subgrids[gridItemWithLocation.location.subgridKey][ - gridItemWithLocation.location.subgridItemIndex - ] = cs.item - } - } - } - } - onDelete={() => { - dispatch('delete') - }} - /> - {/key} + {#if gridItemWithLocation.location.type === 'grid'} + {#each $app.grid as gridItem, gridItemIndex} + {#if gridItem.data.id === gridItemWithLocation.item.id} + { + dispatch('delete') + }} + /> + {/if} + {/each} + {:else if gridItemWithLocation.location.type === 'subgrid' && $app.subgrids} + {#each $app.subgrids[gridItemWithLocation.location.subgridKey] as subgridItem, subgridItemIndex} + {#if subgridItem.data.id === gridItemWithLocation.item.id} + { + dispatch('delete') + }} + /> + {/if} + {/each} + {/if} {:else if tableActionSettings} {#key tableActionSettings?.item?.data?.id} tableActionSettings, - (cs) => { - if (tableActionSettings) { - if (tableActionSettings.gridItemLocation.type === 'grid') { - const { gridItemIndex } = tableActionSettings.gridItemLocation - const { key, index } = tableActionSettings.location - if ($app.grid[gridItemIndex]?.data?.[key]) { - $app.grid[gridItemIndex].data[key][index] = cs.item.data - } - } else if (tableActionSettings.gridItemLocation.type === 'subgrid') { - const { subgridKey, subgridItemIndex } = tableActionSettings.gridItemLocation - const { key, index } = tableActionSettings.location - if ($app.subgrids?.[subgridKey]?.[subgridItemIndex]?.data?.[key]) { - $app.subgrids[subgridKey][subgridItemIndex].data[key][index] = cs.item.data - } - } - } - } - } + bind:item={tableActionSettings.item} + parent={tableActionSettings.parent} duplicateMoveAllowed={false} onDelete={() => { if (tableActionSettings) { @@ -209,24 +188,8 @@ {#key menuItemsSettings?.item?.id} menuItemsSettings, - (cs) => { - if (menuItemsSettings) { - if (menuItemsSettings.gridItemLocation.type === 'grid') { - const { gridItemIndex } = menuItemsSettings.gridItemLocation - if ($app.grid[gridItemIndex]?.data?.type === 'menucomponent') { - $app.grid[gridItemIndex].data.menuItems[cs.index] = cs.item.data - } - } else if (menuItemsSettings.gridItemLocation.type === 'subgrid') { - const { subgridKey, subgridItemIndex } = menuItemsSettings.gridItemLocation - if ($app.subgrids?.[subgridKey]?.[subgridItemIndex]?.data?.type === 'menucomponent') { - $app.subgrids[subgridKey][subgridItemIndex].data.menuItems[cs.index] = cs.item.data - } - } - } - } - } + bind:item={menuItemsSettings.item} + parent={menuItemsSettings.parent} onDelete={() => { if (menuItemsSettings) { const item = findGridItemWithLocation($app, menuItemsSettings.parent) diff --git a/frontend/src/lib/components/apps/editor/SubGridEditor.svelte b/frontend/src/lib/components/apps/editor/SubGridEditor.svelte index d2d1ab7fcc..329bdd7cd3 100644 --- a/frontend/src/lib/components/apps/editor/SubGridEditor.svelte +++ b/frontend/src/lib/components/apps/editor/SubGridEditor.svelte @@ -268,7 +268,7 @@ }} disableMove={!!$connectingInput.opened} > - {#snippet children({ dataItem, overlapped, moveMode, componentDraggedId })} + {#snippet children({ dataItem, overlapped, componentDraggedId })} diff --git a/frontend/src/lib/components/apps/editor/appUtils.ts b/frontend/src/lib/components/apps/editor/appUtils.ts index fe0fc8e47b..c299e3341f 100644 --- a/frontend/src/lib/components/apps/editor/appUtils.ts +++ b/frontend/src/lib/components/apps/editor/appUtils.ts @@ -6,7 +6,8 @@ import type { EditorBreakpoint, FocusedGrid, GeneralAppInput, - GridItem + GridItem, + RichConfiguration } from '../types' import { ccomponents, @@ -38,14 +39,14 @@ import gridHelp from '../svelte-grid/utils/helper' type GridItemLocation = | { - type: 'grid' - gridItemIndex: number - } + type: 'grid' + gridItemIndex: number + } | { - type: 'subgrid' - subgridItemIndex: number - subgridKey: string - } + type: 'subgrid' + subgridItemIndex: number + subgridKey: string + } interface GridItemWithLocation { location: GridItemLocation item: GridItem @@ -186,7 +187,7 @@ export function selectId( selectedComponent: Writable, app: App ) { - ;(document?.activeElement as HTMLElement)?.blur() + ; (document?.activeElement as HTMLElement)?.blur() if (e.shiftKey) { selectedComponent.update((old) => { if (old && old?.[0]) { @@ -482,10 +483,67 @@ export function appComponentFromType( horizontalAlignment: override?.horizontalAlignment ?? init.horizontalAlignment, verticalAlignment: override?.verticalAlignment ?? init.verticalAlignment, id, + datasets: + type === 'plotlycomponentv2' + ? createPlotlyComponentDataset() + : type === 'chartjscomponentv2' + ? createChartjsComponentDataset() + : undefined, + xData: + type === 'plotlycomponentv2' || type === 'chartjscomponentv2' + ? { + type: 'evalv2', + fieldType: 'array', + expr: '[1, 2, 3, 4]', + connections: [] + } + : undefined, ...(extra ?? {}) } } } + +export function createChartjsComponentDataset(): RichConfiguration { + return { + type: 'static', + fieldType: 'array', + subFieldType: 'chartjs', + value: [ + { + value: { + type: 'static', + fieldType: 'array', + subFieldType: 'number', + value: [25, 25, 50] + }, + name: 'Dataset 1' + } + ] + } +} + +export function createPlotlyComponentDataset(): RichConfiguration { + return { + type: 'static', + fieldType: 'array', + subFieldType: 'plotly', + value: [ + { + value: { + type: 'static', + fieldType: 'array', + subFieldType: 'number', + value: [1, 2, 3, 4] + }, + name: 'Dataset 1', + aggregation_method: 'sum', + type: 'bar', + tooltip: '', + color: '#C8A2C8' + } + ] + } +} export function insertNewGridItem( app: App, builddata: (id: string) => AppComponent, @@ -845,33 +903,33 @@ export type InitConfig< | EvalAppInput | EvalV2AppInput | { - type: 'oneOf' - selected: string - configuration: Record< - string, - Record - > - } + type: 'oneOf' + selected: string + configuration: Record< + string, + Record + > + } > > = { - [Property in keyof T]: T[Property] extends StaticAppInput + [Property in keyof T]: T[Property] extends StaticAppInput ? T[Property]['value'] | undefined : T[Property] extends { type: 'oneOf' } - ? { - type: 'oneOf' - selected: keyof T[Property]['configuration'] - configuration: { - [Choice in keyof T[Property]['configuration']]: { - [IT in keyof T[Property]['configuration'][Choice]]: T[Property]['configuration'][Choice][IT] extends StaticAppInput - ? T[Property]['configuration'][Choice][IT] extends StaticAppInputOnDemand - ? () => Promise - : T[Property]['configuration'][Choice][IT]['value'] | undefined - : undefined - } - } + ? { + type: 'oneOf' + selected: keyof T[Property]['configuration'] + configuration: { + [Choice in keyof T[Property]['configuration']]: { + [IT in keyof T[Property]['configuration'][Choice]]: T[Property]['configuration'][Choice][IT] extends StaticAppInput + ? T[Property]['configuration'][Choice][IT] extends StaticAppInputOnDemand + ? () => Promise + : T[Property]['configuration'][Choice][IT]['value'] | undefined + : undefined } - : undefined -} + } + } + : undefined + } export function initConfig< T extends Record< @@ -880,13 +938,13 @@ export function initConfig< | EvalAppInput | EvalV2AppInput | { - type: 'oneOf' - selected: string - configuration: Record< - string, - Record - > - } + type: 'oneOf' + selected: string + configuration: Record< + string, + Record + > + } > >( r: T, @@ -894,13 +952,13 @@ export function initConfig< string, | StaticAppInput | { - type: 'oneOf' - selected: string - configuration: Record< - string, - Record - > - } + type: 'oneOf' + selected: string + configuration: Record< + string, + Record + > + } | any > ): InitConfig { @@ -910,31 +968,31 @@ export function initConfig< Object.entries(r).map(([key, value]) => value.type == 'static' ? [ - key, - configuration?.[key]?.type == 'static' ? configuration?.[key]?.['value'] : undefined - ] + key, + configuration?.[key]?.type == 'static' ? configuration?.[key]?.['value'] : undefined + ] : value.type == 'oneOf' ? [ - key, - { - selected: value.selected, - type: 'oneOf', - configuration: Object.fromEntries( - Object.entries(value.configuration).map(([choice, config]) => { - const conf = initConfig( - config, - configuration?.[key]?.configuration?.[choice] - ) - Object.entries(config).forEach(([innerKey, innerValue]) => { - if (innerValue.type === 'static' && !(innerKey in conf)) { - conf[innerKey] = innerValue.value - } - }) - return [choice, conf] + key, + { + selected: value.selected, + type: 'oneOf', + configuration: Object.fromEntries( + Object.entries(value.configuration).map(([choice, config]) => { + const conf = initConfig( + config, + configuration?.[key]?.configuration?.[choice] + ) + Object.entries(config).forEach(([innerKey, innerValue]) => { + if (innerValue.type === 'static' && !(innerKey in conf)) { + conf[innerKey] = innerValue.value + } }) - ) - } - ] + return [choice, conf] + }) + ) + } + ] : [key, undefined] ) ) as any diff --git a/frontend/src/lib/components/apps/editor/component/Component.svelte b/frontend/src/lib/components/apps/editor/component/Component.svelte index 129f1e2329..d6a9c5528d 100644 --- a/frontend/src/lib/components/apps/editor/component/Component.svelte +++ b/frontend/src/lib/components/apps/editor/component/Component.svelte @@ -5,19 +5,31 @@ import type { AppComponent } from './components' import type { AppViewerContext } from '../../types' - export let component: AppComponent - export let selected: boolean - export let locked: boolean = false - export let render: boolean - export let fullHeight: boolean - export let overlapped: string | undefined = undefined - export let componentDraggedId: string | undefined = undefined - const { app } = getContext('AppViewerContext') - export let moveMode: string | undefined = undefined - let everRender = render + interface Props { + component: AppComponent + selected: boolean + locked?: boolean + render: boolean + fullHeight: boolean + overlapped?: string | undefined + componentDraggedId?: string | undefined + } - $: render && !everRender && (everRender = true) + let { + component, + selected, + locked = false, + render, + fullHeight, + overlapped = undefined, + componentDraggedId = undefined + }: Props = $props() + let everRender = $state(render) + + $effect(() => { + render && !everRender && (everRender = true) + }) {#if everRender || $app.eagerRendering} @@ -25,7 +37,6 @@ on:expand on:lock on:fillHeight - {moveMode} {componentDraggedId} {overlapped} {render} diff --git a/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte b/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte index 61685201b0..8d84d2e609 100644 --- a/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte +++ b/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte @@ -94,7 +94,11 @@ }: Props = $props() - + { + console.error(e) + }} +> {#if component.type === 'displaycomponent'} {:else if component.type === 'agchartscomponentee'} @@ -228,8 +230,6 @@ customCss={component.customCss} bind:initializing componentInput={component.componentInput} - datasets={component.datasets} - xData={component.xData} license={component.license} ee={true} {render} diff --git a/frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte b/frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte index 52d9679ea0..3b113ad9bb 100644 --- a/frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte +++ b/frontend/src/lib/components/apps/editor/component/ComponentRendered.svelte @@ -1,9 +1,11 @@ - - - + +
{ + onmouseover={stopPropagation(() => { outTimeout && clearTimeout(outTimeout) if (component.id !== $hoverStore) { $hoverStore = component.id } - }} - on:mouseout|stopPropagation={mouseOut} + })} + onmouseout={stopPropagation(mouseOut)} class={twMerge( 'h-full flex flex-col w-full component relative', initializing ? 'overflow-hidden h-0' : '' @@ -110,7 +130,7 @@ data-connection-button > {#if render} - {#if locked && componentActive && $componentActive && moveMode === 'move' && componentDraggedId && componentDraggedId !== component.id && cachedAreOnTheSameSubgrid} + {#if locked && componentActive && $componentActive && $moveMode === 'move' && componentDraggedId && componentDraggedId !== component.id && cachedAreOnTheSameSubgrid}
@@ -119,7 +139,7 @@
Anchored: The component cannot be moved.
- {:else if moveMode === 'insert' && isContainer(component.type) && componentDraggedId && componentDraggedId !== component.id && cachedComponentDraggedIsNotChild} + {:else if $moveMode === 'insert' && isContainer(component.type) && componentDraggedId && componentDraggedId !== component.id && cachedComponentDraggedIsNotChild}
{#if initializing && render && showSkeleton} - - + +
{ + onmouseover={stopPropagation(() => { if (component.id !== $hoverStore) { $hoverStore = component.id } - }} - on:mouseout|stopPropagation={() => { + })} + onmouseout={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/editor/component/ComponentWrapper.svelte b/frontend/src/lib/components/apps/editor/component/ComponentWrapper.svelte index 900aeeee0f..036f0455c9 100644 --- a/frontend/src/lib/components/apps/editor/component/ComponentWrapper.svelte +++ b/frontend/src/lib/components/apps/editor/component/ComponentWrapper.svelte @@ -3,8 +3,14 @@ import type { AppViewerContext, ContextPanelContext } from '../../types' import { dfs, selectId } from '../appUtils' - export let id: string - export let type: string + interface Props { + id: string + type: string + class: string + children?: import('svelte').Snippet + } + + let { id, type, class: clazz, children }: Props = $props() const { app, connectingInput, selectedComponent } = getContext('AppViewerContext') @@ -40,34 +46,34 @@ } - - - + + +
{ + class={clazz} + onpointerover={(e) => { if ($connectingInput.opened && $connectingInput.hoveredComponent !== id) { $connectingInput.hoveredComponent = id } e.stopPropagation() }} - on:pointerleave={(e) => { + onpointerleave={(e) => { if ($connectingInput.opened) { $connectingInput.hoveredComponent = undefined e.stopPropagation() } }} - on:focus={(e) => { + onfocus={(e) => { if ($connectingInput.opened) { e.stopPropagation() } }} - on:pointerdown={onPointerDown} - on:click|capture={(event) => + onpointerdown={onPointerDown} + onclickcapture={(event) => preventInteraction(event, type === 'tabscomponent' || type === 'steppercomponent')} - on:drag|capture={preventInteraction} - on:pointerup|capture={(event) => + ondragcapture={preventInteraction} + onpointerupcapture={(event) => preventInteraction(event, type === 'tabscomponent' || type === 'steppercomponent')} > - + {@render children?.()}
diff --git a/frontend/src/lib/components/apps/editor/component/components.ts b/frontend/src/lib/components/apps/editor/component/components.ts index a5775fc09d..3513fab5ea 100644 --- a/frontend/src/lib/components/apps/editor/component/components.ts +++ b/frontend/src/lib/components/apps/editor/component/components.ts @@ -972,7 +972,27 @@ const agchartscomponentconst = { }, initialData: { configuration: {}, - componentInput: undefined + componentInput: { + type: 'evalv2', + noStatic: true, + fieldType: 'object', + expr: `({ + data: [ + { x: 1, y: 5 }, + { x: 2, y: 10 }, + { x: 3, y: 2 }, + { x: 4, y: 8 } + ], + series: [{ + type: 'bar', + xKey: 'x', + yKey: 'y', + fill: '#C8A2C8', + strokeWidth: 2.5 + }] + })`, + connections: [] as InputConnectionEval[] + } } } as const @@ -1628,8 +1648,8 @@ export const components = { backgroundColor: ['#FF6384', '#4BC0C0', '#FFCE56'] } ] - } - } + }, + }, } }, chartjscomponentv2: { @@ -1656,7 +1676,20 @@ export const components = { tooltip: 'ChartJs options object https://www.chartjs.org/docs/latest/general/options.html' } }, - componentInput: undefined + componentInput: { + type: 'static', + fieldType: 'object', + value: { + labels: ['Pie', 'Charts', '<3'], + datasets: [ + { + data: [25, 50, 25], + backgroundColor: ['#FF6384', '#4BC0C0', '#FFCE56'] + } + ] + }, + + }, } }, barchartcomponent: { @@ -1826,7 +1859,8 @@ This is a paragraph. width: 2.5 } } - } + }, + }, configuration: { layout: { @@ -1846,7 +1880,21 @@ This is a paragraph. dims: '2:8-6:8' as AppComponentDimensions, customCss: {}, initialData: { - componentInput: undefined, + componentInput: { + type: 'static', + fieldType: 'object', + value: { + type: 'bar', + x: [1, 2, 3, 4], + y: [5, 10, 2, 8], + marker: { + color: '#C8A2C8', + line: { + width: 2.5 + } + } + }, + }, configuration: { layout: { type: 'static', @@ -1856,7 +1904,8 @@ This is a paragraph. 'Layout options for the plot. See https://plotly.com/javascript/reference/layout/ for more information' } } - } + }, + }, timeseriescomponent: { name: 'Timeseries', diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/CssEval.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/CssEval.svelte index 7c1e88e372..330b1d0b64 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/CssEval.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/CssEval.svelte @@ -3,12 +3,16 @@ import type { AppViewerContext, RichConfiguration } from '../../types' import InputsSpecEditor from '../settingsPanel/InputsSpecEditor.svelte' - export let evalClass: RichConfiguration - export let key: string + interface Props { + evalClass: RichConfiguration + key: string + } + + let { evalClass = $bindable(), key }: Props = $props() const { selectedComponent } = getContext('AppViewerContext') - $: id = Array.isArray($selectedComponent) ? $selectedComponent[0] : $selectedComponent + let id = $derived(Array.isArray($selectedComponent) ? $selectedComponent[0] : $selectedComponent) {#if evalClass && id} diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte index 64f361780d..c3597adb90 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte @@ -98,7 +98,7 @@ } }} > -
+
{name} diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/GroupList.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/GroupList.svelte index 501e1823cb..16302644d8 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/GroupList.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/GroupList.svelte @@ -14,15 +14,19 @@ import type { AppViewerContext, GridItem } from '../../types' import { getAllSubgridsAndComponentIds } from '../appUtils' - export let item: GridItem + interface Props { + item: GridItem + } + + let { item }: Props = $props() const { app } = getContext('AppViewerContext') let groups: Array<{ name: string path: string - }> = [] + }> = $state([]) - let loading: boolean = false + let loading: boolean = $state(false) async function getGroups() { loading = true @@ -79,7 +83,7 @@ nameField = '' } - let nameField: string = '' + let nameField: string = $state('') getGroups() diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/GroupManagementDrawer.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/GroupManagementDrawer.svelte index 3a1d9ca767..aa2697e026 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/GroupManagementDrawer.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/GroupManagementDrawer.svelte @@ -3,17 +3,21 @@ import GroupList from './GroupList.svelte' import type { GridItem } from '../../types' - export let item: GridItem + interface Props { + item: GridItem + } - let codeDrawer: Drawer + let { item }: Props = $props() + + let codeDrawer: Drawer | undefined = $state() export async function openDrawer() { - codeDrawer.openDrawer() + codeDrawer?.openDrawer() } - + codeDrawer?.closeDrawer()}> diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/ListItem.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/ListItem.svelte index 41bc0c7f6e..bf87160878 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/ListItem.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/ListItem.svelte @@ -1,29 +1,52 @@ - + {#snippet trigger()} - - + {/snippet} + {#snippet content({ close })}
Edit {kind} name
- +
-
+ {/snippet}
diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte index 23561814c4..ea9bb21f97 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte @@ -211,7 +211,7 @@ {isOpen[prefix] ? '!bg-surface-secondary hover:!bg-surface-hover' : ''}" > - + {group} diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/ThemeCodePreview.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/ThemeCodePreview.svelte index 85069824f7..879051724b 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/ThemeCodePreview.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/ThemeCodePreview.svelte @@ -5,10 +5,15 @@ import { onMount } from 'svelte' import SimpleEditor from '$lib/components/SimpleEditor.svelte' - export let theme: AppTheme | undefined = undefined + interface Props { + theme?: AppTheme | undefined + children?: import('svelte').Snippet + } - let code: string | undefined = undefined - let cssEditor: SimpleEditor | undefined = undefined + let { theme = undefined, children }: Props = $props() + + let code: string | undefined = $state(undefined) + let cssEditor: SimpleEditor | undefined = $state(undefined) onMount(async () => { code = await resolveTheme(theme, $workspaceStore) @@ -18,7 +23,7 @@
- + {@render children?.()}
diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/ThemeNameEditor.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/ThemeNameEditor.svelte index 36ebd17556..4f3f601533 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/ThemeNameEditor.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/ThemeNameEditor.svelte @@ -7,12 +7,16 @@ import { createEventDispatcher } from 'svelte' import { sendUserToast } from '$lib/toast' - export let row: { - name: string - path: string + interface Props { + row: { + name: string + path: string + } } - let editedName = row.name + let { row }: Props = $props() + + let editedName = $state(row.name) const dispatch = createEventDispatcher() @@ -22,14 +26,14 @@ closeOnOtherPopoverOpen contentClasses="flex flex-col w-80 gap-2 p-4" > - + {#snippet trigger()} - - + {/snippet} + {#snippet content({ close })}
Edit theme name
@@ -52,5 +56,5 @@ Update
-
+ {/snippet} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte index a69d8aadd0..3a2b6fd3f1 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte @@ -11,18 +11,29 @@ // @ts-ignore import MenuItemsOutput from './components/MenuItemsOutput.svelte' - export let gridItem: GridItem - export let first: boolean = false - export let nested: boolean = false - export let expanded: boolean = false - export let renderRec: boolean = true + interface Props { + gridItem: GridItem + first?: boolean + nested?: boolean + expanded?: boolean + renderRec?: boolean + } + + let { + gridItem, + first = false, + nested = false, + expanded = false, + renderRec = true + }: Props = $props() const { connectingInput } = getContext('AppViewerContext') const name = getComponentNameById(gridItem.id) - $: nameOverrides = + let nameOverrides = $derived( gridItem?.data?.type === 'decisiontreecomponent' ? gridItem.data.nodes.map((n, i) => `${n.label} (Tab index ${i})`) : undefined + ) function getComponentNameById(componentId: string) { if (gridItem?.data?.type) { @@ -36,27 +47,30 @@ } } - $: subGrids = Array.from({ length: gridItem.data?.numberOfSubgrids ?? 0 }).map( - (_, i) => `${gridItem.id}-${i}` + let subGrids = $derived( + Array.from({ length: gridItem.data?.numberOfSubgrids ?? 0 }).map( + (_, i) => `${gridItem.id}-${i}` + ) ) - { - connectOutput(connectingInput, gridItem?.data?.type, gridItem.data.id, detail) - }} - /> - - - + {#snippet children({ render })} + { + connectOutput(connectingInput, gridItem?.data?.type, gridItem.data.id, detail) + }} + /> + + + + {/snippet} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte index 1e0b538d69..ffc9e7f750 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutputViewer.svelte @@ -1,18 +1,22 @@ {#if render && object != undefined && Object.keys(object).length > 0} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte b/frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte index 3fb6cbda33..f539447f55 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/ContextPanel.svelte @@ -19,11 +19,11 @@ const dispatch = createEventDispatcher() - let hasState: boolean = false + let hasState: boolean = $state(false) - + {#snippet action()}
{ @@ -33,7 +33,7 @@ />
-
+ {/snippet} State & Context - - { - $connectingInput = connectInput($connectingInput, 'ctx', detail) - }} - /> + + {#snippet children({ render })} + { + $connectingInput = connectInput($connectingInput, 'ctx', detail) + }} + /> + {/snippet} - { - $connectingInput = connectInput($connectingInput, 'state', detail) - }} - /> + {#snippet children({ render })} + { + $connectingInput = connectInput($connectingInput, 'state', detail) + }} + /> + {/snippet}
diff --git a/frontend/src/lib/components/apps/editor/contextPanel/SubGridOutput.svelte b/frontend/src/lib/components/apps/editor/contextPanel/SubGridOutput.svelte index 1c025bdaaa..ee9ccc88fc 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/SubGridOutput.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/SubGridOutput.svelte @@ -3,31 +3,28 @@ import { getContext } from 'svelte' import type { Output } from '../../rx' import type { AppViewerContext } from '../../types' - import { connectInput } from '../appUtils' import ComponentOutput from './ComponentOutput.svelte' - export let name: string | undefined = undefined - export let parentId: string - export let expanded: boolean = false - export let subGrids: string[] - export let nameOverrides: string[] | undefined = undefined - export let render: boolean - const { app, connectingInput, worldStore } = getContext('AppViewerContext') - - let selected = 0 - - $: outputs = $worldStore?.outputsById[parentId] as { - selectedTabIndex: Output + interface Props { + name?: string | undefined + parentId: string + expanded?: boolean + subGrids: string[] + nameOverrides?: string[] | undefined + render: boolean } - $: subgridItems = subGrids.map((k) => ({ - k, - items: $app.subgrids?.[k] ?? [] - })) + let { + name = undefined, + parentId, + expanded = false, + subGrids, + nameOverrides = undefined, + render + }: Props = $props() + const { app, worldStore } = getContext('AppViewerContext') - $: if (outputs?.selectedTabIndex) { - subscribeToOutput() - } + let selected = $state(0) function subscribeToOutput() { outputs.selectedTabIndex.subscribe( @@ -40,19 +37,35 @@ selected ) } + let outputs = $derived( + $worldStore?.outputsById[parentId] as { + selectedTabIndex: Output + } + ) + let subgridItems = $derived( + subGrids.map((k) => ({ + k, + items: $app.subgrids?.[k] ?? [] + })) + ) + $effect(() => { + if (outputs?.selectedTabIndex) { + subscribeToOutput() + } + }) {#each subgridItems as { k, items }, index (k)}
{#if subGrids.length > 1 && render} - - + +
{ + onclick={() => { selected = index }} > @@ -78,9 +91,6 @@ gridItem={subGridItem} first={index === 0} {expanded} - on:select={({ detail }) => { - $connectingInput = connectInput($connectingInput, subGridItem.id, detail) - }} /> {/each} {:else} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/components/BackgroundScriptOutput.svelte b/frontend/src/lib/components/apps/editor/contextPanel/components/BackgroundScriptOutput.svelte index 3ef4011c65..90d163343f 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/components/BackgroundScriptOutput.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/components/BackgroundScriptOutput.svelte @@ -7,17 +7,23 @@ const { connectingInput } = getContext('AppViewerContext') - export let id: string - export let name: string - export let first: boolean = false + interface Props { + id: string; + name: string; + first?: boolean; + } + + let { id, name, first = false }: Props = $props(); - - { - $connectingInput = connectInput($connectingInput, id, detail) - }} - /> + + {#snippet children({ render })} + { + $connectingInput = connectInput($connectingInput, id, detail) + }} + /> + {/snippet} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte b/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte index 88882ced5b..99b682af95 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/components/IdEditor.svelte @@ -8,11 +8,15 @@ const { app, selectedComponent } = getContext('AppViewerContext') - export let id: string + interface Props { + id: string + } + + let { id }: Props = $props() const dispatch = createEventDispatcher() - $: reservedIds = allItems($app.grid, $app.subgrids).map((item) => item.id) + let reservedIds = $derived(allItems($app.grid, $app.subgrids).map((item) => item.id)) - + {#snippet trigger()} - - + {/snippet} + {#snippet content({ close })} close()} @@ -42,5 +46,5 @@ }} {reservedIds} /> - + {/snippet} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/components/MenuItemsOutput.svelte b/frontend/src/lib/components/apps/editor/contextPanel/components/MenuItemsOutput.svelte index 2ddb722eb6..e2d334736c 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/components/MenuItemsOutput.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/components/MenuItemsOutput.svelte @@ -2,8 +2,12 @@ import type { GridItem } from '$lib/components/apps/types' import Output from './Output.svelte' - export let gridItem: GridItem - export let render: boolean + interface Props { + gridItem: GridItem + render: boolean + } + + let { gridItem, render }: Props = $props()
diff --git a/frontend/src/lib/components/apps/editor/contextPanel/components/Output.svelte b/frontend/src/lib/components/apps/editor/contextPanel/components/Output.svelte index c030207504..e585eafbe6 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/components/Output.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/components/Output.svelte @@ -7,18 +7,24 @@ const { connectingInput } = getContext('AppViewerContext') - export let id: string - export let first: boolean = false - export let label: string - export let renderRec: boolean + interface Props { + id: string + first?: boolean + label: string + renderRec: boolean + } + + let { id, first = false, label, renderRec }: Props = $props() - - { - $connectingInput = connectInput($connectingInput, id, detail) - }} - /> + + {#snippet children({ render })} + { + $connectingInput = connectInput($connectingInput, id, detail) + }} + /> + {/snippet} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/components/OutputHeader.svelte b/frontend/src/lib/components/apps/editor/contextPanel/components/OutputHeader.svelte index 3273677583..0629dccb21 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/components/OutputHeader.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/components/OutputHeader.svelte @@ -1,4 +1,6 @@ - +
{#if render && ($search == '' || inSearch)} - - + +
{ + onmouseenter={stopPropagation(() => { if (id !== $hoverStore) { $hoverStore = id } - }} - on:mouseleave|stopPropagation={() => { + })} + onmouseleave={stopPropagation(() => { if ($hoverStore !== undefined) { $hoverStore = undefined } - }} + })} class={classNames( 'flex items-center justify-between p-1 cursor-pointer gap-1 truncate', hoverColor[color], $selectedComponent?.includes(id) ? openBackground[color] : $connectingInput.hoveredComponent === id - ? 'bg-[#fab157]' - : 'bg-surface-secondary', + ? 'bg-[#fab157]' + : 'bg-surface-secondary', first ? 'border-t' : '', nested ? 'border-l' : '', 'transition-all' )} - on:click={() => { + onclick={() => { if (!disabled) { $manuallyOpened[id] = $manuallyOpened[id] != undefined ? !$manuallyOpened[id] : true } @@ -238,7 +258,7 @@
diff --git a/frontend/src/lib/components/apps/editor/contextPanel/components/TableActionsOutput.svelte b/frontend/src/lib/components/apps/editor/contextPanel/components/TableActionsOutput.svelte index 43eb9717dd..0069cd3f65 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/components/TableActionsOutput.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/components/TableActionsOutput.svelte @@ -2,8 +2,12 @@ import type { GridItem } from '$lib/components/apps/types' import Output from './Output.svelte' - export let gridItem: GridItem - export let render: boolean + interface Props { + gridItem: GridItem + render: boolean + } + + let { gridItem, render }: Props = $props()
diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/AppRunButton.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/AppRunButton.svelte index cb63d46ecd..65737951aa 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/AppRunButton.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/AppRunButton.svelte @@ -9,10 +9,19 @@ import RunButtonInner from '$lib/components/RunButton.svelte' - export let id: string - export let inlineScript: InlineScript | undefined = undefined - export let runLoading = false - export let hideShortcut = false + interface Props { + id: string + inlineScript?: InlineScript | undefined + runLoading?: boolean + hideShortcut?: boolean + } + + let { + id, + inlineScript = undefined, + runLoading = $bindable(false), + hideShortcut = false + }: Props = $props() const { runnableComponents } = getContext('AppViewerContext') const { runnableJobEditorPanel } = getContext('AppEditorContext') diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/CacheTtlPopup.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/CacheTtlPopup.svelte index 6734a18a8d..68fbcc35a4 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/CacheTtlPopup.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/CacheTtlPopup.svelte @@ -5,7 +5,11 @@ import Popover from '$lib/components/meltComponents/Popover.svelte' import { autoPlacement } from '@floating-ui/core' - export let cache_ttl: number | undefined + interface Props { + cache_ttl: number | undefined + } + + let { cache_ttl = $bindable() }: Props = $props() - + {#snippet trigger()}
- + {/snippet} diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte index 12cfedd2cf..f15a6bf273 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte @@ -20,14 +20,23 @@ import type { Preview } from '$lib/gen' import type { InlineScript } from '../../types' - export let componentType: string | undefined = undefined - export let showScriptPicker = false - export let rawApps = false - export let unusedInlineScripts: { name: string; inlineScript: InlineScript }[] + interface Props { + componentType?: string | undefined + showScriptPicker?: boolean + rawApps?: boolean + unusedInlineScripts: { name: string; inlineScript: InlineScript }[] + } - let tab = 'workspacescripts' - let filter: string = '' - let picker: Drawer + let { + componentType = undefined, + showScriptPicker = false, + rawApps = false, + unusedInlineScripts + }: Props = $props() + + let tab = $state('workspacescripts') + let filter: string = $state('') + let picker: Drawer | undefined = $state(undefined) const dispatch = createEventDispatcher() @@ -78,13 +87,15 @@ newInlineScript(script.content, script.language) } - $: langs = processLangs(undefined, $defaultScripts?.order ?? Object.keys(defaultScriptLanguages)) - .map((l) => [defaultScriptLanguages[l], l]) - .filter( - (x) => - x[1] != 'docker' && - ($defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1])) - ) as [string, Preview['language']][] + let langs = $derived( + processLangs(undefined, $defaultScripts?.order ?? Object.keys(defaultScriptLanguages)) + .map((l) => [defaultScriptLanguages[l], l]) + .filter( + (x) => + x[1] != 'docker' && + ($defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1])) + ) as [string, Preview['language']][] + ) diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorPanel.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorPanel.svelte index 0fa3cb864e..cd8fa66438 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorPanel.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptEditorPanel.svelte @@ -8,11 +8,21 @@ import type { AppViewerContext } from '../../types' import InlineScriptRunnableByPath from './InlineScriptRunnableByPath.svelte' - export let componentInput: AppInput | undefined - export let defaultUserInput = false - export let componentType: string - export let id: string - export let transformer: boolean + interface Props { + componentInput: AppInput | undefined + defaultUserInput?: boolean + componentType: string + id: string + transformer: boolean + } + + let { + componentInput = $bindable(), + defaultUserInput = false, + componentType, + id, + transformer + }: Props = $props() const { app } = getContext('AppViewerContext') diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptHiddenRunnable.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptHiddenRunnable.svelte index aca0f9c043..cc94f040f7 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptHiddenRunnable.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptHiddenRunnable.svelte @@ -6,9 +6,13 @@ import type { Runnable, StaticAppInput } from '../../inputType' import { createEventDispatcher, getContext } from 'svelte' - export let runnable: HiddenRunnable - export let id: string - export let transformer: boolean + interface Props { + runnable: HiddenRunnable + id: string + transformer: boolean + } + + let { runnable = $bindable(), id, transformer }: Props = $props() const { runnableComponents, app } = getContext('AppViewerContext') async function fork(nrunnable: Runnable) { diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte index cfe33844a4..7d2563bda3 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte @@ -1,10 +1,13 @@ @@ -160,7 +180,7 @@ startIcon={{ icon: Eye }} on:click={() => { flowPath = runnable.path - drawerFlowViewer.openDrawer() + drawerFlowViewer?.openDrawer() }} > Expand @@ -215,7 +235,7 @@ closeButton contentClasses="block text-primary text-xs p-4 w-[20vh]" > - + {#snippet trigger()} - - + {/snippet} + {#snippet content()} Since this is a reference to a workspace {runnable.runType}, set the cache in the {runnable.runType} settings directly by editing it. The cache will be shared by any app or flow that uses this {runnable.runType}. - + {/snippet} { - const [prefix, id] = $selectedComponentInEditor?.split('_') || [] - - if (prefix !== 'bg') return false - - return Number(id) === index - }) - - $: unusedInlineScript = $app?.unusedInlineScripts?.findIndex( - (k_, index) => `unused-${index}` === $selectedComponentInEditor ) - export let width: number | undefined = undefined + let hiddenInlineScript = $derived( + $app?.hiddenInlineScripts?.findIndex((k_, index) => { + const [prefix, id] = $selectedComponentInEditor?.split('_') || [] + + if (prefix !== 'bg') return false + + return Number(id) === index + }) + ) + + let unusedInlineScript = $derived( + $app?.unusedInlineScripts?.findIndex( + (k_, index) => `unused-${index}` === $selectedComponentInEditor + ) + ) + + interface Props { + width?: number | undefined + } + + let { width = undefined }: Props = $props() import { Badge, Button } from '$lib/components/common' import { Plus } from 'lucide-svelte' - import { createEventDispatcher, getContext } from 'svelte' + import { createEventDispatcher, getContext, untrack } from 'svelte' import Tooltip from '../../../Tooltip.svelte' import type { AppEditorContext, AppViewerContext } from '../../types' import { BG_PREFIX, getAllScriptNames } from '../../utils' @@ -26,11 +26,6 @@ } } - $: runnables = getAppScripts($app.grid, $app.subgrids) - - // When selected component changes, update selectedScriptComponentId - $: selectedComponent && handleSelectedComponent($selectedComponent) - function handleSelectedComponent(selectedComponent: string[] | undefined) { if ( selectedComponent != $selectedComponentInEditor && @@ -79,12 +74,17 @@ selectScript(`${BG_PREFIX}${$app.hiddenInlineScripts.length - 1}`) } - let appTutorials: AppTutorials | undefined = undefined + let appTutorials: AppTutorials | undefined = $state(undefined) const dispatch = createEventDispatcher() + let runnables = $derived(getAppScripts($app.grid, $app.subgrids)) + // When selected component changes, update selectedScriptComponentId + $effect(() => { + $selectedComponent && untrack(() => handleSelectedComponent($selectedComponent)) + }) - + {#snippet action()}
-
+ {/snippet}
@@ -109,7 +109,7 @@ {$selectedComponentInEditor === id ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}" - on:click={() => selectScript(id)} + onclick={() => selectScript(id)} > {name}
@@ -124,7 +124,7 @@ {$selectedComponentInEditor === id + '_transformer' ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}" - on:click={() => selectScript(id + '_transformer')} + onclick={() => selectScript(id + '_transformer')} > Transformer @@ -140,7 +140,7 @@ {$selectedComponentInEditor === id ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50'}" - on:click={() => selectScript(id)} + onclick={() => selectScript(id)} > {name} {id} @@ -153,7 +153,7 @@ {$selectedComponentInEditor === id + '_transformer' ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}" - on:click={() => selectScript(id + '_transformer')} + onclick={() => selectScript(id + '_transformer')} > Transformer @@ -171,7 +171,7 @@ {$selectedComponentInEditor === id ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}" - on:click={() => selectScript(id)} + onclick={() => selectScript(id)} > {unusedInlineScript.name} Detached @@ -220,7 +220,7 @@ {$selectedComponentInEditor === id ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}" - on:click={() => selectScript(id)} + onclick={() => selectScript(id)} > {name} {id} @@ -233,7 +233,7 @@ {$selectedComponentInEditor === id + '_transformer' ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}" - on:click={() => selectScript(id + '_transformer')} + onclick={() => selectScript(id + '_transformer')} > Transformer diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelWithTable.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelWithTable.svelte index e3af73f931..6a2a34cd0d 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelWithTable.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/InlineScriptsPanelWithTable.svelte @@ -5,7 +5,11 @@ const { selectedComponentInEditor } = getContext('AppEditorContext') - export let gridItem: GridItem + interface Props { + gridItem: GridItem + } + + let { gridItem = $bindable() }: Props = $props() {#if gridItem?.data?.id === $selectedComponentInEditor || gridItem?.data?.id + '_transformer' === $selectedComponentInEditor} diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/RunButton.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/RunButton.svelte index a4be6ab2d8..b5144d7543 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/RunButton.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/RunButton.svelte @@ -9,14 +9,23 @@ import { Button } from '$lib/components/common' import { CornerDownLeft, Loader2 } from 'lucide-svelte' - export let id: string - export let inlineScript: InlineScript | undefined = undefined - export let runLoading = false - export let hideShortcut = false + interface Props { + id: string + inlineScript?: InlineScript | undefined + runLoading?: boolean + hideShortcut?: boolean + } + + let { + id, + inlineScript = undefined, + runLoading = $bindable(false), + hideShortcut = false + }: Props = $props() const { runnableComponents } = getContext('AppViewerContext') const { runnableJobEditorPanel } = getContext('AppEditorContext') - let cancelable: CancelablePromise[] | undefined = undefined + let cancelable: CancelablePromise[] | undefined = $state(undefined) {#if $runnableComponents[id] != undefined} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/AGChartRichEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/AGChartRichEditor.svelte index bdc24b261d..50c850c86a 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/AGChartRichEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/AGChartRichEditor.svelte @@ -3,9 +3,13 @@ import InputsSpecEditor from './InputsSpecEditor.svelte' import PanelSection from './common/PanelSection.svelte' - export let datasets: RichConfiguration | undefined = undefined - export let xData: RichConfiguration | undefined = undefined - export let id: string + interface Props { + datasets?: RichConfiguration | undefined + xData?: RichConfiguration | undefined + id: string + } + + let { datasets = $bindable(undefined), xData = $bindable(undefined), id }: Props = $props() ('AppViewerContext') function fadeFast(node: HTMLElement) { return fade(node, { duration: 100 }) } - let migrationModalOpen: boolean = false + let migrationModalOpen: boolean = $state(false) export function open() { migrationModalOpen = true @@ -38,9 +42,6 @@ return code } - $: generatedCode = generateCodeFromMigrations(migrations) - $: migrations = new Map() - function getSelector(key: string) { return customisationByComponent .find((c) => c.components.includes(component?.type ?? '')) @@ -126,6 +127,8 @@ } let type: string | undefined = component?.type + let migrations = $derived(new Map()) + let generatedCode = $derived(generateCodeFromMigrations(migrations)) diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ChartJSRichEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ChartJSRichEditor.svelte index 66e30d2bcd..fe91da18f7 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ChartJSRichEditor.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ChartJSRichEditor.svelte @@ -3,9 +3,13 @@ import InputsSpecEditor from './InputsSpecEditor.svelte' import PanelSection from './common/PanelSection.svelte' - export let datasets: RichConfiguration | undefined = undefined - export let xData: RichConfiguration | undefined = undefined - export let id: string + interface Props { + datasets?: RichConfiguration | undefined + xData?: RichConfiguration | undefined + id: string + } + + let { datasets = $bindable(undefined), xData = $bindable(undefined), id }: Props = $props() {#if componentControls?.length > 0} -
- -
+ {#snippet action()} +
+ +
+ {/snippet} {#if collapsed}
diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte index 873e16516d..f6a6bc75ea 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte @@ -47,14 +47,16 @@ import Popover from '$lib/components/Popover.svelte' interface Props { - componentSettings?: { item: GridItem; parent: string | undefined } | undefined + parent: string | undefined + item: GridItem onDelete?: (() => void) | undefined noGrid?: boolean duplicateMoveAllowed?: boolean } let { - componentSettings = $bindable(undefined), + parent, + item = $bindable(), onDelete = undefined, noGrid = false, duplicateMoveAllowed = true @@ -77,7 +79,7 @@ function removeGridElement() { push(history, $app) - const id = componentSettings?.item?.id + const id = item?.id const onDeleteComponentControl = id ? $componentControl[id]?.onDelete : undefined if (onDeleteComponentControl) { onDeleteComponentControl() @@ -86,7 +88,6 @@ onDelete() } - const item = componentSettings?.item let cId = item?.id if (cId) { delete $worldStore.outputsById[cId] @@ -96,18 +97,19 @@ $movingcomponents = $movingcomponents.filter((id) => id !== cId) } } - + const nitem = item + const nparent = parent $selectedComponent = undefined $focusedGrid = undefined - if (item && !noGrid) { - let ids = deleteGridItem($app, item.data, componentSettings?.parent) + if (nitem && !noGrid) { + let ids = deleteGridItem($app, nitem.data, nparent) for (const key of ids) { delete $runnableComponents[key] } } - if (item?.data?.id) { - delete $runnableComponents[item?.data?.id] + if (nitem?.data?.id) { + delete $runnableComponents[nitem?.data?.id] } $app = $app $runnableComponents = $runnableComponents @@ -118,15 +120,10 @@ let viewCssOptions = false let extraLib = $derived( - (componentSettings?.item?.data?.componentInput?.type === 'template' || - componentSettings?.item?.data?.componentInput?.type === 'templatev2') && + (item?.data?.componentInput?.type === 'template' || + item?.data?.componentInput?.type === 'templatev2') && $worldStore - ? buildExtraLib( - $worldStore?.outputsById ?? {}, - componentSettings?.item?.data?.id, - $stateStore, - false - ) + ? buildExtraLib($worldStore?.outputsById ?? {}, item?.data?.id, $stateStore, false) : undefined ) @@ -142,33 +139,31 @@ } } - const initialConfiguration = componentSettings?.item?.data?.type - ? ccomponents[componentSettings.item.data.type]?.initialData?.configuration + const initialConfiguration = item?.data?.type + ? ccomponents[item.data.type]?.initialData?.configuration : {} - const componentInput: RichConfiguration | undefined = componentSettings?.item?.data?.type - ? ccomponents[componentSettings?.item?.data?.type]?.initialData?.componentInput + const componentInput: RichConfiguration | undefined = item?.data?.type + ? ccomponents[item?.data?.type]?.initialData?.componentInput : undefined - const hasInteraction = componentSettings?.item.data.type - ? isTriggerable(componentSettings?.item.data.type) - : false + const hasInteraction = item.data.type ? isTriggerable(item.data.type) : false let evalV2editor: EvalV2InputEditor | undefined = $state(undefined) function transformToFrontend() { - if (componentSettings?.item.data.componentInput) { - const id = componentSettings?.item?.data?.id + if (item.data.componentInput) { + const id = item?.data?.id let appInput: ResultAppInput = { - ...componentSettings.item.data.componentInput, + ...item.data.componentInput, type: 'runnable', runnable: { type: 'runnableByName', name: `Eval of ${id}`, inlineScript: { - content: `return ${componentSettings?.item.data.componentInput?.['expr']}`, + content: `return ${item.data.componentInput?.['expr']}`, language: 'frontend', - refreshOn: componentSettings?.item.data.componentInput?.['connections']?.map((c) => { + refreshOn: item.data.componentInput?.['connections']?.map((c) => { return { id: c.componentId, key: c.id @@ -178,25 +173,26 @@ }, fields: {} } - componentSettings.item.data.componentInput = appInput + item.data.componentInput = appInput } } let templateChangeTimeout: NodeJS.Timeout | undefined = undefined function onTemplateChange(e: CustomEvent<{ code: string }>) { - if (componentSettings?.item.data.componentInput?.type === 'templatev2') { + const currentItem = item + if (currentItem.data.componentInput?.type === 'templatev2') { if (templateChangeTimeout) { clearTimeout(templateChangeTimeout) } templateChangeTimeout = setTimeout(() => { - if (componentSettings?.item.data.componentInput?.type === 'templatev2') { + if (currentItem.data.componentInput?.type === 'templatev2') { inferDeps( '`' + e.detail.code + '`', $worldStore.outputsById, - componentSettings?.item.data.componentInput, + currentItem.data.componentInput, app ) - console.log('inferred deps for', componentSettings?.item.data.id) + console.log('inferred deps for', currentItem.data.id) } }, 200) } @@ -205,7 +201,7 @@ -{#if componentSettings?.item?.id && isTableAction(componentSettings?.item?.id, $app)} +{#if item?.id && isTableAction(item?.id, $app)}
@@ -224,7 +220,7 @@ 'p-1 text-gray-300 hover:!text-gray-600 dark:text-gray-500 dark:hover:!text-gray-200 bg-transparent' )} on:click={() => { - const tableId = componentSettings?.item?.id?.split?.('_')?.[0] + const tableId = item?.id?.split?.('_')?.[0] if (tableId) { $selectedComponent = [tableId] @@ -236,7 +232,7 @@
Table action of table - {componentSettings?.item?.id.split('_')[0]} + {item?.id.split('_')[0]}
@@ -246,22 +242,22 @@
{/if} -{#if componentSettings?.item?.data} - {@const component = componentSettings.item.data} +{#if item?.data} + {@const component = item.data}
{components[componentSettings.item.data.type]?.name ?? 'Unknown'}
{components[item.data.type]?.name ?? 'Unknown'}
- +
- + {#if component.componentInput} {/snippet} - {#if componentSettings.item.data.componentInput} + {#if item.data.componentInput}
- {#if componentSettings.item.data.componentInput.type === 'static'} + {#if item.data.componentInput.type === 'static'} - {:else if componentSettings.item.data?.componentInput?.type === 'template' || componentSettings.item.data?.componentInput?.type === 'templatev2'} + {:else if item.data?.componentInput?.type === 'template' || item.data?.componentInput?.type === 'templatev2'}
- {#if componentSettings.item.data?.componentInput?.type === 'templatev2'} - {#if componentSettings.item.data?.componentInput.connections?.length > 0} + {#if item.data?.componentInput?.type === 'templatev2'} + {#if item.data?.componentInput.connections?.length > 0}
Re-evaluated on changes to:
- {#each componentSettings.item.data?.componentInput.connections ?? [] as connection (connection.componentId + '-' + connection.id)} + {#each item.data?.componentInput.connections ?? [] as connection (connection.componentId + '-' + connection.id)} @@ -324,24 +320,22 @@
{/if} {/if} - {:else if componentSettings.item.data.componentInput.type === 'connected' && component.componentInput !== undefined} - - {:else if componentSettings.item.data.componentInput.type === 'evalv2' && component.componentInput !== undefined} + {:else if item.data.componentInput.type === 'connected' && component.componentInput !== undefined} + + {:else if item.data.componentInput.type === 'evalv2' && component.componentInput !== undefined} transform to a frontend script - {:else if componentSettings.item.data.componentInput?.type === 'runnable' && component.componentInput !== undefined} + {:else if item.data.componentInput?.type === 'runnable' && component.componentInput !== undefined} @@ -352,8 +346,8 @@ {#key $stateId} - {#if componentSettings.item.data.componentInput?.type === 'runnable'} - {#if Object.keys(componentSettings.item.data.componentInput.fields ?? {}).length > 0} + {#if item.data.componentInput?.type === 'runnable'} + {#if Object.keys(item.data.componentInput.fields ?? {}).length > 0}
Runnable Inputs @@ -367,11 +361,10 @@ id={component.id} shouldCapitalize={false} displayType - bind:inputSpecs={componentSettings.item.data.componentInput.fields} + bind:inputSpecs={item.data.componentInput.fields} userInputEnabled={component.type === 'formcomponent' || component.type === 'formbuttoncomponent'} - recomputeOnInputChanged={componentSettings.item.data.componentInput - .recomputeOnInputChanged} + recomputeOnInputChanged={item.data.componentInput.recomputeOnInputChanged} showOnDemandOnlyToggle acceptSelf={component.type === 'aggridinfinitecomponent' || component.type === 'aggridinfinitecomponentee' || @@ -389,83 +382,66 @@ {/if} - - {#if componentSettings.item.data.type === 'navbarcomponent'} - + {#if item.data.type === 'navbarcomponent'} + {/if} - {#if componentSettings.item.data.type === 'tabscomponent'} + {#if item.data.type === 'tabscomponent'} - {:else if componentSettings.item.data.type === 'aggridcomponentee'} - + {:else if item.data.type === 'aggridcomponentee'} + - {:else if componentSettings.item.data.type === 'agchartscomponentee'} - - {:else if componentSettings.item.data.type === 'steppercomponent'} - - {:else if componentSettings.item.data.type === 'containercomponent'} - - {:else if componentSettings.item.data.type === 'conditionalwrapper'} - - {:else if componentSettings.item.data.type === 'decisiontreecomponent'} - - {:else if componentSettings.item.data.type === 'verticalsplitpanescomponent' || componentSettings.item.data.type === 'horizontalsplitpanescomponent'} - - {:else if componentSettings.item.data.type === 'aggridcomponent'} + {:else if item.data.type === 'agchartscomponentee'} + + {:else if item.data.type === 'steppercomponent'} + + {:else if item.data.type === 'containercomponent'} + + {:else if item.data.type === 'conditionalwrapper'} + + {:else if item.data.type === 'decisiontreecomponent'} + + {:else if item.data.type === 'verticalsplitpanescomponent' || item.data.type === 'horizontalsplitpanescomponent'} + + {:else if item.data.type === 'aggridcomponent'} - {:else if componentSettings.item.data.type === 'aggridinfinitecomponent'} + {:else if item.data.type === 'aggridinfinitecomponent'} - {:else if componentSettings.item.data.type === 'aggridinfinitecomponentee'} - + {:else if item.data.type === 'aggridinfinitecomponentee'} + - {:else if componentSettings.item.data.type === 'dbexplorercomponent'} + {:else if item.data.type === 'dbexplorercomponent'} - {:else if componentSettings.item.data.type === 'tablecomponent' && Array.isArray(componentSettings.item.data.actionButtons)} - - {:else if componentSettings.item.data.type === 'menucomponent' && Array.isArray(componentSettings.item.data.menuItems)} - + {:else if item.data.type === 'tablecomponent' && Array.isArray(item.data.actionButtons)} + + {:else if item.data.type === 'menucomponent' && Array.isArray(item.data.menuItems)} + {/if} {#if Object.values(initialConfiguration).length > 0} @@ -473,18 +449,18 @@ - {:else if componentSettings.item.data.type != 'containercomponent'} + {:else if item.data.type != 'containercomponent'}
{ccomponents[component.type].name} has no configuration
{/if} - +
@@ -505,18 +481,18 @@ {/snippet}
Full height
- {#if componentSettings?.item?.[12]?.fullHeight !== undefined} + {#if item?.[12]?.fullHeight !== undefined} {/if} - {#if componentSettings?.item?.[3]?.fullHeight !== undefined} + {#if item?.[3]?.fullHeight !== undefined} {/if}
- + {#if viewCssOptions}
{#each Object.keys(ccomponents[component.type]?.customCss ?? {}) as name} - {#if componentSettings.item.data?.customCss != undefined} + {#if item.data?.customCss != undefined}
{/if} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanelDataSource.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanelDataSource.svelte index 780c6f74ce..a74e81f67f 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanelDataSource.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanelDataSource.svelte @@ -6,10 +6,11 @@ import PlotlyRichEditor from './PlotlyRichEditor.svelte' import ChartJSRichEditor from './ChartJSRichEditor.svelte' import AGChartRichEditor from './AGChartRichEditor.svelte' - import { getContext, onMount } from 'svelte' + import { getContext } from 'svelte' import type { AppViewerContext, RichConfiguration } from '../../types' import type { InputConnectionEval } from '../../inputType' import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte' + import { createChartjsComponentDataset, createPlotlyComponentDataset } from '../appUtils' interface Props { component: AppComponent @@ -19,24 +20,15 @@ let { component = $bindable(), children }: Props = $props() let convertToUIEditorCallback: (() => void) | undefined = $state(undefined) - let selected = $state('ui-editor') - let renderCount = $state(0) + console.log('FOOBAR', component.type) - onMount(() => { - if ( - (component.type === 'plotlycomponentv2' || - component.type === 'chartjscomponentv2' || - component.type === 'agchartscomponent' || - component.type === 'agchartscomponentee') && - component.componentInput === undefined && - component.datasets === undefined - ) { - setUpUIEditor() - renderCount++ - } else if (component.componentInput !== undefined) { - selected = 'json' - } - }) + let selected = $state( + (component.type === 'plotlycomponentv2' || component.type === 'chartjscomponentv2') && + component.datasets !== undefined + ? 'ui-editor' + : 'json' + ) + let renderCount = $state(0) const { worldStore } = getContext('AppViewerContext') interface Dataset { @@ -231,48 +223,6 @@ } } - function createChartjsComponentDataset(): RichConfiguration { - return { - type: 'static', - fieldType: 'array', - subFieldType: 'chartjs', - value: [ - { - value: { - type: 'static', - fieldType: 'array', - subFieldType: 'number', - value: [25, 25, 50] - }, - name: 'Dataset 1' - } - ] - } - } - - function createPlotlyComponentDataset(): RichConfiguration { - return { - type: 'static', - fieldType: 'array', - subFieldType: 'plotly', - value: [ - { - value: { - type: 'static', - fieldType: 'array', - subFieldType: 'number', - value: [1, 2, 3, 4] - }, - name: 'Dataset 1', - aggregation_method: 'sum', - type: 'bar', - tooltip: '', - color: '#C8A2C8' - } - ] - } - } - function createXData(): RichConfiguration { return { type: 'evalv2', @@ -395,7 +345,7 @@ } -{#if component.type === 'plotlycomponentv2' || component.type === 'chartjscomponentv2' || component.type === 'agchartscomponent' || component.type === 'agchartscomponentee'} +{#if component.type === 'plotlycomponentv2' || component.type === 'chartjscomponentv2'}
('AppViewerContext') @@ -31,11 +35,13 @@ renderCount++ }, 300) - $: selectedNode = nodes?.find((node) => node.id == $selectedNodeId) + let selectedNode = $derived(nodes?.find((node) => node.id == $selectedNodeId)) setContext('DecisionTreeEditor', { selectedNodeId }) - $: sortedSelectedNextNodes = selectedNode?.next.sort((n1, n2) => n1.id.localeCompare(n2.id)) + let sortedSelectedNextNodes = $derived( + selectedNode?.next.sort((n1, n2) => n1.id.localeCompare(n2.id)) + ) {}} on:open={() => {}} size="1200px"> @@ -47,7 +53,6 @@ > - {renderCount}
{#if paneWidth && paneHeight}
{ + onkeydown={(e) => { // Prevent keyboard events from bubbling to SvelteFlow e.stopPropagation() }} > {#if selectedNode}
- + {#snippet action()} - + {/snippet}
diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/script/shared/ScriptTriggers.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/script/shared/ScriptTriggers.svelte index fca98ca402..aa9b2d896c 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/script/shared/ScriptTriggers.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/script/shared/ScriptTriggers.svelte @@ -4,24 +4,33 @@ import { classNames, itemsExists } from '$lib/utils' import { Plus, X } from 'lucide-svelte' import { Button } from '$lib/components/common' - import { getContext } from 'svelte' + import { getContext, untrack } from 'svelte' import type { App, AppViewerContext, InlineScript } from '$lib/components/apps/types' import Tooltip from '$lib/components/Tooltip.svelte' import { deepEqual } from 'fast-equals' import { getAllGridItems } from '../../../appUtils' - export let triggerEvents: string[] = [] - export let inlineScript: InlineScript | undefined = undefined - export let isFrontend: boolean = false - export let dependencies: string[] = [] - export let shoudlDisplayChangeEvents: boolean = false - export let id: string + interface Props { + triggerEvents?: string[] + inlineScript?: InlineScript | undefined + isFrontend?: boolean + dependencies?: string[] + shoudlDisplayChangeEvents?: boolean + id: string + } + + let { + triggerEvents = [], + inlineScript = $bindable(undefined), + isFrontend = false, + dependencies = [], + shoudlDisplayChangeEvents = false, + id + }: Props = $props() const { connectingInput, app, stateId } = getContext('AppViewerContext') - let onSuccessEvents: string[] = [] - - $: computeOnSuccessEvents($app, id) + let onSuccessEvents: string[] = $state([]) function computeOnSuccessEvents(app: App, _id: string) { const nr: string[] = [] @@ -47,16 +56,6 @@ }) onSuccessEvents = nr } - $: changeEvents = isFrontend - ? inlineScript?.refreshOn - ? inlineScript.refreshOn.map((x) => `${x.id}.${x.key}`) - : [] - : dependencies - - $: hasNoTriggers = - triggerEvents.length === 0 && - (changeEvents.length === 0 || !shoudlDisplayChangeEvents) && - onSuccessEvents.length == 0 const badgeClass = 'inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium border' const colors = { @@ -87,6 +86,24 @@ inlineScript = inlineScript $app = $app } + $effect(() => { + ;[app, id] + untrack(() => { + computeOnSuccessEvents($app, id) + }) + }) + let changeEvents = $derived( + isFrontend + ? inlineScript?.refreshOn + ? inlineScript.refreshOn.map((x) => `${x.id}.${x.key}`) + : [] + : dependencies + ) + let hasNoTriggers = $derived( + triggerEvents.length === 0 && + (changeEvents.length === 0 || !shoudlDisplayChangeEvents) && + onSuccessEvents.length == 0 + ) {#if hasNoTriggers} @@ -118,7 +135,7 @@ {#if isFrontend}
diff --git a/frontend/src/lib/components/apps/gridUtils.ts b/frontend/src/lib/components/apps/gridUtils.ts index 4cb76c74bb..5944755ffa 100644 --- a/frontend/src/lib/components/apps/gridUtils.ts +++ b/frontend/src/lib/components/apps/gridUtils.ts @@ -1,3 +1,4 @@ +import { writable } from 'svelte/store' import type { GridItem } from './types' type ColumnConfiguration = [number, number][] @@ -7,6 +8,9 @@ const Breakpoints = { lg: 1024 } +export const moveMode = writable<'move' | 'insert'>('move') + + const WIDE_GRID_COLUMNS = 12 as const const NARROW_GRID_COLUMNS = 3 as const diff --git a/frontend/src/lib/components/apps/svelte-grid/Grid.svelte b/frontend/src/lib/components/apps/svelte-grid/Grid.svelte index 1e737917dc..87232c1029 100644 --- a/frontend/src/lib/components/apps/svelte-grid/Grid.svelte +++ b/frontend/src/lib/components/apps/svelte-grid/Grid.svelte @@ -5,11 +5,10 @@ const componentDraggedParentIdStore = writable(undefined) const overlappedStore = writable(undefined) const fakeShadowStore = writable(undefined) - const isCtrlOrMetaPressedStore = writable(false) {#if condition} - + {@render children?.()} {:else} - + {@render children?.()} {/if} diff --git a/frontend/src/lib/components/apps/svelte-select/lib/ConditionalPortalGlobal.svelte b/frontend/src/lib/components/apps/svelte-select/lib/ConditionalPortalGlobal.svelte index 44d2beebe3..b7df8ebf57 100644 --- a/frontend/src/lib/components/apps/svelte-select/lib/ConditionalPortalGlobal.svelte +++ b/frontend/src/lib/components/apps/svelte-select/lib/ConditionalPortalGlobal.svelte @@ -1,11 +1,16 @@ {#if condition} - + {@render children?.()} {:else} - + {@render children?.()} {/if} diff --git a/frontend/src/lib/components/raw_apps/RawAppInlineScriptPanelList.svelte b/frontend/src/lib/components/raw_apps/RawAppInlineScriptPanelList.svelte index 48a26e6cbe..dc39cbb5c4 100644 --- a/frontend/src/lib/components/raw_apps/RawAppInlineScriptPanelList.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppInlineScriptPanelList.svelte @@ -9,8 +9,12 @@ import type { Runnable } from '../apps/inputType' import { getNextId } from '$lib/components/flows/idUtils' - export let selectedRunnable: string | undefined - export let runnables: Writable> + interface Props { + selectedRunnable: string | undefined + runnables: Writable> + } + + let { selectedRunnable = $bindable(), runnables }: Props = $props() function createBackgroundScript() { const nid = getNextId(Object.keys($runnables ?? {})) @@ -30,7 +34,7 @@ - + {#snippet action()}
-
+ {/snippet}
@@ -67,7 +71,7 @@ {selectedRunnable === id ? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50' : 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}" - on:click={() => (selectedRunnable = id)} + onclick={() => (selectedRunnable = id)} > {runnable?.name} {id} diff --git a/frontend/src/lib/components/wizards/NavbarWizard.svelte b/frontend/src/lib/components/wizards/NavbarWizard.svelte index 904bdf5e1e..36d5f44ba7 100644 --- a/frontend/src/lib/components/wizards/NavbarWizard.svelte +++ b/frontend/src/lib/components/wizards/NavbarWizard.svelte @@ -11,9 +11,16 @@ import Alert from '../common/alert/Alert.svelte' import OneOfInputSpecsEditor from '../apps/editor/settingsPanel/OneOfInputSpecsEditor.svelte' - export let value: NavbarItem + interface Props { + value: NavbarItem + trigger?: import('svelte').Snippet + } + + let { value = $bindable(), trigger }: Props = $props() const { selectedComponent } = getContext('AppViewerContext') + + const trigger_render = $derived(trigger) - - - - + {#snippet trigger()} + {@render trigger_render?.()} + {/snippet} + {#snippet content()} {#if value}
{/if} -
+ {/snippet}
diff --git a/frontend/src/lib/components/wizards/TableActionsWizard.svelte b/frontend/src/lib/components/wizards/TableActionsWizard.svelte index 7d1e7f6109..49f2a04f4f 100644 --- a/frontend/src/lib/components/wizards/TableActionsWizard.svelte +++ b/frontend/src/lib/components/wizards/TableActionsWizard.svelte @@ -12,11 +12,23 @@ CheckboxComponent, SelectComponent } from '../apps/editor/component' - export let actionsOrder: RichConfiguration | undefined = undefined - export let selectedId: string | undefined = undefined - export let components: - | (BaseAppComponent & (ButtonComponent | CheckboxComponent | SelectComponent))[] - | undefined + interface Props { + actionsOrder?: RichConfiguration | undefined + selectedId?: string | undefined + components: + | (BaseAppComponent & (ButtonComponent | CheckboxComponent | SelectComponent))[] + | undefined + trigger?: import('svelte').Snippet + } + + let { + actionsOrder = $bindable(undefined), + selectedId = undefined, + components, + trigger + }: Props = $props() + + const trigger_render = $derived(trigger) - - - - + {#snippet trigger()} + {@render trigger_render?.()} + {/snippet} + {#snippet content()}
{#if actionsOrder} @@ -93,5 +105,5 @@
-
+ {/snippet}