Improved json view on console

This commit is contained in:
Emir Karabeg
2025-01-31 17:33:44 -08:00
parent e4a6c8b1a5
commit f188ebb04b
2 changed files with 63 additions and 10 deletions

View File

@@ -41,7 +41,12 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
)
return (
<div className="border-b border-border hover:bg-accent/50 transition-colors">
<div
className={`border-b border-border transition-colors ${
!entry.error ? 'hover:bg-accent/50 cursor-pointer' : ''
}`}
onClick={() => !entry.error && setIsExpanded(!isExpanded)}
>
<div className="p-4 space-y-4">
<div
className={`${
@@ -81,7 +86,7 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
<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} />
<JSONView data={entry.output} initiallyExpanded={isExpanded} />
</div>
</div>
)}

View File

@@ -1,22 +1,65 @@
import { useState } from 'react'
import { useState, useEffect } from 'react'
import { ChevronRight, ChevronDown } from 'lucide-react'
import { Button } from '@/components/ui/button'
interface JSONViewProps {
data: any
level?: number
initiallyExpanded?: boolean
}
export const JSONView = ({ data, level = 0 }: JSONViewProps) => {
const [isCollapsed, setIsCollapsed] = useState(true)
const MAX_STRING_LENGTH = 150
const TruncatedValue = ({ value }: { value: string }) => {
const [isExpanded, setIsExpanded] = useState(false)
if (value.length <= MAX_STRING_LENGTH) {
return <span>{value}</span>
}
return (
<span>
{isExpanded ? value : `${value.slice(0, MAX_STRING_LENGTH)}...`}
<Button
variant="link"
size="sm"
className="px-1 h-auto text-xs text-muted-foreground hover:text-foreground"
onClick={(e) => {
e.stopPropagation()
setIsExpanded(!isExpanded)
}}
>
{isExpanded ? 'Show less' : 'Show more'}
</Button>
</span>
)
}
export const JSONView = ({
data,
level = 0,
initiallyExpanded = false,
}: JSONViewProps) => {
const [isCollapsed, setIsCollapsed] = useState(!initiallyExpanded)
useEffect(() => {
setIsCollapsed(!initiallyExpanded)
}, [initiallyExpanded])
if (data === null) return <span className="text-muted-foreground">null</span>
if (typeof data !== 'object') {
const stringValue = JSON.stringify(data)
return (
<span
className={`${
typeof data === 'string' ? 'text-success' : 'text-info'
} break-all`}
>
{JSON.stringify(data)}
{typeof data === 'string' ? (
<TruncatedValue value={stringValue} />
) : (
stringValue
)}
</span>
)
}
@@ -26,19 +69,24 @@ export const JSONView = ({ data, level = 0 }: JSONViewProps) => {
const isEmpty = items.length === 0
if (isEmpty) {
return <span>{isArray ? '[]' : '{}'}</span>
return (
<span className="text-muted-foreground">{isArray ? '[]' : '{}'}</span>
)
}
return (
<div className="relative">
<span
className="cursor-pointer select-none"
className="cursor-pointer select-none inline-flex items-center text-muted-foreground"
onClick={(e) => {
e.stopPropagation()
setIsCollapsed(!isCollapsed)
}}
>
{isCollapsed ? '▶' : '▼'} {isArray ? '[' : '{'}
<span className="text-xs leading-none mr-1">
{isCollapsed ? '▶' : '▼'}
</span>
<span>{isArray ? '[' : '{'}</span>
{isCollapsed ? '...' : ''}
</span>
{!isCollapsed && (
@@ -59,7 +107,7 @@ export const JSONView = ({ data, level = 0 }: JSONViewProps) => {
))}
</div>
)}
<span>{isArray ? ']' : '}'}</span>
<span className="text-muted-foreground">{isArray ? ']' : '}'}</span>
</div>
)
}