Added block name and changed structure of console component

This commit is contained in:
Emir Karabeg
2025-01-31 13:15:01 -08:00
parent ae4ae535e9
commit 058865f506
5 changed files with 150 additions and 123 deletions
@@ -0,0 +1,75 @@
import { useState, useMemo } from 'react'
import { formatDistanceToNow, format } from 'date-fns'
import {
Terminal,
Clock,
Calendar,
CheckCircle2,
AlertCircle,
} from 'lucide-react'
import { ConsoleEntry as ConsoleEntryType } from '@/stores/console/types'
import { JSONView } from '../json-view/json-view'
interface ConsoleEntryProps {
entry: ConsoleEntryType
}
export function ConsoleEntry({ entry }: ConsoleEntryProps) {
const [isExpanded, setIsExpanded] = useState(false)
const timeAgo = useMemo(
() =>
formatDistanceToNow(new Date(entry.startedAt), {
addSuffix: true,
}),
[entry.startedAt]
)
const statusIcon = entry.error ? (
<AlertCircle className="h-4 w-4 text-destructive" />
) : (
<CheckCircle2 className="h-4 w-4 text-success" />
)
return (
<div className="border-b border-border hover:bg-accent/50 transition-colors">
<div className="p-4 space-y-4">
{entry.blockName && (
<div className="flex items-center gap-2 text-sm">
{statusIcon}
<span className="text-muted-foreground">{entry.blockName}</span>
</div>
)}
<div className="grid grid-cols-2 gap-4 text-sm text-muted-foreground">
<div className="flex items-center gap-2">
<Calendar className="h-4 w-4" />
<span>{format(new Date(entry.startedAt), 'HH:mm:ss')}</span>
</div>
<div className="flex items-center gap-2">
<Clock className="h-4 w-4" />
<span>Duration: {entry.durationMs}ms</span>
</div>
</div>
<div className="space-y-4">
<div className="flex items-start gap-2">
<Terminal className="h-4 w-4 text-muted-foreground mt-1" />
<div className="text-sm font-mono flex-1">
<JSONView data={entry.output} />
</div>
</div>
{entry.error && (
<div className="flex items-start gap-2 border rounded-md p-3 border-red-500 bg-red-50 text-destructive dark:border-border dark:text-foreground dark:bg-background">
<AlertCircle className="h-4 w-4 text-red-500 mt-1" />
<div className="flex-1 break-all">
<div className="font-medium">Error</div>
<pre className="text-sm whitespace-pre-wrap">{entry.error}</pre>
</div>
</div>
)}
</div>
</div>
</div>
)
}
@@ -0,0 +1,65 @@
import { useState } from 'react'
interface JSONViewProps {
data: any
level?: number
}
export const JSONView = ({ data, level = 0 }: JSONViewProps) => {
const [isCollapsed, setIsCollapsed] = useState(true)
if (data === null) return <span className="text-muted-foreground">null</span>
if (typeof data !== 'object') {
return (
<span
className={`${
typeof data === 'string' ? 'text-success' : 'text-info'
} break-all`}
>
{JSON.stringify(data)}
</span>
)
}
const isArray = Array.isArray(data)
const items = isArray ? data : Object.entries(data)
const isEmpty = items.length === 0
if (isEmpty) {
return <span>{isArray ? '[]' : '{}'}</span>
}
return (
<div className="relative">
<span
className="cursor-pointer select-none"
onClick={(e) => {
e.stopPropagation()
setIsCollapsed(!isCollapsed)
}}
>
{isCollapsed ? '▶' : '▼'} {isArray ? '[' : '{'}
{isCollapsed ? '...' : ''}
</span>
{!isCollapsed && (
<div className="ml-4 break-words">
{isArray
? items.map((item, index) => (
<div key={index} className="break-all">
<JSONView data={item} level={level + 1} />
{index < items.length - 1 && ','}
</div>
))
: (items as [string, any][]).map(([key, value], index) => (
<div key={key} className="break-all">
<span className="text-muted-foreground">{key}</span>:{' '}
<JSONView data={value} level={level + 1} />
{index < items.length - 1 && ','}
</div>
))}
</div>
)}
<span>{isArray ? ']' : '}'}</span>
</div>
)
}
+2 -119
View File
@@ -1,16 +1,7 @@
'use client'
import { useState, useMemo, useEffect } from 'react'
import { formatDistanceToNow, format } from 'date-fns'
import {
PanelLeftClose,
Terminal,
XCircle,
Clock,
Calendar,
CheckCircle2,
AlertCircle,
} from 'lucide-react'
import { PanelLeftClose, Terminal } from 'lucide-react'
import {
Tooltip,
TooltipContent,
@@ -19,115 +10,8 @@ import {
import { useConsoleStore } from '@/stores/console/store'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Button } from '@/components/ui/button'
import { ConsoleEntry as ConsoleEntryType } from '@/stores/console/types'
import { useWorkflowRegistry } from '@/stores/workflow/registry'
function JSONView({ data, level = 0 }: { data: any; level?: number }) {
const [isCollapsed, setIsCollapsed] = useState(true)
if (data === null) return <span className="text-muted-foreground">null</span>
if (typeof data !== 'object') {
return (
<span
className={`${
typeof data === 'string' ? 'text-success' : 'text-info'
} break-all`}
>
{JSON.stringify(data)}
</span>
)
}
const isArray = Array.isArray(data)
const items = isArray ? data : Object.entries(data)
const isEmpty = items.length === 0
if (isEmpty) {
return <span>{isArray ? '[]' : '{}'}</span>
}
return (
<div className="relative">
<span
className="cursor-pointer select-none"
onClick={(e) => {
e.stopPropagation()
setIsCollapsed(!isCollapsed)
}}
>
{isCollapsed ? '▶' : '▼'} {isArray ? '[' : '{'}
{isCollapsed ? '...' : ''}
</span>
{!isCollapsed && (
<div className="ml-4 break-words">
{isArray
? items.map((item, index) => (
<div key={index} className="break-all">
<JSONView data={item} level={level + 1} />
{index < items.length - 1 && ','}
</div>
))
: (items as [string, any][]).map(([key, value], index) => (
<div key={key} className="break-all">
<span className="text-muted-foreground">{key}</span>:{' '}
<JSONView data={value} level={level + 1} />
{index < items.length - 1 && ','}
</div>
))}
</div>
)}
<span>{isArray ? ']' : '}'}</span>
</div>
)
}
function ConsoleEntry({ entry }: { entry: ConsoleEntryType }) {
const [isExpanded, setIsExpanded] = useState(false)
const timeAgo = useMemo(
() =>
formatDistanceToNow(new Date(entry.startedAt), {
addSuffix: true,
}),
[entry.startedAt]
)
return (
<div className="border-b border-border hover:bg-accent/50 transition-colors">
<div className="p-4 space-y-4">
<div className="grid grid-cols-2 gap-4 text-sm text-muted-foreground">
<div className="flex items-center gap-2">
<Calendar className="h-4 w-4" />
<span>{format(new Date(entry.startedAt), 'HH:mm:ss')}</span>
</div>
<div className="flex items-center gap-2">
<Clock className="h-4 w-4" />
<span>Duration: {entry.durationMs}ms</span>
</div>
</div>
<div className="space-y-4">
<div className="flex items-start gap-2">
<Terminal className="h-4 w-4 text-muted-foreground mt-1" />
<div className="text-sm font-mono flex-1">
<JSONView data={entry.output} />
</div>
</div>
{entry.error && (
<div className="flex items-start gap-2 border rounded-md p-3 border-red-500 bg-red-50 text-destructive dark:border-border dark:text-foreground dark:bg-background">
<AlertCircle className="h-4 w-4 text-red-500 mt-1" />
<div className="flex-1 break-all">
<div className="font-medium">Error</div>
<pre className="text-sm whitespace-pre-wrap">{entry.error}</pre>
</div>
</div>
)}
</div>
</div>
</div>
)
}
import { ConsoleEntry } from './components/console-entry/console-entry'
export function Console() {
const [isCollapsed, setIsCollapsed] = useState(false)
@@ -137,7 +21,6 @@ export function Console() {
const clearConsole = useConsoleStore((state) => state.clearConsole)
const { activeWorkflowId } = useWorkflowRegistry()
// Filter entries for active workflow
const filteredEntries = useMemo(() => {
return entries.filter((entry) => entry.workflowId === activeWorkflowId)
}, [entries, activeWorkflowId])
+6 -3
View File
@@ -44,7 +44,8 @@ export function useWorkflowExecution() {
startedAt: log.startedAt,
endedAt: log.endedAt,
workflowId: activeWorkflowId,
timestamp: log.startedAt // Using startedAt as the timestamp
timestamp: log.startedAt,
blockName: log.blockTitle
})
})
}
@@ -57,7 +58,8 @@ export function useWorkflowExecution() {
startedAt: result.metadata?.startTime || new Date().toISOString(),
endedAt: result.metadata?.endTime || new Date().toISOString(),
workflowId: activeWorkflowId,
timestamp: result.metadata?.startTime || new Date().toISOString()
timestamp: result.metadata?.startTime || new Date().toISOString(),
blockName: 'Workflow Result'
})
if (result.logs) {
@@ -111,7 +113,8 @@ export function useWorkflowExecution() {
startedAt: new Date().toISOString(),
endedAt: new Date().toISOString(),
workflowId: activeWorkflowId,
timestamp: new Date().toISOString()
timestamp: new Date().toISOString(),
blockName: 'Error'
})
addNotification('error', `Workflow execution failed: ${errorMessage}`, activeWorkflowId)
+2 -1
View File
@@ -6,7 +6,8 @@ export interface ConsoleEntry {
startedAt: string
endedAt: string
workflowId?: string | null
timestamp: string
timestamp: string
blockName?: string
}
export interface ConsoleStore {