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
This commit is contained in:
Vikhyath Mondreti
2025-12-26 12:56:02 -08:00
committed by GitHub
parent 27ec4120bc
commit 66b8434861
3 changed files with 81 additions and 37 deletions

View File

@@ -134,7 +134,11 @@ export function Editor() {
const trimmedName = editedName.trim()
if (trimmedName && trimmedName !== currentBlock?.name) {
collaborativeUpdateBlockName(currentBlockId, trimmedName)
const result = collaborativeUpdateBlockName(currentBlockId, trimmedName)
if (!result.success) {
// Keep rename mode open on error so user can correct the name
return
}
}
setIsRenaming(false)
}, [currentBlockId, isRenaming, editedName, currentBlock?.name, collaborativeUpdateBlockName])

View File

@@ -8,6 +8,7 @@ import { TriggerUtils } from '@/lib/workflows/triggers/triggers'
import { useSocket } from '@/app/workspace/providers/socket-provider'
import { getBlock } from '@/blocks'
import { useUndoRedo } from '@/hooks/use-undo-redo'
import { useNotificationStore } from '@/stores/notifications'
import { registerEmitFunctions, useOperationQueue } from '@/stores/operation-queue/store'
import { usePanelEditorStore } from '@/stores/panel/editor/store'
import { useVariablesStore } from '@/stores/panel/variables/store'
@@ -15,7 +16,7 @@ import { useUndoRedoStore } from '@/stores/undo-redo'
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import { getUniqueBlockName, mergeSubblockState } from '@/stores/workflows/utils'
import { getUniqueBlockName, mergeSubblockState, normalizeName } from '@/stores/workflows/utils'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
import type { BlockState, Position } from '@/stores/workflows/workflow/types'
@@ -1016,14 +1017,43 @@ export function useCollaborativeWorkflow() {
)
const collaborativeUpdateBlockName = useCallback(
(id: string, name: string) => {
executeQueuedOperation('update-name', 'block', { id, name }, () => {
const result = workflowStore.updateBlockName(id, name)
(id: string, name: string): { success: boolean; error?: string } => {
const trimmedName = name.trim()
const normalizedNewName = normalizeName(trimmedName)
if (!normalizedNewName) {
logger.error('Cannot rename block to empty name')
useNotificationStore.getState().addNotification({
level: 'error',
message: 'Block name cannot be empty',
workflowId: activeWorkflowId || undefined,
})
return { success: false, error: 'Block name cannot be empty' }
}
const currentBlocks = workflowStore.blocks
const conflictingBlock = Object.entries(currentBlocks).find(
([blockId, block]) => blockId !== id && normalizeName(block.name) === normalizedNewName
)
if (conflictingBlock) {
const conflictName = conflictingBlock[1].name
logger.error(`Cannot rename block to "${trimmedName}" - conflicts with "${conflictName}"`)
useNotificationStore.getState().addNotification({
level: 'error',
message: `Block name "${trimmedName}" already exists`,
workflowId: activeWorkflowId || undefined,
})
return { success: false, error: `Block name "${trimmedName}" already exists` }
}
executeQueuedOperation('update-name', 'block', { id, name: trimmedName }, () => {
const result = workflowStore.updateBlockName(id, trimmedName)
if (result.success && result.changedSubblocks.length > 0) {
logger.info('Emitting cascaded subblock updates from block rename', {
blockId: id,
newName: name,
newName: trimmedName,
updateCount: result.changedSubblocks.length,
})
@@ -1043,7 +1073,7 @@ export function useCollaborativeWorkflow() {
operation: {
operation: 'subblock-update',
target: 'subblock',
payload: { blockId, subBlockId, value: newValue },
payload: { blockId, subblockId: subBlockId, value: newValue },
},
workflowId: activeWorkflowId || '',
userId: session?.user?.id || 'unknown',
@@ -1052,6 +1082,8 @@ export function useCollaborativeWorkflow() {
)
}
})
return { success: true }
},
[executeQueuedOperation, workflowStore, addToQueue, activeWorkflowId, session?.user?.id]
)

View File

@@ -716,54 +716,62 @@ export const useWorkflowStore = create<WorkflowStore>()(
const workflowValues = subBlockStore.workflowValues[activeWorkflowId] || {}
const updatedWorkflowValues = { ...workflowValues }
// Helper function to recursively update references in any data structure
function updateReferences(value: any, regex: RegExp, replacement: string): any {
// Handle string values
if (typeof value === 'string') {
return regex.test(value) ? value.replace(regex, replacement) : value
}
// Handle arrays
if (Array.isArray(value)) {
return value.map((item) => updateReferences(item, regex, replacement))
}
// Handle objects
if (value !== null && typeof value === 'object') {
const result = { ...value }
for (const key in result) {
result[key] = updateReferences(result[key], regex, replacement)
}
return result
}
// Return unchanged for other types
return value
}
const oldBlockName = normalizeName(oldBlock.name)
const newBlockName = normalizeName(name)
const regex = new RegExp(`<${oldBlockName}\\.`, 'g')
// Loop through blocks
Object.entries(workflowValues).forEach(([blockId, blockValues]) => {
if (blockId === id) return // Skip the block being renamed
let blockHasChanges = false
const updatedBlockValues = { ...blockValues }
// Loop through subblocks and update references
Object.entries(blockValues).forEach(([subBlockId, value]) => {
const oldBlockName = normalizeName(oldBlock.name)
const newBlockName = normalizeName(name)
const regex = new RegExp(`<${oldBlockName}\\.`, 'g')
// Use a recursive function to handle all object types
const updatedValue = updateReferences(value, regex, `<${newBlockName}.`)
// Check if the value actually changed
if (JSON.stringify(updatedValue) !== JSON.stringify(value)) {
updatedWorkflowValues[blockId][subBlockId] = updatedValue
updatedBlockValues[subBlockId] = updatedValue
blockHasChanges = true
changedSubblocks.push({
blockId,
subBlockId,
newValue: updatedValue,
})
}
// Helper function to recursively update references in any data structure
function updateReferences(value: any, regex: RegExp, replacement: string): any {
// Handle string values
if (typeof value === 'string') {
return regex.test(value) ? value.replace(regex, replacement) : value
}
// Handle arrays
if (Array.isArray(value)) {
return value.map((item) => updateReferences(item, regex, replacement))
}
// Handle objects
if (value !== null && typeof value === 'object') {
const result = { ...value }
for (const key in result) {
result[key] = updateReferences(result[key], regex, replacement)
}
return result
}
// Return unchanged for other types
return value
}
})
if (blockHasChanges) {
updatedWorkflowValues[blockId] = updatedBlockValues
}
})
// Update the subblock store with the new values