Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix hmr case for missing workflow loads
  • Loading branch information
icecrasher321 committed Dec 5, 2025
commit 094fad6501239de169c1a86e3512aa4fe5aaf3b3
14 changes: 11 additions & 3 deletions apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1277,7 +1277,7 @@ const WorkflowContent = React.memo(() => {
[screenToFlowPosition, isPointInLoopNode, getNodes]
)

// Initialize workflow when it exists in registry and isn't active
// Initialize workflow when it exists in registry and isn't active or needs hydration
useEffect(() => {
let cancelled = false
const currentId = params.workflowId as string
Expand All @@ -1295,8 +1295,16 @@ const WorkflowContent = React.memo(() => {
return
}

if (activeWorkflowId !== currentId) {
// Clear diff and set as active
// Check if we need to load the workflow state:
// 1. Different workflow than currently active
// 2. Same workflow but hydration phase is not 'ready' (e.g., after a quick refresh)
const needsWorkflowLoad =
activeWorkflowId !== currentId ||
(activeWorkflowId === currentId &&
hydration.phase !== 'ready' &&
hydration.phase !== 'state-loading')

if (needsWorkflowLoad) {
const { clearDiff } = useWorkflowDiffStore.getState()
clearDiff()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,12 @@ interface UseFolderOperationsProps {
export function useFolderOperations({ workspaceId }: UseFolderOperationsProps) {
const createFolderMutation = useCreateFolder()

/**
* Create folder handler - creates folder with auto-generated name.
* Generates name upfront to enable optimistic UI updates.
*/
const handleCreateFolder = useCallback(async (): Promise<string | null> => {
if (createFolderMutation.isPending || !workspaceId) {
logger.info('Folder creation already in progress or no workspaceId available')
if (!workspaceId) {
return null
}

try {
// Generate folder name upfront for optimistic updates
const folderName = await generateFolderName(workspaceId)
const folder = await createFolderMutation.mutateAsync({ name: folderName, workspaceId })
logger.info(`Created folder: ${folderName}`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,9 @@ const logger = createLogger('useWorkflowOperations')

interface UseWorkflowOperationsProps {
workspaceId: string
isWorkspaceValid: (workspaceId: string) => Promise<boolean>
onWorkspaceInvalid: () => void
}

/**
* Custom hook to manage workflow operations including creating and loading workflows.
* Handles workflow state management and navigation.
*
* @param props - Configuration object containing workspaceId and validation handlers
* @returns Workflow operations state and handlers
*/
export function useWorkflowOperations({
workspaceId,
isWorkspaceValid,
onWorkspaceInvalid,
}: UseWorkflowOperationsProps) {
export function useWorkflowOperations({ workspaceId }: UseWorkflowOperationsProps) {
const router = useRouter()
const { workflows } = useWorkflowRegistry()
const workflowsQuery = useWorkflows(workspaceId)
Expand All @@ -44,34 +31,20 @@ export function useWorkflowOperations({
return b.createdAt.getTime() - a.createdAt.getTime()
})

/**
* Create workflow handler - creates workflow and navigates to it.
* Uses React Query mutation's isPending state for immediate loading feedback.
* Generates name and color upfront to enable optimistic UI updates.
*/
const handleCreateWorkflow = useCallback(async (): Promise<string | null> => {
if (createWorkflowMutation.isPending) {
logger.info('Workflow creation already in progress, ignoring request')
return null
}

try {
// Clear workflow diff store when creating a new workflow
const { clearDiff } = useWorkflowDiffStore.getState()
clearDiff()

// Generate name and color upfront for optimistic updates
const name = generateCreativeWorkflowName()
const color = getNextWorkflowColor()

// Use React Query mutation for creation - isPending updates immediately
const result = await createWorkflowMutation.mutateAsync({
workspaceId,
name,
color,
})

// Navigate to the newly created workflow
if (result.id) {
router.push(`/workspace/${workspaceId}/w/${result.id}`)
return result.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,7 @@ export function SidebarNew() {
workflowsLoading,
isCreatingWorkflow,
handleCreateWorkflow: createWorkflow,
} = useWorkflowOperations({
workspaceId,
isWorkspaceValid,
onWorkspaceInvalid: fetchWorkspaces,
})
} = useWorkflowOperations({ workspaceId })

// Folder operations hook
const { isCreatingFolder, handleCreateFolder: createFolder } = useFolderOperations({
Expand Down
14 changes: 12 additions & 2 deletions apps/sim/stores/workflows/registry/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,12 +426,22 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(

// Modified setActiveWorkflow to work with clean DB-only architecture
setActiveWorkflow: async (id: string) => {
const { activeWorkflowId } = get()
const { activeWorkflowId, hydration } = get()

const workflowStoreState = useWorkflowStore.getState()
const hasWorkflowData = Object.keys(workflowStoreState.blocks).length > 0

if (activeWorkflowId === id && hasWorkflowData) {
// Skip loading only if:
// - Same workflow is already active
// - Workflow data exists
// - Hydration is complete (phase is 'ready')
const isFullyHydrated =
activeWorkflowId === id &&
hasWorkflowData &&
hydration.phase === 'ready' &&
hydration.workflowId === id

if (isFullyHydrated) {
logger.info(`Already active workflow ${id} with data loaded, skipping switch`)
return
}
Expand Down