From 4150bbe2cc2537bdeef4748206fa44eae9c58b2c Mon Sep 17 00:00:00 2001 From: Jordi Enric Date: Mon, 16 Jun 2025 16:15:43 +0200 Subject: [PATCH] fix datepicker helper state --- .../interfaces/Reports/Reports.constants.ts | 8 +++ .../Settings/Logs/Logs.DatePickers.tsx | 69 +++++++++++-------- .../Settings/Logs/Logs.constants.ts | 13 ++++ .../interfaces/Settings/Logs/Logs.types.ts | 1 + .../Settings/Logs/LogsQueryPanel.tsx | 42 ++--------- .../studio/hooks/analytics/useLogsUrlState.ts | 14 ++++ .../project/[ref]/logs/explorer/index.tsx | 13 ---- 7 files changed, 81 insertions(+), 79 deletions(-) diff --git a/apps/studio/components/interfaces/Reports/Reports.constants.ts b/apps/studio/components/interfaces/Reports/Reports.constants.ts index 3e2f58af16f..f7e2cac545c 100644 --- a/apps/studio/components/interfaces/Reports/Reports.constants.ts +++ b/apps/studio/components/interfaces/Reports/Reports.constants.ts @@ -12,18 +12,21 @@ interface ReportsDatetimeHelper extends DatetimeHelper { export const REPORTS_DATEPICKER_HELPERS: ReportsDatetimeHelper[] = [ { + id: 'last_10_minutes', text: 'Last 10 minutes', calcFrom: () => dayjs().subtract(10, 'minute').toISOString(), calcTo: () => dayjs().toISOString(), availableIn: ['team', 'enterprise'], }, { + id: 'last_30_minutes', text: 'Last 30 minutes', calcFrom: () => dayjs().subtract(30, 'minute').toISOString(), calcTo: () => dayjs().toISOString(), availableIn: ['team', 'enterprise'], }, { + id: 'last_60_minutes', text: 'Last 60 minutes', calcFrom: () => dayjs().subtract(1, 'hour').startOf('day').toISOString(), calcTo: () => dayjs().toISOString(), @@ -31,30 +34,35 @@ export const REPORTS_DATEPICKER_HELPERS: ReportsDatetimeHelper[] = [ availableIn: ['free', 'pro', 'team', 'enterprise'], }, { + id: 'last_3_hours', text: 'Last 3 hours', calcFrom: () => dayjs().subtract(3, 'hour').startOf('day').toISOString(), calcTo: () => dayjs().toISOString(), availableIn: ['free', 'pro', 'team', 'enterprise'], }, { + id: 'last_24_hours', text: 'Last 24 hours', calcFrom: () => dayjs().subtract(1, 'day').startOf('day').toISOString(), calcTo: () => dayjs().toISOString(), availableIn: ['free', 'pro', 'team', 'enterprise'], }, { + id: 'last_7_days', text: 'Last 7 days', calcFrom: () => dayjs().subtract(7, 'day').startOf('day').toISOString(), calcTo: () => '', availableIn: ['pro', 'team', 'enterprise'], }, { + id: 'last_14_days', text: 'Last 14 days', calcFrom: () => dayjs().subtract(14, 'day').startOf('day').toISOString(), calcTo: () => '', availableIn: ['team', 'enterprise'], }, { + id: 'last_28_days', text: 'Last 28 days', calcFrom: () => dayjs().subtract(28, 'day').startOf('day').toISOString(), calcTo: () => '', diff --git a/apps/studio/components/interfaces/Settings/Logs/Logs.DatePickers.tsx b/apps/studio/components/interfaces/Settings/Logs/Logs.DatePickers.tsx index a113cd1539f..3e4f08ba924 100644 --- a/apps/studio/components/interfaces/Settings/Logs/Logs.DatePickers.tsx +++ b/apps/studio/components/interfaces/Settings/Logs/Logs.DatePickers.tsx @@ -11,6 +11,7 @@ import { Button, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_, Popover_Shadcn_ import { LOGS_LARGE_DATE_RANGE_DAYS_THRESHOLD } from './Logs.constants' import type { DatetimeHelper } from './Logs.types' import { copyToClipboard } from 'lib/helpers' +import { useLogsUrlState } from 'hooks/analytics/useLogsUrlState' export type DatePickerValue = { to: string @@ -20,22 +21,32 @@ export type DatePickerValue = { } interface Props { - value: DatePickerValue - onSubmit: (args: DatePickerValue) => void helpers: DatetimeHelper[] } -export const LogsDatePicker = ({ onSubmit, helpers, value }: PropsWithChildren) => { +export const LogsDatePicker = ({ helpers }: PropsWithChildren) => { + const { timestampStart, timestampEnd, setTimeRange, selectedHelperId, setSelectedHelperId } = + useLogsUrlState() const [open, setOpen] = useState(false) + useEffect(() => { + if (selectedHelperId) { + const helper = helpers.find((h) => h.id === selectedHelperId) + if (helper) { + setTimeRange(helper.calcFrom(), helper.calcTo()) + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedHelperId]) + // Reset the state when the popover closes useEffect(() => { if (!open) { - setStartDate(value.from ? new Date(value.from) : null) - setEndDate(value.to ? new Date(value.to) : new Date()) + setStartDate(timestampStart ? new Date(timestampStart) : null) + setEndDate(timestampEnd ? new Date(timestampEnd) : new Date()) - const fromDate = value.from ? new Date(value.from) : null - const toDate = value.to ? new Date(value.to) : null + const fromDate = timestampStart ? new Date(timestampStart) : null + const toDate = timestampEnd ? new Date(timestampEnd) : null setStartTime({ HH: fromDate?.getHours().toString().padStart(2, '0') || '00', @@ -54,24 +65,23 @@ export const LogsDatePicker = ({ onSubmit, helpers, value }: PropsWithChildren

{ const selectedHelper = helpers.find((h) => h.text === newValue) - if (onSubmit && selectedHelper) { - onSubmit({ - to: selectedHelper.calcTo(), - from: selectedHelper.calcFrom(), - isHelper: true, - text: selectedHelper.text, - }) + if (selectedHelper) { + setTimeRange(selectedHelper.calcFrom(), selectedHelper.calcTo()) + setSelectedHelperId(selectedHelper.id) } - setOpen(false) } - const [startDate, setStartDate] = useState(value.from ? new Date(value.from) : null) - const [endDate, setEndDate] = useState(value.to ? new Date(value.to) : new Date()) + const [startDate, setStartDate] = useState( + timestampStart ? new Date(timestampStart) : null + ) + const [endDate, setEndDate] = useState( + timestampEnd ? new Date(timestampEnd) : new Date() + ) const [startTime, setStartTime] = useState({ HH: startDate?.getHours().toString() || '00', @@ -99,12 +109,8 @@ export const LogsDatePicker = ({ onSubmit, helpers, value }: PropsWithChildren

LOGS_LARGE_DATE_RANGE_DAYS_THRESHOLD - 1 + const selectedHelper = helpers.find((h) => h.id === selectedHelperId) + return ( { + const selected = helpers.find((h) => h.id === selectedHelperId) + return selected ? selected.text : '' + })()} className="border-r p-2 flex flex-col gap-px" > {helpers.map((helper) => ( diff --git a/apps/studio/components/interfaces/Settings/Logs/Logs.constants.ts b/apps/studio/components/interfaces/Settings/Logs/Logs.constants.ts index c84fe325cc8..85a08a6dacc 100644 --- a/apps/studio/components/interfaces/Settings/Logs/Logs.constants.ts +++ b/apps/studio/components/interfaces/Settings/Logs/Logs.constants.ts @@ -672,42 +672,50 @@ export const LOGS_TAILWIND_CLASSES = { export const PREVIEWER_DATEPICKER_HELPERS: DatetimeHelper[] = [ { + id: 'last_15_minutes', text: 'Last 15 minutes', calcFrom: () => dayjs().subtract(15, 'minute').toISOString(), calcTo: () => '', }, { + id: 'last_30_minutes', text: 'Last 30 minutes', calcFrom: () => dayjs().subtract(30, 'minute').toISOString(), calcTo: () => '', }, { + id: 'last_hour', text: 'Last hour', calcFrom: () => dayjs().subtract(1, 'hour').toISOString(), calcTo: () => '', default: true, }, { + id: 'last_3_hours', text: 'Last 3 hours', calcFrom: () => dayjs().subtract(3, 'hour').toISOString(), calcTo: () => '', }, { + id: 'last_24_hours', text: 'Last 24 hours', calcFrom: () => dayjs().subtract(1, 'day').toISOString(), calcTo: () => '', }, { + id: 'last_2_days', text: 'Last 2 days', calcFrom: () => dayjs().subtract(2, 'day').toISOString(), calcTo: () => '', }, { + id: 'last_3_days', text: 'Last 3 days', calcFrom: () => dayjs().subtract(3, 'day').toISOString(), calcTo: () => '', }, { + id: 'last_5_days', text: 'Last 5 days', calcFrom: () => dayjs().subtract(5, 'day').toISOString(), calcTo: () => '', @@ -715,27 +723,32 @@ export const PREVIEWER_DATEPICKER_HELPERS: DatetimeHelper[] = [ ] export const EXPLORER_DATEPICKER_HELPERS: DatetimeHelper[] = [ { + id: 'last_hour', text: 'Last hour', calcFrom: () => dayjs().subtract(1, 'hour').toISOString(), calcTo: () => '', default: true, }, { + id: 'last_3_hours', text: 'Last 3 hours', calcFrom: () => dayjs().subtract(3, 'hour').toISOString(), calcTo: () => '', }, { + id: 'last_24_hours', text: 'Last 24 hours', calcFrom: () => dayjs().subtract(1, 'day').toISOString(), calcTo: () => '', }, { + id: 'last_3_days', text: 'Last 3 days', calcFrom: () => dayjs().subtract(3, 'day').toISOString(), calcTo: () => '', }, { + id: 'last_7_days', text: 'Last 7 days', calcFrom: () => dayjs().subtract(7, 'day').toISOString(), calcTo: () => '', diff --git a/apps/studio/components/interfaces/Settings/Logs/Logs.types.ts b/apps/studio/components/interfaces/Settings/Logs/Logs.types.ts index 06ee5653348..0aff36daf5c 100644 --- a/apps/studio/components/interfaces/Settings/Logs/Logs.types.ts +++ b/apps/studio/components/interfaces/Settings/Logs/Logs.types.ts @@ -138,6 +138,7 @@ export type Override = { } export interface DatetimeHelper { + id: string text: string calcTo: () => string calcFrom: () => string diff --git a/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx b/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx index d6bebe2d1db..8eb4915b81f 100644 --- a/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx +++ b/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx @@ -27,23 +27,21 @@ import { LOGS_SOURCE_DESCRIPTION, LogsTableName, } from './Logs.constants' -import { DatePickerValue, LogsDatePicker } from './Logs.DatePickers' +import { LogsDatePicker } from './Logs.DatePickers' import { LogsWarning, LogTemplate, WarehouseCollection } from './Logs.types' import { WarehouseQueryTemplate } from './Warehouse.utils' +import { useLogsUrlState } from 'hooks/analytics/useLogsUrlState' export type SourceType = 'logs' | 'warehouse' export interface LogsQueryPanelProps { templates?: LogTemplate[] warehouseTemplates?: WarehouseQueryTemplate[] - defaultFrom: string - defaultTo: string warnings: LogsWarning[] warehouseCollections: WarehouseCollection[] dataSource: SourceType onSelectTemplate: (template: LogTemplate) => void onSelectWarehouseTemplate: (template: WarehouseQueryTemplate) => void onSelectSource: (source: string) => void - onDateChange: (value: DatePickerValue) => void onDataSourceChange: (sourceType: SourceType) => void } @@ -59,18 +57,16 @@ function DropdownMenuItemContent({ name, desc }: { name: ReactNode; desc?: strin const LogsQueryPanel = ({ templates = [], warehouseTemplates = [], - defaultFrom, - defaultTo, warnings, warehouseCollections, dataSource, onSelectTemplate, onSelectWarehouseTemplate, onSelectSource, - onDateChange, onDataSourceChange, }: LogsQueryPanelProps) => { const [showReference, setShowReference] = useState(false) + const { timestampStart, timestampEnd, setTimeRange } = useLogsUrlState() const { projectAuthAll: authEnabled, @@ -91,27 +87,6 @@ const LogsQueryPanel = ({ }) .map(([, value]) => value) - function getDefaultDatePickerValue() { - if (defaultFrom && defaultTo) { - return { - to: defaultTo, - from: defaultFrom, - text: `${dayjs(defaultFrom).format('DD MMM, HH:mm')} - ${dayjs(defaultTo).format('DD MMM, HH:mm')}`, - isHelper: false, - } - } - return { - to: EXPLORER_DATEPICKER_HELPERS[0].calcTo(), - from: EXPLORER_DATEPICKER_HELPERS[0].calcFrom(), - text: EXPLORER_DATEPICKER_HELPERS[0].text, - isHelper: true, - } - } - - const [selectedDatePickerValue, setSelectedDatePickerValue] = useState( - getDefaultDatePickerValue() - ) - return (

@@ -222,16 +197,7 @@ const LogsQueryPanel = ({ )} - {dataSource === 'logs' && ( - { - setSelectedDatePickerValue(value) - onDateChange(value) - }} - helpers={EXPLORER_DATEPICKER_HELPERS} - /> - )} + {dataSource === 'logs' && }
@@ -59,6 +61,10 @@ export function useLogsUrlState() { 'f', jsonWithDefault(defaultState.filters) ) + const [selectedHelperIdValue, setSelectedHelperIdValue] = useQueryState( + 'helper', + stringWithDefault(defaultState.selectedHelperId) + ) // Ensure we never return null values const search = searchValue || defaultState.search @@ -66,6 +72,7 @@ export function useLogsUrlState() { const timestampEnd = timestampEndValue || defaultState.timestampEnd const selectedLogId = selectedLogIdValue || null const filters = filtersValue || defaultState.filters + const selectedHelperId = selectedHelperIdValue || defaultState.selectedHelperId const setSearch = (value: string) => { setSearchValue(value || defaultState.search) @@ -88,12 +95,17 @@ export function useLogsUrlState() { setFilters({ ...filters, [key]: value }) } + const setSelectedHelperId = (value: string) => { + setSelectedHelperIdValue(value || defaultState.selectedHelperId) + } + const reset = () => { setSearch(defaultState.search) setTimestampStartValue(defaultState.timestampStart) setTimestampEndValue(defaultState.timestampEnd) setSelectedLogIdValue('') setFiltersValue(defaultState.filters) + setSelectedHelperIdValue(defaultState.selectedHelperId) } return { @@ -103,6 +115,7 @@ export function useLogsUrlState() { timestampEnd, selectedLogId, filters, + selectedHelperId, // Setters setSearch, @@ -110,6 +123,7 @@ export function useLogsUrlState() { setSelectedLogId, setFilters, updateFilter, + setSelectedHelperId, reset, } } diff --git a/apps/studio/pages/project/[ref]/logs/explorer/index.tsx b/apps/studio/pages/project/[ref]/logs/explorer/index.tsx index 02ff3525f1b..44f64cec539 100644 --- a/apps/studio/pages/project/[ref]/logs/explorer/index.tsx +++ b/apps/studio/pages/project/[ref]/logs/explorer/index.tsx @@ -313,16 +313,6 @@ export const LogsExplorerPage: NextPageWithLayout = () => { setSaveModalOpen(!saveModalOpen) } - const handleDateChange = ({ to, from }: DatePickerToFrom) => { - const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from, organization?.plan?.id) - - if (shouldShowUpgradePrompt) { - setShowUpgradePrompt(!showUpgradePrompt) - } else { - setTimeRange(from || '', to || '') - } - } - useEffect(() => { if (warehouseError) toast.error(warehouseError.message) }, [warehouseError]) @@ -379,9 +369,6 @@ export const LogsExplorerPage: NextPageWithLayout = () => { > template.mode === 'custom')} warehouseCollections={warehouseCollections || []}