Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
13 changes: 10 additions & 3 deletions apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { useExecutionStore } from '@/stores/execution/store'
import { useVariablesStore } from '@/stores/panel/variables/store'
import { useGeneralStore } from '@/stores/settings/general/store'
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { hasWorkflowsInitiallyLoaded, useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'

const logger = createLogger('Workflow')
Expand Down Expand Up @@ -908,14 +908,21 @@ const WorkflowContent = React.memo(() => {
const workflowIds = Object.keys(workflows)
const currentId = params.workflowId as string

// Check if workflows have been initially loaded at least once
// This prevents premature navigation decisions on page refresh
if (!hasWorkflowsInitiallyLoaded()) {
logger.info('Waiting for initial workflow load...')
return
}

// Wait for both initialization and workflow loading to complete
if (isLoading) {
logger.info('Workflows still loading, waiting...')
return
}

// If no workflows exist, redirect to workspace root to let server handle workflow creation
if (workflowIds.length === 0 && !isLoading) {
// If no workflows exist after loading, redirect to workspace root
if (workflowIds.length === 0) {
logger.info('No workflows found, redirecting to workspace root')
router.replace(`/workspace/${workspaceId}/w`)
return
Expand Down
38 changes: 25 additions & 13 deletions apps/sim/stores/workflows/registry/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ async function fetchWorkflowsFromDB(workspaceId?: string): Promise<void> {
error: null,
})

// Mark that initial load has completed
hasInitiallyLoaded = true

// Only set first workflow as active if no active workflow is set and we have workflows
const currentState = useWorkflowRegistry.getState()
if (!currentState.activeWorkflowId && Object.keys(registryWorkflows).length > 0) {
Expand All @@ -177,6 +180,11 @@ async function fetchWorkflowsFromDB(workspaceId?: string): Promise<void> {
)
} catch (error) {
logger.error('Error fetching workflows from DB:', error)

// Mark that initial load has completed even on error
// This prevents indefinite waiting for workflows that failed to load
hasInitiallyLoaded = true

useWorkflowRegistry.setState({
isLoading: false,
error: `Failed to load workflows: ${error instanceof Error ? error.message : 'Unknown error'}`,
Expand Down Expand Up @@ -256,21 +264,28 @@ export function isWorkspaceInTransition(): boolean {
return isWorkspaceTransitioning
}

/**
* Checks if workflows have been initially loaded
* @returns True if the initial workflow load has completed at least once
*/
export function hasWorkflowsInitiallyLoaded(): boolean {
return hasInitiallyLoaded
}

// Track if initial load has happened to prevent premature navigation
let hasInitiallyLoaded = false

export const useWorkflowRegistry = create<WorkflowRegistry>()(
devtools(
(set, get) => ({
// Store state
workflows: {},
activeWorkflowId: null,
isLoading: true,
isLoading: false,
error: null,
// Initialize deployment statuses
deploymentStatuses: {},

// Set loading state
setLoading: (loading: boolean) => {
// Remove the broken logic that prevents loading when workflows exist
// This was causing race conditions during deletion and sync operations
set({ isLoading: loading })
},

Expand All @@ -295,6 +310,9 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
try {
logger.info(`Switching to workspace: ${workspaceId}`)

// Reset the initial load flag when switching workspaces
hasInitiallyLoaded = false

// Clear current workspace state
resetWorkflowStores()

Expand Down Expand Up @@ -500,7 +518,6 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
})
})

// Update subblock store for this workflow
useSubBlockStore.setState((state) => ({
workflowValues: {
...state.workflowValues,
Expand Down Expand Up @@ -542,10 +559,6 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
)
}

// Set the workflow state in the store
useWorkflowStore.setState(workflowState)

// CRITICAL: Set deployment status in registry when switching to workflow
if (workflowData?.isDeployed || workflowData?.deployedAt) {
set((state) => ({
deploymentStatuses: {
Expand All @@ -560,11 +573,10 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
}))
}

// Update the active workflow ID
useWorkflowStore.setState(workflowState)

set({ activeWorkflowId: id, error: null })

// Emit a global event to notify that the active workflow has changed
// This allows the workflow component to join the socket room
window.dispatchEvent(
new CustomEvent('active-workflow-changed', {
detail: { workflowId: id },
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/stores/workflows/workflow/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const initialState = {
isDeployed: false,
isPublished: false,
},
timestamp: Date.now(),
timestamp: 0,
action: 'Initial state',
subblockValues: {},
},
Expand Down