Skip to content

Commit b152392

Browse files
committed
fix(workflow): seed structured-output JSON ref and centralize EMPTY_SUBBLOCK_VALUES
- Use null sentinel for prevDataJsonRef and lazily stringify prevDataRef on first compare so the optimization holds on the first stream refresh after mount - Export EMPTY_SUBBLOCK_VALUES from the subblock store; remove three duplicated module constants
1 parent d666844 commit b152392

5 files changed

Lines changed: 15 additions & 13 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/components/api-info-modal.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ import { useDeploymentInfo, useUpdatePublicApi } from '@/hooks/queries/deploymen
2323
import { useUpdateWorkflow, useWorkflowMap } from '@/hooks/queries/workflows'
2424
import { usePermissionConfig } from '@/hooks/use-permission-config'
2525
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
26-
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
26+
import { EMPTY_SUBBLOCK_VALUES, useSubBlockStore } from '@/stores/workflows/subblock/store'
2727
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
2828

2929
type NormalizedField = InputFormatField & { name: string }
3030

31-
const EMPTY_SUBBLOCK_VALUES: Record<string, Record<string, unknown>> = {}
32-
3331
interface ApiInfoModalProps {
3432
open: boolean
3533
onOpenChange: (open: boolean) => void

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,14 @@ import {
2727
type WorkflowMcpServer,
2828
type WorkflowMcpTool,
2929
} from '@/hooks/queries/workflow-mcp-servers'
30-
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
30+
import { EMPTY_SUBBLOCK_VALUES, useSubBlockStore } from '@/stores/workflows/subblock/store'
3131
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
3232

3333
const logger = createLogger('McpToolDeploy')
3434

3535
/** InputFormatField with guaranteed name (after normalization) */
3636
type NormalizedField = InputFormatField & { name: string }
3737

38-
const EMPTY_SUBBLOCK_VALUES: Record<string, Record<string, unknown>> = {}
39-
4038
interface McpDeployProps {
4139
workflowId: string
4240
workflowName: string

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { normalizeName } from '@/executor/constants'
3333
import { useVariablesStore } from '@/stores/variables/store'
3434
import type { Variable } from '@/stores/variables/types'
3535
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
36-
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
36+
import { EMPTY_SUBBLOCK_VALUES, useSubBlockStore } from '@/stores/workflows/subblock/store'
3737
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
3838
import type { BlockState } from '@/stores/workflows/workflow/types'
3939

@@ -167,8 +167,6 @@ const TAG_PREFIXES = {
167167
VARIABLE: 'variable.',
168168
} as const
169169

170-
const EMPTY_SUBBLOCK_VALUES: Record<string, Record<string, unknown>> = {}
171-
172170
/**
173171
* Ensures the root tag is present in the tags array
174172
*/

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/components/output-panel/components/structured-output.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ export const StructuredOutput = memo(function StructuredOutput({
682682
computeInitialPaths(data, isError)
683683
)
684684
const prevDataRef = useRef(data)
685-
const prevDataJsonRef = useRef<string>('')
685+
const prevDataJsonRef = useRef<string | null>(null)
686686
const prevIsErrorRef = useRef(isError)
687687
const internalRef = useRef<HTMLDivElement>(null)
688688
const listRef = useListRef(null)
@@ -723,10 +723,11 @@ export const StructuredOutput = memo(function StructuredOutput({
723723

724724
if (prevDataRef.current !== data) {
725725
const newJson = JSON.stringify(data)
726-
if (prevDataJsonRef.current !== newJson) {
727-
prevDataJsonRef.current = newJson
726+
const prevJson = prevDataJsonRef.current ?? JSON.stringify(prevDataRef.current)
727+
if (prevJson !== newJson) {
728728
setExpandedPaths(computeInitialPaths(data, isError))
729729
}
730+
prevDataJsonRef.current = newJson
730731
prevDataRef.current = data
731732
}
732733
}, [data, isError])

apps/sim/stores/workflows/subblock/store.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@ import { getBlock } from '@/blocks'
66
import type { SubBlockConfig } from '@/blocks/types'
77
import { populateTriggerFieldsFromConfig } from '@/hooks/use-trigger-config-aggregation'
88
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
9-
import type { SubBlockStore } from '@/stores/workflows/subblock/types'
9+
import type { SubBlockStore, SubBlockValue } from '@/stores/workflows/subblock/types'
1010
import { isTriggerValid } from '@/triggers'
1111

1212
const logger = createLogger('SubBlockStore')
1313

14+
/**
15+
* Stable empty fallback for `state.workflowValues[workflowId]` selectors.
16+
* Using a module-level constant avoids returning a fresh `{}` on every
17+
* selector call, which would defeat Zustand's `Object.is` equality.
18+
*/
19+
export const EMPTY_SUBBLOCK_VALUES: Record<string, Record<string, SubBlockValue>> = {}
20+
1421
/**
1522
* SubBlockState stores values for all subblocks in workflows
1623
*

0 commit comments

Comments
 (0)