diff --git a/app/api/workflow/[id]/deploy/route.ts b/app/api/workflow/[id]/deploy/route.ts
index 31790713a6..38bfed672c 100644
--- a/app/api/workflow/[id]/deploy/route.ts
+++ b/app/api/workflow/[id]/deploy/route.ts
@@ -21,6 +21,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
// Generate a new API key
const apiKey = `wf_${uuidv4().replace(/-/g, '')}`
+ const deployedAt = new Date()
// Update the workflow with the API key and deployment status
await db
@@ -28,11 +29,11 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
.set({
apiKey,
isDeployed: true,
- deployedAt: new Date(),
+ deployedAt,
})
.where(eq(workflow.id, id))
- return createSuccessResponse({ apiKey })
+ return createSuccessResponse({ apiKey, isDeployed: true, deployedAt })
} catch (error: any) {
console.error('Error deploying workflow:', error)
return createErrorResponse(error.message || 'Failed to deploy workflow', 500)
diff --git a/app/w/components/control-bar/control-bar.tsx b/app/w/components/control-bar/control-bar.tsx
index 21a1090d9d..6f87c1e2d1 100644
--- a/app/w/components/control-bar/control-bar.tsx
+++ b/app/w/components/control-bar/control-bar.tsx
@@ -32,49 +32,44 @@ import { useWorkflowExecution } from '../../hooks/use-workflow-execution'
import { HistoryDropdownItem } from './components/history-dropdown-item'
import { NotificationDropdownItem } from './components/notification-dropdown-item'
+/**
+ * Control bar for managing workflows - handles editing, deletion, deployment,
+ * history, notifications and execution.
+ */
export function ControlBar() {
- const { notifications, getWorkflowNotifications, addNotification } = useNotificationStore()
- const { history, undo, redo, revertToHistoryState, lastSaved } = useWorkflowStore()
- const [isEditing, setIsEditing] = useState(false)
- const [editedName, setEditedName] = useState('')
- const [historyOpen, setHistoryOpen] = useState(false)
- const [notificationsOpen, setNotificationsOpen] = useState(false)
- const { workflows, updateWorkflow, activeWorkflowId, removeWorkflow } = useWorkflowRegistry()
- const [, forceUpdate] = useState({})
- const { isExecuting, handleRunWorkflow } = useWorkflowExecution()
const router = useRouter()
- // Use client-side only rendering for the timestamp
+ // Store hooks
+ const { notifications, getWorkflowNotifications, addNotification } = useNotificationStore()
+ const { history, revertToHistoryState, lastSaved, isDeployed, setDeploymentStatus } =
+ useWorkflowStore()
+ const { workflows, updateWorkflow, activeWorkflowId, removeWorkflow } = useWorkflowRegistry()
+ const { isExecuting, handleRunWorkflow } = useWorkflowExecution()
+
+ // Local state
const [mounted, setMounted] = useState(false)
- useEffect(() => {
- setMounted(true)
- }, [])
+ const [, forceUpdate] = useState({})
+
+ // Workflow name editing state
+ const [isEditing, setIsEditing] = useState(false)
+ const [editedName, setEditedName] = useState('')
+
+ // Dropdown states
+ const [historyOpen, setHistoryOpen] = useState(false)
+ const [notificationsOpen, setNotificationsOpen] = useState(false)
+
+ // Deployment states
+ const [isDeploying, setIsDeploying] = useState(false)
// Get notifications for current workflow
const workflowNotifications = activeWorkflowId
? getWorkflowNotifications(activeWorkflowId)
: notifications // Show all if no workflow is active
- const handleDeleteWorkflow = () => {
- if (!activeWorkflowId) return
-
- // Remove the workflow from the registry
- const newWorkflows = { ...workflows }
- delete newWorkflows[activeWorkflowId]
-
- // Get remaining workflow IDs
- const remainingIds = Object.keys(newWorkflows)
-
- // Navigate before removing the workflow to avoid any state inconsistencies
- if (remainingIds.length > 0) {
- router.push(`/w/${remainingIds[0]}`)
- } else {
- router.push('/')
- }
-
- // Remove the workflow from the registry
- removeWorkflow(activeWorkflowId)
- }
+ // Client-side only rendering for the timestamp
+ useEffect(() => {
+ setMounted(true)
+ }, [])
// Update the time display every minute
useEffect(() => {
@@ -82,6 +77,30 @@ export function ControlBar() {
return () => clearInterval(interval)
}, [])
+ // Check deployment status on mount or when activeWorkflowId changes
+ useEffect(() => {
+ async function checkStatus() {
+ if (!activeWorkflowId) return
+ try {
+ const response = await fetch(`/api/workflow/${activeWorkflowId}/status`)
+ if (response.ok) {
+ const data = await response.json()
+ // Update the store with the deployment status from the API
+ setDeploymentStatus(
+ data.isDeployed,
+ data.deployedAt ? new Date(data.deployedAt) : undefined
+ )
+ }
+ } catch (error) {
+ console.error('Failed to check deployment status:', error)
+ }
+ }
+ checkStatus()
+ }, [activeWorkflowId, setDeploymentStatus])
+
+ /**
+ * Workflow name handlers
+ */
const handleNameClick = () => {
if (activeWorkflowId) {
setEditedName(workflows[activeWorkflowId].name)
@@ -107,28 +126,29 @@ export function ControlBar() {
}
}
- // Add the deployment state and handlers
- const [isDeploying, setIsDeploying] = useState(false)
- const [isDeployed, setIsDeployed] = useState(false)
+ /**
+ * Workflow deletion handler
+ */
+ const handleDeleteWorkflow = () => {
+ if (!activeWorkflowId) return
- // Check deployment status on mount
- useEffect(() => {
- async function checkStatus() {
- if (!activeWorkflowId) return
- try {
- const response = await fetch(`/api/workflow/${activeWorkflowId}/status`)
- if (response.ok) {
- const data = await response.json()
- setIsDeployed(data.isDeployed)
- }
- } catch (error) {
- console.error('Failed to check deployment status:', error)
- }
+ // Get remaining workflow IDs
+ const remainingIds = Object.keys(workflows).filter((id) => id !== activeWorkflowId)
+
+ // Navigate before removing the workflow to avoid any state inconsistencies
+ if (remainingIds.length > 0) {
+ router.push(`/w/${remainingIds[0]}`)
+ } else {
+ router.push('/')
}
- checkStatus()
- }, [activeWorkflowId])
- // Deploy the workflow
+ // Remove the workflow from the registry
+ removeWorkflow(activeWorkflowId)
+ }
+
+ /**
+ * Workflow deployment handler
+ */
const handleDeploy = async () => {
if (!activeWorkflowId) return
try {
@@ -142,9 +162,12 @@ export function ControlBar() {
if (!response.ok) throw new Error('Failed to deploy workflow')
- const { apiKey } = await response.json()
+ const { apiKey, isDeployed: newDeployStatus, deployedAt } = await response.json()
const endpoint = `${process.env.NEXT_PUBLIC_APP_URL}/api/workflow/${activeWorkflowId}/execute`
+ // Update the store with the deployment status
+ setDeploymentStatus(newDeployStatus, deployedAt ? new Date(deployedAt) : undefined)
+
addNotification('api', 'Workflow successfully deployed', activeWorkflowId, {
isPersistent: true,
sections: [
@@ -162,8 +185,6 @@ export function ControlBar() {
},
],
})
-
- setIsDeployed(true)
} catch (error) {
addNotification('error', 'Failed to deploy workflow. Please try again.', activeWorkflowId)
} finally {
@@ -171,201 +192,236 @@ export function ControlBar() {
}
}
+ /**
+ * Render workflow name section (editable/non-editable)
+ */
+ const renderWorkflowName = () => (
+
+ {isEditing ? (
+
setEditedName(e.target.value)}
+ onBlur={handleNameSubmit}
+ onKeyDown={handleNameKeyDown}
+ autoFocus
+ className="font-semibold text-sm bg-transparent border-none outline-none p-0 w-[200px]"
+ />
+ ) : (
+
+ {activeWorkflowId ? workflows[activeWorkflowId]?.name : 'Workflow'}
+
+ )}
+ {mounted && (
+
+ Saved{' '}
+ {formatDistanceToNow(lastSaved || Date.now(), {
+ addSuffix: true,
+ })}
+
+ )}
+
+ )
+
+ /**
+ * Render delete workflow button with confirmation dialog
+ */
+ const renderDeleteButton = () => (
+
+
+
+
+
+
+
+ Delete Workflow
+
+
+
+
+ Delete Workflow
+
+ Are you sure you want to delete this workflow? This action cannot be undone.
+
+
+
+ Cancel
+
+ Delete
+
+
+
+
+ )
+
+ /**
+ * Render deploy button with tooltip
+ */
+ const renderDeployButton = () => (
+
+
+
+
+
+ {isDeploying ? 'Deploying...' : isDeployed ? 'Deployed' : 'Deploy as API Endpoint'}
+
+
+ )
+
+ /**
+ * Render history dropdown
+ */
+ const renderHistoryDropdown = () => (
+
+
+
+
+
+
+
+ {!historyOpen && History}
+
+
+ {history.past.length === 0 && history.future.length === 0 ? (
+
+
+ No history available
+
+
+ ) : (
+
+ <>
+ {[...history.future].reverse().map((entry, index) => (
+
+ revertToHistoryState(
+ history.past.length + 1 + (history.future.length - 1 - index)
+ )
+ }
+ isFuture={true}
+ />
+ ))}
+ {}}
+ />
+ {[...history.past].reverse().map((entry, index) => (
+ revertToHistoryState(history.past.length - 1 - index)}
+ />
+ ))}
+ >
+
+ )}
+
+ )
+
+ /**
+ * Render notifications dropdown
+ */
+ const renderNotificationsDropdown = () => (
+
+
+
+
+
+
+
+ {!notificationsOpen && Notifications}
+
+
+ {workflowNotifications.length === 0 ? (
+
+
+ No new notifications
+
+
+ ) : (
+
+ {[...workflowNotifications]
+ .sort((a, b) => b.timestamp - a.timestamp)
+ .map((notification) => (
+
+ ))}
+
+ )}
+
+ )
+
+ /**
+ * Render run workflow button
+ */
+ const renderRunButton = () => (
+
+ )
+
return (
{/* Left Section - Workflow Info */}
-
- {isEditing ? (
-
setEditedName(e.target.value)}
- onBlur={handleNameSubmit}
- onKeyDown={handleNameKeyDown}
- autoFocus
- className="font-semibold text-sm bg-transparent border-none outline-none p-0 w-[200px]"
- />
- ) : (
-
- {activeWorkflowId ? workflows[activeWorkflowId].name : 'Workflow'}
-
- )}
- {mounted && (
-
- Saved{' '}
- {formatDistanceToNow(lastSaved || Date.now(), {
- addSuffix: true,
- })}
-
- )}
-
+ {renderWorkflowName()}
{/* Middle Section - Reserved for future use */}
{/* Right Section - Actions */}
-
-
-
-
-
-
-
- Delete Workflow
-
-
-
-
- Delete Workflow
-
- Are you sure you want to delete this workflow? This action cannot be undone.
-
-
-
- Cancel
-
- Delete
-
-
-
-
-
-
-
-
-
-
- {isDeploying ? 'Deploying...' : isDeployed ? 'Deployed' : 'Deploy as API Endpoint'}
-
-
-
-
-
-
-
-
-
-
- {!historyOpen && History}
-
-
- {history.past.length === 0 && history.future.length === 0 ? (
-
-
- No history available
-
-
- ) : (
-
- <>
- {[...history.future].reverse().map((entry, index) => (
-
- revertToHistoryState(
- history.past.length + 1 + (history.future.length - 1 - index)
- )
- }
- isFuture={true}
- />
- ))}
- {}}
- />
- {[...history.past].reverse().map((entry, index) => (
- revertToHistoryState(history.past.length - 1 - index)}
- />
- ))}
- >
-
- )}
-
-
-
-
-
-
-
-
-
- {!notificationsOpen && Notifications}
-
-
- {workflowNotifications.length === 0 ? (
-
-
- No new notifications
-
-
- ) : (
-
- {[...workflowNotifications]
- .sort((a, b) => b.timestamp - a.timestamp)
- .map((notification) => (
-
- ))}
-
- )}
-
-
-
+ {renderDeleteButton()}
+ {renderDeployButton()}
+ {renderHistoryDropdown()}
+ {renderNotificationsDropdown()}
+ {renderRunButton()}
)
diff --git a/stores/workflow/history-types.ts b/stores/workflow/history-types.ts
index 290e96ed8a..60c6d405f6 100644
--- a/stores/workflow/history-types.ts
+++ b/stores/workflow/history-types.ts
@@ -4,6 +4,7 @@ export interface HistoryEntry {
state: WorkflowState
timestamp: number
action: string
+ subblockValues: Record>
}
export interface WorkflowHistory {
diff --git a/stores/workflow/middleware.ts b/stores/workflow/middleware.ts
index e0dbe1cf9c..4669f4f1c3 100644
--- a/stores/workflow/middleware.ts
+++ b/stores/workflow/middleware.ts
@@ -1,6 +1,9 @@
import { StateCreator } from 'zustand'
import { HistoryActions, HistoryEntry, WorkflowHistory } from './history-types'
+import { useWorkflowRegistry } from './registry/store'
+import { useSubBlockStore } from './subblock/store'
import { WorkflowState, WorkflowStore } from './types'
+import { mergeSubblockState } from './utils'
// MAX for each individual workflow
const MAX_HISTORY_LENGTH = 20
@@ -22,9 +25,12 @@ export const withHistory = (
blocks: initialState.blocks,
edges: initialState.edges,
loops: initialState.loops,
+ isDeployed: initialState.isDeployed || false,
+ deployedAt: initialState.deployedAt,
},
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {}, // Add storage for subblock values
}
return {
@@ -49,6 +55,11 @@ export const withHistory = (
const previous = history.past[history.past.length - 1]
const newPast = history.past.slice(0, history.past.length - 1)
+ // Get active workflow ID for subblock handling
+ const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
+ if (!activeWorkflowId) return
+
+ // Apply the state change
set({
...state,
...previous.state,
@@ -58,6 +69,23 @@ export const withHistory = (
future: [history.present, ...history.future],
},
})
+
+ // Restore subblock values from the previous state's snapshot
+ if (previous.subblockValues && activeWorkflowId) {
+ // Update the subblock store with the saved values
+ useSubBlockStore.setState({
+ workflowValues: {
+ ...useSubBlockStore.getState().workflowValues,
+ [activeWorkflowId]: previous.subblockValues,
+ },
+ })
+
+ // Also update localStorage for backup
+ localStorage.setItem(
+ `subblock-values-${activeWorkflowId}`,
+ JSON.stringify(previous.subblockValues)
+ )
+ }
},
// Restore next state from history
@@ -68,6 +96,11 @@ export const withHistory = (
const next = history.future[0]
const newFuture = history.future.slice(1)
+ // Get active workflow ID for subblock handling
+ const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
+ if (!activeWorkflowId) return
+
+ // Apply the state change
set({
...state,
...next.state,
@@ -77,6 +110,23 @@ export const withHistory = (
future: newFuture,
},
})
+
+ // Restore subblock values from the next state's snapshot
+ if (next.subblockValues && activeWorkflowId) {
+ // Update the subblock store with the saved values
+ useSubBlockStore.setState({
+ workflowValues: {
+ ...useSubBlockStore.getState().workflowValues,
+ [activeWorkflowId]: next.subblockValues,
+ },
+ })
+
+ // Also update localStorage for backup
+ localStorage.setItem(
+ `subblock-values-${activeWorkflowId}`,
+ JSON.stringify(next.subblockValues)
+ )
+ }
},
// Reset workflow to empty state
@@ -88,9 +138,10 @@ export const withHistory = (
history: {
past: [],
present: {
- state: { blocks: {}, edges: [], loops: {} },
+ state: { blocks: {}, edges: [], loops: {}, isDeployed: false },
timestamp: Date.now(),
action: 'Clear workflow',
+ subblockValues: {},
},
future: [],
},
@@ -107,6 +158,10 @@ export const withHistory = (
if (!targetState) return
+ // Get active workflow ID for subblock handling
+ const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
+ if (!activeWorkflowId) return
+
const newPast = allStates.slice(0, index)
const newFuture = allStates.slice(index + 1)
@@ -119,21 +174,60 @@ export const withHistory = (
future: newFuture,
},
})
+
+ // Restore subblock values from the target state's snapshot
+ if (targetState.subblockValues && activeWorkflowId) {
+ // Update the subblock store with the saved values
+ useSubBlockStore.setState({
+ workflowValues: {
+ ...useSubBlockStore.getState().workflowValues,
+ [activeWorkflowId]: targetState.subblockValues,
+ },
+ })
+
+ // Also update localStorage for backup
+ localStorage.setItem(
+ `subblock-values-${activeWorkflowId}`,
+ JSON.stringify(targetState.subblockValues)
+ )
+ }
},
}
}
}
// Create a new history entry with current state snapshot
-export const createHistoryEntry = (state: WorkflowState, action: string): HistoryEntry => ({
- state: {
+export const createHistoryEntry = (state: WorkflowState, action: string): HistoryEntry => {
+ // Get active workflow ID for subblock handling
+ const activeWorkflowId = useWorkflowRegistry.getState().activeWorkflowId
+
+ // Create a deep copy of the state
+ const stateCopy = {
blocks: { ...state.blocks },
edges: [...state.edges],
loops: { ...state.loops },
- },
- timestamp: Date.now(),
- action,
-})
+ isDeployed: state.isDeployed !== undefined ? state.isDeployed : false,
+ deployedAt: state.deployedAt,
+ }
+
+ // Capture the current subblock values for this workflow
+ let subblockValues = {}
+
+ if (activeWorkflowId) {
+ // Get the current subblock values from the store
+ const currentValues = useSubBlockStore.getState().workflowValues[activeWorkflowId] || {}
+
+ // Create a deep copy to ensure we don't have reference issues
+ subblockValues = JSON.parse(JSON.stringify(currentValues))
+ }
+
+ return {
+ state: stateCopy,
+ timestamp: Date.now(),
+ action,
+ subblockValues,
+ }
+}
// Add new entry to history and maintain history size limit
export const pushHistory = (
diff --git a/stores/workflow/registry/store.ts b/stores/workflow/registry/store.ts
index 1ec30c1b23..d9cb81ec68 100644
--- a/stores/workflow/registry/store.ts
+++ b/stores/workflow/registry/store.ts
@@ -34,6 +34,8 @@ export const useWorkflowRegistry = create()(
edges: currentState.edges,
loops: currentState.loops,
history: currentState.history,
+ isDeployed: currentState.isDeployed,
+ deployedAt: currentState.deployedAt,
})
)
}
@@ -41,7 +43,8 @@ export const useWorkflowRegistry = create()(
// Load workflow state
const savedState = localStorage.getItem(`workflow-${id}`)
if (savedState) {
- const { blocks, edges, history, loops } = JSON.parse(savedState)
+ const parsedState = JSON.parse(savedState)
+ const { blocks, edges, history, loops } = parsedState
// Initialize subblock store with workflow values
useSubBlockStore.getState().initializeFromWorkflow(id, blocks)
@@ -50,12 +53,21 @@ export const useWorkflowRegistry = create()(
blocks,
edges,
loops,
+ isDeployed: parsedState.isDeployed !== undefined ? parsedState.isDeployed : false,
+ deployedAt: parsedState.deployedAt ? new Date(parsedState.deployedAt) : undefined,
history: history || {
past: [],
present: {
- state: { blocks, edges, loops: {} },
+ state: {
+ blocks,
+ edges,
+ loops: {},
+ isDeployed: parsedState.isDeployed !== undefined ? parsedState.isDeployed : false,
+ deployedAt: parsedState.deployedAt,
+ },
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {},
},
future: [],
},
@@ -65,12 +77,21 @@ export const useWorkflowRegistry = create()(
blocks: {},
edges: [],
loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
history: {
past: [],
present: {
- state: { blocks: {}, edges: [], loops: {} },
+ state: {
+ blocks: {},
+ edges: [],
+ loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
+ },
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {},
},
future: [],
},
@@ -197,6 +218,8 @@ export const useWorkflowRegistry = create()(
},
edges: [],
loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
history: {
past: [],
present: {
@@ -206,9 +229,12 @@ export const useWorkflowRegistry = create()(
},
edges: [],
loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
},
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {},
},
future: [],
},
@@ -263,17 +289,21 @@ export const useWorkflowRegistry = create()(
newActiveWorkflowId = remainingIds[0]
const savedState = localStorage.getItem(`workflow-${newActiveWorkflowId}`)
if (savedState) {
- const { blocks, edges, history, loops } = JSON.parse(savedState)
+ const { blocks, edges, history, loops, isDeployed, deployedAt } =
+ JSON.parse(savedState)
useWorkflowStore.setState({
blocks,
edges,
loops,
+ isDeployed: isDeployed || false,
+ deployedAt: deployedAt ? new Date(deployedAt) : undefined,
history: history || {
past: [],
present: {
- state: { blocks, edges, loops },
+ state: { blocks, edges, loops, isDeployed: isDeployed || false, deployedAt },
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {},
},
future: [],
},
@@ -283,12 +313,21 @@ export const useWorkflowRegistry = create()(
blocks: {},
edges: [],
loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
history: {
past: [],
present: {
- state: { blocks: {}, edges: [], loops: {} },
+ state: {
+ blocks: {},
+ edges: [],
+ loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
+ },
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {},
},
future: [],
},
@@ -354,6 +393,8 @@ const initializeRegistry = () => {
edges: currentState.edges,
loops: currentState.loops,
history: currentState.history,
+ isDeployed: currentState.isDeployed,
+ deployedAt: currentState.deployedAt,
})
)
}
diff --git a/stores/workflow/registry/utils.ts b/stores/workflow/registry/utils.ts
index 0896c4c5ae..a9ccf4d699 100644
--- a/stores/workflow/registry/utils.ts
+++ b/stores/workflow/registry/utils.ts
@@ -3,6 +3,7 @@ import { WorkflowMetadata } from './types'
// Available workflow colors
export const WORKFLOW_COLORS = ['#3972F6', '#F639DD', '#F6B539', '#8139F6', '#F64439']
+// Generates a unique name for a new workflow
export function generateUniqueName(existingWorkflows: Record): string {
// Extract numbers from existing workflow names using regex
const numbers = Object.values(existingWorkflows)
@@ -21,11 +22,7 @@ export function generateUniqueName(existingWorkflows: Record): string {
const workflowArray = Object.values(existingWorkflows)
diff --git a/stores/workflow/store.ts b/stores/workflow/store.ts
index 880dfe0195..75f6dbea15 100644
--- a/stores/workflow/store.ts
+++ b/stores/workflow/store.ts
@@ -15,12 +15,15 @@ const initialState = {
edges: [],
loops: {},
lastSaved: undefined,
+ isDeployed: false,
+ deployedAt: undefined,
history: {
past: [],
present: {
- state: { blocks: {}, edges: [], loops: {} },
+ state: { blocks: {}, edges: [], loops: {}, isDeployed: false },
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {},
},
future: [],
},
@@ -70,6 +73,8 @@ export const useWorkflowStore = create()(
},
edges: [...get().edges],
loops: { ...get().loops },
+ isDeployed: get().isDeployed,
+ deployedAt: get().deployedAt,
}
set(newState)
@@ -100,6 +105,8 @@ export const useWorkflowStore = create()(
blocks: { ...get().blocks },
edges: [...get().edges].filter((edge) => edge.source !== id && edge.target !== id),
loops: { ...get().loops },
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
// Clean up subblock values before removing the block
@@ -192,6 +199,8 @@ export const useWorkflowStore = create()(
blocks: { ...get().blocks },
edges: newEdges,
loops: newLoops,
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
set(newState)
@@ -229,6 +238,8 @@ export const useWorkflowStore = create()(
blocks: { ...get().blocks },
edges: newEdges,
loops: newLoops,
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
set(newState)
@@ -241,12 +252,21 @@ export const useWorkflowStore = create()(
blocks: {},
edges: [],
loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
history: {
past: [],
present: {
- state: { blocks: {}, edges: [], loops: {} },
+ state: {
+ blocks: {},
+ edges: [],
+ loops: {},
+ isDeployed: false,
+ deployedAt: undefined,
+ },
timestamp: Date.now(),
action: 'Initial state',
+ subblockValues: {},
},
future: [],
},
@@ -270,6 +290,8 @@ export const useWorkflowStore = create()(
},
},
edges: [...get().edges],
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
set(newState)
@@ -319,6 +341,8 @@ export const useWorkflowStore = create()(
},
edges: [...get().edges],
loops: { ...get().loops },
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
// Update the subblock store with the duplicated values
@@ -352,6 +376,8 @@ export const useWorkflowStore = create()(
},
},
edges: [...get().edges],
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
set(newState)
@@ -369,6 +395,8 @@ export const useWorkflowStore = create()(
},
edges: [...get().edges],
loops: { ...get().loops },
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
set(newState)
@@ -387,6 +415,8 @@ export const useWorkflowStore = create()(
},
edges: [...state.edges],
loops: { ...get().loops },
+ isDeployed: state.isDeployed || false,
+ deployedAt: state.deployedAt,
}))
get().updateLastSaved()
},
@@ -401,6 +431,8 @@ export const useWorkflowStore = create()(
},
},
edges: [...state.edges],
+ isDeployed: state.isDeployed || false,
+ deployedAt: state.deployedAt,
}))
get().updateLastSaved()
},
@@ -416,6 +448,8 @@ export const useWorkflowStore = create()(
maxIterations: Math.max(1, Math.min(50, maxIterations)), // Clamp between 1-50
},
},
+ isDeployed: get().isDeployed || false,
+ deployedAt: get().deployedAt,
}
set(newState)
@@ -429,6 +463,17 @@ export const useWorkflowStore = create()(
lastUpdate: Date.now(),
}))
},
+
+ setDeploymentStatus: (isDeployed: boolean, deployedAt?: Date) => {
+ const newState = {
+ ...get(),
+ isDeployed,
+ deployedAt: deployedAt || (isDeployed ? new Date() : undefined),
+ }
+
+ set(newState)
+ get().updateLastSaved()
+ },
})),
{ name: 'workflow-store' }
)
diff --git a/stores/workflow/types.ts b/stores/workflow/types.ts
index 14ce32ac63..2c27862733 100644
--- a/stores/workflow/types.ts
+++ b/stores/workflow/types.ts
@@ -37,6 +37,8 @@ export interface WorkflowState {
lastSaved?: number
loops: Record
lastUpdate?: number
+ isDeployed: boolean
+ deployedAt?: Date
}
export interface WorkflowActions {
@@ -55,6 +57,7 @@ export interface WorkflowActions {
updateBlockHeight: (id: string, height: number) => void
updateLoopMaxIterations: (loopId: string, maxIterations: number) => void
triggerUpdate: () => void
+ setDeploymentStatus: (isDeployed: boolean, deployedAt?: Date) => void
}
export type WorkflowStore = WorkflowState & WorkflowActions