Skip to content

Commit 307f284

Browse files
authored
Chore/unified logs fixes 02 (supabase#36710)
* Temporarily disable cmd K shortcut for searching unified logs * Update placeholder for search input * Fix getLogsCountQuery for method * Standardize pathname parameter * Fix refresh button
1 parent 3b3a752 commit 307f284

File tree

7 files changed

+65
-43
lines changed

7 files changed

+65
-43
lines changed

apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.fields.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ export const filterFields = [
5252
return (
5353
<div className="flex w-full items-center justify-between gap-2 font-mono">
5454
<span className="capitalize text-foreground/70 group-hover:text-accent-foreground text-xs">
55-
{props.label}
55+
{props.label.replace('_', ' ')}
5656
</span>
57-
<span className="text-xs text-muted-foreground/70">{props.value}</span>
57+
{/* [Joshen] Temporarily hiding, this feels excessive */}
58+
{/* <span className="text-xs text-muted-foreground/70">{props.value}</span> */}
5859
</div>
5960
)
6061
},

apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.queries.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ const buildQueryConditions = (search: QuerySearchParamsType) => {
3535

3636
// Handle scalar values
3737
if (value !== null && value !== undefined) {
38-
whereConditions.push(`${key} = '${value}'`)
38+
if (['host', 'pathname'].includes(key)) {
39+
whereConditions.push(`${key} LIKE '%${value}%'`)
40+
} else {
41+
whereConditions.push(`${key} = '${value}'`)
42+
}
3943
}
4044
})
4145

