fix: debounce sync on subblock and dropdown zustand load

This commit is contained in:
Emir Karabeg
2025-04-01 14:36:58 -07:00
parent 3234a9a85e
commit 25e59ee695
3 changed files with 61 additions and 14 deletions
@@ -1,4 +1,4 @@
import { useEffect, useMemo } from 'react'
import { useMemo } from 'react'
import {
Select,
SelectContent,
@@ -18,22 +18,13 @@ interface DropdownProps {
}
export function Dropdown({ options, defaultValue, blockId, subBlockId }: DropdownProps) {
const [value, setValue] = useSubBlockValue(blockId, subBlockId, true)
const [value, setValue] = useSubBlockValue<string>(blockId, subBlockId, true)
// Evaluate options if it's a function
const evaluatedOptions = useMemo(() => {
return typeof options === 'function' ? options() : options
}, [options])
// Set the value to the first option if it's not set
useEffect(() => {
if (!value && evaluatedOptions.length > 0) {
const firstOption = evaluatedOptions[0]
const firstValue = typeof firstOption === 'string' ? firstOption : firstOption.id
setValue(firstValue)
}
}, [value, evaluatedOptions, defaultValue, setValue])
const getOptionValue = (option: string | { label: string; id: string }) => {
return typeof option === 'string' ? option : option.id
}
@@ -42,11 +33,38 @@ export function Dropdown({ options, defaultValue, blockId, subBlockId }: Dropdow
return typeof option === 'string' ? option : option.label
}
// Calculate the effective value to use in the dropdown
// Priority: 1. Stored value (value) > 2. Provided defaultValue > 3. First option
const effectiveValue = useMemo(() => {
// If we have a value from the store, use that
if (value !== null && value !== undefined) {
return value
}
// Fall back to provided defaultValue
if (defaultValue !== undefined) {
return defaultValue
}
// Last resort: use first option value if available
if (evaluatedOptions.length > 0) {
return getOptionValue(evaluatedOptions[0])
}
// No valid value available
return undefined
}, [value, defaultValue, evaluatedOptions])
// Handle the case where evaluatedOptions changes and the current selection is no longer valid
const isValueInOptions = useMemo(() => {
if (!effectiveValue || evaluatedOptions.length === 0) return false
return evaluatedOptions.some((opt) => getOptionValue(opt) === effectiveValue)
}, [effectiveValue, evaluatedOptions])
return (
<Select
value={value as string | undefined}
defaultValue={defaultValue ?? getOptionValue(evaluatedOptions[0])}
onValueChange={(value) => setValue(value)}
value={isValueInOptions ? effectiveValue : undefined}
onValueChange={(newValue) => setValue(newValue)}
>
<SelectTrigger className="text-left">
<SelectValue placeholder="Select an option" />
@@ -57,6 +57,8 @@ export function useSubBlockValue<T = any>(
? null
: (typeof newValue === 'object' ? JSON.parse(JSON.stringify(newValue)) : newValue)
// Update the subblock store with the new value
// The store's setValue method will now trigger the debounced sync automatically
useSubBlockStore.getState().setValue(blockId, subBlockId, valueCopy)
if (triggerWorkflowUpdate) {
+27
View File
@@ -3,6 +3,11 @@ import { devtools, persist } from 'zustand/middleware'
import { SubBlockConfig } from '@/blocks/types'
import { loadSubblockValues, saveSubblockValues } from '../persistence'
import { useWorkflowRegistry } from '../registry/store'
import { workflowSync } from '../sync'
// Add debounce utility for syncing
let syncDebounceTimer: NodeJS.Timeout | null = null
const DEBOUNCE_DELAY = 500 // 500ms delay for sync
/**
* SubBlockState stores values for all subblocks in workflows
@@ -24,6 +29,8 @@ interface SubBlockStore extends SubBlockState {
getValue: (blockId: string, subBlockId: string) => any
clear: () => void
initializeFromWorkflow: (workflowId: string, blocks: Record<string, any>) => void
// Add debounced sync function
syncWithDB: () => void
}
export const useSubBlockStore = create<SubBlockStore>()(
@@ -52,6 +59,9 @@ export const useSubBlockStore = create<SubBlockStore>()(
// Persist to localStorage for backup
const currentValues = get().workflowValues[activeWorkflowId] || {}
saveSubblockValues(activeWorkflowId, currentValues)
// Trigger debounced sync to DB
get().syncWithDB()
},
getValue: (blockId: string, subBlockId: string) => {
@@ -73,6 +83,9 @@ export const useSubBlockStore = create<SubBlockStore>()(
}))
saveSubblockValues(activeWorkflowId, {})
// Trigger sync to DB immediately on clear
workflowSync.sync()
},
initializeFromWorkflow: (workflowId: string, blocks: Record<string, any>) => {
@@ -108,6 +121,20 @@ export const useSubBlockStore = create<SubBlockStore>()(
// Save to localStorage
saveSubblockValues(workflowId, values)
},
// Debounced sync function to trigger DB sync
syncWithDB: () => {
// Clear any existing timeout
if (syncDebounceTimer) {
clearTimeout(syncDebounceTimer)
}
// Set new timeout
syncDebounceTimer = setTimeout(() => {
// Trigger workflow sync to DB
workflowSync.sync()
}, DEBOUNCE_DELAY)
},
}),
{
name: 'subblock-store',