diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.test.ts b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.test.ts index 68538d1680d..d78b2f75b86 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.test.ts +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.test.ts @@ -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 }]) + }) +}) diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.ts b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.ts index 32614bf9088..92a4549d208 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.ts +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.filters.ts @@ -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 diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx index 7981955ec75..d9f4ed0f001 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx +++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx @@ -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(null)