Skip to content

Commit 0289efa

Browse files
committed
feat: queries page
1 parent 644b3f8 commit 0289efa

File tree

3 files changed

+425
-10
lines changed

3 files changed

+425
-10
lines changed

apps/dashboard/app/(main)/observability/database/[id]/performance/_components/query-detail-sheet.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const InfoRow = ({
3333
<span className="font-medium text-muted-foreground text-xs uppercase tracking-wide">
3434
{label}
3535
</span>
36-
<div className="rounded-lg border bg-muted/30 px-4 py-3">
36+
<div className="rounded border bg-muted/30 px-4 py-3">
3737
<span className="break-all font-mono text-sm">{value}</span>
3838
</div>
3939
</div>
@@ -163,31 +163,31 @@ Resource Usage:
163163
</div>
164164

165165
<div className="grid grid-cols-2 gap-4 sm:grid-cols-4">
166-
<div className="rounded-lg border bg-card p-4">
166+
<div className="rounded border bg-card p-4">
167167
<div className="font-bold text-xl sm:text-2xl">
168168
{formatTime(query.mean_exec_time)}
169169
</div>
170170
<div className="text-muted-foreground text-xs sm:text-sm">
171171
Average Response
172172
</div>
173173
</div>
174-
<div className="rounded-lg border bg-card p-4">
174+
<div className="rounded border bg-card p-4">
175175
<div className="font-bold text-xl sm:text-2xl">
176176
{query.calls.toLocaleString()}
177177
</div>
178178
<div className="text-muted-foreground text-xs sm:text-sm">
179179
Total Executions
180180
</div>
181181
</div>
182-
<div className="rounded-lg border bg-card p-4">
182+
<div className="rounded border bg-card p-4">
183183
<div className="font-bold text-xl sm:text-2xl">
184184
{query.cache_hit_ratio.toFixed(1)}%
185185
</div>
186186
<div className="text-muted-foreground text-xs sm:text-sm">
187187
Cache Hit Rate
188188
</div>
189189
</div>
190-
<div className="rounded-lg border bg-card p-4">
190+
<div className="rounded border bg-card p-4">
191191
<div className="font-bold text-xl sm:text-2xl">
192192
{query.percentage_of_total_time.toFixed(1)}%
193193
</div>
@@ -304,7 +304,7 @@ Resource Usage:
304304
</h3>
305305
<div className="space-y-3">
306306
{query.mean_exec_time > 100 && (
307-
<div className="rounded-lg border border-orange-200 bg-orange-50 p-4 dark:border-orange-800 dark:bg-orange-950/20">
307+
<div className="rounded border border-orange-200 bg-orange-50 p-4 dark:border-orange-800 dark:bg-orange-950/20">
308308
<div className="flex items-start gap-3">
309309
<div className="mt-0.5 h-2 w-2 flex-shrink-0 rounded-full bg-orange-500" />
310310
<div className="min-w-0">
@@ -321,7 +321,7 @@ Resource Usage:
321321
)}
322322

323323
{query.cache_hit_ratio < 90 && (
324-
<div className="rounded-lg border border-blue-200 bg-blue-50 p-4 dark:border-blue-800 dark:bg-blue-950/20">
324+
<div className="rounded border border-blue-200 bg-blue-50 p-4 dark:border-blue-800 dark:bg-blue-950/20">
325325
<div className="flex items-start gap-3">
326326
<div className="mt-0.5 h-2 w-2 flex-shrink-0 rounded-full bg-blue-500" />
327327
<div className="min-w-0">
@@ -338,7 +338,7 @@ Resource Usage:
338338
)}
339339

340340
{query.calls > 10_000 && (
341-
<div className="rounded-lg border border-purple-200 bg-purple-50 p-4 dark:border-purple-800 dark:bg-purple-950/20">
341+
<div className="rounded border border-purple-200 bg-purple-50 p-4 dark:border-purple-800 dark:bg-purple-950/20">
342342
<div className="flex items-start gap-3">
343343
<div className="mt-0.5 h-2 w-2 flex-shrink-0 rounded-full bg-purple-500" />
344344
<div className="min-w-0">
@@ -355,7 +355,7 @@ Resource Usage:
355355
)}
356356

357357
{query.percentage_of_total_time > 10 && (
358-
<div className="rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-800 dark:bg-red-950/20">
358+
<div className="rounded border border-red-200 bg-red-50 p-4 dark:border-red-800 dark:bg-red-950/20">
359359
<div className="flex items-start gap-3">
360360
<div className="mt-0.5 h-2 w-2 flex-shrink-0 rounded-full bg-red-500" />
361361
<div className="min-w-0">
@@ -374,7 +374,7 @@ Resource Usage:
374374
{query.mean_exec_time <= 50 &&
375375
query.cache_hit_ratio >= 95 &&
376376
query.percentage_of_total_time <= 5 && (
377-
<div className="rounded-lg border border-green-200 bg-green-50 p-4 dark:border-green-800 dark:bg-green-950/20">
377+
<div className="rounded border border-green-200 bg-green-50 p-4 dark:border-green-800 dark:bg-green-950/20">
378378
<div className="flex items-start gap-3">
379379
<div className="mt-0.5 h-2 w-2 flex-shrink-0 rounded-full bg-green-500" />
380380
<div className="min-w-0">
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
'use client';
2+
3+
import type { QueryPerformanceSummary } from '@databuddy/shared';
4+
import {
5+
ChartLineIcon,
6+
ClockIcon,
7+
DatabaseIcon,
8+
EyeIcon,
9+
TrendUpIcon,
10+
} from '@phosphor-icons/react';
11+
import { Badge } from '@/components/ui/badge';
12+
import { SqlHighlighter } from '../../performance/_components/sql-highlighter';
13+
14+
interface QueryRowProps {
15+
query: QueryPerformanceSummary;
16+
onClick: () => void;
17+
}
18+
19+
const formatTime = (ms: number): string => {
20+
if (ms < 1) {
21+
return `${(ms * 1000).toFixed(0)}μs`;
22+
}
23+
if (ms < 1000) {
24+
return `${ms.toFixed(1)}ms`;
25+
}
26+
return `${(ms / 1000).toFixed(2)}s`;
27+
};
28+
29+
const getPerformanceLevel = (time: number) => {
30+
if (time < 10) {
31+
return {
32+
level: 'Excellent',
33+
color: 'border-green-500 bg-green-50 text-green-700',
34+
};
35+
}
36+
if (time < 50) {
37+
return { level: 'Good', color: 'border-blue-500 bg-blue-50 text-blue-700' };
38+
}
39+
if (time < 100) {
40+
return {
41+
level: 'Fair',
42+
color: 'border-yellow-500 bg-yellow-50 text-yellow-700',
43+
};
44+
}
45+
if (time < 500) {
46+
return {
47+
level: 'Poor',
48+
color: 'border-orange-500 bg-orange-50 text-orange-700',
49+
};
50+
}
51+
return { level: 'Critical', color: 'border-red-500 bg-red-50 text-red-700' };
52+
};
53+
54+
const cleanQueryComments = (query: string): string => {
55+
return query
56+
.replace(/--.*$/gm, '')
57+
.replace(/\/\*[\s\S]*?\*\//g, '')
58+
.trim();
59+
};
60+
61+
export const QueryRow = ({ query, onClick }: QueryRowProps) => {
62+
const performance = getPerformanceLevel(query.mean_exec_time);
63+
const cleanedQuery = cleanQueryComments(query.query);
64+
65+
return (
66+
<button
67+
className="w-full cursor-pointer rounded border bg-card p-6 text-left transition-all hover:border-primary/20 hover:bg-muted/50 hover:shadow-sm"
68+
onClick={onClick}
69+
type="button"
70+
>
71+
{/* Header */}
72+
<div className="mb-4 flex items-center justify-between">
73+
<div className="flex items-center gap-3">
74+
<DatabaseIcon
75+
className="h-5 w-5 text-muted-foreground"
76+
weight="duotone"
77+
/>
78+
<Badge className={`${performance.color} border text-xs`}>
79+
{performance.level}
80+
</Badge>
81+
<span className="text-muted-foreground text-sm">
82+
ID: {query.queryid}
83+
</span>
84+
</div>
85+
<div className="text-right">
86+
<div className="font-semibold text-lg">
87+
{formatTime(query.mean_exec_time)}
88+
</div>
89+
<div className="text-muted-foreground text-xs">Average</div>
90+
</div>
91+
</div>
92+
93+
{/* SQL Query */}
94+
<div className="mb-4">
95+
<SqlHighlighter className="text-sm" code={cleanedQuery} />
96+
</div>
97+
98+
{/* Separator */}
99+
<div className="mb-4 border-border/50 border-t" />
100+
101+
{/* Metrics */}
102+
<div className="grid grid-cols-4 gap-3">
103+
<div className="rounded bg-muted/30 p-3 text-center">
104+
<div className="flex items-center justify-center gap-1 text-muted-foreground text-xs">
105+
<TrendUpIcon className="h-3 w-3" />
106+
Calls
107+
</div>
108+
<div className="font-semibold text-sm">
109+
{query.calls.toLocaleString()}
110+
</div>
111+
</div>
112+
<div className="rounded bg-muted/30 p-3 text-center">
113+
<div className="flex items-center justify-center gap-1 text-muted-foreground text-xs">
114+
<ClockIcon className="h-3 w-3" />
115+
Total
116+
</div>
117+
<div className="font-semibold text-sm">
118+
{formatTime(query.total_exec_time)}
119+
</div>
120+
</div>
121+
<div className="rounded bg-muted/30 p-3 text-center">
122+
<div className="flex items-center justify-center gap-1 text-muted-foreground text-xs">
123+
<EyeIcon className="h-3 w-3" />
124+
Cache
125+
</div>
126+
<div className="font-semibold text-sm">
127+
{query.cache_hit_ratio.toFixed(1)}%
128+
</div>
129+
</div>
130+
<div className="rounded bg-muted/30 p-3 text-center">
131+
<div className="flex items-center justify-center gap-1 text-muted-foreground text-xs">
132+
<ChartLineIcon className="h-3 w-3" />
133+
Resource
134+
</div>
135+
<div className="font-semibold text-sm">
136+
{query.percentage_of_total_time.toFixed(1)}%
137+
</div>
138+
</div>
139+
</div>
140+
</button>
141+
);
142+
};

0 commit comments

Comments
 (0)