Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-accesskey-index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hyperdx/api": minor
---

Add unique MongoDB index on accessKey field in User model to eliminate full collection scans during API key authentication. This could cause startup failures if any existing users share duplicate accessKey values.
5 changes: 5 additions & 0 deletions .changeset/good-swans-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hyperdx/common-utils": patch
---

Adding filters to dashboard exports. Implemented validation on dashboard imports to catch potential issues with generated JSON or manually tweaked JSON.
21 changes: 21 additions & 0 deletions .changeset/mcp-dashboard-improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
'@hyperdx/api': patch
---

feat(mcp): add patch_dashboard, get_dashboard_tile, search_dashboards tools

Add three new MCP dashboard tools for granular operations:

- `hyperdx_get_dashboard_tile` — retrieve a single tile by tileId
- `hyperdx_patch_dashboard` — update name/tags and/or replace one tile
without resubmitting the full dashboard
- `hyperdx_search_dashboards` — search by name and/or tags

Fix empty parameter schema on patch/search tools caused by Zod
`.refine()` wrapping. Document Lucene substring matching limitations
prominently in tool descriptions and query guide prompt.

**Breaking (minor):** Tile `name` on `hyperdx_save_dashboard` now requires
at least 1 character (`.min(1)`). Previously empty string `""` was accepted
and silently persisted as a blank title. Callers sending `name: ""` will
now receive a validation error.
20 changes: 20 additions & 0 deletions .changeset/page-header-z-index-below-drawers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
'@hyperdx/app': patch
---

fix(z-index): keep sticky header below drawers and drawers above the fullscreen tile modal

Two related z-index regressions:

- `PageHeader` was pinned at `z-index: 100`, but app drawers opt into a
much lower stack via `ZIndexContext` (`contextZIndex + 10`, so a
top-level drawer renders at `z-index: 10`). The sticky header therefore
floated above the drawer overlay. The header now sits at `z-index: 2` so
drawer overlays reliably cover the page chrome while the header still
wins against normal scrolling content.
- `FullscreenPanelModal` used Mantine's default modal z-index (`200`) and
didn't propagate it through `ZIndexContext`. Clicking a row in a
fullscreen search tile opened a `DBRowSidePanel` drawer at `z-index: 10`
that was hidden behind the modal. The modal now follows the existing
`contextZIndex + 10` pattern and wraps its children in a
`ZIndexContext.Provider`, so child drawers stack on top of it.
7 changes: 7 additions & 0 deletions .changeset/page-migrate-dashboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@hyperdx/app': patch
---

chore: migrate the custom Dashboard page to shared `PageLayout` / `PageHeader`. Breadcrumbs, the editable dashboard name, dashboard actions (Favorite, Tags, Menu), and the "Created by … Updated …" meta now live in a single page header, while the query toolbar (SQL/Lucene WHERE, time range, granularity, Live, refresh, edit filters, Run) is pinned to the top of the scroll container as a dedicated sticky row — the chrome above scrolls away and only the toolbar follows the user. The "Updated …" meta moves to the right side of the breadcrumbs row instead of sitting as a separate body line.

`PageHeader` gains a `stickyRow` slot that any page can use to declare a single row that should be the only pinned element, with the rest of the header treated as scrolling chrome. Other pages are unaffected — a `PageHeader` without `stickyRow` keeps the existing fully-sticky behavior.
10 changes: 10 additions & 0 deletions .changeset/rename-mcp-tools-to-clickstack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@hyperdx/api": patch
"@hyperdx/common-utils": patch
---

refactor(mcp): rename all MCP tool prefixes from `hyperdx_` to `clickstack_`

Rename the MCP server name from `hyperdx` to `clickstack` and update all 19
tool names (e.g. `hyperdx_search` → `clickstack_search`), along with
descriptions, prompts, error messages, and test references.
5 changes: 5 additions & 0 deletions .changeset/source-chip-kebab-menu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperdx/app': patch
---

