Commit graph

1514 commits

Author SHA1 Message Date
Drew Davis
0daa52993c
feat: Improve local-mode deeplinking (#2080)
## Summary

When `IS_LOCAL_MODE` sources are created (e.g. via "Connect to Demo Server" in the onboarding modal), IDs are now derived from a stable hash of the item content instead of `Math.random()`. This ensures every user who connects to the same demo server gets the same source IDs, making deep links with `?source=<id>` work across different users and sessions.

This has the added benefit of ensuring that the dashboards created in local mode will not break due to new sources being created on every new session.

Further, the `<OnboardingModal>` has been added to a few pages where it was previous missing, ensuring that users which are deeplinked to those pages see the modal and are able to create the demo connection.

### How to test locally or on Vercel

1. Open the play/demo environment in two separate browser profiles (or incognito windows) so each has fresh localStorage
2. In the first, connect to the demo server, then navigate to a page where a source is selected
3. Copy the link into the second browser. You should see the "connect to demo server" and once connected you should see the same source as was selected in the 1st browser.

### References

- Linear Issue: Closes HDX-3974
- Related PRs: none
2026-04-10 15:21:04 +00:00
Warren Lee
f8f7634552
Fix release CLI workflow: build common-utils before compilation (#2086)
The "Release CLI Binaries" job fails because `bun build --compile` can't resolve `@hyperdx/common-utils/dist/*` imports. In CI it's a fresh checkout — `yarn install` puts source code in place but `common-utils` needs to be compiled (tsup) to produce its `dist/` output.

Adds a `make ci-build` step between `yarn install` and the CLI compile step.

Fixes https://github.com/hyperdxio/hyperdx/actions/runs/24220292098/job/70710194631
2026-04-10 15:04:09 +00:00
Drew Davis
587819b63e
Add Cursor Cloud specific instructions to AGENTS.md (#2081)
## What

Adds a `## Cursor Cloud specific instructions` section to `AGENTS.md` with development environment notes for cloud agents.

## Why

Future Cursor Cloud agents need non-obvious context about running the dev stack in the cloud VM environment, particularly:

- **Docker requirement**: Docker must be installed and running before `yarn dev` or integration/E2E tests
- **dash/bash incompatibility**: `yarn dev` uses `sh -c` to source `scripts/dev-env.sh` which contains bash-specific syntax (`BASH_SOURCE`). On Ubuntu where `/bin/sh` is `dash`, this fails. A bash workaround command is documented.
- **Port mapping**: The default `/workspace` directory produces slot 76, so services run on non-standard ports (App: 30276, API: 30176, etc.)
- **First-time registration**: Fresh MongoDB means the app shows a registration page with no external auth needed

## Evidence

Full dev stack running with all services operational:

[hyperdx_register_and_search_demo.mp4](https://cursor.com/agents/bc-b3139182-3221-4ea1-9a02-ac2df5e9b062/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fhyperdx_register_and_search_demo.mp4)

[HyperDX logged in search page](https://cursor.com/agents/bc-b3139182-3221-4ea1-9a02-ac2df5e9b062/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fhyperdx_logged_in_search.webp)

[HyperDX search query executed](https://cursor.com/agents/bc-b3139182-3221-4ea1-9a02-ac2df5e9b062/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fhyperdx_search_query.webp)

<sub>To show artifacts inline, <a href="https://cursor.com/dashboard/cloud-agents#team-pull-requests">enable</a> in settings.</sub>


<div><a href="https://cursor.com/agents/bc-b3139182-3221-4ea1-9a02-ac2df5e9b062"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-b3139182-3221-4ea1-9a02-ac2df5e9b062"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>



Co-authored-by: Cursor Agent <199161495+cursoragent@users.noreply.github.com>
2026-04-10 14:54:52 +00:00
Mike Shi
4ef63cc434
feat: Auto-detect trace duration and render in adaptive time units (HDX-3909) (#2046)
## Summary

When a chart uses a trace source with a Duration Expression, the chart now automatically defaults to adaptive time unit formatting (e.g., `120.41s`, `45ms`, `3µs`) instead of requiring users to manually select a format. Users can still override the format through the existing display settings.

**Key changes:**

1. **New `duration` output type** in `NumberFormatSchema` — renders values adaptively as `µs`, `ms`, `s`, `min`, or `h` based on magnitude, instead of the clock-style `hh:mm:ss` format
2. **Auto-detection via exact match** — `getTraceDurationNumberFormat()` checks if any chart select `valueExpression` exactly equals the trace source's `durationExpression`. Only applies for unit-preserving aggregate functions (`avg`, `min`, `max`, `sum`, `quantile`, `any`, `last_value`, etc.) — skips `count` and `count_distinct`
3. **`useResolvedNumberFormat()` hook** — resolves the effective `numberFormat` for a chart: returns the user's explicit format if set, otherwise auto-detects duration format for trace sources
4. **UI form update** — Added "Duration" option to the number format selector with input unit picker (seconds/ms/µs/ns)
5. **Display settings drawer** — Shows the auto-detected format by default so users can see what's being applied
6. **Heatmap support** — Updated `DBHeatmapChart` tick formatter to use `formatDurationMs` for duration-formatted values

**Components updated:** `DBTimeChart`, `DBNumberChart`, `DBListBarChart`, `DBPieChart`, `DBTableChart`, `DBHeatmapChart`, `DBSearchHeatmapChart`, `DBEditTimeChartForm`, `ChartDisplaySettingsDrawer`

### How to test locally or on Vercel

1. Create a chart from a trace source with a unit-preserving aggFn (e.g., avg/p95/p99/min/max of the Duration column)
2. Verify the chart y-axis and tooltips now show values like `120.41s` or `45ms` instead of raw numbers
3. Open the chart display settings and verify the "Duration" output format is shown as the default
4. Change the aggFn to `count` or `count_distinct` — verify duration formatting is NOT applied
5. Change the format to something else (e.g., "Number") and verify the override persists
6. Switch back to "Duration" and pick different input units (seconds, ms, µs, ns) — the preview should update correctly
7. Check that non-trace-source charts are unaffected (no auto-detection triggers)
8. Verify the search heatmap chart for traces still shows proper duration labels
9. Reset to defaults in the display settings drawer and verify it returns to the auto-detected duration format

### References

- Linear Issue: HDX-3909



Linear Issue: [HDX-3909](https://linear.app/clickhouse/issue/HDX-3909/trace-duration-should-render-in-time-unit-by-default)

<div><a href="https://cursor.com/agents/bc-c39f9186-2593-4675-8f23-190cd148818b"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-c39f9186-2593-4675-8f23-190cd148818b"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>



Co-authored-by: Cursor Agent <199161495+cursoragent@users.noreply.github.com>
2026-04-10 11:51:43 +00:00
github-actions[bot]
edb55b4bca
Release HyperDX (#2060)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-09 17:33:14 -07:00
Warren Lee
d995b78c66
[HDX-3919] Add @hyperdx/cli package — terminal TUI, source map upload, and agent-friendly commands (#2043)
## Summary

Adds `packages/cli` (`@hyperdx/cli`) — a unified CLI for HyperDX that provides an interactive TUI for searching/tailing logs and traces, source map upload (migrated from `hyperdx-js`), and agent-friendly commands for programmatic access.

Ref: HDX-3919
Ref: HDX-3920

### CLI Commands

```
hdx tui -s <url>                    # Interactive TUI (main command)
hdx sources -s <url>                # List sources with ClickHouse schemas
hdx sources -s <url> --json         # JSON output for agents / scripts
hdx dashboards -s <url>             # List dashboards with tile summaries
hdx dashboards -s <url> --json      # JSON output for agents / scripts
hdx query --source "Logs" --sql "SELECT count() FROM default.otel_logs"
hdx upload-sourcemaps -k <key>      # Upload source maps (ported from hyperdx-js)
hdx auth login -s <url>             # Sign in (interactive or -e/-p flags)
hdx auth status                     # Show auth status
hdx auth logout                     # Clear saved session
```

### Key Features

**Interactive TUI (`hdx tui`)**
- Table view with dynamic columns derived from query results (percentage-based widths)
- Follow mode (live tail) enabled by default, auto-pauses when detail panel is open
- Vim-like keybindings: j/k navigation, G/g jump, Ctrl+D/U half-page scroll
- `/` for Lucene search, `s` to edit SELECT clause in `$EDITOR`, `t` to edit time range
- Tab to cycle between sources and saved searches
- `w` to toggle line wrap

**Detail Panel (3 tabs, full-screen with Ctrl+D/U scrolling)**
- **Overview** — Structured view: Top Level Attributes, Log/Span Attributes, Resource Attributes
- **Column Values** — Full `SELECT *` row data with `__hdx_*` aliased columns
- **Trace** — Waterfall chart (port of `DBTraceWaterfallChart` DAG builder) with correlated log events, j/k span navigation, inverse highlight, Event Details section

**Agent-friendly commands**
- `hdx sources --json` — Full source metadata with ClickHouse `CREATE TABLE` DDL, expression mappings, and correlated source IDs. Detailed `--help` describes the JSON schema for LLM consumption. Schema queries run in parallel.
- `hdx dashboards --json` — Dashboard metadata with simplified tile summaries (name, type, source, sql). Resolves source names for human-readable output.
- `hdx query --source <name> --sql <query>` — Raw SQL execution against any source's ClickHouse connection. Supports `--format` for ClickHouse output formats (JSON, JSONEachRow, CSV, etc.).

**Source map upload (`hdx upload-sourcemaps`)**
- Ported from `hyperdx-js/packages/cli` to consolidate on a single `@hyperdx/cli` package
- Authenticates via service account API key (`-k` / `HYPERDX_SERVICE_KEY` env var)
- Globs `.js` and `.js.map` files, handles Next.js route groups
- Uploads to presigned URLs in parallel with retry (3 attempts) and progress
- Modernized: native `fetch` (Node 22+), ESM-compatible, proper TypeScript types

### Architecture

```
packages/cli/
├── src/
│   ├── cli.tsx              # Commander CLI: tui, sources, dashboards, query,
│   │                        #   upload-sourcemaps, auth
│   ├── App.tsx              # Ink app shell (login → source picker → EventViewer)
│   ├── sourcemaps.ts        # Source map upload logic (ported from hyperdx-js)
│   ├── api/
│   │   ├── client.ts        # ApiClient + ProxyClickhouseClient
│   │   └── eventQuery.ts    # Query builders (renderChartConfig, raw SQL)
│   ├── components/
│   │   ├── EventViewer/     # Main TUI (9 files)
│   │   │   ├── EventViewer.tsx    # Orchestrator (state, hooks, render shell)
│   │   │   ├── types.ts           # Shared types & constants
│   │   │   ├── utils.ts           # Row formatting functions
│   │   │   ├── SubComponents.tsx  # Header, TabBar, SearchBar, Footer, HelpScreen, TableHeader
│   │   │   ├── TableView.tsx      # Table rows rendering
│   │   │   ├── DetailPanel.tsx    # Detail panel (overview/columns/trace tabs)
│   │   │   ├── useEventData.ts    # Data fetching hook
│   │   │   └── useKeybindings.ts  # Input handler hook
│   │   ├── TraceWaterfall/  # Trace chart (6 files)
│   │   │   ├── TraceWaterfall.tsx  # Orchestrator + render
│   │   │   ├── types.ts           # SpanRow, SpanNode, props
│   │   │   ├── utils.ts           # Duration/status/bar helpers
│   │   │   ├── buildTree.ts       # DAG builder (port of DBTraceWaterfallChart)
│   │   │   └── useTraceData.ts    # Data fetching hook
│   │   ├── RowOverview.tsx
│   │   ├── ColumnValues.tsx
│   │   ├── LoginForm.tsx
│   │   └── SourcePicker.tsx
│   ├── shared/              # Ported from packages/app (@source annotated)
│   └── utils/               # Config, editor, log silencing
├── AGENTS.md
├── CONTRIBUTING.md
└── README.md
```

### Tech Stack
- **Ink v6.8.0** (React 19 for terminals) + Commander.js
- **@clickhouse/client** via ProxyClickhouseClient (routes through `/clickhouse-proxy`)
- **@hyperdx/common-utils** for query generation (`renderChartConfig`, `chSqlToAliasMap`)
- **glob v13** for source map file discovery
- **tsup** for bundling (all deps bundled via `noExternal: [/.*/]`, zero runtime deps)
- **Bun 1.3.11** for standalone binary compilation
- Session stored at `~/.config/hyperdx/cli/session.json`

### CI/CD (`release.yml`)
- CLI binaries compiled for macOS ARM64, macOS x64, and Linux x64
- GitHub Release created with download instructions
- Version-change gate: skips release if `cli-v{version}` tag already exists
- `softprops/action-gh-release` pinned to full SHA (v2.6.1) for supply chain safety
- Bun pinned to `1.3.11` for reproducible builds
- npm publishing handled by changesets

### Keybindings

| Key | Action |
|---|---|
| `j/k` | Navigate rows (or spans in Trace tab) |
| `l/Enter` | Expand row detail |
| `h/Esc` | Close detail / blur search |
| `G/g` | Jump to newest/oldest |
| `Ctrl+D/U` | Scroll half-page (table, detail panels, Event Details) |
| `/` | Search (global or detail filter) |
| `Tab` | Cycle sources/searches or detail tabs |
| `s` | Edit SELECT clause in $EDITOR |
| `t` | Edit time range in $EDITOR |
| `f` | Toggle follow mode (live tail) |
| `w` | Toggle line wrap |
| `?` | Help screen |

### Demo
#### Main Search View
<img width="1004" height="1014" alt="image" src="https://github.com/user-attachments/assets/bb6a7f00-38c9-4281-9915-c71b65d852f8" />

#### Event Details Overview
<img width="1003" height="1024" alt="image" src="https://github.com/user-attachments/assets/57025fa5-fddb-452a-9320-93465538d5b2" />

#### Trace Waterfall
<img width="1004" height="1029" alt="image" src="https://github.com/user-attachments/assets/3443c898-ea0d-47f3-acc5-edb7cdd31946" />
2026-04-09 20:21:34 +00:00
Drew Davis
5de23e1988
fix: Restore some react-hook lint rules (#2084)
## Summary

This PR:

- Updates the eslint config to restore `react-hook` plugin rules which were removed in #2069. Some of them were removed in without any replacements being _enabled_ in the recommended @eslint-react ruleset
- Reverts #2074, as those lint fixes were possible only because the related rules had been removed

Rule equivalence is documented here: https://www.eslint-react.xyz/docs/migrating-from-eslint-plugin-react-hooks

You can view current effective rule states with `cd packages/app && npx eslint --inspect-config`

### How to test locally or on Vercel

Locally:

```
make ci-lint / make dev-lint
```

### References



- Linear Issue: HDX-3467
- Related PRs:
2026-04-09 19:08:23 +00:00
Drew Davis
61db3e8b43
refactor: Create TileAlertEditor component (#2085)
## Summary

This PR extracts a TileAlertEditor component for future re-use in the Raw-SQL Alert UI. The UI has been updated to make the alert section collapsible and co-locate the "Remove Alert" button within the alert section. The collapsibility will be more important in the Raw SQL case, since the Raw SQL Editor is already pretty vertically tall.

### Screenshots or video

https://github.com/user-attachments/assets/4e595fc6-06f0-4ccd-ab1f-08dcb9895c89

### How to test locally or on Vercel

This must be tested locally, since alerts are not supported in local mode.

### References



- Linear Issue: Related to HDX-1605
- Related PRs:
2026-04-09 17:21:34 +00:00
Tom Alexander
d866e99ed7
chore: don't include test files in line count changes for pr tiering (#2083)
Previously test files contributed to the line count of PRs, possibly elevating their tier unintentionally.
2026-04-09 15:47:08 +00:00
Tom Alexander
8f7d0d09c3
chore: increment max calls allowed for claude (#2082)
Allows longer sessions with the claude agent
2026-04-09 15:31:47 +00:00
Drew Davis
6ef3b48e0c
fix: Fix flaky saved search tests (#2079)
## Summary

This PR fixes failing Saved-Search E2E tests by

1. Fixing a bug that caused the saved search's source to sometime not populate when navigating directly to the saved search
2. Updating the saved search modal to wait until the create saved search mutation completes and invalidates saved searches before attempting to navigate (also, added a loading state and error notifications to the modal)
3. Updated a few test assertions to be more explicit about waiting for the saved search to load

### Screenshots or video

### How to test locally or on Vercel

### References



- Linear Issue:
- Related PRs:
2026-04-09 15:22:54 +00:00
Karl Power
337ebff054
feat: add light mode to dev portal (#2072)
## Summary

Adds a light / dark mode toggle to the dev portal.

<img width="1549" height="922" alt="Screenshot 2026-04-08 at 18 57 29" src="https://github.com/user-attachments/assets/e118d21b-6840-4db3-8309-a8af43ea698b" />
<img width="1549" height="922" alt="Screenshot 2026-04-08 at 18 57 24" src="https://github.com/user-attachments/assets/ff08c270-2ba8-4514-b46d-4b671957e8bf" />
2026-04-08 20:17:33 +00:00
Aaron Knudtson
73b746cbcf
chore: automatic fixes from the linter (#2074)
## Summary

I'm tired of seeing automatic lint fixes so I ran `make dev-lint`
2026-04-08 19:44:32 +00:00
Brandon Pereira
52986a943c
fix(app): fix session replay sub-event modal stacking and tab conflict (#2068)
## Summary

Clicking a log/error event in the session replay event list either reopened the session replay instead of showing event details, or rendered the detail panel behind the replay drawer.

Fixed this by ensuring that isSubPanel is correctly set and using the ZIndexProvider to correctly stack the contexts.

## Steps to Reproduce

From the Sessions page:

1. Go to /sessions, select a session source, open a session card
2. In the session replay drawer, wait for the event list to load
3. Click any event row (e.g. a console.error)
4. Bug A: The detail panel opens behind the session replay drawer (overlay darkens but panel is inaccessible), or 
ESC/close doesn't work correctly

From the Search page (URL conflict):

1. Go to /search, open any trace row to open the detail side panel
2. Click the Session Replay tab — this sets sidePanelTab=replay in the URL
3. In the session event list, click any event row
4. Bug B: The inner detail panel opens to the Session Replay tab again instead of event details (e.g. Overview/Trace)
2026-04-08 16:17:22 +00:00
Drew Davis
74536b3af5
chore: Add @eslint-react/eslint-plugin recommended rules (#2069) 2026-04-08 08:54:18 -04:00
Drew Davis
24767c5886
fix: Ensure correct bounds for date-based timestampValueExpr (#2066)
## Summary

This PR fixes the time filter expression generated when a source's timestamp value expression includes a Date-type column. In such cases, the bounds should be inclusive for the date-type columns. This extends the fix from #1915 to date-type columns.

### Screenshots or video

#### Before - Histogram is empty because of exclusive end bounds

<img width="1758" height="700" alt="Screenshot 2026-04-07 at 12 32 05 PM" src="https://github.com/user-attachments/assets/95898655-21f1-4380-9b23-5333fcea007f" />

#### After - Histogram is populated

<img width="1762" height="717" alt="Screenshot 2026-04-07 at 12 30 25 PM" src="https://github.com/user-attachments/assets/d159b131-1f4f-44f8-982e-b26ca68835ff" />

### How to test locally or on Vercel

The unit tests demonstrate the fix.

<details>
<summary>Alternatively, create a table with the following schema and data</summary>

```sql
CREATE TABLE default.otel_logs_date_pk
(
    `Timestamp` DateTime64(9) CODEC(Delta(8), ZSTD(1)),
    `TimestampTime` DateTime DEFAULT toDateTime(Timestamp),
    `TimestampDate` Date DEFAULT toDate(Timestamp),
    `TraceId` String CODEC(ZSTD(1)),
    `SpanId` String CODEC(ZSTD(1)),
    `TraceFlags` UInt8,
    `SeverityText` LowCardinality(String) CODEC(ZSTD(1)),
    `SeverityNumber` UInt8,
    `ServiceName` LowCardinality(String) CODEC(ZSTD(1)),
    `Body` String CODEC(ZSTD(1)),
    `ResourceSchemaUrl` LowCardinality(String) CODEC(ZSTD(1)),
    `ResourceAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
    `ScopeSchemaUrl` LowCardinality(String) CODEC(ZSTD(1)),
    `ScopeName` String CODEC(ZSTD(1)),
    `ScopeVersion` LowCardinality(String) CODEC(ZSTD(1)),
    `ScopeAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
    `LogAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
    `__hdx_materialized_k8s.cluster.name` LowCardinality(String) MATERIALIZED ResourceAttributes['k8s.cluster.name'] CODEC(ZSTD(1)),
    `__hdx_materialized_k8s.container.name` LowCardinality(String) MATERIALIZED ResourceAttributes['k8s.container.name'] CODEC(ZSTD(1)),
    `__hdx_materialized_k8s.deployment.name` LowCardinality(String) MATERIALIZED ResourceAttributes['k8s.deployment.name'] CODEC(ZSTD(1)),
    `__hdx_materialized_k8s.namespace.name` LowCardinality(String) MATERIALIZED ResourceAttributes['k8s.namespace.name'] CODEC(ZSTD(1)),
    `__hdx_materialized_k8s.node.name` LowCardinality(String) MATERIALIZED ResourceAttributes['k8s.node.name'] CODEC(ZSTD(1)),
    `__hdx_materialized_k8s.pod.name` LowCardinality(String) MATERIALIZED ResourceAttributes['k8s.pod.name'] CODEC(ZSTD(1)),
    `__hdx_materialized_k8s.pod.uid` LowCardinality(String) MATERIALIZED ResourceAttributes['k8s.pod.uid'] CODEC(ZSTD(1)),
    `__hdx_materialized_deployment.environment.name` LowCardinality(String) MATERIALIZED ResourceAttributes['deployment.environment.name'] CODEC(ZSTD(1)),
    INDEX idx_trace_id TraceId TYPE bloom_filter(0.001) GRANULARITY 1,
    INDEX idx_res_attr_key mapKeys(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_res_attr_value mapValues(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_scope_attr_key mapKeys(ScopeAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_scope_attr_value mapValues(ScopeAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_log_attr_key mapKeys(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_log_attr_value mapValues(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_lower_body lower(Body) TYPE tokenbf_v1(32768, 3, 0) GRANULARITY 8
)
ENGINE = MergeTree
PARTITION BY toDate(TimestampTime)
PRIMARY KEY (TimestampDate, ServiceName, TimestampTime)
ORDER BY (TimestampDate, ServiceName, TimestampTime, Timestamp)
TTL TimestampTime + toIntervalDay(1)
SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1;

insert into default.otel_logs_date_pk (Timestamp, SeverityText, Body) VALUES (now(), 'info', 'message');
insert into default.otel_logs_date_pk (Timestamp, SeverityText, Body) VALUES (now()-interval 1 minute, 'info', 'message');
```

Then create a source that points to that table with the timestampValueExpr `TimestampTime, TimestampDate`
</details>

### References



- Linear Issue: Closes HDX-3930
- Related PRs:
2026-04-07 19:09:58 +00:00
Elizabet Oliveira
ad71dc2e91
feat(app): keyboard shortcuts modal from Help menu (#2064)
## Why

Users had no in-app list of keyboard shortcuts. Documenting them under **Help** makes discoverability match other support links and reduces guesswork (e.g. command palette vs search bar).

<img width="467" height="201" alt="Screenshot 2026-04-07 at 17 23 40" src="https://github.com/user-attachments/assets/f03e3379-0feb-4912-8f3a-89fca338d02a" />
<img width="901" height="1003" alt="Screenshot 2026-04-07 at 17 23 46" src="https://github.com/user-attachments/assets/d3f7bb0f-3a10-44c2-8e5f-7259382652b8" />



## What

- **Help → Keyboard shortcuts** opens a modal with shortcuts gathered from current hotkey usage (Spotlight ⌘/Ctrl+K, `/` and `s` for search/WHERE, time picker, find-in-table, log navigation, trace timeline, dashboards, etc.).
- Help dropdown order: documentation and setup first, then shortcuts, then Discord.
- Modal: comfortable width, dividers between rows, **or** vs **+** for alternatives vs chords.
- E2E: help menu includes the new item and opens the modal.
- Changeset: `@hyperdx/app` patch.

## Test plan

- [ ] Open Help → Keyboard shortcuts; confirm list and close behavior.
- [ ] CI: rely on PR checks (`make ci-lint` / `make ci-unit` if running locally).
2026-04-07 17:31:29 +00:00
Drew Davis
ffc961c621
fix: Add error message and edit button when tile source is missing (#2063)
## Summary

This PR updates dashboard tiles so that

1. When a tile references a source that no longer exists, there is an appropriate error message
2. When a tile references a source that no longer exists, the user is able to click the edit tile button to fix the issue

### Screenshots or video

<img width="887" height="429" alt="Screenshot 2026-04-07 at 9 40 53 AM" src="https://github.com/user-attachments/assets/ae0f77bc-3fcc-40c3-bf65-9ed454f31a4b" />

### How to test locally or on Vercel

This can be tested in the preview environment by creating a tile and then deleting the associated source.

### References



- Linear Issue: HDX-3926
- Related PRs:
2026-04-07 16:48:09 +00:00
Karl Power
3ffafced5e
feat: show error details in search event patterns (#2065)
## 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:
2026-04-07 15:26:06 +00:00
Drew Davis
f8d2edde5a
feat: Show created/updated metadata for saved searches and dashboards (#2031)
## Summary

This PR adds createdAt/By and updatedAt/By metadata to dashboard and saved searches.

### Screenshots or video

<img width="1466" height="342" alt="Screenshot 2026-04-01 at 3 19 07 PM" src="https://github.com/user-attachments/assets/c349a3d5-f8e3-4155-9938-c8f005cdcd52" />
<img width="1216" height="433" alt="Screenshot 2026-04-01 at 3 19 57 PM" src="https://github.com/user-attachments/assets/9542a631-bdda-484c-9cef-6b780667d1dc" />
<img width="1196" height="345" alt="Screenshot 2026-04-01 at 3 19 46 PM" src="https://github.com/user-attachments/assets/c05cd0cc-2ca4-4397-8acb-e31a81b882ec" />
<img width="1409" height="433" alt="Screenshot 2026-04-01 at 3 19 38 PM" src="https://github.com/user-attachments/assets/593a96d7-86be-45b2-9f0a-b3a8f00d1353" />
<img width="1447" height="181" alt="Screenshot 2026-04-01 at 3 20 59 PM" src="https://github.com/user-attachments/assets/88742578-3dbd-4305-921f-e2ecdd11d5d4" />


### How to test locally or on Vercel

This should be tested locally. In the preview environment, these fields are not populated (since they're maintained through automatic MongoDB createdAt/updatedAt values and createdBy/updatedBy values pulled from User accounts.

### References



- Linear Issue: Closes HDX-3461
- Related PRs:
2026-04-07 14:31:44 +00:00
Karl Power
78a433c8ec
chore: refactor DBEditTimeChartForm component (#2026) 2026-04-07 15:55:08 +02:00
Elizabet Oliveira
800689acba
feat: add reusable EmptyState component and adopt across pages (#2017) 2026-04-06 21:26:59 +01:00
Elizabet Oliveira
7d1a8e549a
fix: Show sidebar favorites empty state for discoverability (#2061) 2026-04-06 20:05:16 +01:00
Zeynel
2570ff844c
Change CPU percentage dashboard to CPU Core according to new otel metric (#2028) 2026-04-06 10:30:11 -07:00
Drew Davis
1bcca2cde6
feat: Add alert icons to dashboard list page (#2053)
## Summary

This PR adds alert icons to the dashboard page, matching the implementation from the search page. Similarly, alerts icons have been added to favorited dashboards in the sidebar.

### Screenshots or video

<img width="1257" height="796" alt="Screenshot 2026-04-03 at 3 05 42 PM" src="https://github.com/user-attachments/assets/9e3fe31d-b757-46e8-8034-9be80529c96e" />
<img width="245" height="353" alt="Screenshot 2026-04-03 at 3 17 54 PM" src="https://github.com/user-attachments/assets/d7b06536-646d-4bd6-950c-b9087c3b3dbd" />

### How to test locally or on Vercel

This can be tested locally by creating some dashboards, favoriting them, and creating alerts on those dashboards.

### References



- Linear Issue: Closes HDX-3921
- Related PRs:
2026-04-06 16:21:42 +00:00
Tom Alexander
fcc0d5ec63
chore: fix PR classification tier logic (#2059) 2026-04-06 10:58:08 -04:00
Tom Alexander
bcb02f3364
chore: add pr classification bot (#2055) 2026-04-06 10:12:10 -04:00
github-actions[bot]
8125d249d9
Release HyperDX (#2009)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-03 15:17:53 -07:00
Drew Davis
011a245f4a
fix: Fix error state and table overflows (#2054)
## Summary

This PR fixes a couple of annoying overflow behaviors.

## Screenshots or video

### Search errors

#### Before

When the original query cannot be formatted, it was on one line, which did not scroll:

<img width="1831" height="652" alt="Screenshot 2026-04-03 at 3 26 48 PM" src="https://github.com/user-attachments/assets/5ce36420-3eeb-431b-9964-e8be17f2f1d6" />

#### After 

Now that same error wraps:

<img width="1831" height="673" alt="Screenshot 2026-04-03 at 3 22 19 PM" src="https://github.com/user-attachments/assets/06787d07-3579-4e78-a83e-9204de2e4587" />

### Chart Errors

#### Before

It was sometimes impossible to see the start of the error:

<img width="1712" height="1163" alt="Screenshot 2026-04-03 at 3 27 27 PM" src="https://github.com/user-attachments/assets/a4630c73-454a-4ed0-a9c0-b63ba973fa06" />

#### After 

Now the start of the error is visible and the rest can be seen by scrolling.

<img width="1707" height="1157" alt="Screenshot 2026-04-03 at 3 22 43 PM" src="https://github.com/user-attachments/assets/80f93dd7-2758-47a3-993b-b1658d80c2b4" />

### ClickHouse Slowest Queries Table

#### Before 

The table contents here overflowed the container:

<img width="1826" height="430" alt="Screenshot 2026-04-03 at 3 25 55 PM" src="https://github.com/user-attachments/assets/48847203-caa5-4410-819d-63bdc4bb9fa1" />

#### After 

Overflow is hidden:

<img width="1831" height="420" alt="Screenshot 2026-04-03 at 3 23 36 PM" src="https://github.com/user-attachments/assets/b3f4e1fb-f0f4-4919-9e3b-a0cdced0d9dc" />

### How to test locally or on Vercel

These can all be tested in the preview

### References



- Linear Issue: Closes HDX-3858 Closes HDX-3720
- Related PRs:
2026-04-03 19:51:01 +00:00
Drew Davis
df170d1e40
fix: Show error on DBInfraPanel when correlated metric source is missing (#2049)
## Summary

This PR adds an error message on the DB Infra Panel when the selected source is missing a correlated metric source.

Previously, this case would have just resulted in an empty page, with no indication of what was wrong.

### Screenshots or video

<img width="2038" height="367" alt="Screenshot 2026-04-03 at 8 28 22 AM" src="https://github.com/user-attachments/assets/4fde26c6-5ea8-4cf8-bdfa-9028ae48b15e" />

### How to test locally or on Vercel

This can be tested locally by creating a source that points to the demo dataset, without a correlated metric source (I suggest the demo dataset because it has K8s metrics).

### References

- Linear Issue:
- Related PRs:
2026-04-03 19:18:57 +00:00
Warren Lee
d84237f98b
fix: add retry logic for docker pull in E2E CI workflow (#2051)
## Summary
- Adds a retry loop (3 attempts, 10s backoff) for `docker compose pull` before `docker compose up -d` in the E2E test workflow
- Fixes transient Docker Hub auth timeout failures where pulling `mongo:5.0.32-focal` failed with `context deadline exceeded`
- Only the E2E workflow is affected; no other CI workflows use `docker compose up`

## Failed run
https://github.com/hyperdxio/hyperdx/actions/runs/23953878483/job/69867599721
2026-04-03 18:08:09 +00:00
Drew Davis
59b1f46fd7
fix: Show alerts on a tile only when dashboard matches (#2048)
## Summary

This PR fixes a bug that caused alerts created on other dashboards to be displayed on tiles with IDs that match the other dashboard. This in turn led to failures updating the alert on the "duplicate" dashboard.

The included integration test demonstrates the case.

### Screenshots or video

### How to test locally or on Vercel

### References



- Linear Issue: Closes HDX-3918
- Related PRs:
2026-04-03 16:40:11 +00:00
Drew Davis
b4e1498eb3
fix: Fix minor bugs in chart editor (#2050)
## Summary

This PR makes a few minor improvements to dashboard tiles and the chart editor

### Hide the "Add Alert" button on dashboard tiles based on raw SQL

These tiles don't yet support alerts

<img width="766" height="424" alt="Screenshot 2026-04-03 at 8 37 36 AM" src="https://github.com/user-attachments/assets/4405c5bb-419d-4ae8-a121-7ddcd2623d87" />
<img width="767" height="447" alt="Screenshot 2026-04-03 at 8 37 42 AM" src="https://github.com/user-attachments/assets/c9b27e7a-9a2b-4f23-863b-d1679d3ea770" />

Closes HDX-3910

### Hide the "Group By" button on the Attribute explorer for Number Charts

Number charts don't support Group By

<img width="1224" height="475" alt="Screenshot 2026-04-03 at 8 41 10 AM" src="https://github.com/user-attachments/assets/e854ff39-09b6-4452-b008-cd7bc1e26d09" />
<img width="1219" height="501" alt="Screenshot 2026-04-03 at 8 41 00 AM" src="https://github.com/user-attachments/assets/4180a784-2b1c-4353-a84f-b25f367ff36c" />
<img width="1224" height="476" alt="Screenshot 2026-04-03 at 8 41 02 AM" src="https://github.com/user-attachments/assets/89780bea-d53a-4287-8056-e73c8ce6927f" />
<img width="1227" height="485" alt="Screenshot 2026-04-03 at 8 40 56 AM" src="https://github.com/user-attachments/assets/197cbcdd-4264-45d5-a0f0-10e4c67ab67d" />

Closes HDX-3871

### Disable the "Custom" Aggregation for Metric queries

These were already broken because there was no input available for the user to provide the custom aggregation. Custom aggregations don't make much sense for metric sources, since the queries we build for metrics would be very difficult for users to build custom aggregations on. We also now have SQL-based charts if users want to do custom aggregations on metric sources.

<img width="459" height="581" alt="Screenshot 2026-04-03 at 9 03 40 AM" src="https://github.com/user-attachments/assets/5230627c-5f51-4640-9b16-4719f9a1ca91" />

Closes HDX-3799

### How to test locally or on Vercel

These can be tested in the preview environment (except for the alert button, that must be tested locally)
2026-04-03 15:44:54 +00:00
Drew Davis
58e2e8c660
chore: Enable and fix @eslint-react/no-unstable-default-props (#1989)
## Summary

This PR

1. Replaces `eslint-config-react` with the modernized equivalent `@eslint-react/eslint-plugin`. Note that `eslint-config-react` was not actually enabled previously, as none of its rules were added to the eslint config.
2. Enables the `no-unstable-default-props` rule and fixes existing violations. This rule catches components with optional props of unstable types (objects, arrays) which have a default value assigned. The default value changes on each render, which can cause unecessary re-renders and re-computations of useMemos and useEffects.

We can enable more rules from this plugin in future PRs.

### Screenshots or video

There are no expected behavior changes

### How to test locally or on Vercel

The app can be regression tested in the preview environment.

### References



- Linear Issue: Closes HDX-3809
- Related PRs:
2026-04-03 14:19:52 +00:00
James
859ced5cd0
feat(chart): Auto-execute chart on chart explorer page load (#1961)
## Summary

Updates the chart explorer page so that the chart query is executed automatically once on page load instead of waiting for the user to click the run button.

The motivation is external tools that translate queries from other systems into HyperDX chart configs and deeplink the user into the `/chart` page. Today the user lands on a fully-populated form but still has to click once to see results; with this change the chart renders immediately.

The form gains an `autoRun` prop. When true, a latched effect calls `onSubmit()` exactly once after the source data has loaded, so form validation has the table metadata it needs.

### How to test locally or on Vercel

1. `yarn dev` in `packages/app`
2. Open `/chart?config=%7B%22name%22%3A%22%22%2C%22select%22%3A%5B%7B%22aggFn%22%3A%22count%22%2C%22aggCondition%22%3A%22%22%2C%22aggConditionLanguage%22%3A%22sql%22%2C%22valueExpression%22%3A%22%22%7D%5D%2C%22where%22%3A%22%22%2C%22whereLanguage%22%3A%22sql%22%2C%22displayType%22%3A%22line%22%2C%22granularity%22%3A%22auto%22%2C%22source%22%3A%22<your-source-id>%22%7D` — replace `<your-source-id>` with a real source id from your instance
3. The chart should render results without clicking the run button
2026-04-03 13:39:37 +00:00
Mike Shi
76323dae35
fix: handle special characters in quoted filter values (HDX-3901) (#2038)
## Summary

Fixes a bug where search page filters were silently hidden when their values contained special SQL keywords, operators, or escaped quotes inside single-quoted strings. The parsing functions in `searchFilters.tsx` used naive `.includes()` and `.split()` calls that matched these patterns even inside quoted values.

**Bugs fixed:**
- `extractInClauses()` skipped valid IN clauses when quoted values contained `=`, `>`, `<`, or ` OR ` (e.g., `Body IN ('key=value')` was hidden)
- `parseQuery()` misinterpreted IN clauses as BETWEEN ranges when quoted values contained ` BETWEEN ` (e.g., `Body IN ('I AM BETWEEN THE HEDGES')`)
- `extractInClauses()` misidentified IN clauses as NOT IN exclusions when quoted values contained ` NOT IN ` (e.g., `Body IN ('this is NOT IN scope')`)
- All four quote-tracking loops only handled `\'` escaping, not the SQL-standard `''` escaping used by ClickHouse (e.g., `Body IN ('it''s a test')` would break quote tracking)

**Fix:**
- Added `containsOutsideQuotes()` — checks for keywords/operators while respecting single-quoted string boundaries
- Added `splitOnFirstOutsideQuotes()` — splits on the first unquoted occurrence of a delimiter
- Added `isQuoteBoundary()` / `handleQuoteEscape()` — shared helpers for quote-tracking that handle both `''` (SQL standard) and `\'` (backslash) escaping
- Updated `getBooleanOrUnquotedString()` to un-escape `''` → `'` in parsed values

**Tests**: 12 new unit tests (45 total) covering all edge cases.

### How to test locally or on Vercel

1. Navigate to the search page
2. Apply a filter on a value that contains `=`, `>`, `<`, `OR`, `BETWEEN`, `NOT IN`, or escaped quotes (e.g., `Body IN ('key=value')`, `Body IN ('it''s a test')`)
3. Verify the filter appears as checked in the sidebar — previously it would be silently hidden

### References

- Linear Issue: HDX-3901



Linear Issue: [HDX-3901](https://linear.app/clickhouse/issue/HDX-3901/hidden-filters-bug)

<div><a href="https://cursor.com/agents/bc-2b1e64da-d6df-4cd7-b894-43675c312e34"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-2b1e64da-d6df-4cd7-b894-43675c312e34"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>



Co-authored-by: Cursor Agent <199161495+cursoragent@users.noreply.github.com>
2026-04-03 03:13:17 +00:00
Mike Shi
20e4720761
feat: Add input filter pills below search input to make filters usage more clear on seach page (#2039)
<img width="1470" height="754" alt="image" src="https://github.com/user-attachments/assets/fd6281c5-ded2-48d4-9fcd-01e5d0fb9c8e" />

Fixes HDX-2405
2026-04-02 22:18:58 +00:00
Aaron Knudtson
676e4f4bc9
fix: differentiate map key index vs array indexing (#2032)
## Summary

Previously array indexes were treated as map lookups, which caused them to be wrapped in quotations. This fixes array index query rendering by handling array indexes.

### References


- Related PRs: Closes https://github.com/hyperdxio/hyperdx/issues/1863
2026-04-02 19:32:27 +00:00
Tom Alexander
2bb8ccdc5a
fix: Fix query error when searching nested JSON values (#2044)
## Summary
Fixes a query error when clicking Search, Add to Filters, Chart, or Column on nested JSON values inside Map column attributes (e.g., LogAttributes['config'] containing '{"host": "localhost"}').

buildJSONExtractQuery was using only the last element of parsedJsonRootPath as the base column, producing invalid ClickHouse expressions like JSONExtractString(config, 'host') instead of JSONExtractString(LogAttributes['config'], 'host'). Fixed by using mergePath to construct the full column path and passing jsonColumns through so both Map (bracket notation) and JSON (dot notation) columns are handled correctly.

## How to test locally or on Vercel
Open a log or trace side panel where a Map column attribute (e.g., LogAttributes) has a value containing a JSON string (e.g., {"host": "localhost", "port": 5432})
Expand the JSON value in the side panel by clicking "Expand JSON"
Hover over a nested key (e.g., host) and click Search — verify the search page opens without a query error and the WHERE clause uses the full column path (e.g., JSONExtractString(LogAttributes['config'], 'host') = 'localhost')
Repeat step 3 with Add to Filters, Column, and Chart (for numeric values) to verify all actions produce valid queries

## References
Linear Issue: Fixes [HDX-3906](https://linear.app/clickhouse/issue/HDX-3906/clicking-search-on-nested-logattributes-map-key-results-in-query-error)
2026-04-02 19:24:41 +00:00
Drew Davis
bfc938118d
feat: Group Dashboards and Searches by Tag (#2033)
## Summary

This PR

1. Updates the Saved Searches and Dashboards pages to group objects by tag when in the card view
2. Fixes a display bug on the sidebar which resulted in favorited saved searches with long names and alerts configured to wrap
3. Adds the "Saved searches and dashboards have moved!" message back to the sidebar - it was inadvertently removed in a previous PR.

### Screenshots or video

<img width="1749" height="1024" alt="Screenshot 2026-04-01 at 3 46 42 PM" src="https://github.com/user-attachments/assets/b5f03bcb-7588-47cb-acc5-af56f0f9ddf4" />


### How to test locally or on Vercel

This can be tested in the preview environment by creating and tagging some saved searches and dashboards.

### References



- Linear Issue:
- Related PRs:
2026-04-02 17:24:53 +00:00
Tom Alexander
0abce12242
chore: allow more bots to run code review workflow (#2045)
## Summary
Allow common bots to trigger code review workflow
2026-04-02 16:38:31 +00:00
Warren Lee
1f19bbcb20
fix: Source dev-env.sh in app:dev:local for port isolation (#2042)
## Summary

- `yarn app:dev:local` was broken because it didn't source `scripts/dev-env.sh`, so port variables (`HYPERDX_APP_PORT`, `HYPERDX_API_PORT`, etc.) referenced in `.env.development` were undefined
- This caused `dotenv-expand` to hit infinite recursion (stack overflow) when trying to interpolate the unset variables
- Now `app:dev:local` sources `dev-env.sh`, builds common-utils, and tees logs — matching the pattern used by `yarn dev`
2026-04-02 16:12:44 +00:00
Dale McDiarmid
b7581db806
more units for charts (#2004)
Co-authored-by: Drew Davis <drew.davis@clickhouse.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2026-04-02 11:16:57 -04:00
Aaron Knudtson
91d950fc2e
feat: Add copy row as JSON button to DBRowJsonViewer (#2035)
## Summary

Adds ability to copy JSON button for entire row

### Screenshots or video


https://github.com/user-attachments/assets/0a30db15-6db0-4858-8503-d1b1688615ca

### How to test locally or on Vercel

1. Go to vercel preview
2. Click on any row
3. Copy to clipboard by clicking copy icon

### References

- Linear Issue: Closes HDX-3900
2026-04-02 14:53:27 +00:00
Aaron Knudtson
bb24994f68
feat: use 1 minute window for searches (#2019)
## Summary

This PR changes searches to a 1 minute up front window, rather than a 6h. Also, the refresh time was moved from 4s back to 10s.

### How to test locally or on Vercel

1. Go to preview
2. Inspect console and check a search query
3. See search query is searching over 60 seconds

### References

Closes HDX-3866
2026-04-02 14:36:06 +00:00
Karl Power
464fb231be
feat: add "Open ClickHouse" button to portal (#2041)
## Summary

- Adds an "Open ClickHouse" to the dev portal that opens the ClickHouse web UI.



### Screenshots or video



<img width="334" height="168" alt="Screenshot 2026-04-02 at 12 29 59" src="https://github.com/user-attachments/assets/1482044a-f7ff-4b42-a05e-49fd6b4f50ca" />


### How to test locally or on Vercel



1. Run the dev portal.
2. Check the "Open ClickHouse" button appears for all instances of the stack, and opens the web UI when clicked.
2026-04-02 12:33:55 +00:00
Mike Shi
777cf3de8c
fix: escape single quotes in search filter values (HDX-3902) (#2036)
## Summary

Filter values containing single quotes (e.g. `my 'filter' key`) produced invalid SQL because the quotes were not escaped when building `IN`/`NOT IN` clauses in the search page sidebar filters. This caused broken queries and prevented users from filtering on values that contain single quotes.

The fix applies SQL-standard quote escaping (`'` → `''`) in four places within `searchFilters.tsx`:

- **`filtersToQuery`**: Escapes `'` as `''` when wrapping string values in SQL single quotes for `IN`/`NOT IN` conditions
- **`splitValuesOnComma`**: Recognizes `''` as an escaped quote inside quoted strings, instead of treating it as a string boundary
- **`getBooleanOrUnquotedString`**: Unescapes `''` back to `'` when stripping surrounding quotes from parsed values
- **`extractInClauses`**: Handles `''` correctly when splitting conditions on `AND` inside quoted strings

This fix also applies to dashboard filters since `useDashboardFilters.tsx` imports the same `filtersToQuery`/`parseQuery` functions.

### How to test locally or on Vercel

1. Open the search page and add a sidebar filter whose value contains single quotes (e.g. filter on `message = "my 'filter' key"`)
2. Confirm the filter is applied correctly and the query executes without errors
3. Remove and re-add the filter to confirm round-trip parsing works (filter state is correctly restored from the SQL condition)

### References

- Linear Issue: HDX-3902



Linear Issue: [HDX-3902](https://linear.app/clickhouse/issue/HDX-3902/filter-keys-dont-support-quotes)

<div><a href="https://cursor.com/agents/bc-bbd50ba9-f23a-4c6f-989e-b4ff6f9e81d5"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-bbd50ba9-f23a-4c6f-989e-b4ff6f9e81d5"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>



Co-authored-by: Cursor Agent <199161495+cursoragent@users.noreply.github.com>
2026-04-02 12:25:45 +00:00
Mike Shi
8e05af5e07
fix: allow search where input to expand full width on smaller screens (#2037)
## Summary

On smaller screens (e.g. half MacBook screen), the search WHERE input on the search page was shrinking to be unusably small. This happened because the WHERE input (`flex: 1 1 0%`, `min-width: 0`) competed with fixed-width siblings — the TimePicker (`w={350}`), optional live-tail interval select (80px, `flexShrink: 0`), and submit button (`flexShrink: 0`) — inside a non-wrapping flex row.

**Fix:**

`DBSearchPage.tsx`:
- Added `wrap="wrap"` to the outer flex container so items can flow to the next line when space is insufficient
- Set `minWidth="min(600px, 100%)"` on `SearchWhereInput` so it wraps to full width at 600px, while capping at 100% on very narrow viewports to prevent horizontal overflow
- Grouped TimePicker, live tail select, and Run button in a flexible inner `Flex` (`flex: 0 1 500px`, `minWidth: 0`) so they wrap together and can shrink to fit
- TimePicker sits in a `Box` with `minWidth: 100` so it compresses on narrow screens while live tail select and Run button keep their fixed sizes

`TimePicker.tsx`:
- Added `width` prop (defaults to `350` for backward compatibility) so the search page can pass `width="100%"` to make TimePicker fill its flexible container

`SearchPage.ts` (E2E page object):
- Fixed flaky tests by pressing Escape after filling the search input to dismiss the autocomplete suggestions dropdown before clicking the submit button

**Behavior:**
- **Wide screens**: WHERE input and controls share a row as before, TimePicker stays at 350px
- **Narrow screens**: WHERE input takes full width on its own row; TimePicker compresses to fit alongside live tail select and Run button without overflow
- **Very narrow screens (<600px viewport)**: Everything still fits without horizontal overflow

### How to test locally or on Vercel

1. Navigate to the Search page (`/search`)
2. Resize the browser window to be narrow (e.g. half of a MacBook screen, ~700px wide)
3. Verify the WHERE input expands to full width on its own row
4. Verify TimePicker, live tail select, and Run button all fit on the second row without horizontal overflow
5. Resize even narrower and verify TimePicker compresses while the Run button remains visible
6. At wider widths, verify the WHERE input and controls remain on the same row as before

### References

- Linear Issue: HDX-3903



Linear Issue: [HDX-3903](https://linear.app/clickhouse/issue/HDX-3903/on-smaller-screens-on-the-search-page-the-search-where-input-shrinks)

<div><a href="https://cursor.com/agents/bc-dbc6584f-4844-40c4-9649-66a94ef7b017"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-dbc6584f-4844-40c4-9649-66a94ef7b017"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>



Co-authored-by: Cursor Agent <199161495+cursoragent@users.noreply.github.com>
2026-04-02 11:53:58 +00:00
Mike Shi
cf45ddd3cc
feat: Preserve whitespace in results table when wrap is enabled (#2040)
Now multi-line logs with whitespace will be properly rendered/preserved in the search results table when line wrap is enabled.

<img width="5060" height="2486" alt="image" src="https://github.com/user-attachments/assets/77b9da8d-de36-48f9-be14-506e6008e75b" />

Resolves HDX-3904
2026-04-02 08:33:38 +00:00
Mike Shi
48a8d32b39
handle more nullable types (#1984)
## Summary

Fix ClickHouse query error when expanding log rows with Nullable(DateTime64) columns (and other Nullable types).

- The `convertCHDataTypeToJSType` function didn't generically unwrap `Nullable(...)` types, so `Nullable(DateTime64(...))` fell through to the default string comparison instead of using `parseDateTime64BestEffort()`
- Added general `Nullable(...)` recursive unwrapping (matching the existing `LowCardinality(...)` pattern)
- Hoisted null value handling above the type switch in `processRowToWhereClause` so all column types (Date, Array, Map, etc.) correctly emit `isNull()` for null values

### Screenshots or video

N/A — no UI changes.

### How to test locally or on Vercel

1. Set up a ClickHouse table with a `Nullable(DateTime64)` column and ingest some rows (including rows with null values in that column).
2. Open the log explorer and expand a row that has a `Nullable(DateTime64)` column.
3. Verify that clicking into the row no longer returns a 400 error.
4. Verify that clicking into a row where the `Nullable(DateTime64)` column is null correctly filters using `isNull()`.

### References

- Related PRs:


---

📍 Connect Copilot coding agent with [Jira](https://gh.io/cca-jira-docs), [Azure Boards](https://gh.io/cca-azure-boards-docs) or [Linear](https://gh.io/cca-linear-docs) to delegate work to Copilot in one click without leaving your project management tool.
2026-04-02 06:48:53 +00:00