From 1e7956c42e51bbb1eb1892cd7cd8b109ac3f39c4 Mon Sep 17 00:00:00 2001 From: Dhiraj Kumar Date: Mon, 25 May 2026 22:01:10 +0530 Subject: [PATCH 1/4] fix: flashing red error on charts --- .../canvas/components/BaseCanvasComponent.ts | 7 ++--- .../cartesian/CartesianChartProvider.ts | 10 ++++--- .../charts/circular/CircularChartProvider.ts | 13 ++++---- .../charts/combo/ComboChartProvider.ts | 8 +++-- .../components/charts/data-provider.ts | 7 ++++- .../charts/funnel/FunnelChartProvider.ts | 9 ++++-- .../charts/heatmap/HeatmapChartProvider.ts | 7 +++-- .../features/components/charts/query-util.ts | 12 ++++++++ .../scatter/ScatterPlotChartProvider.ts | 30 ++++++++++++------- 9 files changed, 70 insertions(+), 33 deletions(-) diff --git a/web-common/src/features/canvas/components/BaseCanvasComponent.ts b/web-common/src/features/canvas/components/BaseCanvasComponent.ts index 47831b787e48..22abf8b412ac 100644 --- a/web-common/src/features/canvas/components/BaseCanvasComponent.ts +++ b/web-common/src/features/canvas/components/BaseCanvasComponent.ts @@ -15,6 +15,7 @@ import type { V1TimeRange, } from "@rilldata/web-common/runtime-client"; import type { ComponentType, SvelteComponent } from "svelte"; +import type { Readable } from "svelte/store"; import { derived, get, writable, type Writable } from "svelte/store"; import { mergeFilters } from "../../dashboards/pivot/pivot-merge-filters"; import { @@ -31,9 +32,8 @@ import type { ComponentPath, SearchParamsStore, } from "../stores/canvas-entity"; -import { TimeState } from "../stores/time-state"; import type { FilterState } from "../stores/filter-state"; -import type { Readable } from "svelte/store"; +import { TimeState } from "../stores/time-state"; export abstract class BaseCanvasComponent { id: string; @@ -198,8 +198,7 @@ export abstract class BaseCanvasComponent { ], set, ) => { - const hasTimeSeries = - hasTimeSeriesMap.get(this.metricsViewName) ?? false; + const hasTimeSeries = hasTimeSeriesMap.get(this.metricsViewName); const mvFilters = metricsViewFilters.get(this.metricsViewName); diff --git a/web-common/src/features/components/charts/cartesian/CartesianChartProvider.ts b/web-common/src/features/components/charts/cartesian/CartesianChartProvider.ts index e504c6b30fab..f44fa1101381 100644 --- a/web-common/src/features/components/charts/cartesian/CartesianChartProvider.ts +++ b/web-common/src/features/components/charts/cartesian/CartesianChartProvider.ts @@ -36,6 +36,7 @@ import { type Writable, } from "svelte/store"; import { + canQueryWithTimeRange, getFilterWithNullHandling, isSortByDelta, vegaSortToAggregationSort, @@ -186,6 +187,7 @@ export class CartesianChartProvider { const dimensionName = config.x?.field; const rawSort = config.x?.sort; const sortIsDelta = isSortByDelta(rawSort); + const requiresTimeRange = config.x?.type === "temporal"; if (config.x?.type === "nominal" && dimensionName) { limit = config.x.limit ?? 100; @@ -218,7 +220,7 @@ export class CartesianChartProvider { } = $timeAndFilterStore; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && config.x?.type === "nominal" && !Array.isArray(config.x?.sort) && !!dimensionName; @@ -292,7 +294,7 @@ export class CartesianChartProvider { const enabled = $visible && !hasExplicitColorValues && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange, requiresTimeRange) && hasColorDimension && !!colorDimensionName && !!colorLimit; @@ -342,7 +344,7 @@ export class CartesianChartProvider { const topNColorData = $topNColorQuery?.data?.data; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange, requiresTimeRange) && !!measures?.length && !!dimensions?.length && (hasColorDimension && @@ -448,7 +450,7 @@ export class CartesianChartProvider { comparisonTimeRange?.end ? comparisonTimeRange : undefined, - fillMissing: config.x?.type === "temporal", + fillMissing: requiresTimeRange, limit: hasColorDimension || !limit ? "5000" : limit?.toString(), }, { diff --git a/web-common/src/features/components/charts/circular/CircularChartProvider.ts b/web-common/src/features/components/charts/circular/CircularChartProvider.ts index 631934dbaaf4..4a7c588320a2 100644 --- a/web-common/src/features/components/charts/circular/CircularChartProvider.ts +++ b/web-common/src/features/components/charts/circular/CircularChartProvider.ts @@ -27,7 +27,10 @@ import { type Readable, type Writable, } from "svelte/store"; -import { getFilterWithNullHandling } from "../query-util"; +import { + canQueryWithTimeRange, + getFilterWithNullHandling, +} from "../query-util"; import { OTHER_VALUE, OTHER_VALUE_DOMAIN_KEY, @@ -106,7 +109,7 @@ export class CircularChartProvider { const { timeRange, where, hasTimeSeries } = $timeAndFilterStore; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!colorDimensionName && config.color?.type === "nominal" && !Array.isArray(config.color?.sort); @@ -146,7 +149,7 @@ export class CircularChartProvider { const { timeRange, where, hasTimeSeries } = $timeAndFilterStore; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!config.measure?.field; const totalWhere = getFilterWithNullHandling(where, config.color); @@ -192,7 +195,7 @@ export class CircularChartProvider { showOther && !!visibleValues && visibleValues.length > 0 && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!config.measure?.field && !!colorDimensionName; @@ -245,7 +248,7 @@ export class CircularChartProvider { const topNColorData = $topNColorQuery?.data?.data; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!measures?.length && (config.color?.type === "nominal" && !Array.isArray(config.color?.sort) diff --git a/web-common/src/features/components/charts/combo/ComboChartProvider.ts b/web-common/src/features/components/charts/combo/ComboChartProvider.ts index 62d1122b73b8..c0b8309f0fbf 100644 --- a/web-common/src/features/components/charts/combo/ComboChartProvider.ts +++ b/web-common/src/features/components/charts/combo/ComboChartProvider.ts @@ -27,6 +27,7 @@ import { type Writable, } from "svelte/store"; import { + canQueryWithTimeRange, getFilterWithNullHandling, vegaSortToAggregationSort, } from "../query-util"; @@ -101,6 +102,7 @@ export class ComboChartProvider { } const dimensionName = config.x?.field; + const requiresTimeRange = config.x?.type === "temporal"; const xAxisQueryOptionsStore = derived( [timeAndFilterStore, visibleStore], @@ -108,7 +110,7 @@ export class ComboChartProvider { const { timeRange, where, hasTimeSeries } = $timeAndFilterStore; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!dimensionName && config?.x?.type === "nominal" && !Array.isArray(config.x?.sort) && @@ -162,7 +164,7 @@ export class ComboChartProvider { const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange, requiresTimeRange) && !!measures?.length && (config.x?.type === "nominal" && !Array.isArray(config.x?.sort) ? xTopNData !== undefined @@ -215,7 +217,7 @@ export class ComboChartProvider { dimensions, where: combinedWhere, timeRange, - fillMissing: config.x?.type === "temporal", + fillMissing: requiresTimeRange, sort: config.x?.type === "temporal" ? [{ name: config.x?.field, desc: false }] diff --git a/web-common/src/features/components/charts/data-provider.ts b/web-common/src/features/components/charts/data-provider.ts index 1f7f8dde0c13..af4023e061c2 100644 --- a/web-common/src/features/components/charts/data-provider.ts +++ b/web-common/src/features/components/charts/data-provider.ts @@ -115,10 +115,15 @@ export function getChartData( const domainValues = getDomainValues(); const hasComparison = $timeAndFilterStore.showTimeComparison; + const waitingForTimeState = + $timeAndFilterStore.hasTimeSeries === undefined || + ($timeAndFilterStore.hasTimeSeries === true && + (!$timeAndFilterStore.timeRange?.start || + !$timeAndFilterStore.timeRange?.end)); return { data: data || [], - isFetching: chartData?.isFetching ?? false, + isFetching: waitingForTimeState || (chartData?.isFetching ?? false), error: chartData?.error, fields: fieldSpecMap, domainValues, diff --git a/web-common/src/features/components/charts/funnel/FunnelChartProvider.ts b/web-common/src/features/components/charts/funnel/FunnelChartProvider.ts index 8d3ec76139e8..2a65f9fca111 100644 --- a/web-common/src/features/components/charts/funnel/FunnelChartProvider.ts +++ b/web-common/src/features/components/charts/funnel/FunnelChartProvider.ts @@ -25,7 +25,10 @@ import { type Readable, type Writable, } from "svelte/store"; -import { getFilterWithNullHandling } from "../query-util"; +import { + canQueryWithTimeRange, + getFilterWithNullHandling, +} from "../query-util"; export type FunnelMode = "width" | "order"; export type FunnelColorMode = "stage" | "measure" | "name" | "value"; @@ -131,7 +134,7 @@ export class FunnelChartProvider { const { timeRange, where, hasTimeSeries } = $timeAndFilterStore; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!stageDimensionName && !isMultiMeasure && !Array.isArray(config.stage?.sort); @@ -167,7 +170,7 @@ export class FunnelChartProvider { const topNStageData = $topNStageQuery?.data?.data; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!measures?.length && (isMultiMeasure || !!dimensions?.length) && (!isMultiMeasure && diff --git a/web-common/src/features/components/charts/heatmap/HeatmapChartProvider.ts b/web-common/src/features/components/charts/heatmap/HeatmapChartProvider.ts index d47fdf32c5a9..84280efdca34 100644 --- a/web-common/src/features/components/charts/heatmap/HeatmapChartProvider.ts +++ b/web-common/src/features/components/charts/heatmap/HeatmapChartProvider.ts @@ -26,6 +26,7 @@ import { type Writable, } from "svelte/store"; import { + canQueryWithTimeRange, getFilterWithNullHandling, vegaSortToAggregationSort, } from "../query-util"; @@ -89,7 +90,7 @@ export class HeatmapChartProvider { const { timeRange, where, hasTimeSeries } = $timeAndFilterStore; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!config.x?.field && config?.x?.type !== "temporal" && !Array.isArray(config.x?.sort); @@ -134,7 +135,7 @@ export class HeatmapChartProvider { const { timeRange, where, hasTimeSeries } = $timeAndFilterStore; const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && !!config.y?.field && config?.y?.type !== "temporal" && !Array.isArray(config.y?.sort); @@ -185,7 +186,7 @@ export class HeatmapChartProvider { const enabled = $visible && - (!hasTimeSeries || (!!timeRange?.start && !!timeRange?.end)) && + canQueryWithTimeRange(hasTimeSeries, timeRange) && (config.x?.type === "nominal" && !Array.isArray(config.x?.sort) ? xTopNData !== undefined : true) && diff --git a/web-common/src/features/components/charts/query-util.ts b/web-common/src/features/components/charts/query-util.ts index 95d864ea490b..578e540ae3b8 100644 --- a/web-common/src/features/components/charts/query-util.ts +++ b/web-common/src/features/components/charts/query-util.ts @@ -13,8 +13,20 @@ import { createInExpression } from "@rilldata/web-common/features/dashboards/sto import type { V1Expression, V1MetricsViewAggregationSort, + V1TimeRange, } from "@rilldata/web-common/runtime-client"; +export function canQueryWithTimeRange( + hasTimeSeries: boolean | undefined, + timeRange: V1TimeRange | undefined, + requiresTimeRange = false, +): boolean { + const hasTimeRange = !!timeRange?.start && !!timeRange?.end; + return requiresTimeRange + ? hasTimeRange + : hasTimeSeries === false || (hasTimeSeries === true && hasTimeRange); +} + export function getFilterWithNullHandling( where: V1Expression | undefined, fieldConfig: FieldConfig | undefined, diff --git a/web-common/src/features/components/charts/scatter/ScatterPlotChartProvider.ts b/web-common/src/features/components/charts/scatter/ScatterPlotChartProvider.ts index 3cd9d274875e..3e4467cc1512 100644 --- a/web-common/src/features/components/charts/scatter/ScatterPlotChartProvider.ts +++ b/web-common/src/features/components/charts/scatter/ScatterPlotChartProvider.ts @@ -24,7 +24,10 @@ import { type Readable, type Writable, } from "svelte/store"; -import { getFilterWithNullHandling } from "../query-util"; +import { + canQueryWithTimeRange, + getFilterWithNullHandling, +} from "../query-util"; export type ScatterPlotChartSpec = { metrics_view: string; @@ -95,14 +98,20 @@ export class ScatterPlotChartProvider { hasColorDimension = true; } + const hasTemporalDimension = + config.x?.type === "temporal" || config.y?.type === "temporal"; + const topNColorQueryOptionsStore = derived( [timeAndFilterStore, visibleStore], ([$timeAndFilterStore, $visible]) => { - const { timeRange, where } = $timeAndFilterStore; + const { timeRange, where, hasTimeSeries } = $timeAndFilterStore; const enabled = $visible && - !!timeRange?.start && - !!timeRange?.end && + canQueryWithTimeRange( + hasTimeSeries, + timeRange, + hasTemporalDimension, + ) && hasColorDimension && !!colorDimensionName && !!colorLimit; @@ -139,12 +148,16 @@ export class ScatterPlotChartProvider { const queryOptionsStore = derived( [timeAndFilterStore, topNColorQuery, visibleStore], ([$timeAndFilterStore, $topNColorQuery, $visible]) => { - const { timeRange, where, timeGrain } = $timeAndFilterStore; + const { timeRange, where, timeGrain, hasTimeSeries } = + $timeAndFilterStore; const topNColorData = $topNColorQuery?.data?.data; const enabled = $visible && - !!timeRange?.start && - !!timeRange?.end && + canQueryWithTimeRange( + hasTimeSeries, + timeRange, + hasTemporalDimension, + ) && !!measures?.length && !!dimensions?.length && (hasColorDimension && colorDimensionName && colorLimit @@ -169,9 +182,6 @@ export class ScatterPlotChartProvider { } let finalDimensions = dimensions; - const hasTemporalDimension = - config.x?.type === "temporal" || config.y?.type === "temporal"; - if (timeGrain && hasTemporalDimension) { finalDimensions = dimensions.map((d) => { if ( From 5cd0e474681f99c6d554f5b2af10692f818cf743 Mon Sep 17 00:00:00 2001 From: Dhiraj Kumar Date: Mon, 25 May 2026 22:08:12 +0530 Subject: [PATCH 2/4] fix: flashing error in pivot table --- .../features/canvas/components/pivot/util.ts | 18 ++++++++++++++++-- .../dashboards/pivot/pivot-data-store.ts | 10 ++++++++++ .../features/dashboards/pivot/pivot-queries.ts | 2 +- .../src/features/dashboards/pivot/types.ts | 1 + 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/web-common/src/features/canvas/components/pivot/util.ts b/web-common/src/features/canvas/components/pivot/util.ts index 82d29a325930..36928dc5fe82 100644 --- a/web-common/src/features/canvas/components/pivot/util.ts +++ b/web-common/src/features/canvas/components/pivot/util.ts @@ -114,8 +114,14 @@ export function createPivotConfig( const { timeRange, comparisonTimeRange, where } = $timeAndFilterStore; const metricsViewName = $tableSpec.metrics_view; const metricsView = - $canvasData?.data?.metricsViews[metricsViewName]?.state?.validSpec ?? - {}; + $canvasData?.data?.metricsViews[metricsViewName]?.state?.validSpec; + const ready = + !!metricsViewName && + !!metricsView && + ($timeAndFilterStore.hasTimeSeries === false || + ($timeAndFilterStore.hasTimeSeries === true && + !!timeRange?.start && + !!timeRange?.end)); let queryWhere: V1Expression | undefined; if (!$selfFiltered || $selfFiltered.size === 0) { @@ -135,6 +141,7 @@ export function createPivotConfig( comparisonTimeRange, pivotState, timeRange, + ready, ) : processPivot( $tableSpec, @@ -145,6 +152,7 @@ export function createPivotConfig( comparisonTimeRange, pivotState, timeRange, + ready, ); }, ); @@ -159,9 +167,11 @@ export function processPivot( comparisonTimeRange: V1TimeRange | undefined, pivotState: Writable, timeRange: V1TimeRange, + ready: boolean, ) { if (!$tableSpec) { return { + ready: false, measureNames: [], rowDimensionNames: [], colDimensionNames: [], @@ -182,6 +192,7 @@ export function processPivot( $timeAndFilterStore.showTimeComparison; const config: PivotDataStoreConfig = { + ready, measureNames: ($tableSpec?.measures || []).flatMap((name) => { const group = [name]; if (enableComparison) { @@ -239,9 +250,11 @@ export function processFlat( comparisonTimeRange: V1TimeRange | undefined, pivotState: Writable, timeRange: V1TimeRange, + ready: boolean, ) { if (!$tableSpec) { return { + ready: false, measureNames: [], rowDimensionNames: [], colDimensionNames: [], @@ -269,6 +282,7 @@ export function processFlat( $timeAndFilterStore.showTimeComparison; const config: PivotDataStoreConfig = { + ready, measureNames: (measures || []).flatMap((name) => { const group = [name]; if (enableComparison) { diff --git a/web-common/src/features/dashboards/pivot/pivot-data-store.ts b/web-common/src/features/dashboards/pivot/pivot-data-store.ts index 72e349b0538b..0bf8ecbf437f 100644 --- a/web-common/src/features/dashboards/pivot/pivot-data-store.ts +++ b/web-common/src/features/dashboards/pivot/pivot-data-store.ts @@ -219,6 +219,16 @@ export function createPivotDataStore( const { rowDimensionNames, colDimensionNames, measureNames, isFlat } = config; + if (config.ready === false) { + return configSet({ + isFetching: true, + data: [], + columnDef: [], + assembled: false, + totalColumns: 0, + }); + } + if ( (!rowDimensionNames.length && !measureNames.length) || (colDimensionNames.length && !measureNames.length) diff --git a/web-common/src/features/dashboards/pivot/pivot-queries.ts b/web-common/src/features/dashboards/pivot/pivot-queries.ts index b214ce205c37..ba286f455aed 100644 --- a/web-common/src/features/dashboards/pivot/pivot-queries.ts +++ b/web-common/src/features/dashboards/pivot/pivot-queries.ts @@ -100,7 +100,7 @@ export function createPivotAggregationRowQuery( }, { query: { - enabled, + enabled: enabled && config.ready !== false, placeholderData: keepPreviousData, }, }, diff --git a/web-common/src/features/dashboards/pivot/types.ts b/web-common/src/features/dashboards/pivot/types.ts index 2e8b8528567d..32da2f4803d0 100644 --- a/web-common/src/features/dashboards/pivot/types.ts +++ b/web-common/src/features/dashboards/pivot/types.ts @@ -95,6 +95,7 @@ export interface PivotQueryError { * This is the config that is passed to the pivot data store methods */ export interface PivotDataStoreConfig { + ready?: boolean; measureNames: string[]; rowDimensionNames: string[]; colDimensionNames: string[]; From dbd797027415fa3c63145d68a25ce183881104f3 Mon Sep 17 00:00:00 2001 From: Dhiraj Kumar Date: Mon, 25 May 2026 22:12:49 +0530 Subject: [PATCH 3/4] rewrite branches to be readable --- web-common/src/features/components/charts/query-util.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web-common/src/features/components/charts/query-util.ts b/web-common/src/features/components/charts/query-util.ts index 578e540ae3b8..374ccdc9e7dc 100644 --- a/web-common/src/features/components/charts/query-util.ts +++ b/web-common/src/features/components/charts/query-util.ts @@ -22,9 +22,10 @@ export function canQueryWithTimeRange( requiresTimeRange = false, ): boolean { const hasTimeRange = !!timeRange?.start && !!timeRange?.end; - return requiresTimeRange - ? hasTimeRange - : hasTimeSeries === false || (hasTimeSeries === true && hasTimeRange); + if (requiresTimeRange) return hasTimeRange; + if (hasTimeSeries === false) return true; + if (hasTimeSeries === true) return hasTimeRange; + return false; } export function getFilterWithNullHandling( From 2bb8a9c0c8f80aeef69412619528ddb606e56d61 Mon Sep 17 00:00:00 2001 From: Dhiraj Kumar Date: Tue, 26 May 2026 18:32:08 +0530 Subject: [PATCH 4/4] add comment --- web-common/src/features/components/charts/query-util.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web-common/src/features/components/charts/query-util.ts b/web-common/src/features/components/charts/query-util.ts index 374ccdc9e7dc..301ca758ecca 100644 --- a/web-common/src/features/components/charts/query-util.ts +++ b/web-common/src/features/components/charts/query-util.ts @@ -25,6 +25,7 @@ export function canQueryWithTimeRange( if (requiresTimeRange) return hasTimeRange; if (hasTimeSeries === false) return true; if (hasTimeSeries === true) return hasTimeRange; + // hasTimeSeries === undefined: metrics view spec not yet resolved, block the query. return false; }