Skip to content

Commit 66b8434

Browse files
fix(block-name): updating block name should update downstream var refs (#2592)
* fix(block-name): updating block name should update downstream var refs * remove random comments
1 parent 27ec412 commit 66b8434

File tree

3 files changed

+81
-37
lines changed

3 files changed

+81
-37
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,11 @@ export function Editor() {
134134

135135
const trimmedName = editedName.trim()
136136
if (trimmedName && trimmedName !== currentBlock?.name) {
137-
collaborativeUpdateBlockName(currentBlockId, trimmedName)
137+
const result = collaborativeUpdateBlockName(currentBlockId, trimmedName)
138+
if (!result.success) {
139+
// Keep rename mode open on error so user can correct the name
140+
return
141+
}
138142
}
139143
setIsRenaming(false)
140144
}, [currentBlockId, isRenaming, editedName, currentBlock?.name, collaborativeUpdateBlockName])

apps/sim/hooks/use-collaborative-workflow.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ import { TriggerUtils } from '@/lib/workflows/triggers/triggers'
88
import { useSocket } from '@/app/workspace/providers/socket-provider'
99
import { getBlock } from '@/blocks'
1010
import { useUndoRedo } from '@/hooks/use-undo-redo'
11+
import { useNotificationStore } from '@/stores/notifications'
1112
import { registerEmitFunctions, useOperationQueue } from '@/stores/operation-queue/store'
1213
import { usePanelEditorStore } from '@/stores/panel/editor/store'
1314
import { useVariablesStore } from '@/stores/panel/variables/store'
1415
import { useUndoRedoStore } from '@/stores/undo-redo'
1516
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
1617
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
1718
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
18-
import { getUniqueBlockName, mergeSubblockState } from '@/stores/workflows/utils'
19+
import { getUniqueBlockName, mergeSubblockState, normalizeName } from '@/stores/workflows/utils'
1920
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
2021
import type { BlockState, Position } from '@/stores/workflows/workflow/types'
2122

@@ -1016,14 +1017,43 @@ export function useCollaborativeWorkflow() {
10161017
)
10171018

