This commit is contained in:
Siddharth Ganesan
2025-08-28 18:11:18 -07:00
parent 6df565e4c8
commit 694538e1ee
5 changed files with 564 additions and 387 deletions

View File

@@ -8,8 +8,6 @@ import {
Layers,
Play,
RefreshCw,
SkipForward,
StepForward,
Store,
Trash2,
WifiOff,
@@ -44,6 +42,7 @@ import {
getKeyboardShortcutText,
useKeyboardShortcuts,
} from '@/app/workspace/[workspaceId]/w/hooks/use-keyboard-shortcuts'
import { useExecutionStore } from '@/stores/execution/store'
import { useFolderStore } from '@/stores/folders/store'
import { usePanelStore } from '@/stores/panel/store'
import { useGeneralStore } from '@/stores/settings/general/store'
@@ -52,7 +51,6 @@ import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
import type { WorkflowState } from '@/stores/workflows/workflow/types'
import { useExecutionStore } from '@/stores/execution/store'
const logger = createLogger('ControlBar')

View File

@@ -10,16 +10,16 @@ import {
import { ScrollArea } from '@/components/ui/scroll-area'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { useCopilotStore } from '@/stores/copilot/store'
import { useExecutionStore } from '@/stores/execution/store'
import { useChatStore } from '@/stores/panel/chat/store'
import { useConsoleStore } from '@/stores/panel/console/store'
import { usePanelStore } from '@/stores/panel/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useExecutionStore } from '@/stores/execution/store'
import { Chat } from './components/chat/chat'
import { Console } from './components/console/console'
import { Copilot } from './components/copilot/copilot'
import { Variables } from './components/variables/variables'
import { DebugPanel } from './components/debug/debug'
import { Variables } from './components/variables/variables'
export function Panel() {
const [chatMessage, setChatMessage] = useState<string>('')
@@ -45,7 +45,7 @@ export function Panel() {
const clearChat = useChatStore((state) => state.clearChat)
const exportChatCSV = useChatStore((state) => state.exportChatCSV)
const { activeWorkflowId } = useWorkflowRegistry()
// Get debug state
const isDebugging = useExecutionStore((state) => state.isDebugging)
@@ -313,7 +313,10 @@ export function Panel() {
return (
<>
{/* Tab Selector - Always visible */}
<div className='fixed top-[76px] right-4 z-20 flex h-9 items-center gap-1 rounded-[14px] border bg-card px-[2.5px] py-1 shadow-xs' style={{ width: isDebugging ? '380px' : '308px' }}>
<div
className='fixed top-[76px] right-4 z-20 flex h-9 items-center gap-1 rounded-[14px] border bg-card px-[2.5px] py-1 shadow-xs'
style={{ width: isDebugging ? '380px' : '308px' }}
>
<button
onClick={() => handleTabClick('chat')}
className={`panel-tab-base inline-flex flex-1 cursor-pointer items-center justify-center rounded-[10px] border border-transparent py-1 font-[450] text-sm outline-none transition-colors duration-200 ${

View File

@@ -13,6 +13,8 @@ import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/provide
import type { BlockConfig, SubBlockConfig, SubBlockType } from '@/blocks/types'
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
import { useExecutionStore } from '@/stores/execution/store'
import { usePanelStore } from '@/stores/panel/store'
import { useGeneralStore } from '@/stores/settings/general/store'
import { useWorkflowDiffStore } from '@/stores/workflow-diff'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
@@ -22,8 +24,6 @@ import { useCurrentWorkflow } from '../../hooks'
import { ActionBar } from './components/action-bar/action-bar'
import { ConnectionBlocks } from './components/connection-blocks/connection-blocks'
import { SubBlock } from './components/sub-block/sub-block'
import { usePanelStore } from '@/stores/panel/store'
import { useGeneralStore } from '@/stores/settings/general/store'
interface WorkflowBlockProps {
type: string
@@ -607,34 +607,45 @@ export function WorkflowBlock({ id, data }: NodeProps<WorkflowBlockProps>) {
const isExecutingNow = isDebugModeEnabled ? executingBlockIds.has(id) : activeBlockIds.has(id)
const isCurrentBlock = isDebugModeEnabled && isPending
const isPanelFocused = isDebugModeEnabled && panelFocusedBlockId === id
// Check if block has errored during debug execution
const hasError = isDebugModeEnabled && debugContext ? (() => {
// Check direct block state for error
const directState = debugContext.blockStates?.get(id)
if (directState?.output && typeof directState.output === 'object' && 'error' in directState.output) {
return true
}
// Check virtual executions for errors (for blocks inside parallels)
for (const [key, state] of (debugContext.blockStates?.entries() || [])) {
// Check if this is a virtual ID for our block
if (typeof key === 'string' && key.startsWith(`${id}_parallel_`)) {
if (state?.output && typeof state.output === 'object' && 'error' in state.output) {
return true
}
}
}
// Also check block logs for this block
const hasErrorLog = debugContext.blockLogs?.some((log: any) => {
if (log.blockId === id && !log.success) return true
// Check if log is for a virtual version of this block
if (typeof log.blockId === 'string' && log.blockId.startsWith(`${id}_parallel_`) && !log.success) {
return true
}
return false
})
return hasErrorLog || false
})() : false
const hasError =
isDebugModeEnabled && debugContext
? (() => {
// Check direct block state for error
const directState = debugContext.blockStates?.get(id)
if (
directState?.output &&
typeof directState.output === 'object' &&
'error' in directState.output
) {
return true
}
// Check virtual executions for errors (for blocks inside parallels)
for (const [key, state] of debugContext.blockStates?.entries() || []) {
// Check if this is a virtual ID for our block
if (typeof key === 'string' && key.startsWith(`${id}_parallel_`)) {
if (state?.output && typeof state.output === 'object' && 'error' in state.output) {
return true
}
}
}
// Also check block logs for this block
const hasErrorLog = debugContext.blockLogs?.some((log: any) => {
if (log.blockId === id && !log.success) return true
// Check if log is for a virtual version of this block
if (
typeof log.blockId === 'string' &&
log.blockId.startsWith(`${id}_parallel_`) &&
!log.success
) {
return true
}
return false
})
return hasErrorLog || false
})()
: false
return (
<div className='group relative'>
@@ -654,8 +665,12 @@ export function WorkflowBlock({ id, data }: NodeProps<WorkflowBlockProps>) {
// Pending blocks show blue border when not executing
!hasError && !isExecutingNow && isCurrentBlock && 'ring-2 ring-blue-500',
// Diff highlighting (only if not in debug error state)
!hasError && diffStatus === 'new' && 'bg-green-50/50 ring-2 ring-green-500 dark:bg-green-900/10',
!hasError && diffStatus === 'edited' && 'bg-orange-50/50 ring-2 ring-orange-500 dark:bg-orange-900/10',
!hasError &&
diffStatus === 'new' &&
'bg-green-50/50 ring-2 ring-green-500 dark:bg-green-900/10',
!hasError &&
diffStatus === 'edited' &&
'bg-orange-50/50 ring-2 ring-orange-500 dark:bg-orange-900/10',
// Deleted block highlighting (in original workflow)
isDeletedBlock && 'bg-red-50/50 ring-2 ring-red-500 dark:bg-red-900/10',
'z-[20]'
@@ -668,14 +683,14 @@ export function WorkflowBlock({ id, data }: NodeProps<WorkflowBlockProps>) {
Error
</div>
)}
{/* Show debug indicator for current blocks in debug mode (pending or executing) - but not if errored */}
{!hasError && isDebugModeEnabled && (isPending || executingBlockIds.has(id)) && (
<div className='-top-6 -translate-x-1/2 absolute left-1/2 z-10 transform rounded-t-md bg-blue-500 px-2 py-0.5 text-white text-xs'>
Current
</div>
)}
{/* Show breakpoint indicator */}
{isDebugModeEnabled && breakpointId === id && (
<div className='-bottom-6 -translate-x-1/2 absolute left-1/2 z-10 transform rounded-b-md bg-red-500 px-2 py-0.5 text-white text-xs'>

View File

@@ -503,7 +503,8 @@ export function useWorkflowExecution() {
})
return errorResult
}
}, [
},
[
activeWorkflowId,
currentWorkflow,
toggleConsole,
@@ -516,7 +517,8 @@ export function useWorkflowExecution() {
setExecutor,
setPendingBlocks,
setActiveBlocks,
])
]
)
const executeWorkflow = async (
workflowInput?: any,