feat(source-picker): chip + kebab menu UX
91 changes: 91 additions & 0 deletions .github/actions/e2e-setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: E2E Setup
description: |
Shared setup for E2E test workflows: sets the HDX_E2E_* port env vars and
common Playwright env vars, then runs Node.js setup, dependency install,
build, Playwright browser install, and starts the E2E Docker Compose stack
(MongoDB + ClickHouse) with health checks. The caller is responsible for
`actions/checkout`, running Playwright, uploading artifacts, and tearing
down the Docker stack.
runs:
using: composite
steps:
# E2E port configuration (slot 0 defaults — must match scripts/test-e2e.sh)
- name: Set E2E environment variables
shell: bash
run: |
MONGO_PORT=21100
echo "HDX_E2E_SLOT=0" >> $GITHUB_ENV
echo "HDX_E2E_OPAMP_PORT=20320" >> $GITHUB_ENV
echo "HDX_E2E_CH_PORT=20500" >> $GITHUB_ENV
echo "HDX_E2E_CH_NATIVE_PORT=20600" >> $GITHUB_ENV
echo "HDX_E2E_API_PORT=21000" >> $GITHUB_ENV
echo "HDX_E2E_MONGO_PORT=$MONGO_PORT" >> $GITHUB_ENV
echo "HDX_E2E_APP_LOCAL_PORT=21200" >> $GITHUB_ENV
echo "HDX_E2E_APP_PORT=21300" >> $GITHUB_ENV
echo "MONGO_URI=mongodb://localhost:$MONGO_PORT/hyperdx-e2e" >> $GITHUB_ENV
echo "E2E_FULLSTACK=true" >> $GITHUB_ENV
echo "E2E_UNIQUE_USER=true" >> $GITHUB_ENV
echo "E2E_API_HEALTH_CHECK_MAX_RETRIES=60" >> $GITHUB_ENV

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache-dependency-path: yarn.lock
cache: yarn

- name: Install dependencies
shell: bash
run: yarn install

- name: Build dependencies
shell: bash
run: npx nx run-many -t ci:build

- name: Install Playwright browsers
shell: bash
run: cd packages/app && npx playwright install --with-deps chromium

- name: Start E2E Docker Compose
shell: bash
run: |
# Pre-pull images with retries to handle transient Docker Hub timeouts
for attempt in 1 2 3; do
if docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml pull; then
echo "Docker images pulled successfully on attempt $attempt"
break
fi
if [ "$attempt" -eq 3 ]; then
echo "Failed to pull Docker images after 3 attempts"
exit 1
fi
echo "Docker pull failed (attempt $attempt/3), retrying in 10s..."
sleep 10
done
docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml up -d
echo "Waiting for MongoDB..."
for i in $(seq 1 30); do
if docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml exec -T db mongosh --quiet --eval "db.adminCommand({ping:1})" >/dev/null 2>&1; then
echo "MongoDB is ready"
break
fi
if [ "$i" -eq 30 ]; then
echo "MongoDB failed to become ready after 30 seconds"
exit 1
fi
echo "Waiting for MongoDB... ($i/30)"
sleep 1
done
echo "Waiting for ClickHouse..."
for i in $(seq 1 60); do
if curl -sf http://localhost:${HDX_E2E_CH_PORT}/ping >/dev/null 2>&1; then
echo "ClickHouse is ready"
break
fi
if [ "$i" -eq 60 ]; then
echo "ClickHouse failed to become ready after 60 seconds"
exit 1
fi
echo "Waiting for ClickHouse... ($i/60)"
sleep 1
done
35 changes: 35 additions & 0 deletions .github/actions/e2e-teardown/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: E2E Teardown
description: |
Upload Playwright artifacts and stop the E2E Docker Compose stack.
Always runs (even on failure) so containers are cleaned up and reports
are available for failed runs.
inputs:
artifact-suffix:
description: >
Suffix appended to artifact names, e.g. "1" → playwright-report-1.
required: true
runs:
using: composite
steps:
- name: Upload Playwright report
uses: actions/upload-artifact@v7
if: always()
with:
name: playwright-report-${{ inputs.artifact-suffix }}
path: packages/app/playwright-report/
retention-days: 30

- name: Upload test results
uses: actions/upload-artifact@v7
if: always()
with:
name: test-results-${{ inputs.artifact-suffix }}
path: packages/app/test-results/
retention-days: 30

- name: Stop E2E containers
if: always()
shell: bash
run:
docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml
down -v
99 changes: 5 additions & 94 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,109 +14,20 @@ jobs:
matrix:
shard: [1, 2, 3, 4]

