Skip to content

Commit 434d495

Browse files
committed
improvement(ux): add/collapse all on console entry
1 parent b37e3e6 commit 434d495

File tree

2 files changed

+80
-8
lines changed

2 files changed

+80
-8
lines changed

sim/app/w/[id]/components/panel/components/console/components/console-entry/console-entry.tsx

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import { useMemo, useState } from 'react'
22
import { format } from 'date-fns'
3-
import { AlertCircle, AlertTriangle, Calendar, CheckCircle2, Clock, Terminal } from 'lucide-react'
3+
import {
4+
AlertCircle,
5+
AlertTriangle,
6+
Calendar,
7+
CheckCircle2,
8+
ChevronDown,
9+
ChevronUp,
10+
Clock,
11+
Terminal,
12+
} from 'lucide-react'
13+
import { Button } from '@/components/ui/button'
414
import { ConsoleEntry as ConsoleEntryType } from '@/stores/panel/console/types'
515
import { getBlock } from '@/blocks'
616
import { JSONView } from '../json-view/json-view'
@@ -47,6 +57,7 @@ const WordWrap = ({ text }: { text: string }) => {
4757

4858
export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
4959
const [isExpanded, setIsExpanded] = useState(false)
60+
const [expandAllJson, setExpandAllJson] = useState(false)
5061

5162
const blockConfig = useMemo(() => {
5263
if (!entry.blockType) return null
@@ -63,6 +74,22 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
6374
<CheckCircle2 className="h-4 w-4 text-muted-foreground" />
6475
)
6576

77+
// Helper function to check if data has nested objects or arrays
78+
const hasNestedStructure = (data: any): boolean => {
79+
if (data === null || typeof data !== 'object') return false
80+
81+
// Check if it's an empty object or array
82+
if (Object.keys(data).length === 0) return false
83+
84+
// For arrays, check if any element is an object
85+
if (Array.isArray(data)) {
86+
return data.some((item) => typeof item === 'object' && item !== null)
87+
}
88+
89+
// For objects, check if any value is an object
90+
return Object.values(data).some((value) => typeof value === 'object' && value !== null)
91+
}
92+
6693
return (
6794
<div
6895
className={`border-b border-border transition-colors ${
@@ -106,8 +133,37 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
106133
{!entry.error && !entry.warning && (
107134
<div className="flex items-start gap-2">
108135
<Terminal className="h-4 w-4 text-muted-foreground mt-1" />
109-
<div className="text-sm font-mono flex-1 break-normal whitespace-normal overflow-wrap-anywhere">
110-
<JSONView data={entry.output} initiallyExpanded={isExpanded} />
136+
<div className="text-sm font-mono flex-1 break-normal whitespace-normal overflow-wrap-anywhere relative">
137+
{typeof entry.output === 'object' &&
138+
entry.output !== null &&
139+
hasNestedStructure(entry.output) && (
140+
<div className="absolute right-0 top-0 z-10">
141+
<Button
142+
variant="ghost"
143+
size="sm"
144+
className="h-6 px-2 text-muted-foreground hover:text-foreground"
145+
onClick={(e) => {
146+
e.stopPropagation()
147+
setExpandAllJson(!expandAllJson)
148+
}}
149+
>
150+
<span className="flex items-center">
151+
{expandAllJson ? (
152+
<>
153+
<ChevronUp className="h-3 w-3 mr-1" />
154+
<span className="text-xs">Collapse all</span>
155+
</>
156+
) : (
157+
<>
158+
<ChevronDown className="h-3 w-3 mr-1" />
159+
<span className="text-xs">Expand all</span>
160+
</>
161+
)}
162+
</span>
163+
</Button>
164+
</div>
165+
)}
166+
<JSONView data={entry.output} initiallyExpanded={expandAllJson} />
111167
</div>
112168
</div>
113169
)}

sim/app/w/[id]/components/panel/components/console/components/json-view/json-view.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,11 @@ export const JSONView = ({ data, level = 0, initiallyExpanded = false }: JSONVie
355355
/>
356356
</div>
357357
) : (
358-
<JSONView data={value} level={level + 1} />
358+
<JSONView
359+
data={value}
360+
level={level + 1}
361+
initiallyExpanded={initiallyExpanded}
362+
/>
359363
)}
360364
{index < Object.entries(data).length - 1 && ','}
361365
</div>
@@ -470,7 +474,11 @@ export const JSONView = ({ data, level = 0, initiallyExpanded = false }: JSONVie
470474
/>
471475
</div>
472476
) : (
473-
<JSONView data={outputValue} level={level + 2} />
477+
<JSONView
478+
data={outputValue}
479+
level={level + 2}
480+
initiallyExpanded={initiallyExpanded}
481+
/>
474482
)}
475483
{idx < Object.entries(value).length - 1 && ','}
476484
</div>
@@ -481,7 +489,11 @@ export const JSONView = ({ data, level = 0, initiallyExpanded = false }: JSONVie
481489
<span className="text-muted-foreground">{'}'}</span>
482490
</div>
483491
) : (
484-
<JSONView data={value} level={level + 1} />
492+
<JSONView
493+
data={value}
494+
level={level + 1}
495+
initiallyExpanded={initiallyExpanded}
496+
/>
485497
)}
486498
{index < Object.entries(data).length - 1 && ','}
487499
</div>
@@ -577,7 +589,7 @@ export const JSONView = ({ data, level = 0, initiallyExpanded = false }: JSONVie
577589
{isArray
578590
? items.map((item, index) => (
579591
<div key={index} className="break-all">
580-
<JSONView data={item} level={level + 1} />
592+
<JSONView data={item} level={level + 1} initiallyExpanded={initiallyExpanded} />
581593
{index < items.length - 1 && ','}
582594
</div>
583595
))
@@ -594,7 +606,11 @@ export const JSONView = ({ data, level = 0, initiallyExpanded = false }: JSONVie
594606
<TruncatedValue value={JSON.stringify('[base64 image data]')} />
595607
</span>
596608
) : (
597-
<JSONView data={value} level={level + 1} />
609+
<JSONView
610+
data={value}
611+
level={level + 1}
612+
initiallyExpanded={initiallyExpanded}
613+
/>
598614
)}
599615
{index < items.length - 1 && ','}
600616
</div>

0 commit comments

Comments
 (0)