@@ -51,12 +51,13 @@ import {
5151 getKeyboardShortcutText ,
5252 useKeyboardShortcuts ,
5353} from '../../../hooks/use-keyboard-shortcuts'
54- import { useDeploymentChangeDetection } from '../../hooks/use-deployment-change-detection'
5554import { useWorkflowExecution } from '../../hooks/use-workflow-execution'
5655import { DeploymentControls } from './components/deployment-controls/deployment-controls'
5756import { HistoryDropdownItem } from './components/history-dropdown-item/history-dropdown-item'
5857import { MarketplaceModal } from './components/marketplace-modal/marketplace-modal'
5958import { NotificationDropdownItem } from './components/notification-dropdown-item/notification-dropdown-item'
59+ import { useSubBlockStore } from '@/stores/workflows/subblock/store'
60+ import { mergeSubblockState } from '@/stores/workflows/utils'
6061
6162const logger = createLogger ( 'ControlBar' )
6263
@@ -87,7 +88,8 @@ export function ControlBar() {
8788 showNotification,
8889 removeNotification,
8990 } = useNotificationStore ( )
90- const { history, revertToHistoryState, lastSaved, setNeedsRedeploymentFlag } = useWorkflowStore ( )
91+ const { history, revertToHistoryState, lastSaved, setNeedsRedeploymentFlag, blocks } = useWorkflowStore ( )
92+ const { workflowValues } = useSubBlockStore ( )
9193 const {
9294 workflows,
9395 updateWorkflow,
@@ -112,6 +114,9 @@ export function ControlBar() {
112114 const [ deployedState , setDeployedState ] = useState < WorkflowState | null > ( null )
113115 const [ isLoadingDeployedState , setIsLoadingDeployedState ] = useState < boolean > ( false )
114116
117+ // Change detection state
118+ const [ changeDetected , setChangeDetected ] = useState ( false )
119+
115120 // Workflow name editing state
116121 const [ isEditing , setIsEditing ] = useState ( false )
117122 const [ editedName , setEditedName ] = useState ( '' )
@@ -179,10 +184,6 @@ export function ControlBar() {
179184 )
180185 const isDeployed = deploymentStatus ?. isDeployed || false
181186
182- // Custom hook for deployment change detection
183- const { needsRedeployment, setNeedsRedeployment, clearNeedsRedeployment } =
184- useDeploymentChangeDetection ( activeWorkflowId , isDeployed )
185-
186187 // Client-side only rendering for the timestamp
187188 useEffect ( ( ) => {
188189 setMounted ( true )
@@ -258,31 +259,54 @@ export function ControlBar() {
258259 }
259260
260261 if ( isDeployed ) {
261- // When deployed - fetch the actual deployed state
262- setNeedsRedeployment ( false )
263262 setNeedsRedeploymentFlag ( false )
264263 fetchDeployedState ( )
265264 } else {
266265 // When not deployed - clear the deployed state
267266 setDeployedState ( null )
268267 setIsLoadingDeployedState ( false )
269268 }
270- } , [ activeWorkflowId , isDeployed , setNeedsRedeploymentFlag , setNeedsRedeployment ] )
269+ } , [ activeWorkflowId , isDeployed , setNeedsRedeploymentFlag ] )
271270
272- // Update existing API notifications when needsRedeployment changes
271+ // Subscribe to workflow and subblock changes to detect differences from deployed state
273272 useEffect ( ( ) => {
274- if ( ! activeWorkflowId ) return
273+ if ( ! activeWorkflowId || ! deployedState ) {
274+ setChangeDetected ( false )
275+ return
276+ }
275277
276- const apiNotification = notifications . find (
277- ( n ) => n . type === 'api' && n . workflowId === activeWorkflowId && n . options ?. isPersistent
278- )
278+ const checkForChanges = ( ) => {
279+ // Get fresh state each time
280+ const currentBlocks = useWorkflowStore . getState ( ) . blocks
281+ if ( ! currentBlocks || ! deployedState ) return
282+
283+ // Merge current workflow state with subblock values
284+ const currentMergedState = mergeSubblockState ( currentBlocks , activeWorkflowId )
285+
286+ // Compare with deployed state
287+ const deployedBlocks = ( deployedState as any ) ?. blocks
288+ if ( ! deployedBlocks ) return
289+
290+ const hasChanges = JSON . stringify ( currentMergedState ) !== JSON . stringify ( deployedBlocks )
291+
292+ // Only update if the state actually changed to prevent unnecessary renders
293+ setChangeDetected ( prev => prev !== hasChanges ? hasChanges : prev )
294+ }
279295
280- if ( apiNotification && apiNotification . options ?. needsRedeployment !== needsRedeployment ) {
281- if ( apiNotification . isVisible ) {
282- removeNotification ( apiNotification . id )
283- }
296+ // Check immediately
297+ checkForChanges ( )
298+
299+ // Subscribe to workflow store changes (blocks structure/content changes)
300+ const unsubscribeWorkflow = useWorkflowStore . subscribe ( checkForChanges )
301+
302+ // Subscribe to subblock store changes (subblock values changes)
303+ const unsubscribeSubBlocks = useSubBlockStore . subscribe ( checkForChanges )
304+
305+ return ( ) => {
306+ unsubscribeWorkflow ( )
307+ unsubscribeSubBlocks ( )
284308 }
285- } , [ needsRedeployment , activeWorkflowId , notifications , removeNotification ] )
309+ } , [ activeWorkflowId , deployedState ] )
286310
287311 // Check usage limits when component mounts and when user executes a workflow
288312 useEffect ( ( ) => {
@@ -604,8 +628,8 @@ export function ControlBar() {
604628 const renderDeployButton = ( ) => (
605629 < DeploymentControls
606630 activeWorkflowId = { activeWorkflowId }
607- needsRedeployment = { needsRedeployment }
608- setNeedsRedeployment = { setNeedsRedeployment }
631+ needsRedeployment = { changeDetected }
632+ setNeedsRedeployment = { setChangeDetected }
609633 deployedState = { deployedState }
610634 isLoadingDeployedState = { isLoadingDeployedState }
611635 refetchDeployedState = { fetchDeployedState }
0 commit comments