Skip to content

Commit 8e5b538

Browse files
committed
minor UX enhancements
1 parent 857ae8b commit 8e5b538

File tree

2 files changed

+148
-44
lines changed

2 files changed

+148
-44
lines changed

dashboard/components/benchmark-dashboard.tsx

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22

33
import { useState, useEffect, Suspense } from "react"
44
import { useRouter, useSearchParams } from "next/navigation"
5-
import { Info } from "lucide-react"
65
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
7-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
86
import { DatabaseSidebar } from "@/components/database-sidebar"
97
import { LatencyTable } from "@/components/latency-table"
10-
import { LatencyGraphs } from "@/components/latency-graphs"
118
import { QASection } from "@/components/qa-section"
129
import { Database, Function, Stat } from "@/lib/schema"
1310

@@ -79,17 +76,25 @@ function BenchmarkDashboardClient({
7976
newParams.set('databases', selectedDatabases.join(','))
8077
}
8178

82-
if (!newParams.has('queries')) {
79+
// Only set default values if parameters don't already exist
80+
// This preserves URL parameters on initial load
81+
if (!searchParams.has('queries')) {
8382
newParams.set('queries', 'hot')
8483
}
85-
if (!newParams.has('regions')) {
84+
85+
if (!searchParams.has('regions')) {
8686
newParams.set('regions', 'match')
8787
}
8888

89-
// Update connection filter
90-
newParams.set('connection', connectionFilter)
89+
// Update connection filter, but only if it's changed from the URL
90+
if (!searchParams.has('connection') || connectionFilter !== searchParams.get('connection')) {
91+
newParams.set('connection', connectionFilter)
92+
}
9193

92-
window.history.replaceState({}, '', `?${newParams.toString()}`)
94+
// Only update URL if we've changed something
95+
if (newParams.toString() !== searchParams.toString()) {
96+
window.history.replaceState({}, '', `?${newParams.toString()}`)
97+
}
9398
}, [selectedDatabases, searchParams, initialDatabases, initialLoadComplete, connectionFilter])
9499

95100

@@ -99,7 +104,44 @@ function BenchmarkDashboardClient({
99104

100105
// Function to update connection filter
101106
const updateConnectionFilter = (filter: string) => {
102-
setConnectionFilter(filter)
107+
// Check if this is an auto-select request
108+
if (filter.includes(':autoselect')) {
109+
const actualFilter = filter.split(':')[0]; // Extract the actual filter (http, ws, all)
110+
111+
// Update the connection filter first
112+
setConnectionFilter(actualFilter);
113+
114+
// Find all databases that match the new filter
115+
const matchingDatabases = initialDatabases
116+
.filter(db => actualFilter === 'all' || db.connectionMethod === actualFilter)
117+
.map(db => db.id);
118+
119+
// Get databases that would remain selected after the filter is applied
120+
const remainingSelectedDatabases = selectedDatabases.filter(dbId => {
121+
const db = initialDatabases.find(db => db.id === dbId);
122+
return db && (actualFilter === 'all' || db.connectionMethod === actualFilter);
123+
});
124+
125+
// Check if we need to select databases
126+
if (matchingDatabases.length > 0) {
127+
// Case 1: No databases are currently selected - select all matching ones
128+
if (selectedDatabases.length === 0) {
129+
setSelectedDatabases(matchingDatabases);
130+
}
131+
// Case 2: Some databases are selected but none match the new filter
132+
else if (remainingSelectedDatabases.length === 0) {
133+
setSelectedDatabases(matchingDatabases);
134+
}
135+
// Case 3: We're switching to a specific type (ws/http) and have some databases that don't match
136+
else if (actualFilter !== 'all') {
137+
setSelectedDatabases(remainingSelectedDatabases);
138+
}
139+
// For 'all' filter and there are some matching databases, we don't need to change anything
140+
}
141+
} else {
142+
// Normal filter change (not auto-select)
143+
setConnectionFilter(filter);
144+
}
103145
}
104146

105147
const filteredDatabases = initialDatabases.filter((db) => {

dashboard/components/latency-table.tsx

Lines changed: 97 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
4545
const param = searchParams.get('queries')
4646
if (param === 'cold') return 'cold'
4747
if (param === 'hot') return 'hot'
48-
return 'hot' // Default is 'hot' now instead of 'both'
48+
if (param === 'all') return 'both'
49+
return 'hot' // Default is 'hot' if no param is specified
4950
})
5051

5152
const [regionFilter, setRegionFilter] = useState<RegionFilter>(() => {
@@ -64,8 +65,29 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
6465
// Function to update connection filter
6566
const handleConnectionFilterChange = (value: string) => {
6667
setLocalConnectionFilter(value)
68+
6769
if (onUpdateConnectionFilter) {
68-
onUpdateConnectionFilter(value)
70+
// First update with just the filter to ensure the connection filter changes
71+
onUpdateConnectionFilter(value);
72+
73+
// Then check if we need to auto-select databases
74+
setTimeout(() => {
75+
if (databases.length === 0) {
76+
// If there are no selected databases, send auto-select signal
77+
onUpdateConnectionFilter(value + ':autoselect');
78+
} else {
79+
// If there are selected databases but with a different connection method
80+
// Check if any of them match the new filter
81+
const hasMatchingDatabase = databases.some(db =>
82+
value === 'all' || db.connectionMethod === value
83+
);
84+
85+
// If none match, trigger auto-select
86+
if (!hasMatchingDatabase) {
87+
onUpdateConnectionFilter(value + ':autoselect');
88+
}
89+
}
90+
}, 0);
6991
}
7092
}
7193

@@ -77,30 +99,51 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
7799
const queryParamValue = queryType === 'both' ? 'all' : queryType
78100
const regionParamValue = regionFilter === 'matching' ? 'match' : 'all'
79101

80-
newParams.set('queries', queryParamValue)
81-
newParams.set('regions', regionParamValue)
82-
newParams.set('connection', connectionFilter)
102+
// Only update if the values have changed
103+
if (searchParams.get('queries') !== queryParamValue) {
104+
newParams.set('queries', queryParamValue)
105+
}
106+
107+
if (searchParams.get('regions') !== regionParamValue) {
108+
newParams.set('regions', regionParamValue)
109+
}
110+
111+
if (searchParams.get('connection') !== connectionFilter) {
112+
newParams.set('connection', connectionFilter)
113+
}
83114

84115
if (!newParams.has('databases')) {
85116
newParams.set('databases', 'all')
86117
}
87118

88-
window.history.replaceState({}, '', `?${newParams.toString()}`)
119+
// Only update URL if we've changed something
120+
if (newParams.toString() !== searchParams.toString()) {
121+
window.history.replaceState({}, '', `?${newParams.toString()}`)
122+
}
89123
} else {
90124
// If connection filter is managed externally, only sync query type and region filter
91125
const newParams = new URLSearchParams(searchParams.toString())
92126

93127
const queryParamValue = queryType === 'both' ? 'all' : queryType
94128
const regionParamValue = regionFilter === 'matching' ? 'match' : 'all'
95129

96-
newParams.set('queries', queryParamValue)
97-
newParams.set('regions', regionParamValue)
130+
// Only update if the values have changed
131+
if (searchParams.get('queries') !== queryParamValue) {
132+
newParams.set('queries', queryParamValue)
133+
}
134+
135+
if (searchParams.get('regions') !== regionParamValue) {
136+
newParams.set('regions', regionParamValue)
137+
}
98138

99139
if (!newParams.has('databases')) {
100140
newParams.set('databases', 'all')
101141
}
102142

103-
window.history.replaceState({}, '', `?${newParams.toString()}`)
143+
// Only update URL if we've changed something
144+
if (newParams.toString() !== searchParams.toString()) {
145+
window.history.replaceState({}, '', `?${newParams.toString()}`)
146+
}
104147
}
105148
}, [queryType, regionFilter, connectionFilter, searchParams, onUpdateConnectionFilter])
106149

@@ -319,7 +362,7 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
319362
</div>
320363
<div className="max-h-[80vh]">
321364
<div className="rounded-md border">
322-
<Table>
365+
<Table className="table-fixed">
323366
<TableHeader className="sticky top-0 bg-background z-20">
324367
<TableRow>
325368
<TableHead
@@ -339,36 +382,46 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
339382
</TableHead>
340383
</TableRow>
341384
<TableRow>
342-
{filteredRegionGroups.map((group, groupIndex) => (
343-
<TableHead
344-
key={`${group.regionLabel}-${group.connectionMethod}`}
345-
colSpan={queryType === "both" ? 2 : 1}
346-
className={cn(
347-
"text-center border-b bg-background",
348-
groupIndex !== 0 && "border-l-2 border-l-muted"
349-
)}
350-
style={{
351-
width: queryType === "both" ? '400px' : '200px',
352-
minWidth: queryType === "both" ? '400px' : '200px'
353-
}}
354-
>
355-
<div className="font-medium break-words text-sm">
356-
{group.regionLabel}
357-
<div className="font-normal text-xs text-muted-foreground mt-1 break-all">
358-
{group.regionCode} via<br />@neondatabase/serverless{" "}{group.connectionMethod === 'http' ? <strong>http</strong> : <strong>websocket</strong>}
385+
{filteredRegionGroups.map((group, groupIndex) => {
386+
// Calculate equal width for all columns
387+
const colWidth = `${100 / filteredRegionGroups.length}%`;
388+
return (
389+
<TableHead
390+
key={`${group.regionLabel}-${group.connectionMethod}`}
391+
colSpan={queryType === "both" ? 2 : 1}
392+
className={cn(
393+
"text-center border-b bg-background",
394+
groupIndex !== 0 && "border-l-2 border-l-muted"
395+
)}
396+
style={{
397+
width: colWidth,
398+
minWidth: queryType === "both" ? '400px' : '200px'
399+
}}
400+
>
401+
<div className="font-medium break-words text-sm">
402+
{group.regionLabel}
403+
<div className="font-normal text-xs text-muted-foreground mt-1 break-all">
404+
{group.regionCode} via<br />@neondatabase/serverless{" "}{group.connectionMethod === 'http' ? <strong>http</strong> : <strong>websocket</strong>}
405+
</div>
359406
</div>
360-
</div>
361-
</TableHead>
362-
))}
407+
</TableHead>
408+
);
409+
})}
363410
</TableRow>
364411
<TableRow>
365412
{filteredRegionGroups.flatMap((group) => {
366413
const cells = [];
414+
// Calculate equal width for cells when we have both hot and cold
415+
const cellStyle = queryType === "both"
416+
? { width: `${50 / filteredRegionGroups.length}%`, minWidth: '200px' }
417+
: { width: `${100 / filteredRegionGroups.length}%`, minWidth: '200px' };
418+
367419
if (queryType === "both" || queryType === "cold") {
368420
cells.push(
369421
<TableHead
370422
key={`${group.regionLabel}-${group.connectionMethod}-cold`}
371-
className="text-center font-medium text-sm bg-background px-2 w-full min-w-[200px]"
423+
className="text-center font-medium text-sm bg-background px-2"
424+
style={cellStyle}
372425
>
373426
Cold
374427
</TableHead>
@@ -378,7 +431,8 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
378431
cells.push(
379432
<TableHead
380433
key={`${group.regionLabel}-${group.connectionMethod}-hot`}
381-
className="text-center font-medium text-sm bg-background px-2 w-full min-w-[200px]"
434+
className="text-center font-medium text-sm bg-background px-2"
435+
style={cellStyle}
382436
>
383437
Hot
384438
</TableHead>
@@ -414,17 +468,24 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
414468
</div>
415469
</TableCell>
416470
{filteredRegionGroups.flatMap((group, groupIndex) => {
417-
const isSameRegionMatch = isExactSameRegion(group, fn)
471+
const isSameRegionMatch = isExactSameRegion(group, fn);
418472
const cells = [];
473+
474+
// Calculate equal width for cells when we have both hot and cold
475+
const cellStyle = queryType === "both"
476+
? { width: `${50 / filteredRegionGroups.length}%`, minWidth: '200px' }
477+
: { width: `${100 / filteredRegionGroups.length}%`, minWidth: '200px' };
478+
419479
if (queryType === "both" || queryType === "cold") {
420480
cells.push(
421481
<TableCell
422482
key={`${fn.id}-${group.regionLabel}-${group.connectionMethod}-cold`}
423483
className={cn(
424-
"text-center w-full min-w-[200px]",
484+
"text-center",
425485
isSameRegionMatch ? "bg-green-50" : group.connectionMethod === "ws" && "bg-yellow-50",
426486
groupIndex !== 0 && "border-l-2 border-l-muted"
427487
)}
488+
style={cellStyle}
428489
>
429490
{formatLatency(getRegionGroupLatency(fn.id, group, "cold"), "cold")}
430491
</TableCell>
@@ -435,11 +496,12 @@ function LatencyTableClient({ databases, functions, latencyData, connectionFilte
435496
<TableCell
436497
key={`${fn.id}-${group.regionLabel}-${group.connectionMethod}-hot`}
437498
className={cn(
438-
"text-center w-full min-w-[200px]",
499+
"text-center",
439500
isSameRegionMatch ? "bg-green-50" : group.connectionMethod === "ws" && "bg-yellow-50",
440501
queryType === "both" && "border-l",
441502
groupIndex !== 0 && queryType !== "both" && "border-l-2 border-l-muted"
442503
)}
504+
style={cellStyle}
443505
>
444506
{formatLatency(getRegionGroupLatency(fn.id, group, "hot"), "hot")}
445507
</TableCell>

0 commit comments

Comments
 (0)