mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix(studio): preserve deep-linked date range in Unified Logs FE-4020 (#48685)
## Problem Clicking a bar in a usage chart (e.g. the Postgres activity chart on the project dashboard) navigates to Unified Logs with the log_type filter applied correctly, but the clicked bar's time range is silently dropped: the page falls back to the default last-hour window. If the actual matching logs are outside that window, the main list shows "No results found" even though the sidebar facet count (computed from the correct deep-linked range) shows a nonzero count. Root cause: the table's initial `columnFilters` state was seeded only from the `filter` URL param, never from `date`. A debounced effect syncs `columnFilters` back into the URL shortly after mount, and for the `date` field it treats a missing `columnFilters` entry as a cleared brush, overwriting the deep-linked `date` param with null. ## Fix Added `buildDefaultColumnFilters` in `UnifiedLogs.filters.ts`, which seeds a `date` entry into the initial `columnFilters` from `search.date` when present, alongside the existing filter-param seeding. `UnifiedLogs.tsx` now uses this helper instead of building `defaultColumnFilters` inline, so a deep-linked range survives the debounced round-trip instead of getting nulled out. ## How to test - On the project dashboard, click a bar in a usage chart (e.g. Postgres activity) for a time period further back than the last hour. - Expected result: Unified Logs opens with both the log_type filter and the clicked bar's date range applied, and the row list matches the sidebar facet count instead of showing "No results found". - `UnifiedLogs.filters.test.ts` has unit tests covering the new seeding behavior. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved log filtering from URL parameters. * Preserved valid date ranges when opening deep-linked log views. * Prevented malformed or duplicate date filters from appearing in the logs table. * **Tests** * Added coverage for valid, missing, malformed, and duplicate date filter scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
afda8461a3
commit
2ba2c37163
3 files changed
+59
-2
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
buildDefaultColumnFilters,
|
||||
buildFilterSearchUpdate,
|
||||
columnFiltersToLogsFilters,
|
||||
logsFiltersToColumnFilters,
|
||||
@@ -122,3 +123,46 @@ describe('buildFilterSearchUpdate', () => {
|
||||
expect(update.date).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('buildDefaultColumnFilters', () => {
|
||||
const fields = [
|
||||
{ value: 'date', type: 'timerange' },
|
||||
{ value: 'log_type', type: 'checkbox' },
|
||||
]
|
||||
|
||||
it('seeds a deep-linked `date` range so it survives the debounced sync back to the URL', () => {
|
||||
const range = [new Date('2026-05-08T00:00:00Z'), new Date('2026-05-08T01:00:00Z')]
|
||||
const columnFilters = buildDefaultColumnFilters({
|
||||
filter: ['log_type:eq:postgres'],
|
||||
date: range,
|
||||
})
|
||||
expect(columnFilters).toEqual([
|
||||
{ id: 'log_type', value: ['postgres'] },
|
||||
{ id: 'date', value: range },
|
||||
])
|
||||
|
||||
// Regression guard: without the `date` entry above, this would null out the range.
|
||||
const update = buildFilterSearchUpdate(columnFilters, fields)
|
||||
expect(update.date).toBe(range)
|
||||
})
|
||||
|
||||
it('omits `date` when no range is present, matching the pre-existing no-filter case', () => {
|
||||
expect(buildDefaultColumnFilters({ filter: ['log_type:eq:postgres'], date: null })).toEqual([
|
||||
{ id: 'log_type', value: ['postgres'] },
|
||||
])
|
||||
})
|
||||
|
||||
it('omits `date` for a malformed single-element range', () => {
|
||||
const columnFilters = buildDefaultColumnFilters({
|
||||
filter: ['log_type:eq:postgres'],
|
||||
date: [new Date('2026-05-08T00:00:00Z')],
|
||||
})
|
||||
expect(columnFilters).toEqual([{ id: 'log_type', value: ['postgres'] }])
|
||||
})
|
||||
|
||||
it('does not duplicate the `date` id when a hand-crafted `filter` param also targets it', () => {
|
||||
const range = [new Date('2026-05-08T00:00:00Z'), new Date('2026-05-08T01:00:00Z')]
|
||||
const columnFilters = buildDefaultColumnFilters({ filter: ['date:eq:123'], date: range })
|
||||
expect(columnFilters).toEqual([{ id: 'date', value: range }])
|
||||
})
|
||||
})
|
||||
@@ -89,6 +89,19 @@ export const logsFiltersToColumnFilters = (
|
||||
)
|
||||
}
|
||||
|
||||
// Seeds `date` too, so `logsFiltersToColumnFilters` (which only covers the `filter`
|
||||
// param) doesn't leave it out and get nulled by the debounced sync back to `search`.
|
||||
export const buildDefaultColumnFilters = (search: {
|
||||
filter?: string[] | null
|
||||
date?: Date[] | null
|
||||
}): { id: string; value: unknown }[] => {
|
||||
const filters: { id: string; value: unknown }[] = logsFiltersToColumnFilters(
|
||||
parseLogsFilterUrlParams(search.filter)
|
||||
).filter((f) => f.id !== 'date')
|
||||
if (search.date?.length === 2) filters.push({ id: 'date', value: search.date })
|
||||
return filters
|
||||
}
|
||||
|
||||
export const columnFiltersToLogsFilters = (
|
||||
columnFilters: { id: string; value: unknown }[],
|
||||
filterableNames?: Set<string>
|
||||
|
||||
@@ -38,8 +38,8 @@ import { ServiceFlowPanel } from './ServiceFlowPanel'
|
||||
import { SEARCH_PARAMS_PARSER } from './UnifiedLogs.constants'
|
||||
import { filterFields as defaultFilterFields } from './UnifiedLogs.fields'
|
||||
import {
|
||||
buildDefaultColumnFilters,
|
||||
buildFilterSearchUpdate,
|
||||
logsFiltersToColumnFilters,
|
||||
parseLogsFilterUrlParams,
|
||||
} from './UnifiedLogs.filters'
|
||||
import { useLiveMode, useResetFocus } from './UnifiedLogs.hooks'
|
||||
@@ -96,7 +96,7 @@ export const UnifiedLogs = () => {
|
||||
|
||||
const defaultColumnSorting = search.sort ? [search.sort] : []
|
||||
const defaultColumnVisibility = { uuid: false }
|
||||
const defaultColumnFilters = logsFiltersToColumnFilters(parseLogsFilterUrlParams(search.filter))
|
||||
const defaultColumnFilters = buildDefaultColumnFilters(search)
|
||||
|
||||
const [topBarHeight, setTopBarHeight] = useState(0)
|
||||
const topBarRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
Reference in new issue
Block a user