diff --git a/apps/sim/app/api/workflows/sync/route.ts b/apps/sim/app/api/workflows/sync/route.ts index afa0a43365f..49949a30540 100644 --- a/apps/sim/app/api/workflows/sync/route.ts +++ b/apps/sim/app/api/workflows/sync/route.ts @@ -428,6 +428,11 @@ export async function POST(req: NextRequest) { color: clientWorkflow.color, state: stateToSave, marketplaceData: clientWorkflow.marketplaceData || null, + // Include deployment status from client state + isDeployed: clientWorkflow.state.isDeployed || false, + deployedAt: clientWorkflow.state.deployedAt || null, + // deployedState is null for new workflows - only set during deployment + deployedState: null, lastSynced: now, createdAt: now, updatedAt: now, @@ -485,6 +490,32 @@ export async function POST(req: NextRequest) { needsUpdate = true } + // Check deployment status changes - ensure dual-write consistency + const clientIsDeployed = clientWorkflow.state.isDeployed || false + const clientDeployedAt = clientWorkflow.state.deployedAt || null + + if (dbWorkflow.isDeployed !== clientIsDeployed) { + updateData.isDeployed = clientIsDeployed + needsUpdate = true + } + + // Handle deployedAt comparison (convert to comparable format) + const dbDeployedAtTime = dbWorkflow.deployedAt + ? new Date(dbWorkflow.deployedAt).getTime() + : null + const clientDeployedAtTime = clientDeployedAt + ? new Date(clientDeployedAt).getTime() + : null + + if (dbDeployedAtTime !== clientDeployedAtTime) { + updateData.deployedAt = clientDeployedAt + needsUpdate = true + } + + // CRITICAL: Always preserve deployedState - it should only be modified by deploy/undeploy operations + // The sync operation should never touch deployedState to prevent data loss + // Note: We don't add deployedState to updateData because we want to preserve the existing value + if (needsUpdate) { updateData.lastSynced = now updateData.updatedAt = now diff --git a/apps/sim/stores/workflows/registry/store.ts b/apps/sim/stores/workflows/registry/store.ts index 42a401e7be5..a75cada4aa1 100644 --- a/apps/sim/stores/workflows/registry/store.ts +++ b/apps/sim/stores/workflows/registry/store.ts @@ -630,6 +630,21 @@ export const useWorkflowRegistry = create()( // 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: { + ...state.deploymentStatuses, + [id]: { + isDeployed: workflowData.isDeployed || false, + deployedAt: workflowData.deployedAt ? new Date(workflowData.deployedAt) : undefined, + apiKey: workflowData.apiKey || undefined, + needsRedeployment: false, // Default to false when loading from DB + }, + }, + })) + } + // Update the active workflow ID set({ activeWorkflowId: id, error: null }) diff --git a/apps/sim/stores/workflows/sync.ts b/apps/sim/stores/workflows/sync.ts index 0318d4b59c1..dd85be310ed 100644 --- a/apps/sim/stores/workflows/sync.ts +++ b/apps/sim/stores/workflows/sync.ts @@ -198,6 +198,7 @@ export async function fetchWorkflowsFromDB(): Promise { // Process workflows const registryWorkflows: Record = {} + const deploymentStatuses: Record = {} data.forEach((workflow) => { const { @@ -210,6 +211,9 @@ export async function fetchWorkflowsFromDB(): Promise { marketplaceData, workspaceId, folderId, + isDeployed, + deployedAt, + apiKey, } = workflow // Skip if workflow doesn't belong to active workspace @@ -229,6 +233,16 @@ export async function fetchWorkflowsFromDB(): Promise { folderId: folderId || null, } + // CRITICAL: Extract deployment status from database and add to registry + if (isDeployed || deployedAt) { + deploymentStatuses[id] = { + isDeployed: isDeployed || false, + deployedAt: deployedAt ? new Date(deployedAt) : undefined, + apiKey: apiKey || undefined, + needsRedeployment: false, // Default to false when loading from DB + } + } + // Initialize subblock values const subblockValues: Record> = {} if (state?.blocks) { @@ -251,9 +265,10 @@ export async function fetchWorkflowsFromDB(): Promise { })) }) - // Update registry with loaded workflows + // Update registry with loaded workflows and deployment statuses useWorkflowRegistry.setState({ workflows: registryWorkflows, + deploymentStatuses: deploymentStatuses, isLoading: false, error: null, })