@@ -155,7 +157,7 @@
default:
break
}
- dispatch('render')
+ dispatchIfMounted('render')
}
function graphBuilder(decisionTreeNodes: DecisionTreeNode[]) {
diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/ColorInput.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/ColorInput.svelte
index 04c8992bef..cb0278853f 100644
--- a/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/ColorInput.svelte
+++ b/frontend/src/lib/components/apps/editor/settingsPanel/inputEditor/ColorInput.svelte
@@ -5,14 +5,16 @@
import { createPopperActions } from 'svelte-popperjs'
import { fade } from 'svelte/transition'
import { zIndexes } from '$lib/zIndexes'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
export let value: string = '#fff'
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
const [popperRef, popperContent] = createPopperActions()
let isOpen = false
let width: number
- $: dispatch('change', value)
+ $: dispatchIfMounted('change', value)
function open() {
isOpen = true
diff --git a/frontend/src/lib/components/apps/svelte-select/lib/Select.svelte b/frontend/src/lib/components/apps/svelte-select/lib/Select.svelte
index 41c69cc00a..09c7123af7 100644
--- a/frontend/src/lib/components/apps/svelte-select/lib/Select.svelte
+++ b/frontend/src/lib/components/apps/svelte-select/lib/Select.svelte
@@ -1,10 +1,11 @@
diff --git a/frontend/src/lib/components/common/menu/ResolveOpen.svelte b/frontend/src/lib/components/common/menu/ResolveOpen.svelte
index a0c356783a..ec32904a3e 100644
--- a/frontend/src/lib/components/common/menu/ResolveOpen.svelte
+++ b/frontend/src/lib/components/common/menu/ResolveOpen.svelte
@@ -1,14 +1,10 @@
diff --git a/frontend/src/lib/components/common/tabs/Tabs.svelte b/frontend/src/lib/components/common/tabs/Tabs.svelte
index d6778d334d..32017b3749 100644
--- a/frontend/src/lib/components/common/tabs/Tabs.svelte
+++ b/frontend/src/lib/components/common/tabs/Tabs.svelte
@@ -11,8 +11,10 @@
import { writable, type Writable } from 'svelte/store'
import { createEventDispatcher } from 'svelte'
import { twMerge } from 'tailwind-merge'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
export let selected: string
export let hideTabs = false
@@ -28,16 +30,7 @@
const selectedStore = writable(selected)
- $: $selectedStore && onSelectedStoreChange()
-
- let initial = true
- function onSelectedStoreChange() {
- if (initial) {
- initial = false
- return
- }
- dispatch('selected', $selectedStore)
- }
+ $: $selectedStore && dispatchIfMounted('selected', $selectedStore)
$: hashValues = values ? values.map((x) => '#' + x) : undefined
setContext('Tabs', {
diff --git a/frontend/src/lib/components/copilot/IteratorGen.svelte b/frontend/src/lib/components/copilot/IteratorGen.svelte
index f8e15fadfa..644e1e7c65 100644
--- a/frontend/src/lib/components/copilot/IteratorGen.svelte
+++ b/frontend/src/lib/components/copilot/IteratorGen.svelte
@@ -14,6 +14,7 @@
import { yamlStringifyExceptKeys } from './utils'
import { copilotInfo, stepInputCompletionEnabled } from '$lib/stores'
import { twMerge } from 'tailwind-merge'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
let generatedContent = ''
let loading = false
@@ -96,6 +97,7 @@ Only output the expression, do not explain or discuss.`
}
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
function automaticGeneration() {
if (empty) {
@@ -125,7 +127,7 @@ Only output the expression, do not explain or discuss.`
generatedContent = ''
}
- $: dispatch('showExpr', generatedContent)
+ $: dispatchIfMounted('showExpr', generatedContent)
let out = true // hack to prevent regenerating answer when accepting the answer due to mouseenter on new icon
diff --git a/frontend/src/lib/components/copilot/MetadataGen.svelte b/frontend/src/lib/components/copilot/MetadataGen.svelte
index c734b37b41..3eaa1d20e3 100644
--- a/frontend/src/lib/components/copilot/MetadataGen.svelte
+++ b/frontend/src/lib/components/copilot/MetadataGen.svelte
@@ -10,6 +10,7 @@
import type { FlowValue } from '$lib/gen'
import { yamlStringifyExceptKeys } from './utils'
import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
type PromptConfig = {
system: string
@@ -151,10 +152,9 @@ Generate a description for the flow below:
}
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
- $: if (content) {
- dispatch('change', { content })
- }
+ $: content && dispatchIfMounted('change', { content })
$: active =
$copilotInfo.enabled &&
diff --git a/frontend/src/lib/components/copilot/StepInputGen.svelte b/frontend/src/lib/components/copilot/StepInputGen.svelte
index f84fe5a3dc..efc995b06b 100644
--- a/frontend/src/lib/components/copilot/StepInputGen.svelte
+++ b/frontend/src/lib/components/copilot/StepInputGen.svelte
@@ -17,6 +17,7 @@
import type { SchemaProperty } from '$lib/common'
import FlowCopilotInputsModal from './FlowCopilotInputsModal.svelte'
import { twMerge } from 'tailwind-merge'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
let generatedContent = ''
let loading = false
@@ -155,6 +156,7 @@ Only return the expression without any wrapper.`
}
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
function cancel() {
abortController.abort()
@@ -184,9 +186,9 @@ Only return the expression without any wrapper.`
automaticGeneration()
}
- $: dispatch('showExpr', generatedContent)
+ $: dispatchIfMounted('showExpr', generatedContent)
- $: dispatch('showExpr', $generatedExprs?.[argName] || '')
+ $: dispatchIfMounted('showExpr', $generatedExprs?.[argName] || '')
let out = true // hack to prevent regenerating answer when accepting the answer due to mouseenter on new icon
let openInputsModal = false
@@ -238,8 +240,8 @@ Only return the expression without any wrapper.`
loading || ($stepInputsLoading && empty)
? Loader2
: generatedContent.length > 0
- ? Check
- : Wand2,
+ ? Check
+ : Wand2,
classes: loading || ($stepInputsLoading && empty) ? 'animate-spin' : ''
}}
on:focus={() => {
diff --git a/frontend/src/lib/components/schema/FlowPropertyEditor.svelte b/frontend/src/lib/components/schema/FlowPropertyEditor.svelte
index 60882e96ff..e975324a42 100644
--- a/frontend/src/lib/components/schema/FlowPropertyEditor.svelte
+++ b/frontend/src/lib/components/schema/FlowPropertyEditor.svelte
@@ -18,6 +18,7 @@
import { Pen, Plus, Trash2 } from 'lucide-svelte'
import Popover from '$lib/components/meltComponents/Popover.svelte'
import { deepEqual } from 'fast-equals'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
export let format: string | undefined = undefined
export let contentEncoding: 'base64' | 'binary' | undefined = undefined
@@ -92,6 +93,7 @@
$: orderUpdate(order)
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
function getResourceTypesFromFormat(format: string | undefined): string[] {
if (format?.startsWith('resource-')) {
@@ -132,7 +134,7 @@
}
}
})
- dispatch('schemaChange', { properties, order, requiredProperty, oneOf })
+ dispatchIfMounted('schemaChange', { properties, order, requiredProperty, oneOf })
}
}
diff --git a/frontend/src/lib/components/schema/PropertyEditor.svelte b/frontend/src/lib/components/schema/PropertyEditor.svelte
index 68e9f32951..9071a64841 100644
--- a/frontend/src/lib/components/schema/PropertyEditor.svelte
+++ b/frontend/src/lib/components/schema/PropertyEditor.svelte
@@ -15,6 +15,7 @@
import ToggleButtonGroup from '../common/toggleButton-v2/ToggleButtonGroup.svelte'
import ToggleButton from '../common/toggleButton-v2/ToggleButton.svelte'
import { createEventDispatcher, onMount } from 'svelte'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
export let description: string = ''
export let format: string | undefined = undefined
@@ -43,6 +44,7 @@
| undefined = undefined
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
let el: HTMLTextAreaElement | undefined = undefined
let oneOfSelected: string | undefined =
@@ -102,7 +104,7 @@
if (!deepEqual(extra, initialExtra)) {
initialExtra = structuredClone(extra)
console.debug('property content updated')
- dispatch('change')
+ dispatchIfMounted('change')
}
}
@@ -115,7 +117,7 @@
order
}
console.debug('property schema updated')
- dispatch('change')
+ dispatchIfMounted('change')
}
}
diff --git a/frontend/src/lib/components/table/DataTable.svelte b/frontend/src/lib/components/table/DataTable.svelte
index 298c0906ea..2452ae44a2 100644
--- a/frontend/src/lib/components/table/DataTable.svelte
+++ b/frontend/src/lib/components/table/DataTable.svelte
@@ -10,6 +10,7 @@
import { ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, Loader2 } from 'lucide-svelte'
import { twMerge } from 'tailwind-merge'
import List from '$lib/components/common/layout/List.svelte'
+ import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
export let paginated: boolean = false
export let currentPage: number = 1
@@ -31,6 +32,7 @@
let footerHeight: number = 0
let tableHeight: number = 0
const dispatch = createEventDispatcher()
+ const dispatchIfMounted = createDispatcherIfMounted(dispatch)
let tableContainer: HTMLDivElement
export let loading = false
export let loadingMore = false
@@ -45,7 +47,7 @@
const hasScrollbar = tableContainer.scrollHeight > tableContainer.clientHeight
if (!hasScrollbar && hasMore) {
- dispatch('loadMore')
+ dispatchIfMounted('loadMore')
}
}
diff --git a/frontend/src/lib/createDispatcherIfMounted.ts b/frontend/src/lib/createDispatcherIfMounted.ts
new file mode 100644
index 0000000000..e1626358dc
--- /dev/null
+++ b/frontend/src/lib/createDispatcherIfMounted.ts
@@ -0,0 +1,19 @@
+import { onMount, type EventDispatcher } from 'svelte'
+
+/**
+ * This wrapper emulates the behavior of an event dispatcher in Svelte 4
+ *
+ * A lot of svelte 4 code depended on events not being picked up when they
+ * were dispatched before being mounted. In svelte 5, these events are
+ * being reacted to which cause infinite loops.
+ */
+export function createDispatcherIfMounted = any>(
+ dispatch: EventDispatcher
+): EventDispatcher {
+ let mounted = false
+ onMount(() => (mounted = true))
+ return ((...args: Parameters) => {
+ if (!mounted) return false
+ return dispatch(...args)
+ }) as any
+}
diff --git a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte
index e8a8f823a4..11fc0732ac 100644
--- a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte
+++ b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte
@@ -199,12 +199,14 @@
tag ||
graph ||
maxTs ||
+ minTs ||
allWorkspaces ||
allowWildcards ||
$workspaceStore) &&
setQuery(false)
$: minTs || setQuery(true)
+ $: maxTs || setQuery(true)
function setQuery(replaceState: boolean) {
let searchParams = new URLSearchParams()
@@ -330,7 +332,7 @@
$page.url.pathname != newUrl.split('?')[0]
) {
// replaceState(newUrl.toString(), $page.state)
- goto(newUrl.toString(), { replaceState: replaceState })
+ goto(newUrl.toString(), { replaceState: replaceState, keepFocus: true })
}
}