@@ -69,6 +69,14 @@ import { requireUser } from "~/services/session.server";
6969import parse from "parse-duration" ;
7070import { SimpleTooltip } from "~/components/primitives/Tooltip" ;
7171
72+ /** Convert a Date or ISO string to ISO string format */
73+ function toISOString ( value : Date | string ) : string {
74+ if ( typeof value === "string" ) {
75+ return value ;
76+ }
77+ return value . toISOString ( ) ;
78+ }
79+
7280async function hasQueryAccess (
7381 userId : string ,
7482 isAdmin : boolean ,
@@ -295,6 +303,13 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
295303 source : "DASHBOARD" ,
296304 userId : user . id ,
297305 skip : user . isImpersonating ,
306+ timeFilter : {
307+ // Save the effective period used for the query (timeFilters() handles defaults)
308+ // Only save period if no custom from/to range was specified
309+ period : timeFilter . from || timeFilter . to ? undefined : timeFilter . period ,
310+ from : timeFilter . from ,
311+ to : timeFilter . to ,
312+ } ,
298313 } ,
299314 } ) ;
300315
@@ -344,6 +359,7 @@ interface QueryEditorFormHandle {
344359 setQuery : ( query : string ) => void ;
345360 setScope : ( scope : QueryScope ) => void ;
346361 getQuery : ( ) => string ;
362+ setTimeFilter : ( filter : { period ?: string ; from ?: string ; to ?: string } ) => void ;
347363}
348364
349365/** Self-contained query editor with form - isolates query state from parent */
@@ -352,20 +368,21 @@ const QueryEditorForm = forwardRef<
352368 {
353369 defaultQuery : string ;
354370 defaultScope : QueryScope ;
371+ defaultTimeFilter ?: { period ?: string ; from ?: string ; to ?: string } ;
355372 history : QueryHistoryItem [ ] ;
356373 fetcher : ReturnType < typeof useTypedFetcher < typeof action > > ;
357374 isAdmin : boolean ;
358375 }
359- > ( function QueryEditorForm ( { defaultQuery, defaultScope, history, fetcher, isAdmin } , ref ) {
376+ > ( function QueryEditorForm ( { defaultQuery, defaultScope, defaultTimeFilter , history, fetcher, isAdmin } , ref ) {
360377 const isLoading = fetcher . state === "submitting" || fetcher . state === "loading" ;
361378 const [ query , setQuery ] = useState ( defaultQuery ) ;
362379 const [ scope , setScope ] = useState < QueryScope > ( defaultScope ) ;
363380 const formRef = useRef < HTMLFormElement > ( null ) ;
364381
365- // Get time filter values from URL search params
366- const [ period , setPeriod ] = useState < string | undefined > ( ) ;
367- const [ from , setFrom ] = useState < string | undefined > ( ) ;
368- const [ to , setTo ] = useState < string | undefined > ( ) ;
382+ // Get time filter values - initialize from props (which may come from history)
383+ const [ period , setPeriod ] = useState < string | undefined > ( defaultTimeFilter ?. period ) ;
384+ const [ from , setFrom ] = useState < string | undefined > ( defaultTimeFilter ?. from ) ;
385+ const [ to , setTo ] = useState < string | undefined > ( defaultTimeFilter ?. to ) ;
369386
370387 // Check if the query contains triggered_at in a WHERE clause
371388 // This disables the time filter UI since the user is filtering in their query
@@ -378,13 +395,23 @@ const QueryEditorForm = forwardRef<
378395 setQuery,
379396 setScope,
380397 getQuery : ( ) => query ,
398+ setTimeFilter : ( filter : { period ?: string ; from ?: string ; to ?: string } ) => {
399+ setPeriod ( filter . period ) ;
400+ setFrom ( filter . from ) ;
401+ setTo ( filter . to ) ;
402+ } ,
381403 } ) ,
382404 [ query ]
383405 ) ;
384406
385407 const handleHistorySelected = useCallback ( ( item : QueryHistoryItem ) => {
386408 setQuery ( item . query ) ;
387409 setScope ( item . scope ) ;
410+ // Apply time filter from history item
411+ // Note: filterFrom/filterTo might be Date objects or ISO strings depending on serialization
412+ setPeriod ( item . filterPeriod ?? undefined ) ;
413+ setFrom ( item . filterFrom ? toISOString ( item . filterFrom ) : undefined ) ;
414+ setTo ( item . filterTo ? toISOString ( item . filterTo ) : undefined ) ;
388415 } , [ ] ) ;
389416
390417 return (
@@ -488,6 +515,14 @@ export default function Page() {
488515 // Use most recent history item if available, otherwise fall back to defaults
489516 const initialQuery = history . length > 0 ? history [ 0 ] . query : defaultQuery ;
490517 const initialScope : QueryScope = history . length > 0 ? history [ 0 ] . scope : "environment" ;
518+ const initialTimeFilter = history . length > 0
519+ ? {
520+ period : history [ 0 ] . filterPeriod ?? undefined ,
521+ // Note: filterFrom/filterTo might be Date objects or ISO strings depending on serialization
522+ from : history [ 0 ] . filterFrom ? toISOString ( history [ 0 ] . filterFrom ) : undefined ,
523+ to : history [ 0 ] . filterTo ? toISOString ( history [ 0 ] . filterTo ) : undefined ,
524+ }
525+ : undefined ;
491526
492527 const editorRef = useRef < QueryEditorFormHandle > ( null ) ;
493528 const [ prettyFormatting , setPrettyFormatting ] = useState ( true ) ;
@@ -552,6 +587,7 @@ export default function Page() {
552587 ref = { editorRef }
553588 defaultQuery = { initialQuery }
554589 defaultScope = { initialScope }
590+ defaultTimeFilter = { initialTimeFilter }
555591 history = { history }
556592 fetcher = { fetcher }
557593 isAdmin = { isAdmin }
0 commit comments