# E2E port configuration (slot 0 defaults — must match scripts/test-e2e.sh)
env:
HDX_E2E_SLOT: '0'
HDX_E2E_OPAMP_PORT: '20320'
HDX_E2E_CH_PORT: '20500'
HDX_E2E_CH_NATIVE_PORT: '20600'
HDX_E2E_API_PORT: '21000'
HDX_E2E_MONGO_PORT: '21100'
HDX_E2E_APP_LOCAL_PORT: '21200'
HDX_E2E_APP_PORT: '21300'

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache-dependency-path: 'yarn.lock'
cache: 'yarn'

- name: Install dependencies
run: yarn install

- name: Build dependencies
run: npx nx run-many -t ci:build

- name: Install Playwright browsers
run: cd packages/app && npx playwright install --with-deps chromium

- name: Start E2E Docker Compose
run: |
# Pre-pull images with retries to handle transient Docker Hub timeouts
for attempt in 1 2 3; do
if docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml pull; then
echo "Docker images pulled successfully on attempt $attempt"
break
fi
if [ "$attempt" -eq 3 ]; then
echo "Failed to pull Docker images after 3 attempts"
exit 1
fi
echo "Docker pull failed (attempt $attempt/3), retrying in 10s..."
sleep 10
done
docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml up -d
echo "Waiting for MongoDB..."
for i in $(seq 1 30); do
if docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml exec -T db mongosh --quiet --eval "db.adminCommand({ping:1})" >/dev/null 2>&1; then
echo "MongoDB is ready"
break
fi
if [ "$i" -eq 30 ]; then
echo "MongoDB failed to become ready after 30 seconds"
exit 1
fi
echo "Waiting for MongoDB... ($i/30)"
sleep 1
done
echo "Waiting for ClickHouse..."
for i in $(seq 1 60); do
if curl -sf http://localhost:${HDX_E2E_CH_PORT}/ping >/dev/null 2>&1; then
echo "ClickHouse is ready"
break
fi
if [ "$i" -eq 60 ]; then
echo "ClickHouse failed to become ready after 60 seconds"
exit 1
fi
echo "Waiting for ClickHouse... ($i/60)"
sleep 1
done
- name: E2E setup
uses: ./.github/actions/e2e-setup

- name: Run Playwright tests (full-stack mode)
env:
E2E_FULLSTACK: 'true'
E2E_UNIQUE_USER: 'true'
E2E_API_HEALTH_CHECK_MAX_RETRIES: '60'
MONGO_URI:
mongodb://localhost:${{ env.HDX_E2E_MONGO_PORT }}/hyperdx-e2e
run: |
cd packages/app
yarn test:e2e --shard=${{ matrix.shard }}/4

- name: Upload Playwright report
uses: actions/upload-artifact@v7
if: always()
with:
name: playwright-report-${{ matrix.shard }}
path: packages/app/playwright-report/
retention-days: 30

- name: Upload test results
uses: actions/upload-artifact@v7
- name: E2E teardown
if: always()
uses: ./.github/actions/e2e-teardown
with:
name: test-results-${{ matrix.shard }}
path: packages/app/test-results/
retention-days: 30

- name: Stop E2E containers
if: always()
run:
docker compose -p e2e-0 -f packages/app/tests/e2e/docker-compose.yml
down -v
artifact-suffix: ${{ matrix.shard }}
13 changes: 0 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,6 @@ and lint issues across all packages. Pre-commit hooks handle this when
committing, but if you finish edits without committing, run `yarn lint:fix`
before stopping.

## Before Writing New Utility Functions

Before implementing a new parsing, formatting, or transformation function,
search for existing functions that already do the same thing or something close.
Common places to check:

- `packages/common-utils/src/core/metadata.ts` — key/column parsing utilities
(e.g. `parseKeyPath`)
- `packages/common-utils/src/queryParser.ts` — Lucene parsing (`parse`,
`decodeSpecialTokens`), AST type guards, serialization helpers
- `packages/common-utils/src/filters.ts` — filter state serialization and
parsing (`filtersToQuery`, `parseLuceneFilter`)

## Key Principles

1. **Multi-tenancy**: All data is scoped to `Team` - ensure proper filtering
Expand Down
Loading
Loading