## Summary
- Shows query errors in search page event patterns in the same way as for event deltas.
- Previously, a loading state was shown indefinitely if there was an error.
### Screenshots or video
<img width="1375" height="554" alt="Screenshot 2026-04-07 at 16 14 37" src="https://github.com/user-attachments/assets/25417f1a-bfd3-44ca-bcd6-aa24156fad14" />
### How to test locally or on Vercel
1. Easiest to test locally by manually throwing from the `useQueriedChartConfig` query function.
### References
- Linear Issue: Closes HDX-3933
- Related PRs:
## Summary
Large refactor changing the TSource type to a true discriminated union. This means that the expected fields for `kind: 'log'` will differ from those for `'trace', 'session', 'metrics'`. This avoids the current laissez faire source type that currently exists, and required extensive changes across the api and app packages. Also includes a nice addition to `useSource` - you can now specify a `kind` field, which will properly infer the type of the returned source.
This also makes use of discriminators in mongoose. This does change a bit of the way that we create and update sources. Obvious changes to sources have also been made, namely making `timeValueExpression` required on sources. Care has been taken to avoid requiring a migration.
### How to test locally or on Vercel
1. `yarn dev`
2. Play around with the app, especially around source creation, source edits, and loading existing sources from a previous version
### References
- Linear Issue: References HDX-3352
- Related PRs:
Ref: HDX-3352
## Summary
This PR is the first step towards raw SQL-driven charts.
- It introduces updated ChartConfig types, which are now unions of `BuilderChartConfig` (which is unchanged from the current `ChartConfig` types` and `RawSqlChartConfig` types which represent sql-driven charts.
- It adds _very basic_ support for SQL-driven tables in the Chart Explorer and Dashboard pages. This is currently behind a feature toggle and enabled only in preview environments and for local development.
The changes in most of the files in this PR are either type updates or the addition of type guards to handle the new ChartConfig union type.
The DBEditTimeChartForm has been updated significantly to (a) add the Raw SQL option to the table chart editor and (b) handle conversion from internal form state (which can now include properties from either branch of the ChartConfig union) to valid SavedChartConfigs (which may only include properties from one branch).
Significant changes are in:
- packages/app/src/components/ChartEditor/types.ts
- packages/app/src/components/ChartEditor/RawSqlChartEditor.tsx
- packages/app/src/components/ChartEditor/utils.ts
- packages/app/src/components/DBEditTimeChartForm.tsx
- packages/app/src/components/DBTableChart.tsx
- packages/app/src/components/SQLEditor.tsx
- packages/app/src/hooks/useOffsetPaginatedQuery.tsx
Future PRs will add templating to the Raw SQL driven charts for date range and granularity injection; support for other chart types driven by SQL; improved placeholder, validation, and error states; and improved support in the external API and import/export.
### Screenshots or video
https://github.com/user-attachments/assets/008579cc-ef3c-496e-9899-88bbb21eaa5e
### How to test locally or on Vercel
The SQL-driven table can be tested in the preview environment or locally.
### References
- Linear Issue: HDX-3580
- Related PRs:
Revisit the bug fix for https://github.com/hyperdxio/hyperdx/pull/1614.
The alias map should be used in useRowWhere hook
Ref: HDX-3196
Example:
For select
```
Timestamp,ServiceName,SeverityText,Body AS b, concat(b, 'blabla')
```
The generated query from useRowWhere is
```
WITH (Body) AS b
SELECT
*,
Timestamp AS "__hdx_timestamp",
Body AS "__hdx_body",
TraceId AS "__hdx_trace_id",
SpanId AS "__hdx_span_id",
SeverityText AS "__hdx_severity_text",
ServiceName AS "__hdx_service_name",
ResourceAttributes AS "__hdx_resource_attributes",
LogAttributes AS "__hdx_event_attributes"
FROM
DEFAULT.otel_logs
WHERE
(
Timestamp = parseDateTime64BestEffort('2026-01-20T06:11:00.170000000Z', 9)
AND ServiceName = 'hdx-oss-dev-api'
AND SeverityText = 'info'
AND Body = 'Received alert metric [saved_search source]'
AND concat(b, 'blabla') = 'Received alert metric [saved_search source]blabla'
AND TimestampTime = parseDateTime64BestEffort('2026-01-20T06:11:00Z', 9)
)
LIMIT
1
```
# Summary
Closes HDX-2310
Closes HDX-2616
This PR implements chunking of chart queries to improve performance of charts on large data sets and long time ranges. Recent data is loaded first, then older data is loaded one-chunk-at-a-time until the full chart date range has been queried.
https://github.com/user-attachments/assets/83333041-9e41-438a-9763-d6f6c32a0576
## Performance Impacts
### Expectations
This change is intended to improve performance in a few ways:
1. Queries over long time ranges are now much less likely to time out, since the range is chunked into several smaller queries
2. Average memory usage should decrease, since the total result size and number of rows being read are smaller
3. _Perceived_ latency of queries over long date ranges is likely to decrease, because users will start seeing charts render (more recent) data as soon as the first chunk is queried, instead of after the entire date range has been queried. **However**, _total_ latency to display results for the entire date range is likely to increase, due to additional round-trip network latency being added for each additional chunk.
### Measured Results
Overall, the results match the expectations outlined above.
- Total latency changed between ~-4% and ~25%
- Average memory usage decreased by between 18% and 80%
<details>
<summary>Scenarios and data</summary>
In each of the following tests:
1. Queries were run 5 times before starting to measure, to ensure data is filesystem cached.
2. Queries were then run 3 times. The results shown are the median result from the 3 runs.
#### Scenario: Log Search Histogram in Staging V2, 2 Day Range, No Filter
| | Total Latency | Memory Usage (Avg) | Memory Usage (Max) | Chunk Count |
|---|---|---|---|---|
| Original | 5.36 | 409.23 MiB | 409.23 MiB | 1 |
| Chunked | 5.14 | 83.06 MiB | 232.69 MiB | 4 |
#### Scenario: Log Search Histogram in Staging V2, 14 Day Range, No Filter
| | Total Latency | Memory Usage (Avg) | Memory Usage (Max) | Chunk Count |
|---|---|---|---|---|
| Original | 26.56 | 383.63 MiB | 383.63 MiB | 1 |
| Chunked | 33.08 | 130.00 MiB | 241.21 MiB | 16 |
#### Scenario: Chart Explorer Line Chart with p90 and p99 trace durations, Staging V2 Traces, Filtering for "GET" spans, 7 Day range
| | Total Latency | Memory Usage (Avg) | Memory Usage (Max) | Chunk Count |
|---|---|---|---|---|
| Original | 2.79 | 346.12 MiB | 346.12 MiB | 1 |
| Chunked | 3.26 | 283.00 MiB | 401.38 MiB | 9 |
</details>
## Implementation Notes
<details>
<summary>When is chunking used?</summary>
Chunking is used when all of the following are true:
1. `granularity` and `timestampValueExpression` are defined in the config. This ensures that the query is already being bucketed. Without bucketing, chunking would break aggregation queries, since groups can span multiple chunks.
4. `dateRange` is defined in the config. Without a date range, we'd need an unbounded set of chunks or the start and end chunks would have to be unbounded at their start and end, respectively.
5. The config is not a metrics query. Metrics queries have complex logic which we want to avoid breaking with the initial delivery of this feature.
6. The consumer of `useQueriedChartConfig` does not pass the `disableQueryChunking: true` option. This option is provided to disable chunking when necessary.
</details>
<details>
<summary>How are time windows chosen?</summary>
1. First, generate the windows as they are generated for the existing search chunking feature (eg. 6 hours back, 6 hours back, 12 hours back, 24 hours back...)
4. Then, the start and end of each window is aligned to the start of a time bucket that depends on the "granularity" of the chart.
7. The first and last windows are shortened or extended so that the combined date range of all of the windows matches the start and end of the original config.
</details>
<details>
<summary>Which order are the chunks queried in?</summary>
Chunks are queried sequentially, most-recent first, due to the expectation that more recent data is typically more important to the user. Unlike with `useOffsetPaginatedSearch`, we are not paginating the data beyond the chunks, and all data is typically displayed together, so there is no need to support "ascending" order.
</details>
<details>
<summary>Does this improve client-side caching behavior?</summary>
One theoretical way in which query chunking could improve performance to enable client-side caching of individual chunks, which could then be re-used if the same query is run over a longer time range.
Unfortunately, using streamedQuery, react-query stores the entire time range as one item in the cache, so it does not re-use individual chunks or "pages" from another query.
We could accomplish this improvement by using useQueries instead of streamedQuery or useInfiniteQuery. In that case, we'd treat each chunk as its own query. This would require a number of changes:
1. Our query key would have to include the chunk's window duration
2. We'd need some hacky way of making the useQueries requests fire in sequence. This can be done using `enabled` but requires some additional state to figure out whether the previous query is done.
5. We'd need to emulate the return value of a useQuery using the useQueries result, or update consumers.
</details>
Across the app, we are inconsistent with when we can open the sidebar and expand functionality. This is because the sidebar and logic was managed by the parent component.
Additionally, the expand logic was set to assume a certain structure that some places in the application could not support (ex clickhouse dashboard doesn't have a 'source').
As a result, I have created the `DBSqlRowTableWithSideBar` component which will manage a lot of the common use cases for us. This PR introduces that new component, and updates all references (that could be easily upgraded) to use the new component when applciable.
The result: a lot less duplicate code (see # of lines removed) and the ability to more easily maintain the components down the road.
This PR also fixes several bugs I found as I tested these flows, especially around sidebars opening subpanels.
Fixes: HDX-2341