Skip to content

Commit 403ed1e

Browse files
committed
fix: add missing logs components and fix .gitignore
- Add missing src/renderer/src/components/logs/ directory with all components - Fix .gitignore to exclude logs component directory from being ignored - Include RequestLogList, RequestLogDetail, RequestLogStats, LogDetail, LogFilter, LogList, LogRow components
1 parent 3784b78 commit 403ed1e

File tree

11 files changed

+1601
-0
lines changed

11 files changed

+1601
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ electron.vite.config.*.mjs
1515

1616
# Logs
1717
logs/
18+
!src/renderer/src/components/logs/
1819
*.log
1920
npm-debug.log*
2021
yarn-debug.log*
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
import { useCallback } from 'react'
2+
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '@/components/ui/sheet'
3+
import { Button } from '@/components/ui/button'
4+
import { Badge } from '@/components/ui/badge'
5+
import { Separator } from '@/components/ui/separator'
6+
import { ScrollArea } from '@/components/ui/scroll-area'
7+
import { useToast } from '@/hooks/use-toast'
8+
import { Copy, X } from 'lucide-react'
9+
import { cn } from '@/lib/utils'
10+
import { useLogsStore } from '@/stores/logsStore'
11+
12+
const levelColors: Record<string, string> = {
13+
debug: 'bg-gray-500',
14+
info: 'bg-blue-500',
15+
warn: 'bg-yellow-500',
16+
error: 'bg-red-500',
17+
}
18+
19+
function formatTime(timestamp: string | number | Date): string {
20+
const date = new Date(timestamp)
21+
return date.toLocaleString()
22+
}
23+
24+
export function LogDetail() {
25+
const { selectedLog, setSelectedLog } = useLogsStore()
26+
const { toast } = useToast()
27+
28+
const handleCopy = useCallback(
29+
async (text: string) => {
30+
try {
31+
await navigator.clipboard.writeText(text)
32+
toast({
33+
title: 'Copied',
34+
description: 'Copied to clipboard',
35+
})
36+
} catch {
37+
toast({
38+
title: 'Copy Failed',
39+
description: 'Unable to copy to clipboard',
40+
variant: 'destructive',
41+
})
42+
}
43+
},
44+
[toast]
45+
)
46+
47+
const handleCopyAll = useCallback(() => {
48+
if (!selectedLog) return
49+
50+
const logText = [
51+
`Time: ${formatTime(selectedLog.timestamp)}`,
52+
`Level: ${selectedLog.level.toUpperCase()}`,
53+
`Message: ${selectedLog.message}`,
54+
selectedLog.providerId && `Provider: ${selectedLog.providerId}`,
55+
selectedLog.accountId && `Account: ${selectedLog.accountId}`,
56+
selectedLog.requestId && `Request ID: ${selectedLog.requestId}`,
57+
selectedLog.data && `Data: ${JSON.stringify(selectedLog.data, null, 2)}`,
58+
]
59+
.filter(Boolean)
60+
.join('\n')
61+
62+
handleCopy(logText)
63+
}, [selectedLog, handleCopy])
64+
65+
const handleClose = useCallback(() => {
66+
setSelectedLog(null)
67+
}, [setSelectedLog])
68+
69+
return (
70+
<Sheet open={!!selectedLog} onOpenChange={(open) => !open && handleClose()}>
71+
<SheetContent className="w-[500px] sm:max-w-[500px]">
72+
<SheetHeader>
73+
<div className="flex items-center justify-between">
74+
<SheetTitle>Log Details</SheetTitle>
75+
<Button variant="ghost" size="sm" onClick={handleClose}>
76+
<X className="h-4 w-4" />
77+
</Button>
78+
</div>
79+
<SheetDescription>View complete log information</SheetDescription>
80+
</SheetHeader>
81+
82+
{selectedLog && (
83+
<ScrollArea className="h-[calc(100vh-120px)] mt-4">
84+
<div className="space-y-4">
85+
<div className="flex items-center justify-between">
86+
<div className="flex items-center gap-2">
87+
<Badge
88+
className={cn('text-white', levelColors[selectedLog.level])}
89+
>
90+
{selectedLog.level.toUpperCase()}
91+
</Badge>
92+
<span className="text-sm text-muted-foreground">
93+
{formatTime(selectedLog.timestamp)}
94+
</span>
95+
</div>
96+
<Button variant="outline" size="sm" onClick={handleCopyAll}>
97+
<Copy className="h-4 w-4 mr-1" />
98+
Copy All
99+
</Button>
100+
</div>
101+
102+
<Separator />
103+
104+
<div className="space-y-3">
105+
<div>
106+
<label className="text-sm font-medium text-muted-foreground">
107+
Message
108+
</label>
109+
<div className="mt-1 p-3 bg-muted rounded-md font-mono text-sm break-all">
110+
{selectedLog.message}
111+
<Button
112+
variant="ghost"
113+
size="sm"
114+
className="ml-2 h-6 w-6 p-0"
115+
onClick={() => handleCopy(selectedLog.message)}
116+
>
117+
<Copy className="h-3 w-3" />
118+
</Button>
119+
</div>
120+
</div>
121+
122+
{selectedLog.providerId && (
123+
<div>
124+
<label className="text-sm font-medium text-muted-foreground">
125+
Provider ID
126+
</label>
127+
<div className="mt-1 flex items-center gap-2">
128+
<code className="px-2 py-1 bg-muted rounded text-sm">
129+
{selectedLog.providerId}
130+
</code>
131+
<Button
132+
variant="ghost"
133+
size="sm"
134+
className="h-6 w-6 p-0"
135+
onClick={() => handleCopy(selectedLog.providerId!)}
136+
>
137+
<Copy className="h-3 w-3" />
138+
</Button>
139+
</div>
140+
</div>
141+
)}
142+
143+
{selectedLog.accountId && (
144+
<div>
145+
<label className="text-sm font-medium text-muted-foreground">
146+
Account ID
147+
</label>
148+
<div className="mt-1 flex items-center gap-2">
149+
<code className="px-2 py-1 bg-muted rounded text-sm">
150+
{selectedLog.accountId}
151+
</code>
152+
<Button
153+
variant="ghost"
154+
size="sm"
155+
className="h-6 w-6 p-0"
156+
onClick={() => handleCopy(selectedLog.accountId!)}
157+
>
158+
<Copy className="h-3 w-3" />
159+
</Button>
160+
</div>
161+
</div>
162+
)}
163+
164+
{selectedLog.requestId && (
165+
<div>
166+
<label className="text-sm font-medium text-muted-foreground">
167+
Request ID
168+
</label>
169+
<div className="mt-1 flex items-center gap-2">
170+
<code className="px-2 py-1 bg-muted rounded text-sm">
171+
{selectedLog.requestId}
172+
</code>
173+
<Button
174+
variant="ghost"
175+
size="sm"
176+
className="h-6 w-6 p-0"
177+
onClick={() => handleCopy(selectedLog.requestId!)}
178+
>
179+
<Copy className="h-3 w-3" />
180+
</Button>
181+
</div>
182+
</div>
183+
)}
184+
185+
{selectedLog.data && Object.keys(selectedLog.data).length > 0 && (
186+
<div>
187+
<label className="text-sm font-medium text-muted-foreground">
188+
Additional Data
189+
</label>
190+
<div className="mt-1 p-3 bg-muted rounded-md">
191+
<pre className="text-sm font-mono overflow-x-auto">
192+
{JSON.stringify(selectedLog.data, null, 2)}
193+
</pre>
194+
<Button
195+
variant="ghost"
196+
size="sm"
197+
className="mt-2"
198+
onClick={() =>
199+
handleCopy(JSON.stringify(selectedLog.data, null, 2))
200+
}
201+
>
202+
<Copy className="h-4 w-4 mr-1" />
203+
Copy Data
204+
</Button>
205+
</div>
206+
</div>
207+
)}
208+
209+
<div>
210+
<label className="text-sm font-medium text-muted-foreground">
211+
Log ID
212+
</label>
213+
<div className="mt-1 flex items-center gap-2">
214+
<code className="px-2 py-1 bg-muted rounded text-sm text-muted-foreground">
215+
{selectedLog.id}
216+
</code>
217+
<Button
218+
variant="ghost"
219+
size="sm"
220+
className="h-6 w-6 p-0"
221+
onClick={() => handleCopy(selectedLog.id)}
222+
>
223+
<Copy className="h-3 w-3" />
224+
</Button>
225+
</div>
226+
</div>
227+
</div>
228+
</div>
229+
</ScrollArea>
230+
)}
231+
</SheetContent>
232+
</Sheet>
233+
)
234+
}

0 commit comments

Comments
 (0)