Skip to content

Commit a8a693f

Browse files
authored
fix(deploy): add sockets op for renaming blocks (#2043)
* fix(deploy): add sockets op for renaming blocks * remove old unused helpers
1 parent e0aade8 commit a8a693f

6 files changed

Lines changed: 60 additions & 148 deletions

File tree

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

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,10 +937,42 @@ export function useCollaborativeWorkflow() {
937937
const collaborativeUpdateBlockName = useCallback(
938938
(id: string, name: string) => {
939939
executeQueuedOperation('update-name', 'block', { id, name }, () => {
940-
workflowStore.updateBlockName(id, name)
940+
const result = workflowStore.updateBlockName(id, name)
941+
942+
if (result.success && result.changedSubblocks.length > 0) {
943+
logger.info('Emitting cascaded subblock updates from block rename', {
944+
blockId: id,
945+
newName: name,
946+
updateCount: result.changedSubblocks.length,
947+
})
948+
949+
result.changedSubblocks.forEach(
950+
({
951+
blockId,
952+
subBlockId,
953+
newValue,
954+
}: {
955+
blockId: string
956+
subBlockId: string
957+
newValue: any
958+
}) => {
959+
const operationId = crypto.randomUUID()
960+
addToQueue({
961+
id: operationId,
962+
operation: {
963+
operation: 'subblock-update',
964+
target: 'subblock',
965+
payload: { blockId, subBlockId, value: newValue },
966+
},
967+
workflowId: activeWorkflowId || '',
968+
userId: session?.user?.id || 'unknown',
969+
})
970+
}
971+
)
972+
}
941973
})
942974
},
943-
[executeQueuedOperation, workflowStore]
975+
[executeQueuedOperation, workflowStore, addToQueue, activeWorkflowId, session?.user?.id]
944976
)
945977

946978
const collaborativeToggleBlockEnabled = useCallback(

apps/sim/lib/workflows/db-helpers.test.ts

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -791,101 +791,6 @@ describe('Database Helpers', () => {
791791
})
792792
})
793793

794-
describe('migrateWorkflowToNormalizedTables', () => {
795-
const mockJsonState = {
796-
blocks: mockWorkflowState.blocks,
797-
edges: mockWorkflowState.edges,
798-
loops: mockWorkflowState.loops,
799-
parallels: mockWorkflowState.parallels,
800-
lastSaved: Date.now(),
801-
isDeployed: false,
802-
deploymentStatuses: {},
803-
}
804-
805-
it('should successfully migrate workflow from JSON to normalized tables', async () => {
806-
const mockTransaction = vi.fn().mockImplementation(async (callback) => {
807-
const tx = {
808-
select: vi.fn().mockReturnValue({
809-
from: vi.fn().mockReturnValue({
810-
where: vi.fn().mockResolvedValue([]),
811-
}),
812-
}),
813-
delete: vi.fn().mockReturnValue({
814-
where: vi.fn().mockResolvedValue([]),
815-
}),
816-
insert: vi.fn().mockReturnValue({
817-
values: vi.fn().mockResolvedValue([]),
818-
}),
819-
}
820-
return await callback(tx)
821-
})
822-
823-
mockDb.transaction = mockTransaction
824-
825-
const result = await dbHelpers.migrateWorkflowToNormalizedTables(
826-
mockWorkflowId,
827-
mockJsonState
828-
)
829-
830-
expect(result.success).toBe(true)
831-
expect(result.error).toBeUndefined()
832-
})
833-
834-
it('should return error when migration fails', async () => {
835-
const mockTransaction = vi.fn().mockRejectedValue(new Error('Migration failed'))
836-
mockDb.transaction = mockTransaction
837-
838-
const result = await dbHelpers.migrateWorkflowToNormalizedTables(
839-
mockWorkflowId,
840-
mockJsonState
841-
)
842-
843-
expect(result.success).toBe(false)
844-
expect(result.error).toBe('Migration failed')
845-
})
846-
847-
it('should handle missing properties in JSON state gracefully', async () => {
848-
const incompleteJsonState = {
849-
blocks: mockWorkflowState.blocks,
850-
edges: mockWorkflowState.edges,
851-
// Missing loops, parallels, and other properties
852-
}
853-
854-
const mockTransaction = vi.fn().mockImplementation(async (callback) => {
855-
const tx = {
856-
select: vi.fn().mockReturnValue({
857-
from: vi.fn().mockReturnValue({
858-
where: vi.fn().mockResolvedValue([]),
859-
}),
860-
}),
861-
delete: vi.fn().mockReturnValue({
862-
where: vi.fn().mockResolvedValue([]),
863-
}),
864-
insert: vi.fn().mockReturnValue({
865-
values: vi.fn().mockResolvedValue([]),
866-
}),
867-
}
868-
return await callback(tx)
869-
})
870-
871-
mockDb.transaction = mockTransaction
872-
873-
const result = await dbHelpers.migrateWorkflowToNormalizedTables(
874-
mockWorkflowId,
875-
incompleteJsonState
876-
)
877-
878-
expect(result.success).toBe(true)
879-
})
880-
881-
it('should handle null/undefined JSON state', async () => {
882-
const result = await dbHelpers.migrateWorkflowToNormalizedTables(mockWorkflowId, null)
883-
884-
expect(result.success).toBe(false)
885-
expect(result.error).toContain('Cannot read properties')
886-
})
887-
})
888-
889794
describe('error handling and edge cases', () => {
890795
it('should handle very large workflow data', async () => {
891796
const largeWorkflowState: WorkflowState = {

apps/sim/lib/workflows/db-helpers.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -402,36 +402,6 @@ export async function workflowExistsInNormalizedTables(workflowId: string): Prom
402402
}
403403
}
404404

405-
/**
406-
* Migrate a workflow from JSON blob to normalized tables
407-
*/
408-
export async function migrateWorkflowToNormalizedTables(
409-
workflowId: string,
410-
jsonState: any
411-
): Promise<{ success: boolean; error?: string }> {
412-
try {
413-
// Convert JSON state to WorkflowState format
414-
// Only include fields that are actually persisted to normalized tables
415-
const workflowState: WorkflowState = {
416-
blocks: jsonState.blocks || {},
417-
edges: jsonState.edges || [],
418-
loops: jsonState.loops || {},
419-
parallels: jsonState.parallels || {},
420-
lastSaved: jsonState.lastSaved,
421-
isDeployed: jsonState.isDeployed,
422-
deployedAt: jsonState.deployedAt,
423-
}
424-
425-
return await saveWorkflowToNormalizedTables(workflowId, workflowState)
426-
} catch (error) {
427-
logger.error(`Error migrating workflow ${workflowId} to normalized tables:`, error)
428-
return {
429-
success: false,
430-
error: error instanceof Error ? error.message : 'Unknown error',
431-
}
432-
}
433-
}
434-
435405
/**
436406
* Deploy a workflow by creating a new deployment version
437407
*/

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ describe('workflow store', () => {
587587

588588
const result = updateBlockName('block1', 'Data Processor')
589589

590-
expect(result).toBe(true)
590+
expect(result.success).toBe(true)
591591

592592
const state = useWorkflowStore.getState()
593593
expect(state.blocks.block1.name).toBe('Data Processor')
@@ -598,7 +598,7 @@ describe('workflow store', () => {
598598

599599
const result = updateBlockName('block1', 'column ad')
600600

601-
expect(result).toBe(true)
601+
expect(result.success).toBe(true)
602602

603603
const state = useWorkflowStore.getState()
604604
expect(state.blocks.block1.name).toBe('column ad')
@@ -609,7 +609,7 @@ describe('workflow store', () => {
609609

610610
const result = updateBlockName('block2', 'Column AD')
611611

612-
expect(result).toBe(false)
612+
expect(result.success).toBe(false)
613613

614614
const state = useWorkflowStore.getState()
615615
expect(state.blocks.block2.name).toBe('Employee Length')
@@ -620,7 +620,7 @@ describe('workflow store', () => {
620620

621621
const result = updateBlockName('block2', 'columnad')
622622

623-
expect(result).toBe(false)
623+
expect(result.success).toBe(false)
624624

625625
const state = useWorkflowStore.getState()
626626
expect(state.blocks.block2.name).toBe('Employee Length')
@@ -631,7 +631,7 @@ describe('workflow store', () => {
631631

632632
const result = updateBlockName('block3', 'employee length')
633633

634-
expect(result).toBe(false)
634+
expect(result.success).toBe(false)
635635

636636
const state = useWorkflowStore.getState()
637637
expect(state.blocks.block3.name).toBe('Start')
@@ -641,10 +641,10 @@ describe('workflow store', () => {
641641
const { updateBlockName } = useWorkflowStore.getState()
642642

643643
const result1 = updateBlockName('block1', '')
644-
expect(result1).toBe(true)
644+
expect(result1.success).toBe(true)
645645

646646
const result2 = updateBlockName('block2', ' ')
647-
expect(result2).toBe(true)
647+
expect(result2.success).toBe(true)
648648

649649
const state = useWorkflowStore.getState()
650650
expect(state.blocks.block1.name).toBe('')
@@ -656,7 +656,7 @@ describe('workflow store', () => {
656656

657657
const result = updateBlockName('nonexistent', 'New Name')
658658

659-
expect(result).toBe(false)
659+
expect(result.success).toBe(false)
660660
})
661661

662662
it('should handle complex normalization cases correctly', () => {
@@ -673,11 +673,11 @@ describe('workflow store', () => {
673673

674674
for (const name of conflictingNames) {
675675
const result = updateBlockName('block2', name)
676-
expect(result).toBe(false)
676+
expect(result.success).toBe(false)
677677
}
678678

679679
const result = updateBlockName('block2', 'Unique Name')
680-
expect(result).toBe(true)
680+
expect(result.success).toBe(true)
681681

682682
const state = useWorkflowStore.getState()
683683
expect(state.blocks.block2.name).toBe('Unique Name')

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ export const useWorkflowStore = create<WorkflowStore>()(
626626

627627
updateBlockName: (id: string, name: string) => {
628628
const oldBlock = get().blocks[id]
629-
if (!oldBlock) return false
629+
if (!oldBlock) return { success: false, changedSubblocks: [] }
630630

631631
// Check for normalized name collisions
632632
const normalizedNewName = normalizeBlockName(name)
@@ -646,7 +646,7 @@ export const useWorkflowStore = create<WorkflowStore>()(
646646
logger.error(
647647
`Cannot rename block to "${name}" - another block "${conflictingBlock[1].name}" already uses the normalized name "${normalizedNewName}"`
648648
)
649-
return false
649+
return { success: false, changedSubblocks: [] }
650650
}
651651

652652
// Create a new state with the updated block name
@@ -666,12 +666,13 @@ export const useWorkflowStore = create<WorkflowStore>()(
666666
// Update references in subblock store
667667
const subBlockStore = useSubBlockStore.getState()
668668
const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
669+
const changedSubblocks: Array<{ blockId: string; subBlockId: string; newValue: any }> = []
670+
669671
if (activeWorkflowId) {
670672
// Get the workflow values for the active workflow
671673
// workflowValues: {[block_id]:{[subblock_id]:[subblock_value]}}
672674
const workflowValues = subBlockStore.workflowValues[activeWorkflowId] || {}
673675
const updatedWorkflowValues = { ...workflowValues }
674-
const changedSubblocks: Array<{ blockId: string; subBlockId: string; newValue: any }> = []
675676

676677
// Loop through blocks
677678
Object.entries(workflowValues).forEach(([blockId, blockValues]) => {
@@ -730,19 +731,17 @@ export const useWorkflowStore = create<WorkflowStore>()(
730731
[activeWorkflowId]: updatedWorkflowValues,
731732
},
732733
})
733-
734-
// Store changed subblocks for collaborative sync
735-
if (changedSubblocks.length > 0) {
736-
// Store the changed subblocks for the collaborative function to pick up
737-
;(window as any).__pendingSubblockUpdates = changedSubblocks
738-
}
739734
}
740735

741736
set(newState)
742737
get().updateLastSaved()
743738
// Note: Socket.IO handles real-time sync automatically
744739

745-
return true
740+
// Return both success status and changed subblocks for collaborative sync
741+
return {
742+
success: true,
743+
changedSubblocks,
744+
}
746745
},
747746

748747
setBlockAdvancedMode: (id: string, advancedMode: boolean) => {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,13 @@ export interface WorkflowActions {
198198
toggleBlockEnabled: (id: string) => void
199199
duplicateBlock: (id: string) => void
200200
toggleBlockHandles: (id: string) => void
201-
updateBlockName: (id: string, name: string) => boolean
201+
updateBlockName: (
202+
id: string,
203+
name: string
204+
) => {
205+
success: boolean
206+
changedSubblocks: Array<{ blockId: string; subBlockId: string; newValue: any }>
207+
}
202208
setBlockAdvancedMode: (id: string, advancedMode: boolean) => void
203209
setBlockTriggerMode: (id: string, triggerMode: boolean) => void
204210
updateBlockLayoutMetrics: (id: string, dimensions: { width: number; height: number }) => void

0 commit comments

Comments
 (0)