mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 15:07:55 -05:00
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:
committed by
GitHub
parent
27ec4120bc
commit
66b8434861
@@ -134,7 +134,11 @@ export function Editor() {
|
|||||||
|
|
||||||
const trimmedName = editedName.trim()
|
const trimmedName = editedName.trim()
|
||||||
if (trimmedName && trimmedName !== currentBlock?.name) {
|
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)
|
setIsRenaming(false)
|
||||||
}, [currentBlockId, isRenaming, editedName, currentBlock?.name, collaborativeUpdateBlockName])
|
}, [currentBlockId, isRenaming, editedName, currentBlock?.name, collaborativeUpdateBlockName])
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { TriggerUtils } from '@/lib/workflows/triggers/triggers'
|
|||||||
import { useSocket } from '@/app/workspace/providers/socket-provider'
|
import { useSocket } from '@/app/workspace/providers/socket-provider'
|
||||||
import { getBlock } from '@/blocks'
|
import { getBlock } from '@/blocks'
|
||||||
import { useUndoRedo } from '@/hooks/use-undo-redo'
|
import { useUndoRedo } from '@/hooks/use-undo-redo'
|
||||||
|
import { useNotificationStore } from '@/stores/notifications'
|
||||||
import { registerEmitFunctions, useOperationQueue } from '@/stores/operation-queue/store'
|
import { registerEmitFunctions, useOperationQueue } from '@/stores/operation-queue/store'
|
||||||
import { usePanelEditorStore } from '@/stores/panel/editor/store'
|
import { usePanelEditorStore } from '@/stores/panel/editor/store'
|
||||||
import { useVariablesStore } from '@/stores/panel/variables/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 { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
|
||||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||||
import { useSubBlockStore } from '@/stores/workflows/subblock/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 { useWorkflowStore } from '@/stores/workflows/workflow/store'
|
||||||
import type { BlockState, Position } from '@/stores/workflows/workflow/types'
|
import type { BlockState, Position } from '@/stores/workflows/workflow/types'
|
||||||
|
|
||||||
@@ -1016,14 +1017,43 @@ export function useCollaborativeWorkflow() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const collaborativeUpdateBlockName = useCallback(
|
const collaborativeUpdateBlockName = useCallback(
|
||||||
(id: string, name: string) => {
|
(id: string, name: string): { success: boolean; error?: string } => {
|
||||||
executeQueuedOperation('update-name', 'block', { id, name }, () => {
|
const trimmedName = name.trim()
|
||||||
const result = workflowStore.updateBlockName(id, name)
|
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) {
|
if (result.success && result.changedSubblocks.length > 0) {
|
||||||
logger.info('Emitting cascaded subblock updates from block rename', {
|
logger.info('Emitting cascaded subblock updates from block rename', {
|
||||||
blockId: id,
|
blockId: id,
|
||||||
newName: name,
|
newName: trimmedName,
|
||||||
updateCount: result.changedSubblocks.length,
|
updateCount: result.changedSubblocks.length,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1043,7 +1073,7 @@ export function useCollaborativeWorkflow() {
|
|||||||
operation: {
|
operation: {
|
||||||
operation: 'subblock-update',
|
operation: 'subblock-update',
|
||||||
target: 'subblock',
|
target: 'subblock',
|
||||||
payload: { blockId, subBlockId, value: newValue },
|
payload: { blockId, subblockId: subBlockId, value: newValue },
|
||||||
},
|
},
|
||||||
workflowId: activeWorkflowId || '',
|
workflowId: activeWorkflowId || '',
|
||||||
userId: session?.user?.id || 'unknown',
|
userId: session?.user?.id || 'unknown',
|
||||||
@@ -1052,6 +1082,8 @@ export function useCollaborativeWorkflow() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
},
|
},
|
||||||
[executeQueuedOperation, workflowStore, addToQueue, activeWorkflowId, session?.user?.id]
|
[executeQueuedOperation, workflowStore, addToQueue, activeWorkflowId, session?.user?.id]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -716,54 +716,62 @@ export const useWorkflowStore = create<WorkflowStore>()(
|
|||||||
const workflowValues = subBlockStore.workflowValues[activeWorkflowId] || {}
|
const workflowValues = subBlockStore.workflowValues[activeWorkflowId] || {}
|
||||||
const updatedWorkflowValues = { ...workflowValues }
|
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
|
// Loop through blocks
|
||||||
Object.entries(workflowValues).forEach(([blockId, blockValues]) => {
|
Object.entries(workflowValues).forEach(([blockId, blockValues]) => {
|
||||||
if (blockId === id) return // Skip the block being renamed
|
if (blockId === id) return // Skip the block being renamed
|
||||||
|
|
||||||
|
let blockHasChanges = false
|
||||||
|
const updatedBlockValues = { ...blockValues }
|
||||||
|
|
||||||
// Loop through subblocks and update references
|
// Loop through subblocks and update references
|
||||||
Object.entries(blockValues).forEach(([subBlockId, value]) => {
|
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
|
// Use a recursive function to handle all object types
|
||||||
const updatedValue = updateReferences(value, regex, `<${newBlockName}.`)
|
const updatedValue = updateReferences(value, regex, `<${newBlockName}.`)
|
||||||
|
|
||||||
// Check if the value actually changed
|
// Check if the value actually changed
|
||||||
if (JSON.stringify(updatedValue) !== JSON.stringify(value)) {
|
if (JSON.stringify(updatedValue) !== JSON.stringify(value)) {
|
||||||
updatedWorkflowValues[blockId][subBlockId] = updatedValue
|
updatedBlockValues[subBlockId] = updatedValue
|
||||||
|
blockHasChanges = true
|
||||||
changedSubblocks.push({
|
changedSubblocks.push({
|
||||||
blockId,
|
blockId,
|
||||||
subBlockId,
|
subBlockId,
|
||||||
newValue: updatedValue,
|
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
|
// Update the subblock store with the new values
|
||||||
|
|||||||
Reference in New Issue
Block a user