@@ -50,6 +50,8 @@ interface QueryResultsChartProps {
5050 rows : Record < string , unknown > [ ] ;
5151 columns : OutputColumnMetadata [ ] ;
5252 config : ChartConfiguration ;
53+ /** The effective time range from the query filter (used to show the full x-axis period) */
54+ timeRange ?: { from : string ; to : string } ;
5355 fullLegend ?: boolean ;
5456 /** Callback when "View all" legend button is clicked */
5557 onViewAllLegendItems ?: ( ) => void ;
@@ -159,7 +161,7 @@ function formatDateByGranularity(date: Date, granularity: TimeGranularity): stri
159161 * This helps us understand the natural granularity of the data
160162 */
161163function detectDataInterval ( timestamps : number [ ] ) : number {
162- if ( timestamps . length < 2 ) return 60 * 1000 ; // Default to 1 minute
164+ if ( timestamps . length < 2 ) return 24 * 60 * 60 * 1000 ; // Default to 1 day
163165
164166 const sorted = [ ...timestamps ] . sort ( ( a , b ) => a - b ) ;
165167 const gaps : number [ ] = [ ] ;
@@ -464,7 +466,8 @@ function tryParseDate(value: unknown): Date | null {
464466 */
465467function transformDataForChart (
466468 rows : Record < string , unknown > [ ] ,
467- config : ChartConfiguration
469+ config : ChartConfiguration ,
470+ timeRange ?: { from : string ; to : string }
468471) : TransformedData {
469472 const { xAxisColumn, yAxisColumns, groupByColumn, aggregation } = config ;
470473
@@ -490,24 +493,37 @@ function transformDataForChart(
490493 }
491494
492495 // Determine if X-axis is date-based (most values should be parseable as dates)
493- const isDateBased = dateValues . length >= rows . length * 0.8 ; // At least 80% are dates
494- const granularity = isDateBased ? detectTimeGranularity ( dateValues ) : "days" ;
496+ // When there are no results but a timeRange is provided, treat as date-based
497+ const isDateBased =
498+ rows . length === 0 && timeRange ? true : dateValues . length >= rows . length * 0.8 ; // At least 80% are dates
499+
500+ // Detect granularity from the full time range when available, otherwise from data
501+ const granularity = isDateBased
502+ ? timeRange
503+ ? detectTimeGranularity ( [ new Date ( timeRange . from ) , new Date ( timeRange . to ) ] )
504+ : detectTimeGranularity ( dateValues )
505+ : "days" ;
495506
496507 // For date-based axes, use a special key for the timestamp
497508 const xDataKey = isDateBased ? "__timestamp" : xAxisColumn ;
498509
499510 // Calculate time domain and ticks for date-based axes
511+ // When a timeRange is provided (from the query filter), use it so the chart
512+ // shows the full requested period rather than just the range of returned data.
500513 let timeDomain : [ number , number ] | null = null ;
501514 let timeTicks : number [ ] | null = null ;
502- if ( isDateBased && dateValues . length > 0 ) {
503- const timestamps = dateValues . map ( ( d ) => d . getTime ( ) ) ;
504- const minTime = Math . min ( ...timestamps ) ;
505- const maxTime = Math . max ( ...timestamps ) ;
515+ // Raw min/max used for gap filling (without padding)
516+ let rawMinTime = 0 ;
517+ let rawMaxTime = 0 ;
518+ if ( isDateBased && ( dateValues . length > 0 || timeRange ) ) {
519+ const dataTimestamps = dateValues . map ( ( d ) => d . getTime ( ) ) ;
520+ rawMinTime = timeRange ? new Date ( timeRange . from ) . getTime ( ) : Math . min ( ...dataTimestamps ) ;
521+ rawMaxTime = timeRange ? new Date ( timeRange . to ) . getTime ( ) : Math . max ( ...dataTimestamps ) ;
506522 // Add a small padding (2% on each side) so points aren't at the very edge
507- const padding = ( maxTime - minTime ) * 0.02 ;
508- timeDomain = [ minTime - padding , maxTime + padding ] ;
523+ const padding = ( rawMaxTime - rawMinTime ) * 0.02 ;
524+ timeDomain = [ rawMinTime - padding , rawMaxTime + padding ] ;
509525 // Generate evenly-spaced ticks across the entire range using nice intervals
510- timeTicks = generateTimeTicks ( minTime , maxTime ) ;
526+ timeTicks = generateTimeTicks ( rawMinTime , rawMaxTime ) ;
511527 }
512528
513529 // Helper to format X value for categorical axes (non-date)
@@ -569,8 +585,8 @@ function transformDataForChart(
569585 data ,
570586 xDataKey ,
571587 yAxisColumns ,
572- timeDomain [ 0 ] ,
573- timeDomain [ 1 ] ,
588+ rawMinTime ,
589+ rawMaxTime ,
574590 dataInterval ,
575591 granularity ,
576592 aggregation
@@ -638,8 +654,8 @@ function transformDataForChart(
638654 data ,
639655 xDataKey ,
640656 series ,
641- timeDomain [ 0 ] ,
642- timeDomain [ 1 ] ,
657+ rawMinTime ,
658+ rawMaxTime ,
643659 dataInterval ,
644660 granularity ,
645661 aggregation
@@ -726,6 +742,7 @@ export const QueryResultsChart = memo(function QueryResultsChart({
726742 rows,
727743 columns,
728744 config,
745+ timeRange,
729746 fullLegend = false ,
730747 onViewAllLegendItems,
731748 isLoading = false ,
@@ -750,7 +767,7 @@ export const QueryResultsChart = memo(function QueryResultsChart({
750767 xDataKey,
751768 timeDomain,
752769 timeTicks,
753- } = useMemo ( ( ) => transformDataForChart ( rows , config ) , [ rows , config ] ) ;
770+ } = useMemo ( ( ) => transformDataForChart ( rows , config , timeRange ) , [ rows , config , timeRange ] ) ;
754771
755772 // Apply sorting (for date-based, sort by timestamp to ensure correct order)
756773 const data = useMemo ( ( ) => {
0 commit comments