diff --git a/frontend/BUGS.txt b/frontend/BUGS.txt new file mode 100644 index 0000000000..aae0762777 --- /dev/null +++ b/frontend/BUGS.txt @@ -0,0 +1,39 @@ +# Svelte 5 Migration - Bug Report +# Testing started: 2026-03-02 + +## Warnings (not blocking but worth fixing) + +1. [WARNING] binding_property_non_reactive in Grid.svelte:372:5 + - `bind:this={moveResizes[item.id]}` is binding to a non-reactive property + - File: src/lib/components/apps/svelte-grid/Grid.svelte + - Appears multiple times in App editor + - Status: NOT FIXED (non-blocking warning) + +2. [WARNING] legacy_recursive_reactive_block in RecomputeAllComponents.svelte + - Migrated `$:` reactive block that both accesses and updates the same reactive value + - File: src/lib/components/apps/editor/RecomputeAllComponents.svelte + - May cause recursive updates when converted to $effect + - Status: NOT FIXED (non-blocking warning) + +3. [WARNING] ownership_invalid_mutation in SchemaForm.svelte:70:16 + - Mutating unbound props (`schema`) is strongly discouraged + - Parent: src/lib/components/ApiConnectForm.svelte should use `bind:schema={...}` + - Appears when opening PostgreSQL resource creation form + - Status: NOT FIXED (non-blocking warning) + +4. [WARNING] ownership_invalid_binding in InputTransformSchemaForm.svelte + - Passes `schema` to InputTransformForm.svelte with `bind:`, but parent Pane.svelte didn't declare `schema` as binding + - Appears in flow editor when adding a TypeScript step + - Status: NOT FIXED (non-blocking warning) + +## Bugs + +1. [BUG] state_descriptors_fixed in Chart.svelte (Queue metrics drawer) + - Error: "Property descriptors defined on `$state` objects must contain `value` and always be `enumerable`, `configurable` and `writable`." + - Triggered by: Clicking "Queue metrics" on /workers page + - File: src/lib/components/chartjs-wrappers/Chart.svelte + - Root cause: Chart.js's `listenArrayEvents` calls Object.defineProperty on data arrays that are Svelte 5 $state proxies, which reject non-standard property descriptors + - Fix: Use $state.snapshot() to pass plain copies of data and options to Chart.js + - Status: FIXED + + diff --git a/frontend/src/lib/components/AppConnectDrawer.svelte b/frontend/src/lib/components/AppConnectDrawer.svelte index d8ad4cd389..8156b2c1f4 100644 --- a/frontend/src/lib/components/AppConnectDrawer.svelte +++ b/frontend/src/lib/components/AppConnectDrawer.svelte @@ -1,4 +1,6 @@ @@ -47,7 +54,7 @@ @@ -68,7 +75,7 @@ {/if} {#if isGoogleSignin} - diff --git a/frontend/src/lib/components/Description.svelte b/frontend/src/lib/components/Description.svelte index c3cd74c7d6..2078b74cd2 100644 --- a/frontend/src/lib/components/Description.svelte +++ b/frontend/src/lib/components/Description.svelte @@ -2,11 +2,19 @@ import { ExternalLink } from 'lucide-svelte' import { twMerge } from 'tailwind-merge' - export let link: string | undefined = undefined + + interface Props { + link?: string | undefined; + class?: string; + children?: import('svelte').Snippet; + } + + let { link = undefined, class: className = '', children }: Props = $props(); + -
- +
+ {@render children?.()} {#if link} Learn more initial) + if (untrackedInitial) { + if (untrackedInitial.type == 'script') { + replaceScript(untrackedInitial.script) + } else if (untrackedInitial.type == 'flow') { + replaceFlow(untrackedInitial.flow) } modeInitialized = true } @@ -596,9 +597,9 @@ } }) } - let token = $derived($page.url.searchParams.get('wm_token') ?? undefined) - let workspace = $derived($page.url.searchParams.get('workspace') ?? undefined) - let themeDarkRaw = $derived($page.url.searchParams.get('activeColorTheme')) + let token = $derived(page.url.searchParams.get('wm_token') ?? undefined) + let workspace = $derived(page.url.searchParams.get('workspace') ?? undefined) + let themeDarkRaw = $derived(page.url.searchParams.get('activeColorTheme')) let themeDark = $derived(themeDarkRaw == '2' || themeDarkRaw == '4') $effect.pre(() => { diff --git a/frontend/src/lib/components/DropdownSubmenuItem.svelte b/frontend/src/lib/components/DropdownSubmenuItem.svelte index 45346aaa3c..ed08fd7abd 100644 --- a/frontend/src/lib/components/DropdownSubmenuItem.svelte +++ b/frontend/src/lib/components/DropdownSubmenuItem.svelte @@ -1,4 +1,5 @@ diff --git a/frontend/src/lib/components/DropdownV2.svelte b/frontend/src/lib/components/DropdownV2.svelte index 902de661aa..c6243f3529 100644 --- a/frontend/src/lib/components/DropdownV2.svelte +++ b/frontend/src/lib/components/DropdownV2.svelte @@ -76,7 +76,7 @@ ids: { menu: dropdownId } } = createDropdownMenu({ positioning: { - placement + placement: untrack(() => placement) }, loop: true, onOpenChange: ({ next }) => { diff --git a/frontend/src/lib/components/DurationMs.svelte b/frontend/src/lib/components/DurationMs.svelte index 451925c0c6..60d2964ffe 100644 --- a/frontend/src/lib/components/DurationMs.svelte +++ b/frontend/src/lib/components/DurationMs.svelte @@ -4,9 +4,13 @@ import { Hourglass } from 'lucide-svelte' import WaitTimeWarning from './common/waitTimeWarning/WaitTimeWarning.svelte' - export let duration_ms: number - export let self_wait_time_ms: number | undefined = undefined - export let aggregate_wait_time_ms: number | undefined = undefined + interface Props { + duration_ms: number; + self_wait_time_ms?: number | undefined; + aggregate_wait_time_ms?: number | undefined; + } + + let { duration_ms, self_wait_time_ms = undefined, aggregate_wait_time_ms = undefined }: Props = $props();
diff --git a/frontend/src/lib/components/DynamicInput.svelte b/frontend/src/lib/components/DynamicInput.svelte index bd6cceaf99..692272d50e 100644 --- a/frontend/src/lib/components/DynamicInput.svelte +++ b/frontend/src/lib/components/DynamicInput.svelte @@ -113,10 +113,10 @@ } }) - let lastArgs = $state.snapshot(otherArgs) + let lastArgs = $state.snapshot(untrack(() => otherArgs)) let timeout: number | undefined = $state() - let nargs = $state($state.snapshot(otherArgs)) + let nargs = $state($state.snapshot(untrack(() => otherArgs))) $effect(() => { otherArgs untrack(() => clearTimeout(timeout)) diff --git a/frontend/src/lib/components/EditableSchemaForm.svelte b/frontend/src/lib/components/EditableSchemaForm.svelte index 99fe00bdb0..989ce6a2fe 100644 --- a/frontend/src/lib/components/EditableSchemaForm.svelte +++ b/frontend/src/lib/components/EditableSchemaForm.svelte @@ -286,7 +286,7 @@ } } - let jsonView: boolean = $state(customUi?.jsonOnly == true) + let jsonView: boolean = $state(untrack(() => customUi)?.jsonOnly == true) let schemaString: string = $state(JSON.stringify(schema, null, '\t')) let error: string | undefined = $state(undefined) let editor: SimpleEditor | undefined = $state(undefined) @@ -296,8 +296,8 @@ editor?.setCode(schemaString) } - const editTabDefaultSize = noPreview ? 100 : 50 - editPanelSize = editTab ? (editPanelInitialSize ?? editTabDefaultSize) : 0 + const editTabDefaultSize = untrack(() => noPreview) ? 100 : 50 + editPanelSize = untrack(() => editTab) ? (untrack(() => editPanelInitialSize) ?? editTabDefaultSize) : 0 let inputPanelSize = $state(100 - editPanelSize) let editPanelSizeSmooth = tweened(editPanelSize, { duration: 150 @@ -592,7 +592,7 @@ {argName} {#if !uiOnly}
- + {#snippet trigger()}
@@ -221,7 +224,7 @@
diff --git a/frontend/src/lib/components/FlowInputViewer.svelte b/frontend/src/lib/components/FlowInputViewer.svelte index 94c25ffcc4..62aef2dd37 100644 --- a/frontend/src/lib/components/FlowInputViewer.svelte +++ b/frontend/src/lib/components/FlowInputViewer.svelte @@ -3,7 +3,11 @@ import FieldHeader from './FieldHeader.svelte' - export let schema: Schema | { [key: string]: unknown } | undefined + interface Props { + schema: Schema | { [key: string]: unknown } | undefined; + } + + let { schema }: Props = $props();
    diff --git a/frontend/src/lib/components/FlowLogViewerWrapper.svelte b/frontend/src/lib/components/FlowLogViewerWrapper.svelte index 4549fc8304..648dbc9f06 100644 --- a/frontend/src/lib/components/FlowLogViewerWrapper.svelte +++ b/frontend/src/lib/components/FlowLogViewerWrapper.svelte @@ -62,7 +62,7 @@ const timelineItems = $derived(timelineCompute?.items ?? undefined) const timelineNow = $derived(timelineCompute?.now ?? Date.now()) - let moduleTracker = new ChangeTracker($state.snapshot(job.raw_flow?.modules ?? [])) + let moduleTracker = new ChangeTracker($state.snapshot(untrack(() => job).raw_flow?.modules ?? [])) $effect(() => { readFieldsRecursively(job.raw_flow?.modules ?? []) untrack(() => moduleTracker.track($state.snapshot(job.raw_flow?.modules ?? []))) @@ -123,7 +123,7 @@ } let timelineAvailableWidths = $state>({}) - let lastJobId: string | undefined = $state(job.id) + let lastJobId: string | undefined = $state(untrack(() => job).id) const timelinelWidth = $derived.by(() => { const widths = Object.values(timelineAvailableWidths) diff --git a/frontend/src/lib/components/FlowPlugConnect.svelte b/frontend/src/lib/components/FlowPlugConnect.svelte index da70d882db..cd44f3d1bd 100644 --- a/frontend/src/lib/components/FlowPlugConnect.svelte +++ b/frontend/src/lib/components/FlowPlugConnect.svelte @@ -4,9 +4,13 @@ import AnimatedButton from './common/button/AnimatedButton.svelte' import { twMerge } from 'tailwind-merge' - export let connecting: boolean - export let id: undefined | string = undefined - export let wrapperClasses = '' + interface Props { + connecting: boolean; + id?: undefined | string; + wrapperClasses?: string; + } + + let { connecting, id = undefined, wrapperClasses = '' }: Props = $props(); diff --git a/frontend/src/lib/components/FlowStatusViewer.svelte b/frontend/src/lib/components/FlowStatusViewer.svelte index 5da8b31419..950eb7354f 100644 --- a/frontend/src/lib/components/FlowStatusViewer.svelte +++ b/frontend/src/lib/components/FlowStatusViewer.svelte @@ -62,7 +62,7 @@ showLogsWithResult = false }: Props = $props() - let lastJobId: string = jobId + let lastJobId: string = untrack(() => jobId) let retryStatus = $state({ val: {} }) let globalRefreshes: Record Promise)[]> = $state({}) @@ -71,11 +71,11 @@ flowState, suspendStatus, retryStatus, - hideDownloadInGraph, - hideNodeDefinition, - hideTimeline, - hideJobId, - hideDownloadLogs + hideDownloadInGraph: untrack(() => hideDownloadInGraph), + hideNodeDefinition: untrack(() => hideNodeDefinition), + hideTimeline: untrack(() => hideTimeline), + hideJobId: untrack(() => hideJobId), + hideDownloadLogs: untrack(() => hideDownloadLogs) }) function loadOwner(path: string) { diff --git a/frontend/src/lib/components/FlowStatusViewerInner.svelte b/frontend/src/lib/components/FlowStatusViewerInner.svelte index 410ba822ab..25731f82c8 100644 --- a/frontend/src/lib/components/FlowStatusViewerInner.svelte +++ b/frontend/src/lib/components/FlowStatusViewerInner.svelte @@ -181,7 +181,7 @@ let resultStreams: Record = $state({}) - if (onResultStreamUpdate == undefined) { + if (untrack(() => onResultStreamUpdate) == undefined) { onResultStreamUpdate = ({ jobId, result_stream @@ -234,7 +234,7 @@ }) let jobResults: any[] = $state( - flowJobIds?.flowJobs?.map((x, id) => `iter #${id + 1} not loaded by frontend yet`) ?? [] + untrack(() => flowJobIds)?.flowJobs?.map((x, id) => `iter #${id + 1} not loaded by frontend yet`) ?? [] ) let retry_selected = $state('') @@ -805,7 +805,7 @@ let destroyed = false - updateRecursiveRefresh(jobId) + updateRecursiveRefresh(untrack(() => jobId)) async function updateJobId() { if (jobId !== job?.id || innerModules == undefined) { diff --git a/frontend/src/lib/components/FlowViewer.svelte b/frontend/src/lib/components/FlowViewer.svelte index 8a78637519..2355ddf68d 100644 --- a/frontend/src/lib/components/FlowViewer.svelte +++ b/frontend/src/lib/components/FlowViewer.svelte @@ -1,4 +1,5 @@ {#if tabular} diff --git a/frontend/src/lib/components/GraphqlSchemaViewer.svelte b/frontend/src/lib/components/GraphqlSchemaViewer.svelte index 7929083d9a..1ab4c68f00 100644 --- a/frontend/src/lib/components/GraphqlSchemaViewer.svelte +++ b/frontend/src/lib/components/GraphqlSchemaViewer.svelte @@ -5,10 +5,17 @@ import { onDestroy, onMount } from 'svelte' - let divEl: HTMLDivElement | null = null + let divEl: HTMLDivElement | null = $state(null) let editor: meditor.IStandaloneCodeEditor - export let code: string = '' + + interface Props { + code?: string; + class?: string; + } + + let { code = '', class: className = '' }: Props = $props(); + async function loadMonaco() { editor = meditor.create(divEl as HTMLDivElement, { @@ -43,4 +50,4 @@ }) -
    +
    diff --git a/frontend/src/lib/components/GroupEditor.svelte b/frontend/src/lib/components/GroupEditor.svelte index a8391bd8a6..5a8c4cb411 100644 --- a/frontend/src/lib/components/GroupEditor.svelte +++ b/frontend/src/lib/components/GroupEditor.svelte @@ -159,12 +159,14 @@ {/if} {#if members} - - - user - - - + + {#snippet headerRow()} + + user + + + + {/snippet} {#snippet body()} {#each members ?? [] as { member_name, role }} @@ -301,10 +303,12 @@ {#if instance_group?.emails}

    Members from the instance group

    - - - user - + + {#snippet headerRow()} + + user + + {/snippet} {#snippet body()} {#each instance_group?.emails ?? [] as email} diff --git a/frontend/src/lib/components/IdEditorInput.svelte b/frontend/src/lib/components/IdEditorInput.svelte index 7b85d8e52b..611dbc2d3e 100644 --- a/frontend/src/lib/components/IdEditorInput.svelte +++ b/frontend/src/lib/components/IdEditorInput.svelte @@ -1,4 +1,5 @@ {#if entries.length} diff --git a/frontend/src/lib/components/InstanceGroupEditor.svelte b/frontend/src/lib/components/InstanceGroupEditor.svelte index cf2a3ded0a..f3d8df33de 100644 --- a/frontend/src/lib/components/InstanceGroupEditor.svelte +++ b/frontend/src/lib/components/InstanceGroupEditor.svelte @@ -1,4 +1,6 @@
    @@ -85,17 +91,20 @@
    {#if members} - - user - - - - {#each members as { member_email }} - {member_email} - - - - {/each} - + > + + {/each} + + {/snippet} {:else}
    diff --git a/frontend/src/lib/components/InstanceNameEditor.svelte b/frontend/src/lib/components/InstanceNameEditor.svelte index 31fc3d738b..cb710cddce 100644 --- a/frontend/src/lib/components/InstanceNameEditor.svelte +++ b/frontend/src/lib/components/InstanceNameEditor.svelte @@ -1,4 +1,7 @@
    - +
    + {/snippet} diff --git a/frontend/src/lib/components/PageHeader.svelte b/frontend/src/lib/components/PageHeader.svelte index 07b02227d4..556ac1b0cc 100644 --- a/frontend/src/lib/components/PageHeader.svelte +++ b/frontend/src/lib/components/PageHeader.svelte @@ -1,11 +1,23 @@
    @@ -31,9 +43,9 @@ {/if} - {#if $$slots.default} + {#if children}
    - + {@render children?.()}
    {/if}
    diff --git a/frontend/src/lib/components/ParqetCsvTableRenderer.svelte b/frontend/src/lib/components/ParqetCsvTableRenderer.svelte index 07a8c267a9..262be32363 100644 --- a/frontend/src/lib/components/ParqetCsvTableRenderer.svelte +++ b/frontend/src/lib/components/ParqetCsvTableRenderer.svelte @@ -1,4 +1,6 @@ @@ -182,7 +189,7 @@
    - mountGrid()}> diff --git a/frontend/src/lib/components/PermissionHistory.svelte b/frontend/src/lib/components/PermissionHistory.svelte index 82d646bd53..23f3ec151f 100644 --- a/frontend/src/lib/components/PermissionHistory.svelte +++ b/frontend/src/lib/components/PermissionHistory.svelte @@ -79,12 +79,14 @@

    No permission changes recorded yet

    {:else} - - Changed By - Change Type - Affected - Date - + {#snippet headerRow()} + + Changed By + Change Type + Affected + Date + + {/snippet} {#snippet body()} {#each history as change} diff --git a/frontend/src/lib/components/PersistentScriptDrawer.svelte b/frontend/src/lib/components/PersistentScriptDrawer.svelte index aa5c869f31..23fa122b7d 100644 --- a/frontend/src/lib/components/PersistentScriptDrawer.svelte +++ b/frontend/src/lib/components/PersistentScriptDrawer.svelte @@ -10,19 +10,19 @@ import { Hourglass, Loader2, Play, RefreshCw } from 'lucide-svelte' let dispatch = createEventDispatcher() - let drawer: Drawer + let drawer: Drawer | undefined = $state() - let script: Script - let loadQueuedJobs = true - let queuedJobsLoading = false + let script: Script | undefined = $state() + let loadQueuedJobs = $state(true) + let queuedJobsLoading = $state(false) let queuedJobs: { status: 'running' | 'queued' jobId: string scheduledFor: string scriptHash: string - }[] = [] + }[] = $state([]) - let cancellingInProgress = false + let cancellingInProgress = $state(false) async function continuouslyLoadQueuedJobs() { while (loadQueuedJobs) { @@ -40,7 +40,7 @@ let qjs = await JobService.listQueue({ workspace: $workspaceStore ?? '', orderDesc: false, - scriptPathExact: script.path + scriptPathExact: script?.path }) let loadingQueuedJobs: { status: 'running' | 'queued' @@ -71,12 +71,12 @@ cancellingInProgress = true await JobService.cancelPersistentQueuedJobs({ workspace: $workspaceStore ?? '', - path: script.path, + path: script?.path ?? '', requestBody: { reason: undefined } }) - sendUserToast(`All jobs cancelled for ${script.path}`) + sendUserToast(`All jobs cancelled for ${script?.path}`) cancellingInProgress = false } @@ -88,12 +88,12 @@ script = persistentScript! loadQueuedJobs = true continuouslyLoadQueuedJobs() - drawer.openDrawer?.() + drawer?.openDrawer?.() } async function exit() { loadQueuedJobs = false - drawer.closeDrawer?.() + drawer?.closeDrawer?.() } onDestroy(() => { @@ -117,51 +117,57 @@ >

    - Queued jobs for {script.path} + Queued jobs for {script?.path}

    - - Script Hash - Job ID - Status - Scheduled For - - - {#each queuedJobs as { jobId, status, scriptHash, scheduledFor }} - - - - {scriptHash} - - - - {jobId.substring(24)} - - - {#if status === 'running'} - - - - {:else} - - - - {/if} - - {scheduledFor} - - {/each} - + {#snippet headerRow()} + + Script Hash + Job ID + Status + Scheduled For + + {/snippet} + {#snippet body()} + + {#each queuedJobs as { jobId, status, scriptHash, scheduledFor }} + + + + {scriptHash} + + + + {jobId.substring(24)} + + + {#if status === 'running'} + + + + {:else} + + + + {/if} + + {scheduledFor} + + {/each} + + {/snippet} {#snippet actions()} diff --git a/frontend/src/lib/components/Popover.svelte b/frontend/src/lib/components/Popover.svelte index 1fa0a0d88d..07447b2e4a 100644 --- a/frontend/src/lib/components/Popover.svelte +++ b/frontend/src/lib/components/Popover.svelte @@ -43,10 +43,10 @@ onClick }: Props = $props() - const [popperRef, popperContent] = createPopperActions({ placement }) + const [popperRef, popperContent] = createPopperActions({ placement: untrack(() => placement) }) const popperOptions: PopperOptions<{}> = { - placement, + placement: untrack(() => placement), strategy: 'fixed', modifiers: [ { name: 'offset', options: { offset: [8, 8] } }, diff --git a/frontend/src/lib/components/PrefixedInput.svelte b/frontend/src/lib/components/PrefixedInput.svelte index c548418855..2a1dccf386 100644 --- a/frontend/src/lib/components/PrefixedInput.svelte +++ b/frontend/src/lib/components/PrefixedInput.svelte @@ -1,4 +1,5 @@ diff --git a/frontend/src/lib/components/RadioButton.svelte b/frontend/src/lib/components/RadioButton.svelte index efa9a62b40..c7e5dc8dce 100644 --- a/frontend/src/lib/components/RadioButton.svelte +++ b/frontend/src/lib/components/RadioButton.svelte @@ -1,13 +1,24 @@ @@ -28,7 +39,7 @@ class="sr-only" bind:group={value} aria-labelledby="memory-option-0-label" - on:click={() => dispatch('change', val)} + onclick={() => dispatch('change', val)} />

    {#if typeof label !== 'string'} diff --git a/frontend/src/lib/components/Range.svelte b/frontend/src/lib/components/Range.svelte index 0e92ac72de..72129aada2 100644 --- a/frontend/src/lib/components/Range.svelte +++ b/frontend/src/lib/components/Range.svelte @@ -1,29 +1,47 @@

    - +
    {#if max <= min}
    Impossible to display range: {`max (${max}) <= min (${min})`}
    + import { untrack } from 'svelte' import { GitSyncService } from '$lib/gen' import Select from './select/Select.svelte' @@ -32,7 +33,7 @@ }: Props = $props() // Track all loaded repositories across pages - let loadedRepositories = $state(initialRepositories) + let loadedRepositories = $state(untrack(() => initialRepositories)) let currentPage = $state(1) let isLoadingMore = $state(false) diff --git a/frontend/src/lib/components/Required.svelte b/frontend/src/lib/components/Required.svelte index 2163efa976..3ee1deec1a 100644 --- a/frontend/src/lib/components/Required.svelte +++ b/frontend/src/lib/components/Required.svelte @@ -1,12 +1,19 @@ {#if required} - * + * {:else if detail || detail != ''} - ({detail != '' ? `${detail}` : ''}) {/if} diff --git a/frontend/src/lib/components/ResourceEditor.svelte b/frontend/src/lib/components/ResourceEditor.svelte index 0ffed949d1..70aaf6a2ee 100644 --- a/frontend/src/lib/components/ResourceEditor.svelte +++ b/frontend/src/lib/components/ResourceEditor.svelte @@ -30,7 +30,6 @@ canSave?: boolean resource_type?: string | undefined path?: string - newResource?: boolean hidePath?: boolean onChange?: (args: { path: string; args: Record; description: string }) => void defaultValues?: Record | undefined @@ -40,7 +39,6 @@ canSave = $bindable(true), resource_type = $bindable(undefined), path = $bindable(''), - newResource = false, hidePath = false, onChange, defaultValues = undefined @@ -63,6 +61,7 @@ let resourceTypeInfo: ResourceType | undefined = $state(undefined) let editDescription = $state(false) let viewJsonSchema = $state(false) + let newResource = $derived(!path) const dispatch = createEventDispatcher() @@ -82,7 +81,7 @@ .map(([k, _]) => k) } - if (!newResource) { + if (!untrack(() => newResource)) { initEdit() } else if (resource_type) { loadResourceType() diff --git a/frontend/src/lib/components/ResourceEditorDrawer.svelte b/frontend/src/lib/components/ResourceEditorDrawer.svelte index 50db916f13..dae6943868 100644 --- a/frontend/src/lib/components/ResourceEditorDrawer.svelte +++ b/frontend/src/lib/components/ResourceEditorDrawer.svelte @@ -5,50 +5,44 @@ import { Loader2, Save } from 'lucide-svelte' - let drawer: Drawer - let canSave = true - let resource_type: string | undefined = undefined - let defaultValues: Record | undefined = undefined + let drawer: Drawer | undefined = $state() + let canSave = $state(true) + let resource_type: string | undefined = $state(undefined) + let defaultValues: Record | undefined = $state(undefined) let resourceEditor: { editResource: () => void; createResource: () => void } | undefined = - undefined + $state(undefined) - let path: string | undefined = undefined + let path: string | undefined = $state(undefined) - let newResource = false export async function initEdit(p: string): Promise { resource_type = undefined - newResource = false path = p - drawer.openDrawer?.() + drawer?.openDrawer?.() } export async function initNew( resourceType: string, nDefaultValues?: Record ): Promise { - newResource = true path = undefined resource_type = resourceType defaultValues = nDefaultValues - drawer.openDrawer?.() + drawer?.openDrawer?.() } - let mode: 'edit' | 'new' = newResource ? 'new' : 'edit' - - $: path ? (mode = 'edit') : (mode = 'new') + let mode: 'edit' | 'new' = $derived(!path ? 'new' : 'edit') {#await import('./ResourceEditor.svelte')} {:then Module} diff --git a/frontend/src/lib/components/ResourcePicker.svelte b/frontend/src/lib/components/ResourcePicker.svelte index 6806e60d3c..fddf9205f5 100644 --- a/frontend/src/lib/components/ResourcePicker.svelte +++ b/frontend/src/lib/components/ResourcePicker.svelte @@ -152,7 +152,7 @@ loading = false } - let previousResourceType = resourceType + let previousResourceType = untrack(() => resourceType) $effect(() => { $workspaceStore && resourceType diff --git a/frontend/src/lib/components/RunForm.svelte b/frontend/src/lib/components/RunForm.svelte index 969576a06b..da0c87a15f 100644 --- a/frontend/src/lib/components/RunForm.svelte +++ b/frontend/src/lib/components/RunForm.svelte @@ -15,7 +15,7 @@ import Popover from './meltComponents/Popover.svelte' import { Calendar, Check, CornerDownLeft } from 'lucide-svelte' import RunFormAdvancedPopup from './RunFormAdvancedPopup.svelte' - import { page } from '$app/stores' + import { page } from '$app/state' import { replaceState } from '$app/navigation' import JsonInputs from '$lib/components/JsonInputs.svelte' import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' @@ -108,7 +108,7 @@ nurl.hash = computeSharableHash(args) try { - replaceState(nurl.toString(), $page.state) + replaceState(nurl.toString(), page.state) } catch (e) { console.error(e) } diff --git a/frontend/src/lib/components/RunFormAdvancedPopup.svelte b/frontend/src/lib/components/RunFormAdvancedPopup.svelte index 7d6ef01bb2..399e55f772 100644 --- a/frontend/src/lib/components/RunFormAdvancedPopup.svelte +++ b/frontend/src/lib/components/RunFormAdvancedPopup.svelte @@ -8,7 +8,9 @@ import { WorkerService } from '$lib/gen' import DateTimeInput from './DateTimeInput.svelte' - export let runnable: + + interface Props { + runnable: | { summary?: string description?: string @@ -21,11 +23,18 @@ created_by?: string extra_perms?: Record } - | undefined + | undefined; + scheduledForStr: string | undefined; + invisible_to_owner: boolean | undefined; + overrideTag: string | undefined; + } - export let scheduledForStr: string | undefined - export let invisible_to_owner: boolean | undefined - export let overrideTag: string | undefined + let { + runnable, + scheduledForStr = $bindable(), + invisible_to_owner = $bindable(), + overrideTag = $bindable() + }: Props = $props(); loadWorkerGroups() async function loadWorkerGroups() { diff --git a/frontend/src/lib/components/RunsPage.svelte b/frontend/src/lib/components/RunsPage.svelte index d03495c052..5aee359a4a 100644 --- a/frontend/src/lib/components/RunsPage.svelte +++ b/frontend/src/lib/components/RunsPage.svelte @@ -96,8 +96,8 @@ let batchRerunOptionsIsOpen = $state(false) // Initialize path filter from route param if provided and not already set via query params - if (initialPath && !filters.val.path) { - filters.val.path = initialPath + if (untrack(() => initialPath) && !filters.val.path) { + filters.val.path = untrack(() => initialPath) } // Apply persistent toggle values from local storage if URL doesn't specify them diff --git a/frontend/src/lib/components/S3ObjectPicker.svelte b/frontend/src/lib/components/S3ObjectPicker.svelte index c70983ee83..1c461708cd 100644 --- a/frontend/src/lib/components/S3ObjectPicker.svelte +++ b/frontend/src/lib/components/S3ObjectPicker.svelte @@ -11,15 +11,19 @@ import S3FilePicker from './S3FilePicker.svelte' import FileUpload from './common/fileUpload/FileUpload.svelte' - export let value: any - export let editor: SimpleEditor | undefined = undefined + interface Props { + value: any + editor?: SimpleEditor | undefined + } + + let { value = $bindable(), editor = $bindable(undefined) }: Props = $props() const dispatch = createEventDispatcher() - let s3FilePicker: S3FilePicker - let s3FileUploadRawMode: false + let s3FilePicker: S3FilePicker | undefined = $state() + let s3FileUploadRawMode: boolean | undefined = $state() let el: HTMLTextAreaElement | undefined = undefined - let rawValue: string | undefined = undefined + let rawValue: string | undefined = $state(undefined) function evalValueToRaw() { rawValue = JSON.stringify(value, null, 2) diff --git a/frontend/src/lib/components/SaveInputsButton.svelte b/frontend/src/lib/components/SaveInputsButton.svelte index 414e5ff205..4bddde54ca 100644 --- a/frontend/src/lib/components/SaveInputsButton.svelte +++ b/frontend/src/lib/components/SaveInputsButton.svelte @@ -10,14 +10,25 @@ const dispatch = createEventDispatcher() - export let runnableId: string | undefined - export let runnableType: RunnableType | undefined - export let args: object - export let disabled: boolean = false - export let small: boolean | undefined = undefined - export let showTooltip: boolean | undefined = undefined + interface Props { + runnableId: string | undefined; + runnableType: RunnableType | undefined; + args: object; + disabled?: boolean; + small?: boolean | undefined; + showTooltip?: boolean | undefined; + } - let savingInputs = false + let { + runnableId, + runnableType, + args, + disabled = false, + small = undefined, + showTooltip = undefined + }: Props = $props(); + + let savingInputs = $state(false) async function saveInput(args: object) { savingInputs = true diff --git a/frontend/src/lib/components/SavedInputsPickerViewer.svelte b/frontend/src/lib/components/SavedInputsPickerViewer.svelte index 150e2b9b97..f033bbf4d9 100644 --- a/frontend/src/lib/components/SavedInputsPickerViewer.svelte +++ b/frontend/src/lib/components/SavedInputsPickerViewer.svelte @@ -1,20 +1,34 @@ - + {#snippet trigger({ isOpen })}
    - - {#if isCloudHosted()} - The cloud version is updated daily. - {:else} - How to update?
    - - docker: docker compose up -d
    - - helm - {/if} -
    + {#snippet text()} + + {#if isCloudHosted()} + The cloud version is updated daily. + {:else} + How to update?
    + - docker: docker compose up -d
    + - helm + {/if} + + {/snippet} {/snippet} {#snippet actions()} diff --git a/frontend/src/lib/components/SuperadminSettingsInner.svelte b/frontend/src/lib/components/SuperadminSettingsInner.svelte index 4d6b0e33f1..1f33e768d8 100644 --- a/frontend/src/lib/components/SuperadminSettingsInner.svelte +++ b/frontend/src/lib/components/SuperadminSettingsInner.svelte @@ -8,7 +8,7 @@ import { sendUserToast } from '$lib/toast' import { base } from '$lib/base' import SearchItems from './SearchItems.svelte' - import { page } from '$app/stores' + import { page } from '$app/state' import { goto as gotoUrl } from '$app/navigation' import Version from './Version.svelte' import Uptodate from './Uptodate.svelte' @@ -50,9 +50,9 @@ } = $props() function removeHash() { - const index = $page.url.href.lastIndexOf('#') + const index = page.url.href.lastIndexOf('#') if (index === -1) return - const hashRemoved = $page.url.href.slice(0, index) + const hashRemoved = page.url.href.slice(0, index) gotoUrl(hashRemoved) } diff --git a/frontend/src/lib/components/TableCustom.svelte b/frontend/src/lib/components/TableCustom.svelte index e40a2c9706..a508d48c8f 100644 --- a/frontend/src/lib/components/TableCustom.svelte +++ b/frontend/src/lib/components/TableCustom.svelte @@ -1,37 +1,53 @@ -
    +
    - + {@render headerRow?.()} - + {@render body?.()}
    {#if paginated}
    diff --git a/frontend/src/lib/components/TemplateEditor.svelte b/frontend/src/lib/components/TemplateEditor.svelte index f3ad00ffc3..8046e6ec97 100644 --- a/frontend/src/lib/components/TemplateEditor.svelte +++ b/frontend/src/lib/components/TemplateEditor.svelte @@ -412,7 +412,7 @@ const lang = 'template' const dispatch = createEventDispatcher() - const uri = `file:///${hash}.ts` + const uri = `file:///${untrack(() => hash)}.ts` export function insertAtCursor(code: string): void { if (editor) { diff --git a/frontend/src/lib/components/TestConnection.svelte b/frontend/src/lib/components/TestConnection.svelte index 576bbc9334..7c59a2a324 100644 --- a/frontend/src/lib/components/TestConnection.svelte +++ b/frontend/src/lib/components/TestConnection.svelte @@ -7,10 +7,19 @@ import { workspaceStore } from '$lib/stores' import { tryEvery } from '$lib/utils' - export let workspaceOverride: string | undefined = undefined - export let resourceType: string | undefined - export let args: Record | any = {} - export let buttonTextOverride: string | undefined = undefined + interface Props { + workspaceOverride?: string | undefined; + resourceType: string | undefined; + args?: Record | any; + buttonTextOverride?: string | undefined; + } + + let { + workspaceOverride = undefined, + resourceType, + args = {}, + buttonTextOverride = undefined + }: Props = $props(); const scripts: { [key: string]: { @@ -166,7 +175,7 @@ export async function main(bucket: any) { } } - let loading = false + let loading = $state(false) async function testConnection() { if (!resourceType) return loading = true diff --git a/frontend/src/lib/components/Toast.svelte b/frontend/src/lib/components/Toast.svelte index 13e857ed6f..034887235e 100644 --- a/frontend/src/lib/components/Toast.svelte +++ b/frontend/src/lib/components/Toast.svelte @@ -82,14 +82,14 @@ } }) - let color = classes[type] + let color = classes[untrack(() => type)] let containerClass = { success: 'toast-success', error: 'toast-error', info: 'toast-info', warning: 'toast-warning' - }[type] + }[untrack(() => type)] let Icon = $derived(icons[type]) diff --git a/frontend/src/lib/components/Toggle.svelte b/frontend/src/lib/components/Toggle.svelte index 6b502bcbfa..4ae37d325f 100644 --- a/frontend/src/lib/components/Toggle.svelte +++ b/frontend/src/lib/components/Toggle.svelte @@ -3,7 +3,7 @@ const bubble = createBubbler() import { classNames } from '$lib/utils' - import { createEventDispatcher } from 'svelte' + import { createEventDispatcher, untrack } from 'svelte' import { twMerge } from 'tailwind-merge' import Tooltip from './Tooltip.svelte' import { AlertTriangle } from 'lucide-svelte' @@ -54,7 +54,7 @@ }: Props = $props() const dispatch = createEventDispatcher<{ change: boolean }>() - const bothOptions = Boolean(options.left) && Boolean(options.right) + const bothOptions = Boolean(untrack(() => options).left) && Boolean(untrack(() => options).right)
    {/if} +
    diff --git a/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte b/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte index e5307b4d15..0ab7b2795c 100644 --- a/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte +++ b/frontend/src/lib/components/apps/components/display/ResolveNavbarItemPath.svelte @@ -1,4 +1,5 @@ {#each Object.keys(components['checkboxcomponent'].initialData.configuration) as key (key)} diff --git a/frontend/src/lib/components/apps/components/inputs/AppCodeInputComponent.svelte b/frontend/src/lib/components/apps/components/inputs/AppCodeInputComponent.svelte index 9566f39866..62eedc3fc6 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppCodeInputComponent.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppCodeInputComponent.svelte @@ -1,5 +1,5 @@ diff --git a/frontend/src/lib/components/apps/components/layout/AppDecisionTree.svelte b/frontend/src/lib/components/apps/components/layout/AppDecisionTree.svelte index d42fdc3ba5..62b785c486 100644 --- a/frontend/src/lib/components/apps/components/layout/AppDecisionTree.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppDecisionTree.svelte @@ -51,7 +51,7 @@ untrack(() => (counter += 1)) }) - let everRender = $state(render) + let everRender = $state(untrack(() => render)) $effect.pre(() => { render && !everRender && (everRender = true) }) @@ -66,11 +66,11 @@ debuggingComponents } = getContext('AppViewerContext') - let css = $state(initCss($app.css?.conditionalwrapper, customCss)) + let css = $state(initCss($app.css?.conditionalwrapper, untrack(() => customCss))) let selectedConditionIndex = 0 - let currentNodeId = $state(getFirstNode(nodes)?.id ?? '') + let currentNodeId = $state(getFirstNode(untrack(() => nodes))?.id ?? '') - let outputs = initOutput($worldStore, id, { + let outputs = initOutput($worldStore, untrack(() => id), { currentNodeId: untrack(() => currentNodeId), currentNodeIndex: selectedConditionIndex }) @@ -154,7 +154,7 @@ } } - $componentControl[id] = { + $componentControl[untrack(() => id)] = { setTab: (conditionIndex: number) => { if (conditionIndex !== -1) { onFocus(conditionIndex) diff --git a/frontend/src/lib/components/apps/components/layout/AppDivider.svelte b/frontend/src/lib/components/apps/components/layout/AppDivider.svelte index 97a698dd60..af68c3ad55 100644 --- a/frontend/src/lib/components/apps/components/layout/AppDivider.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppDivider.svelte @@ -1,5 +1,5 @@ {#each Object.keys(components['drawercomponent'].initialData.configuration) as key (key)} @@ -162,6 +162,7 @@ }} fullScreen={$mode !== 'dnd'} > +
    - import { getContext } from 'svelte' + import { getContext, untrack } from 'svelte' import { initConfig, initOutput } from '../../editor/appUtils' import SubGridEditor from '../../editor/SubGridEditor.svelte' import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types' @@ -37,12 +37,12 @@ getContext('AppViewerContext') let page = $state(0) - let everRender = $state(render) + let everRender = $state(untrack(() => render)) $effect.pre(() => { render && !everRender && (everRender = true) }) - const outputs = initOutput($worldStore, id, { + const outputs = initOutput($worldStore, untrack(() => id), { result: undefined, loading: false, inputs: {}, @@ -50,7 +50,7 @@ }) let resolvedConfig = $state( - initConfig(components['listcomponent'].initialData.configuration, configuration) + initConfig(components['listcomponent'].initialData.configuration, untrack(() => configuration)) ) function onFocus() { @@ -60,7 +60,7 @@ } } - let css = $state(initCss($app.css?.listcomponent, customCss)) + let css = $state(initCss($app.css?.listcomponent, untrack(() => customCss))) let result: any[] | undefined = $state(undefined) let isCard = $derived(resolvedConfig.width?.selected == 'card') diff --git a/frontend/src/lib/components/apps/components/layout/AppModal.svelte b/frontend/src/lib/components/apps/components/layout/AppModal.svelte index 6232b667fd..9508303630 100644 --- a/frontend/src/lib/components/apps/components/layout/AppModal.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppModal.svelte @@ -1,7 +1,7 @@ diff --git a/frontend/src/lib/components/apps/editor/AppJsonEditor.svelte b/frontend/src/lib/components/apps/editor/AppJsonEditor.svelte index 7572c8c0fe..5a955a8ce6 100644 --- a/frontend/src/lib/components/apps/editor/AppJsonEditor.svelte +++ b/frontend/src/lib/components/apps/editor/AppJsonEditor.svelte @@ -10,12 +10,12 @@ import { createEventDispatcher } from 'svelte' import { Globe, Loader2, Save } from 'lucide-svelte' - let jsonViewerDrawer: Drawer + let jsonViewerDrawer: Drawer | undefined = $state() - let code: string = '' + let code: string = $state('') let path: string = '' - let useDraft: boolean = false - let loading = true + let useDraft: boolean = $state(false) + let loading = $state(true) const dispatch = createEventDispatcher() let app: any | undefined = undefined @@ -73,7 +73,7 @@ - jsonViewerDrawer.toggleDrawer()}> + jsonViewerDrawer?.toggleDrawer()}> {#if useDraft}
    +Draft diff --git a/frontend/src/lib/components/apps/editor/AppPreview.svelte b/frontend/src/lib/components/apps/editor/AppPreview.svelte index 02114e1210..67c7ef4313 100644 --- a/frontend/src/lib/components/apps/editor/AppPreview.svelte +++ b/frontend/src/lib/components/apps/editor/AppPreview.svelte @@ -59,9 +59,9 @@ gotoFn = (path: string, opt?: Record) => window.history.pushState(null, '', path) }: Props = $props() - migrateApp(app) + migrateApp(untrack(() => app)) - const appStore = writable(app) + const appStore = writable(untrack(() => app)) const selectedComponent = writable(undefined) const mode = writable('preview') @@ -74,11 +74,11 @@ const allIdsInPath = writable([]) let ncontext: any = { - ...context, - workspace, + ...untrack(() => context), + workspace: untrack(() => workspace), mode: 'viewer', - summary: summary, - author: policy.on_behalf_of_email + summary: untrack(() => summary), + author: untrack(() => policy).on_behalf_of_email } function resizeWindow() { @@ -90,7 +90,7 @@ const parentWidth = writable(0) let previousDarkMode = document.documentElement.classList.contains('dark') - const darkMode: Writable = writable(app?.darkMode ?? previousDarkMode) + const darkMode: Writable = writable(untrack(() => app)?.darkMode ?? previousDarkMode) onDestroy(() => { setTheme(previousDarkMode) @@ -132,7 +132,7 @@ }) } - let writablePath = writable(appPath) + let writablePath = writable(untrack(() => appPath)) function onPathChange() { writablePath.set(appPath) @@ -146,21 +146,21 @@ runnableInitialized: {} }), app: appStore, - summary: writable(summary), + summary: writable(untrack(() => summary)), selectedComponent, bgRuns: writable([]), mode, connectingInput, - breakpoint, + breakpoint: untrack(() => breakpoint), runnableComponents: writable({}), appPath: writablePath, - workspace, + workspace: untrack(() => workspace), onchange: undefined, - isEditor, + isEditor: untrack(() => isEditor), jobs: parentContext?.jobs ?? writable([]), jobsById: parentContext?.jobsById ?? writable({}), staticExporter: writable({}), - noBackend, + noBackend: untrack(() => noBackend), errorByComponent: writable({}), openDebugRun: writable(undefined), focusedGrid: writable(undefined), @@ -174,9 +174,9 @@ cssEditorOpen: writable(false), previewTheme: writable(undefined), debuggingComponents: writable({}), - replaceStateFn, - gotoFn, - policy, + replaceStateFn: untrack(() => replaceStateFn), + gotoFn: untrack(() => gotoFn), + policy: untrack(() => policy), recomputeAllContext: writable({ loading: false, componentNumber: 0, @@ -319,6 +319,7 @@ {#snippet children({ dataItem })} +
    ($selectedComponent = [dataItem.id])} diff --git a/frontend/src/lib/components/apps/editor/ComponentHeader.svelte b/frontend/src/lib/components/apps/editor/ComponentHeader.svelte index e717205670..28d8e5912a 100644 --- a/frontend/src/lib/components/apps/editor/ComponentHeader.svelte +++ b/frontend/src/lib/components/apps/editor/ComponentHeader.svelte @@ -297,7 +297,7 @@ 'text-red-500 px-1 text-2xs py-0.5 font-bold w-fit absolute border border-red-500 -bottom-1 shadow left-1/2 transform -translate-x-1/2 z-50 cursor-pointer' )} > - + {#snippet trigger()} {/snippet} diff --git a/frontend/src/lib/components/apps/editor/DecisionTreeDebug.svelte b/frontend/src/lib/components/apps/editor/DecisionTreeDebug.svelte index bf70dafd61..c5452be83e 100644 --- a/frontend/src/lib/components/apps/editor/DecisionTreeDebug.svelte +++ b/frontend/src/lib/components/apps/editor/DecisionTreeDebug.svelte @@ -4,7 +4,7 @@ const bubble = createBubbler() import Dropdown from '$lib/components/DropdownV2.svelte' import { classNames } from '$lib/utils' - import { createEventDispatcher, getContext } from 'svelte' + import { createEventDispatcher, getContext, untrack } from 'svelte' import type { AppViewerContext } from '../types' import type { DecisionTreeNode } from './component' import { isDebugging } from './settingsPanel/decisionTree/utils' @@ -27,7 +27,7 @@ getContext('AppViewerContext') const dispatch = createEventDispatcher() - let currentNodeId: string = $state($worldStore.outputsById[id]?.currentNodeId?.peak() ?? 'a') + let currentNodeId: string = $state($worldStore.outputsById[untrack(() => id)]?.currentNodeId?.peak() ?? 'a') function subscribeToCurrentNode(id: string) { return $worldStore.outputsById[id]?.currentNodeId?.subscribe( @@ -41,7 +41,7 @@ ) } - let subscription = subscribeToCurrentNode(id) + let subscription = subscribeToCurrentNode(untrack(() => id)) function onDebugNode(debuggedNodeIndex: number | undefined) { if (debuggedNodeIndex === undefined) { @@ -63,7 +63,7 @@ }) let renderCount: number = $state(0) - let lastNodes: DecisionTreeNode[] = nodes + let lastNodes: DecisionTreeNode[] = untrack(() => nodes) function onNodesChange(newNodes: DecisionTreeNode[]) { if (JSON.stringify(newNodes) !== JSON.stringify(lastNodes)) { diff --git a/frontend/src/lib/components/apps/editor/GridEditor.svelte b/frontend/src/lib/components/apps/editor/GridEditor.svelte index d412bc1c56..d787564c0c 100644 --- a/frontend/src/lib/components/apps/editor/GridEditor.svelte +++ b/frontend/src/lib/components/apps/editor/GridEditor.svelte @@ -184,6 +184,7 @@
    +
    rowHeight) let containerHeight = $derived(getContainerHeight(items, yPerPx, getComputedCols)) @@ -71,7 +71,7 @@ yPerPx, width: containerWidth }) - }, throttleUpdate) + }, untrack(() => throttleUpdate)) onMount(() => { setTimeout(() => { diff --git a/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte b/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte index 687262cf36..e00a128bf4 100644 --- a/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte +++ b/frontend/src/lib/components/apps/editor/RecomputeAllComponents.svelte @@ -1,4 +1,6 @@ (isActive = x)) - let everVisible = $state(visible) + let everVisible = $state(untrack(() => visible)) $effect.pre(() => { visible && !everVisible && (everVisible = true) @@ -199,6 +199,7 @@ {#if everVisible || $app.eagerRendering} +
    - import { getContext } from 'svelte' + import { getContext, untrack } from 'svelte' import ComponentInner from './ComponentInner.svelte' import ComponentRendered from './ComponentRendered.svelte' import type { AppComponent } from './components' @@ -25,7 +25,7 @@ overlapped = undefined, componentDraggedId = undefined }: Props = $props() - let everRender = $state(render) + let everRender = $state(untrack(() => render)) $effect(() => { render && !everRender && (everRender = true) diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte index c50b0ad656..2971a52654 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte @@ -76,7 +76,7 @@ entries.sort((a, b) => (b.order ?? 0) - (a.order ?? 0) + a.name.localeCompare(b.name)) - let search = '' + let search = $state('')
    @@ -98,12 +98,15 @@ } }} > -
    - - - {name} - -
    + {#snippet titleSlot()} + {@const SvelteComponent = icon} +
    + + + {name} + +
    + {/snippet} {#if description}
    {description}
    {/if} diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/CustomComponentsList.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/CustomComponentsList.svelte index 7460c30de9..3f65904c77 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/CustomComponentsList.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/CustomComponentsList.svelte @@ -15,9 +15,9 @@ let customcomponents: Array<{ name: string path: string - }> = [] + }> = $state([]) - let loading: boolean = false + let loading: boolean = $state(false) async function getCustomComponents() { loading = true @@ -44,7 +44,7 @@ } }, name: nameField, - js: await files[0].text() + js: await files?.[0]?.text?.() } } }) @@ -61,10 +61,10 @@ nameField = '' } - let nameField: string = '' - let reactVersion: string = '18.2.0' - let files: FileList - let useReact = true + let nameField: string = $state('') + let reactVersion: string = $state('18.2.0') + let files: FileList | undefined = $state() + let useReact = $state(true) getCustomComponents() diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/NameEditor.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/NameEditor.svelte index 6263bc8026..f4d8c40f72 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/NameEditor.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/NameEditor.svelte @@ -2,7 +2,7 @@ import Button from '$lib/components/common/button/Button.svelte' import Popover from '$lib/components/meltComponents/Popover.svelte' import { Pen } from 'lucide-svelte' - import { createEventDispatcher } from 'svelte' + import { createEventDispatcher, untrack } from 'svelte' interface Props { kind: string @@ -14,7 +14,7 @@ let { kind, row }: Props = $props() - let editedName = $state(row.name) + let editedName = $state(untrack(() => row).name) const dispatch = createEventDispatcher() function onkeydown(e) { diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte index cf5bda33c7..676c59c12d 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleMenu.svelte @@ -30,7 +30,7 @@ componentProperty = undefined }: Props = $props() const { app } = getContext('AppViewerContext') - const styleStore = createStyleStore(properties) + const styleStore = createStyleStore(untrack(() => properties)) setContext(STYLE_STORE_KEY, styleStore) let multiValues: Record = $state(initiateMultiValues()) @@ -210,12 +210,11 @@ toggleClasses=" !rounded-b-none !py-0 {isOpen[prefix] ? '!bg-surface-secondary hover:!bg-surface-hover' : ''}" > - - + {#snippet titleSlot()} {group} - + {/snippet}
    {#each property[group] as p} {@const { diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleProperty.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleProperty.svelte index b4efdb87d4..54d9da3a33 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleProperty.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/QuickStyleProperty.svelte @@ -1,5 +1,5 @@ diff --git a/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte index 579b769801..3c1a63ad81 100644 --- a/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte +++ b/frontend/src/lib/components/apps/editor/contextPanel/ComponentOutput.svelte @@ -1,6 +1,6 @@
    diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentControl.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentControl.svelte index 9b9d1f3563..992c52de83 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentControl.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentControl.svelte @@ -1,4 +1,5 @@ diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ContextVariables.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ContextVariables.svelte index 6fb7b7be9b..be54285d84 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ContextVariables.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ContextVariables.svelte @@ -1,7 +1,7 @@
    - - - - - + {#snippet selectedTitle()} + + + + + {/snippet} {/if} diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/mainInput/RunnableSelector.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/mainInput/RunnableSelector.svelte index af6f20e510..23419e51be 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/mainInput/RunnableSelector.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/mainInput/RunnableSelector.svelte @@ -6,7 +6,7 @@ import type { InlineScript, Runnable, StaticAppInput } from '$lib/components/apps/inputType' import WorkspaceScriptList from './WorkspaceScriptList.svelte' import WorkspaceFlowList from './WorkspaceFlowList.svelte' - import { createEventDispatcher } from 'svelte' + import { createEventDispatcher, untrack } from 'svelte' import type { Schema } from '$lib/common' import { schemaToInputsSpec } from '$lib/components/apps/utils' import { defaultIfEmptyString, emptySchema } from '$lib/utils' @@ -34,7 +34,7 @@ // const { app, workspace } = getContext('AppViewerContext') let tab: TabType = $state( - onlyFlow + untrack(() => onlyFlow) ? 'workspaceflows' : unusedInlineScripts?.length > 0 ? 'inlinescripts' diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/secondaryMenu/SecondaryMenu.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/secondaryMenu/SecondaryMenu.svelte index 877c48bf35..915e66e4db 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/secondaryMenu/SecondaryMenu.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/secondaryMenu/SecondaryMenu.svelte @@ -1,4 +1,5 @@ diff --git a/frontend/src/lib/components/apps/svelte-grid/Grid.svelte b/frontend/src/lib/components/apps/svelte-grid/Grid.svelte index 4ffb2414ee..fd61edce4f 100644 --- a/frontend/src/lib/components/apps/svelte-grid/Grid.svelte +++ b/frontend/src/lib/components/apps/svelte-grid/Grid.svelte @@ -16,7 +16,7 @@ import { getContainerHeight } from './utils/container' import { moveItem, getItemById, specifyUndefinedColumns } from './utils/item' - import { onMount, getContext } from 'svelte' + import { onMount, getContext, untrack } from 'svelte' import { getColumn, throttle } from './utils/other' import MoveResize from './MoveResize.svelte' import type { FilledItem } from './types' @@ -97,7 +97,7 @@ let container = $state() let xPerPx = $state(0) - let yPerPx = rowHeight + let yPerPx = untrack(() => rowHeight) const onResizeThrottled = throttle(() => { if (!getComputedCols) return @@ -108,7 +108,7 @@ yPerPx, width: containerWidth }) - }, throttleUpdate) + }, untrack(() => throttleUpdate)) let mounted = $state(false) @@ -261,7 +261,7 @@ } } - const throttleMatrix = throttle(updateMatrix, throttleResize) + const throttleMatrix = throttle(updateMatrix, untrack(() => throttleResize)) //let hiddenComponents = writable({}) diff --git a/frontend/src/lib/components/apps/svelte-grid/MoveResize.svelte b/frontend/src/lib/components/apps/svelte-grid/MoveResize.svelte index 033a1a016c..d138023eed 100644 --- a/frontend/src/lib/components/apps/svelte-grid/MoveResize.svelte +++ b/frontend/src/lib/components/apps/svelte-grid/MoveResize.svelte @@ -1,5 +1,5 @@ @@ -41,29 +42,33 @@ {/if} {#if (asset.kind === 'resource' && resourceDataCacheValue === undefined) || ducklakeNotFound || datatableNotFound} - - - {:else if datatableNotFound} - - {:else if asset.kind === 'resource' && resourceDataCacheValue === undefined} - - {/if} - + {#snippet trigger()} + + + {:else if datatableNotFound} + + {:else if asset.kind === 'resource' && resourceDataCacheValue === undefined} + + {/if} + + {/snippet} {:else if assetCanBeExplored(asset, { resource_type: resourceDataCacheValue })} {@render badge()} - - {accessType2} access to column "{columnName}" - + {#snippet text()} + + {accessType2} access to column "{columnName}" + + {/snippet} {/if} {/each} diff --git a/frontend/src/lib/components/assets/AssetsDropdownButton.svelte b/frontend/src/lib/components/assets/AssetsDropdownButton.svelte index 5c530cf606..351ee68331 100644 --- a/frontend/src/lib/components/assets/AssetsDropdownButton.svelte +++ b/frontend/src/lib/components/assets/AssetsDropdownButton.svelte @@ -102,7 +102,7 @@ bind:isOpen escapeBehavior="ignore" > - + {#snippet trigger()}
    -
    - + {/snippet} + {#snippet content()}
      {#each assets as asset} {@const ducklakeNotFound = @@ -144,7 +144,7 @@ contentClasses="py-2 px-4 flex flex-col gap-2" disablePopup={!!asset.access_type} > - + {#snippet trigger()}
      {formatAssetAccessType(getAccessType(asset)) ?? '?'}
      -
      - + {/snippet} + {#snippet content()} {#if !asset.access_type} Could not infer automatically
      @@ -180,14 +180,14 @@
    {/if} - + {/snippet}
    {asset.path} - + {#snippet text()} {asset.path} - + {/snippet} {liSubtitle?.(asset) ?? @@ -216,7 +216,7 @@ {/each}
- + {/snippet} diff --git a/frontend/src/lib/components/assets/AssetsUsageDrawer.svelte b/frontend/src/lib/components/assets/AssetsUsageDrawer.svelte index 177032341b..16effb700a 100644 --- a/frontend/src/lib/components/assets/AssetsUsageDrawer.svelte +++ b/frontend/src/lib/components/assets/AssetsUsageDrawer.svelte @@ -71,11 +71,13 @@
{text}
- - {#if tooltip} - {tooltip} - {/if} - + {#snippet text()} + + {#if tooltip} + {tooltip} + {/if} + + {/snippet} {/if} {/snippet} diff --git a/frontend/src/lib/components/assets/VolumesDrawer.svelte b/frontend/src/lib/components/assets/VolumesDrawer.svelte index bd00dd0dba..06d4f9529a 100644 --- a/frontend/src/lib/components/assets/VolumesDrawer.svelte +++ b/frontend/src/lib/components/assets/VolumesDrawer.svelte @@ -52,10 +52,7 @@ refreshKey++ } - function canReadVolume( - createdBy: string, - extraPerms?: { [key: string]: unknown } - ): boolean { + function canReadVolume(createdBy: string, extraPerms?: { [key: string]: unknown }): boolean { if ($userStore?.is_admin) return true const username = $userStore?.username if (username === createdBy || `u/${username}` === createdBy) return true @@ -67,10 +64,7 @@ return pgroups.some((g) => g in perms) } - function canWriteVolume( - createdBy: string, - extraPerms?: { [key: string]: unknown } - ): boolean { + function canWriteVolume(createdBy: string, extraPerms?: { [key: string]: unknown }): boolean { if ($userStore?.is_admin) return true const username = $userStore?.username if (username === createdBy || `u/${username}` === createdBy) return true @@ -83,10 +77,7 @@ (open = false)}> (open = false)}> {#snippet actions()} - + {#snippet trigger()} - Volumes are limited to 20 per workspace and 50 MB per file. Upgrade to Enterprise - Edition to remove these limits. + Volumes are limited to 20 per workspace and 50 MB per file. Upgrade to Enterprise Edition + to remove these limits.
{/if} @@ -133,7 +124,8 @@
{:else if !volumes.current?.length}
- No volumes yet. Create one above or they are auto-created when a job declares a volume annotation. + No volumes yet. Create one above or they are auto-created when a job declares a volume + annotation.
{:else}
@@ -151,7 +143,8 @@ />
- {vol.file_count} {vol.file_count === 1 ? 'file' : 'files'} + {vol.file_count} + {vol.file_count === 1 ? 'file' : 'files'} · {displaySize(vol.size_bytes) ?? '0 B'} · owner: {vol.created_by.replace(/^u\//, '')} @@ -167,8 +160,7 @@ iconOnly unifiedSize="sm" endIcon={{ icon: Shield }} - on:click={() => - shareModal?.openDrawer(vol.name, 'volume', true)} + on:click={() => shareModal?.openDrawer(vol.name, 'volume', true)} /> {/if} {#if onExplore && readable} diff --git a/frontend/src/lib/components/chartjs-wrappers/Chart.svelte b/frontend/src/lib/components/chartjs-wrappers/Chart.svelte index 9fdacd47de..66739a7859 100644 --- a/frontend/src/lib/components/chartjs-wrappers/Chart.svelte +++ b/frontend/src/lib/components/chartjs-wrappers/Chart.svelte @@ -27,8 +27,8 @@ untrack(() => { chart = new Chart(canvasElem, { type, - data, - options + data: $state.snapshot(data) as typeof data, + options: $state.snapshot(options) as typeof options }) }) return () => { @@ -37,10 +37,10 @@ }) $effect(() => { - chart + data untrack(() => { if (chart) { - chart.data = data + chart.data = $state.snapshot(data) as typeof data chart.update() } }) diff --git a/frontend/src/lib/components/common/FileProgressBar.svelte b/frontend/src/lib/components/common/FileProgressBar.svelte index d339d9477f..5cb864981b 100644 --- a/frontend/src/lib/components/common/FileProgressBar.svelte +++ b/frontend/src/lib/components/common/FileProgressBar.svelte @@ -1,23 +1,38 @@ {#key color}
{#if ended} - + {@render children?.()} {:else}
- export let notificationCount = 0 - export let notificationLimit: number | undefined = undefined + interface Props { + notificationCount?: number; + notificationLimit?: number | undefined; + } + + let { notificationCount = 0, notificationLimit = undefined }: Props = $props(); {#if notificationCount > 0} diff --git a/frontend/src/lib/components/common/button/AnimatedButton.svelte b/frontend/src/lib/components/common/button/AnimatedButton.svelte index 7248b891dc..3ceb0ebd4c 100644 --- a/frontend/src/lib/components/common/button/AnimatedButton.svelte +++ b/frontend/src/lib/components/common/button/AnimatedButton.svelte @@ -1,12 +1,26 @@ {#if animate} @@ -19,10 +33,10 @@ {ringColor} {darkMode} > - + {@render children?.()} {:else}
- + {@render children?.()}
{/if} diff --git a/frontend/src/lib/components/common/button/AnimatedButtonInner.svelte b/frontend/src/lib/components/common/button/AnimatedButtonInner.svelte index 7396b5314b..9ba46928a0 100644 --- a/frontend/src/lib/components/common/button/AnimatedButtonInner.svelte +++ b/frontend/src/lib/components/common/button/AnimatedButtonInner.svelte @@ -1,27 +1,41 @@ @@ -33,7 +47,7 @@ bind:clientWidth bind:clientHeight > - + {@render children?.()}