11import { ArrowDownTrayIcon , ClipboardIcon } from "@heroicons/react/20/solid" ;
2- import type { OutputColumnMetadata } from "@internal/clickhouse" ;
2+ import type { OutputColumnMetadata , WhereClauseFallback } from "@internal/clickhouse" ;
33import { Form , useNavigation } from "@remix-run/react" ;
44import {
55 redirect ,
@@ -21,6 +21,8 @@ import { autoFormatSQL, TSQLEditor } from "~/components/code/TSQLEditor";
2121import { TSQLResultsTable } from "~/components/code/TSQLResultsTable" ;
2222import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel" ;
2323import { PageBody , PageContainer } from "~/components/layout/AppLayout" ;
24+ import { TimeFilter , timeFilters } from "~/components/runs/v3/SharedFilters" ;
25+ import { useSearchParams } from "~/hooks/useSearchParam" ;
2426import { Button } from "~/components/primitives/Buttons" ;
2527import { Callout } from "~/components/primitives/Callout" ;
2628import { Card } from "~/components/primitives/charts/Card" ;
@@ -62,6 +64,8 @@ import { querySchemas } from "~/v3/querySchemas";
6264import { QueryHelpSidebar } from "./QueryHelpSidebar" ;
6365import { QueryHistoryPopover } from "./QueryHistoryPopover" ;
6466import { formatQueryStats } from "./utils" ;
67+ import { requireUser } from "~/services/session.server" ;
68+ import parse from "parse-duration" ;
6569
6670async function hasQueryAccess (
6771 userId : string ,
@@ -148,12 +152,15 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
148152 } ) ;
149153} ;
150154
151- import { requireUser } from "~/services/session.server ";
155+ const DEFAULT_PERIOD = "7d ";
152156
153157const ActionSchema = z . object ( {
154158 query : z . string ( ) . min ( 1 , "Query is required" ) ,
155159 scope : z . enum ( [ "environment" , "project" , "organization" ] ) ,
156160 explain : z . enum ( [ "true" , "false" ] ) . nullable ( ) . optional ( ) ,
161+ period : z . string ( ) . nullable ( ) . optional ( ) ,
162+ from : z . string ( ) . nullable ( ) . optional ( ) ,
163+ to : z . string ( ) . nullable ( ) . optional ( ) ,
157164} ) ;
158165
159166export const action = async ( { request, params } : ActionFunctionArgs ) => {
@@ -218,6 +225,9 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
218225 query : formData . get ( "query" ) ,
219226 scope : formData . get ( "scope" ) ,
220227 explain : formData . get ( "explain" ) ,
228+ period : formData . get ( "period" ) ,
229+ from : formData . get ( "from" ) ,
230+ to : formData . get ( "to" ) ,
221231 } ) ;
222232
223233 if ( ! parsed . success ) {
@@ -235,11 +245,35 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
235245 ) ;
236246 }
237247
238- const { query, scope, explain : explainParam } = parsed . data ;
248+ const { query, scope, explain : explainParam , period , from , to } = parsed . data ;
239249 // Only allow explain for admins/impersonating users
240250 const isAdmin = user . admin || user . isImpersonating ;
241251 const explain = explainParam === "true" && isAdmin ;
242252
253+ // Build time filter fallback for triggered_at column
254+ const timeFilter = timeFilters ( {
255+ period : period ?? undefined ,
256+ from : from ?? undefined ,
257+ to : to ?? undefined ,
258+ defaultPeriod : DEFAULT_PERIOD ,
259+ } ) ;
260+
261+ let triggeredAtFallback : WhereClauseFallback ;
262+ if ( timeFilter . from && timeFilter . to ) {
263+ // Both from and to specified - use BETWEEN
264+ triggeredAtFallback = { op : "between" , low : timeFilter . from , high : timeFilter . to } ;
265+ } else if ( timeFilter . from ) {
266+ // Only from specified
267+ triggeredAtFallback = { op : "gte" , value : timeFilter . from } ;
268+ } else if ( timeFilter . to ) {
269+ // Only to specified
270+ triggeredAtFallback = { op : "lte" , value : timeFilter . to } ;
271+ } else {
272+ // Period specified (or default) - calculate from now
273+ const periodMs = parse ( timeFilter . period ?? DEFAULT_PERIOD ) ?? 7 * 24 * 60 * 60 * 1000 ;
274+ triggeredAtFallback = { op : "gte" , value : new Date ( Date . now ( ) - periodMs ) } ;
275+ }
276+
243277 try {
244278 const [ error , result ] = await executeQuery ( {
245279 name : "query-page" ,
@@ -252,6 +286,9 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
252286 projectId : project . id ,
253287 environmentId : environment . id ,
254288 explain,
289+ whereClauseFallback : {
290+ triggered_at : triggeredAtFallback ,
291+ } ,
255292 history : {
256293 source : "DASHBOARD" ,
257294 userId : user . id ,
@@ -320,6 +357,12 @@ const QueryEditorForm = forwardRef<
320357> ( function QueryEditorForm ( { defaultQuery, defaultScope, history, isLoading, isAdmin } , ref ) {
321358 const [ query , setQuery ] = useState ( defaultQuery ) ;
322359 const [ scope , setScope ] = useState < QueryScope > ( defaultScope ) ;
360+ const { value : searchParamValue } = useSearchParams ( ) ;
361+
362+ // Get time filter values from URL search params
363+ const period = searchParamValue ( "period" ) ;
364+ const from = searchParamValue ( "from" ) ;
365+ const to = searchParamValue ( "to" ) ;
323366
324367 // Expose methods to parent for external query setting (history, AI, examples)
325368 useImperativeHandle (
@@ -352,6 +395,10 @@ const QueryEditorForm = forwardRef<
352395 < Form method = "post" className = "flex items-center justify-between gap-2 px-2" >
353396 < input type = "hidden" name = "query" value = { query } />
354397 < input type = "hidden" name = "scope" value = { scope } />
398+ { /* Pass time filter values to action */ }
399+ < input type = "hidden" name = "period" value = { period ?? "" } />
400+ < input type = "hidden" name = "from" value = { from ?? "" } />
401+ < input type = "hidden" name = "to" value = { to ?? "" } />
355402 < QueryHistoryPopover history = { history } onQuerySelected = { handleHistorySelected } />
356403 < div className = "flex items-center gap-1" >
357404 < Select
@@ -372,6 +419,7 @@ const QueryEditorForm = forwardRef<
372419 ) )
373420 }
374421 </ Select >
422+ < TimeFilter defaultPeriod = { DEFAULT_PERIOD } />
375423 { isAdmin && (
376424 < Button
377425 type = "submit"
0 commit comments