@@ -234,7 +238,7 @@ const getEdgeLogsQuery = () => {
234238
WHEN edge_logs_response.status_code >= 500 THEN 'error'
235239
ELSE 'success'
236240
END as level,
237-
edge_logs_request.path as path,
241+
edge_logs_request.path as pathname,
238242
edge_logs_request.host as host,
239243
null as event_message,
240244
edge_logs_request.method as method,
@@ -273,7 +277,7 @@ const getPostgrestLogsQuery = () => {
273277
WHEN edge_logs_response.status_code >= 500 THEN 'error'
274278
ELSE 'success'
275279
END as level,
276-
edge_logs_request.path as path,
280+
edge_logs_request.path as pathname,
277281
edge_logs_request.host as host,
278282
null as event_message,
279283
edge_logs_request.method as method,
@@ -311,7 +315,7 @@ const getPostgresLogsQuery = () => {
311315
WHEN pgl_parsed.error_severity = 'ERROR' THEN 'error'
312316
ELSE null
313317
END as level,
314-
null as path,
318+
null as pathname,
315319
null as host,
316320
event_message as event_message,
317321
null as method,
@@ -341,7 +345,7 @@ const getEdgeFunctionLogsQuery = () => {
341345
WHEN fel_response.status_code >= 500 THEN 'error'
342346
ELSE 'success'
343347
END as level,
344-
fel_request.url as path,
348+
fel_request.url as pathname,
345349
fel_request.host as host,
346350
COALESCE(function_logs_agg.last_event_message, '') as event_message,
347351
fel_request.method as method,
@@ -387,7 +391,7 @@ const getAuthLogsQuery = () => {
387391
WHEN el_in_al_response.status_code >= 500 THEN 'error'
388392
ELSE 'success'
389393
END as level,
390-
el_in_al_request.path as path,
394+
el_in_al_request.path as pathname,
391395
el_in_al_request.host as host,
392396
null as event_message,
393397
el_in_al_request.method as method,
@@ -428,7 +432,7 @@ const getSupavisorLogsQuery = () => {
428432
WHEN LOWER(svl_metadata.level) = 'warn' OR LOWER(svl_metadata.level) = 'warning' THEN 'warning'
429433
ELSE 'success'
430434
END as level,
431-
null as path,
435+
null as pathname,
432436
null as host,
433437
null as event_message,
434438
null as method,
@@ -478,7 +482,7 @@ SELECT
478482
log_type,
479483
status,
480484
level,
481-
path,
485+
pathname,
482486
host,
483487
event_message,
484488
method,
@@ -498,8 +502,9 @@ ${finalWhere}
498502
* Also returns facets for all filter dimensions
499503
*/
500504
export const getLogsCountQuery = (search: QuerySearchParamsType): string => {
501-
// Use the buildQueryConditions helper
502505
const { finalWhere } = buildQueryConditions(search)
506+
const methodWhere =
507+
finalWhere.length > 0 ? `${finalWhere} AND method is NOT NULL` : 'WHERE method IS NOT NULL'
503508

504509
// Create a count query using the same unified logs CTE
505510
const sql = `
@@ -530,8 +535,7 @@ UNION ALL
530535
-- Get counts by method
531536
SELECT 'method' as dimension, method as value, COUNT(*) as count
532537
FROM unified_logs
533-
${finalWhere}
534-
WHERE method IS NOT NULL
538+
${methodWhere}
535539
GROUP BY method
536540
`
537541

apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import { FilterSideBar } from 'components/ui/DataTable/FilterSideBar'
2727
import { LiveButton } from 'components/ui/DataTable/LiveButton'
2828
import { LiveRow } from 'components/ui/DataTable/LiveRow'
2929
import { DataTableProvider } from 'components/ui/DataTable/providers/DataTableProvider'
30-
import { RefreshButton } from 'components/ui/DataTable/RefreshButton'
3130
import { TimelineChart } from 'components/ui/DataTable/TimelineChart'
3231
import { useUnifiedLogsChartQuery } from 'data/logs/unified-logs-chart-query'
3332
import { useUnifiedLogsCountQuery } from 'data/logs/unified-logs-count-query'
@@ -45,6 +44,7 @@ import {
4544
TabsList_Shadcn_ as TabsList,
4645
TabsTrigger_Shadcn_ as TabsTrigger,
4746
} from 'ui'
47+
import { RefreshButton } from '../../ui/DataTable/RefreshButton'
4848
import { UNIFIED_LOGS_COLUMNS } from './components/Columns'
4949
import { MemoizedDataTableSheetContent } from './components/DataTableSheetContent'
5050
import { FunctionLogsTab } from './components/FunctionLogsTab'
@@ -100,19 +100,36 @@ export const UnifiedLogs = () => {
100100
isLoading,
101101
isFetching,
102102
hasNextPage,
103-
refetch,
103+
refetch: refetchLogs,
104104
fetchNextPage,
105105
fetchPreviousPage,
106106
} = useUnifiedLogsInfiniteQuery({ projectRef, search: searchParameters })
107-
const { data: counts, isLoading: isLoadingCounts } = useUnifiedLogsCountQuery({
107+
const {
108+
data: counts,
109+
isLoading: isLoadingCounts,
110+
isFetching: isFetchingCounts,
111+
refetch: refetchCounts,
112+
} = useUnifiedLogsCountQuery({
108113
projectRef,
109114
search: searchParameters,
110115
})
111-
const { data: unifiedLogsChart = [] } = useUnifiedLogsChartQuery({
116+
const {
117+
data: unifiedLogsChart = [],
118+
isFetching: isFetchingCharts,
119+
refetch: refetchCharts,
120+
} = useUnifiedLogsChartQuery({
112121
projectRef,
113122
search: searchParameters,
114123
})
115124

125+
const refetchAllData = () => {
126+
refetchLogs()
127+
refetchCounts()
128+
refetchCharts()
129+
}
130+
131+
const isRefetchingData = isFetching || isFetchingCounts || isFetchingCharts
132+
116133
const rawFlatData = useMemo(() => {
117134
return unifiedLogsData?.pages?.flatMap((page) => page.data ?? []) ?? []
118135
}, [unifiedLogsData?.pages])
@@ -275,10 +292,13 @@ export const UnifiedLogs = () => {
275292
<FilterSideBar />
276293
<div className="flex max-w-full flex-1 flex-col border-border sm:border-l overflow-hidden">
277294
<DataTableHeaderLayout setTopBarHeight={setTopBarHeight}>
278-
<DataTableFilterCommand searchParamsParser={SEARCH_PARAMS_PARSER} />
295+
<DataTableFilterCommand
296+
placeholder="Search logs..."
297+
searchParamsParser={SEARCH_PARAMS_PARSER}
298+
/>
279299
<DataTableToolbar
280300
renderActions={() => [
281-
<RefreshButton key="refresh" onClick={refetch} />,
301+
<RefreshButton isLoading={isRefetchingData} onRefresh={refetchAllData} />,
282302
fetchPreviousPage ? (
283303
<LiveButton
284304
key="live"

apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterCommand.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { ParserBuilder } from 'nuqs'
44
import { useEffect, useMemo, useRef, useState } from 'react'
55

66
import { useLocalStorage } from 'hooks/misc/useLocalStorage'
7-
import { useHotKey } from 'hooks/ui/useHotKey'
87
import {
98
cn,
109
Command_Shadcn_ as Command,
@@ -33,9 +32,13 @@ import {
3332
interface DataTableFilterCommandProps {
3433
// TODO: maybe use generics for the parser
3534
searchParamsParser: Record<string, ParserBuilder<any>>
35+
placeholder?: string
3636
}
3737

38-
export function DataTableFilterCommand({ searchParamsParser }: DataTableFilterCommandProps) {
38+
export function DataTableFilterCommand({
39+
searchParamsParser,
40+
placeholder = 'Search data table...',
41+
}: DataTableFilterCommandProps) {
3942
const { table, isLoading, filterFields: _filterFields, getFacetedUniqueValues } = useDataTable()
4043
const columnFilters = table.getState().columnFilters
4144
const inputRef = useRef<HTMLInputElement>(null)
@@ -59,7 +62,8 @@ export function DataTableFilterCommand({ searchParamsParser }: DataTableFilterCo
5962

6063
const trimmedInputValue = inputValue.trim()
6164

62-
useHotKey(() => setOpen((open) => !open), 'k')
65+
// [Joshen] Temporarily disabling as this conflicts with our current CMD K behaviour
66+
// useHotKey(() => setOpen((open) => !open), 'k')
6367

6468
useEffect(() => {
6569
// TODO: we could check for ARRAY_DELIMITER or SLIDER_DELIMITER to auto-set filter when typing
@@ -139,13 +143,15 @@ export function DataTableFilterCommand({ searchParamsParser }: DataTableFilterCo
139143
trimmedInputValue ? 'text-foreground' : 'text-foreground-light'
140144
)}
141145
>
142-
{trimmedInputValue ? inputValue : 'Search data table...'}
146+
{trimmedInputValue ? inputValue : placeholder}
143147
</span>
144-
<Kbd className="ml-auto text-muted-foreground group-hover:text-accent-foreground">
148+
{/* [Joshen] Temporarily disabling as this conflicts with existing CMD K shortcut */}
149+
{/* <Kbd className="ml-auto text-muted-foreground group-hover:text-accent-foreground">
145150
<span className="mr-1">⌘</span>
146151
<span>K</span>
147-
</Kbd>
152+
</Kbd> */}
148153
</button>
154+
149155
<Command
150156
className={cn(
151157
'overflow-visible rounded-lg border border-border shadow-md [&>div]:border-none bg',
@@ -185,7 +191,7 @@ export function DataTableFilterCommand({ searchParamsParser }: DataTableFilterCo
185191
const word = getWordByCaretPosition({ value, caretPosition })
186192
setCurrentWord(word)
187193
}}
188-
placeholder="Search data table..."
194+
placeholder={placeholder}
189195
className="text-foreground"
190196
/>
191197
<div className="relative">

apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterResetButton.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@ export function DataTableFilterResetButton<TData>({ value: _value }: DataTableFi
99
const value = _value as string
1010
const column = table.getColumn(value)
1111
const filterValue = columnFilters.find((f) => f.id === value)?.value
12-
13-
// TODO: check if we could useMemo
1412
const filters = filterValue ? (Array.isArray(filterValue) ? filterValue : [filterValue]) : []
1513

1614
if (filters.length === 0) return null
1715

1816
return (
1917
<Button
2018
type="outline"
21-
className="h-5 rounded-full px-1.5 py-1 font-mono text-[10px]"
19+
icon={<X />}
20+
className="h-5 rounded-full px-1.5 py-1 font-mono text-[10px] [&>span]:-translate-y-[0.6px] space-x-1"
2221
onClick={(e) => {
2322
e.stopPropagation()
2423
column?.setFilterValue(undefined)
@@ -29,13 +28,8 @@ export function DataTableFilterResetButton<TData>({ value: _value }: DataTableFi
2928
column?.setFilterValue(undefined)
3029
}
3130
}}
32-
icon={<X className="h-2.5 w-2.5 text-muted-foreground" />}
33-
asChild
3431
>
35-
{/* REMINDER: `AccordionTrigger` is also a button(!) and we get Hydration error when rendering button within button */}
36-
<div role="button" tabIndex={0}>
37-
<span>{filters.length}</span>
38-
</div>
32+
{filters.length}
3933
</Button>
4034
)
4135
}

apps/studio/components/ui/DataTable/RefreshButton.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
import { LoaderCircle, RefreshCcw } from 'lucide-react'
22
import { Button } from 'ui'
33

4-
import { useDataTable } from './providers/DataTableProvider'
5-
64
interface RefreshButtonProps {
7-
onClick: () => void
5+
isLoading: boolean
6+
onRefresh: () => void
87
}
98

10-
export function RefreshButton({ onClick }: RefreshButtonProps) {
11-
const { isLoading } = useDataTable()
12-
9+
export const RefreshButton = ({ isLoading, onRefresh }: RefreshButtonProps) => {
1310
return (
1411
<Button
1512
size="tiny"
1613
type="outline"
1714
disabled={isLoading}
18-
onClick={onClick}
15+
onClick={onRefresh}
1916
className="w-[26px]"
2017
icon={
2118
isLoading ? (

apps/studio/data/logs/unified-logs-infinite-query.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ async function getUnifiedLogs(
116116
status: row.status || 200,
117117
method: row.method,
118118
host: row.host,
119-
pathname: (row.url || '').replace(/^https?:\/\/[^\/]+/, '') || row.path || '',
119+
pathname: (row.url || '').replace(/^https?:\/\/[^\/]+/, '') || row.pathname || '',
120120
event_message: row.event_message || row.body || '',
121121
headers:
122122
typeof row.headers === 'string' ? JSON.parse(row.headers || '{}') : row.headers || {},

0 commit comments

Comments
 (0)