10181019
const collaborativeUpdateBlockName = useCallback(
1019-
(id: string, name: string) => {
1020-
executeQueuedOperation('update-name', 'block', { id, name }, () => {
1021-
const result = workflowStore.updateBlockName(id, name)
1020+
(id: string, name: string): { success: boolean; error?: string } => {
1021+
const trimmedName = name.trim()
1022+
const normalizedNewName = normalizeName(trimmedName)
1023+
1024+
if (!normalizedNewName) {
1025+
logger.error('Cannot rename block to empty name')
1026+
useNotificationStore.getState().addNotification({
1027+
level: 'error',
1028+
message: 'Block name cannot be empty',
1029+
workflowId: activeWorkflowId || undefined,
1030+
})
1031+
return { success: false, error: 'Block name cannot be empty' }
1032+
}
1033+
1034+
const currentBlocks = workflowStore.blocks
1035+
const conflictingBlock = Object.entries(currentBlocks).find(
1036+
([blockId, block]) => blockId !== id && normalizeName(block.name) === normalizedNewName
1037+
)
1038+
1039+
if (conflictingBlock) {
1040+
const conflictName = conflictingBlock[1].name
1041+
logger.error(`Cannot rename block to "${trimmedName}" - conflicts with "${conflictName}"`)
1042+
useNotificationStore.getState().addNotification({
1043+
level: 'error',
1044+
message: `Block name "${trimmedName}" already exists`,
1045+
workflowId: activeWorkflowId || undefined,
1046+
})
1047+
return { success: false, error: `Block name "${trimmedName}" already exists` }
1048+
}
1049+
1050+
executeQueuedOperation('update-name', 'block', { id, name: trimmedName }, () => {
1051+
const result = workflowStore.updateBlockName(id, trimmedName)
10221052

10231053
if (result.success && result.changedSubblocks.length > 0) {
10241054
logger.info('Emitting cascaded subblock updates from block rename', {
10251055
blockId: id,
1026-
newName: name,
1056+
newName: trimmedName,
10271057
updateCount: result.changedSubblocks.length,
10281058
})
10291059

@@ -1043,7 +1073,7 @@ export function useCollaborativeWorkflow() {
10431073
operation: {
10441074
operation: 'subblock-update',
10451075
target: 'subblock',
1046-
payload: { blockId, subBlockId, value: newValue },
1076+
payload: { blockId, subblockId: subBlockId, value: newValue },
10471077
},
10481078
workflowId: activeWorkflowId || '',
10491079
userId: session?.user?.id || 'unknown',
@@ -1052,6 +1082,8 @@ export function useCollaborativeWorkflow() {
10521082
)
10531083
}
10541084
})
1085+
1086+
return { success: true }
10551087
},
10561088
[executeQueuedOperation, workflowStore, addToQueue, activeWorkflowId, session?.user?.id]
10571089
)

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

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -716,54 +716,62 @@ export const useWorkflowStore = create<WorkflowStore>()(
716716
const workflowValues = subBlockStore.workflowValues[activeWorkflowId] || {}
717717
const updatedWorkflowValues = { ...workflowValues }
718718

719+
// Helper function to recursively update references in any data structure
720+
function updateReferences(value: any, regex: RegExp, replacement: string): any {
721+
// Handle string values
722+
if (typeof value === 'string') {
723+
return regex.test(value) ? value.replace(regex, replacement) : value
724+
}
725+
726+
// Handle arrays
727+
if (Array.isArray(value)) {
728+
return value.map((item) => updateReferences(item, regex, replacement))
729+
}
730+
731+
// Handle objects
732+
if (value !== null && typeof value === 'object') {
733+
const result = { ...value }
734+
for (const key in result) {
735+
result[key] = updateReferences(result[key], regex, replacement)
736+
}
737+
return result
738+
}
739+
740+
// Return unchanged for other types
741+
return value
742+
}
743+
744+
const oldBlockName = normalizeName(oldBlock.name)
745+
const newBlockName = normalizeName(name)
746+
const regex = new RegExp(`<${oldBlockName}\\.`, 'g')
747+
719748
// Loop through blocks
720749
Object.entries(workflowValues).forEach(([blockId, blockValues]) => {
721750
if (blockId === id) return // Skip the block being renamed
722751

752+
let blockHasChanges = false
753+
const updatedBlockValues = { ...blockValues }
754+
723755
// Loop through subblocks and update references
724756
Object.entries(blockValues).forEach(([subBlockId, value]) => {
725-
const oldBlockName = normalizeName(oldBlock.name)
726-
const newBlockName = normalizeName(name)
727-
const regex = new RegExp(`<${oldBlockName}\\.`, 'g')
728-
729757
// Use a recursive function to handle all object types
730758
const updatedValue = updateReferences(value, regex, `<${newBlockName}.`)
731759

732760
// Check if the value actually changed
733761
if (JSON.stringify(updatedValue) !== JSON.stringify(value)) {
734-
updatedWorkflowValues[blockId][subBlockId] = updatedValue
762+
updatedBlockValues[subBlockId] = updatedValue
763+
blockHasChanges = true
735764
changedSubblocks.push({
736765
blockId,
737766
subBlockId,
738767
newValue: updatedValue,
739768
})
740769
}
741-
742-
// Helper function to recursively update references in any data structure
743-
function updateReferences(value: any, regex: RegExp, replacement: string): any {
744-
// Handle string values
745-
if (typeof value === 'string') {
746-
return regex.test(value) ? value.replace(regex, replacement) : value
747-
}
748-
749-
// Handle arrays
750-
if (Array.isArray(value)) {
751-
return value.map((item) => updateReferences(item, regex, replacement))
752-
}
753-
754-
// Handle objects
755-
if (value !== null && typeof value === 'object') {
756-
const result = { ...value }
757-
for (const key in result) {
758-
result[key] = updateReferences(result[key], regex, replacement)
759-
}
760-
return result
761-
}
762-
763-
// Return unchanged for other types
764-
return value
765-
}
766770
})
771+
772+
if (blockHasChanges) {
773+
updatedWorkflowValues[blockId] = updatedBlockValues
774+
}
767775
})
768776

769777
// Update the subblock store with the new values

0 commit comments

Comments
 (0)