release: v2.1 (reconciled onto release/2.0 base) - #776
Conversation
Two new documentation pages explaining how to extend NeoBoard: - developer/extending/new-chart-plugin.mdx — full guide with defineChartPlugin() reference, PluginProps table, ECharts vs custom patterns, and heatmap example - developer/extending/new-connector-plugin.mdx — ConnectorPlugin reference, ConnectionModule implementation guide, registry API, and testing patterns Updated developer index to link plugin guides prominently. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docs: chart plugin + connector plugin developer guides
release/1.1 → dev: all v1.1 features + plugin system
1. /dashboards route 404 — add static redirect to / so [id] segment doesn't capture "dashboards" as a dashboard ID 2. Theme toggle dead zone — wrap SidebarItem in <button> instead of <div> so the entire label area triggers the dropdown 3. Delete dialog shows dashboard name — "Delete X?" instead of generic 4. Create dashboard validation — add required attr + helper text 5. Fullscreen dialog accessibility — replace <h2> with <DialogTitle> to fix Radix "DialogContent requires DialogTitle" warning 6. Hide Users nav for non-admin — creator/reader don't see the nav item that would just show them a 403 All 1877 tests pass. TypeScript clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: UX audit findings — 6 issues (route, a11y, validation, nav)
- Widget Lab: aria-labels "Edit" → "Edit template", "Delete" → "Delete template" to match E2E selectors - Graph chart: increase dialog dismiss timeout from 5s → 10s for Radix animation timing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- scripts/setup.sh and setup-local-demo.sh now use docker mode (default) instead of --mode local which skips Docker containers - Health check timeout increased from 60s to 120s — Neo4j cold start from empty volumes takes 90-120s - Health check interval increased from 1s to 2s — less polling noise Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…st health Root causes of slow/broken setup: 1. start.ts used full=true → built entire Next.js Docker image (minutes) 2. db/migrate.ts used docker exec into neoboard-app (doesn't exist) 3. Neo4j health used cypher-shell (slow JVM startup per poll) 4. Scripts hardcoded --mode local (skipped Docker) 5. Health timeout 60s too short for Neo4j cold start Fixes: - start.ts: full=false → docker-compose.yml (DBs only, ~30s) - db/migrate.ts: always runs locally with DATABASE_URL resolved from .env.local (priority) or neoboard.config.json (fallback). Works whether DB is Docker, local, or remote. - docker.ts: isNeo4jReady uses docker inspect (instant) not cypher-shell - health.ts: timeout 60s→120s, interval 1s→2s - scripts: removed --mode local (uses docker default) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- start.ts accepts { full } option — full=true uses docker-compose.full.yml
(app + DBs), full=false uses docker-compose.yml (DBs only)
- demo.ts always passes full=true — users get the complete experience
- setup.ts passes full=false by default — developers start DBs,
then run the app locally with npm run dev
neoboard demo: ~3.5min → full stack in Docker, seeded, ready
neoboard setup + neoboard dev: ~30s → DBs in Docker, app locally
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…entials Addresses CodeRabbit review: - Strip surrounding quotes from DATABASE_URL in .env.local - URI-encode user/password/database in config fallback URL - Add tests for both edge cases Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix 3 ReDoS vulnerabilities (S5852) and suppress 2 CLI false positives: - widget-lab: remove nested \s* quantifier in copy-name regex - form-field-validation: exclude dots from domain char class in email regex - cypher-lang/autocomplete: remove captured star loop (\w)*$ → \w*$ - cli/exec.ts: suppress S4721 + S4036 (hardcoded CLI commands, trusted PATH) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses CodeRabbit review: storybook core was ^10.2.6 while all @storybook/* addons were already ^10.3.4. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: combined release 1.1 fixes — CLI setup, security hotspots, E2E stability
Move all transform and validate functions from the monolithic chart-registry.ts into app/src/plugins/transforms/ so each plugin can import its own transform directly. The chart-registry.ts now imports from these modules (shim layer) keeping the same public API for existing consumers (card-container, dashboard-container, etc.). - 14 transform modules + shared utilities barrel - All 17 plugins updated to import from ./transforms/ instead of chartRegistry - 83 new transform unit tests + all 332 existing chart-registry tests pass - Zero-breaking change: all exports from chart-registry.ts unchanged Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…stry Add unregister() to ConnectorRegistry interface and implementation for parity with the chart plugin registry. Add ConnectorFormField interface and formFields to ConnectorPlugin for auto-generated connection forms. Update Neo4j and PostgreSQL built-in plugins with form field definitions. Export new types from the connection package public API. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sforms refactor(plugins): extract chart transforms into standalone modules
…nment feat(connection): align connector registry API — unregister + formFields
Phase 2: chart-registry.ts is now a thin shim that registers lightweight plugin entries with pluginRegistry and delegates all lookups via a Proxy. The static chartRegistry object, getChartConfig, and all helper functions continue to work unchanged for consumers. Phase 3: ChartType union is now derived from a single CHART_TYPES constant in plugins/chart-types.ts. Startup validation in plugins/index.ts warns if any declared type lacks a registered plugin. All 1971+ existing tests pass unchanged. New tests verify delegation behavior and CHART_TYPES/plugin registry alignment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 2: chart-registry.ts is now a thin shim that registers lightweight plugin entries with pluginRegistry and delegates all lookups via a Proxy. The static chartRegistry object, getChartConfig, and all helper functions continue to work unchanged for consumers. Phase 3: ChartType union is now derived from a single CHART_TYPES constant in plugins/chart-types.ts. Startup validation in plugins/index.ts warns if any declared type lacks a registered plugin. All 1971+ existing tests pass unchanged. New tests verify delegation behavior and CHART_TYPES/plugin registry alignment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added settingsSchema field to ChartPluginConfig interface - Created settings/ directory with Zod schemas for all 17 chart types - Updated all plugin components to parse settings via schema (no more `as` casts) - 75 new tests covering defaults, validation, passthrough, and coercion Closes #420 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… refactor/plugin-system-integration
…(Phase 5) Each of the 17 plugins now bundles its chart options via getChartOptions() from @neoboard/components, replacing scattered lookups. Adds deprecation comment to the component package's chart-options index. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… (Phase 7) Replace all imports from @/lib/chart-registry with @/lib/chart-helpers. The new module delegates to pluginRegistry and includes lightweight plugin registration for test environments. - Create app/src/lib/chart-helpers.ts with helper functions - Create app/src/lib/__tests__/chart-helpers.test.ts with 21 tests - Migrate 15 consumer files from chart-registry to chart-helpers - Delete chart-registry.ts and its 3 test files - Update test mocks to include getChartOptions for plugin imports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- capture-preview: access isECharts via capabilities object - card-container: fallback to transform when transformWithMapping undefined - chart-renderer: accept string type, remove unused ChartType import - graph plugin: explicit type annotation for onNodeSelect callback Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- chart-helpers.test.ts: add next/dynamic and next/navigation mocks (Critical) - single-value.tsx: use safeParse with fallback for resilience (Major) - json settings: constrain initialExpanded to non-negative integers (Minor) - pie settings: constrain topN to non-negative integers (Minor) - chart-plugin-registry: tighten settingsSchema type to Record<string, unknown> (Minor) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cleans up the lint warning introduced in the previous Batch 9 commit. The integration test only uses beforeAll for container startup; afterAll was carried over from a draft and never wired up. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure coverage addition — release/2.1 added 3 branch tests for ChartRenderer (empty data, JsonViewer fallback, MarkdownWidget fallback). Component code is byte-identical between branches; only the tests were missing in the reconciled tree. Found during Batch 10 audit comparing the test-file diff between top-of-stack and origin/release/2.1. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gration script The Batch 9 demo-flow integration test runs full `docker compose up`, which collides with the postgres service container in the regular "Unit & Integration Tests" CI job (port 5432 already allocated). Set SKIP_INTEGRATION=1 in the default `test` and `test:coverage` scripts so the integration test self-skips (the existing SKIP guard in demo-flow.test.ts already respects that env var). Add `test:integration` so the dedicated cli-integration.yml workflow can opt back in (the workflow already references this script name). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 273 files, which is 123 over the limit of 150. To get a review, narrow the scope: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (27)
📒 Files selected for processing (273)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776: #779 — Refresh button silently no-op'd dashboard-container.tsx invalidated TanStack Query with a 4-element key (["widget-query", connectionId, query, params]) but useWidgetQuery's actual key is 6 elements (["widget-query", connectionId, database, query, params, staleTime]). Position 2 mismatched (query string vs null/database) so the prefix match failed and no refetch ever fired. Fixed in: e2e/auto-refresh.spec.ts:107 manual per-widget refresh re-fetch e2e/auto-refresh.spec.ts:221 manual refresh, auto-refresh disabled e2e/widget-states.spec.ts:222 showRefreshButton re-fetches e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh Fix: align invalidation prefix to match through `query` slot. Stop at `query` because params/staleTime are merged at hook call time and not reproducible at refresh time. #778 — Write route leaked raw driver error handleRouteError -> sanitizeErrorMessage was deliberately permissive (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax errors echoed user SQL into the response body. Fixed in: e2e/write-permissions.spec.ts:255 "safe 500 message" assertion expected "Write query execution failed", got 'syntax error at or near "THIS"'. Fix: opt-in `safeMessage` flag on handleRouteError that collapses untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise) still get specific handling. Used by /api/query/write only — read routes preserve current behavior so users can debug their own queries. Tests: - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass) - write/route.test.ts: updated leaky-behavior assertion to verify the sanitized message + negative match against /syntax error/ - dashboard-container tests: 27/27 still pass - E2E: all 5 originally-failing tests now pass locally (20/20)
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776: #779 — Refresh button silently no-op'd dashboard-container.tsx invalidated TanStack Query with a 4-element key (["widget-query", connectionId, query, params]) but useWidgetQuery's actual key is 6 elements (["widget-query", connectionId, database, query, params, staleTime]). Position 2 mismatched (query string vs null/database) so the prefix match failed and no refetch ever fired. Fixed in: e2e/auto-refresh.spec.ts:107 manual per-widget refresh re-fetch e2e/auto-refresh.spec.ts:221 manual refresh, auto-refresh disabled e2e/widget-states.spec.ts:222 showRefreshButton re-fetches e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh Fix: align invalidation prefix to match through `query` slot. Stop at `query` because params/staleTime are merged at hook call time and not reproducible at refresh time. #778 — Write route leaked raw driver error handleRouteError -> sanitizeErrorMessage was deliberately permissive (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax errors echoed user SQL into the response body. Fixed in: e2e/write-permissions.spec.ts:255 "safe 500 message" assertion expected "Write query execution failed", got 'syntax error at or near "THIS"'. Fix: opt-in `safeMessage` flag on handleRouteError that collapses untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise) still get specific handling. Used by /api/query/write only — read routes preserve current behavior so users can debug their own queries. Tests: - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass) - write/route.test.ts: updated leaky-behavior assertion to verify the sanitized message + negative match against /syntax error/ - dashboard-container tests: 27/27 still pass - E2E: all 5 originally-failing tests now pass locally (20/20)
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776: #779 — Refresh button silently no-op'd dashboard-container.tsx invalidated TanStack Query with a 4-element key (["widget-query", connectionId, query, params]) but useWidgetQuery's actual key is 6 elements (["widget-query", connectionId, database, query, params, staleTime]). Position 2 mismatched (query string vs null/database) so the prefix match failed and no refetch ever fired. Fixed in: e2e/auto-refresh.spec.ts:107 manual per-widget refresh re-fetch e2e/auto-refresh.spec.ts:221 manual refresh, auto-refresh disabled e2e/widget-states.spec.ts:222 showRefreshButton re-fetches e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh Fix: align invalidation prefix to match through `query` slot. Stop at `query` because params/staleTime are merged at hook call time and not reproducible at refresh time. #778 — Write route leaked raw driver error handleRouteError -> sanitizeErrorMessage was deliberately permissive (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax errors echoed user SQL into the response body. Fixed in: e2e/write-permissions.spec.ts:255 "safe 500 message" assertion expected "Write query execution failed", got 'syntax error at or near "THIS"'. Fix: opt-in `safeMessage` flag on handleRouteError that collapses untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise) still get specific handling. Used by /api/query/write only — read routes preserve current behavior so users can debug their own queries. Tests: - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass) - write/route.test.ts: updated leaky-behavior assertion to verify the sanitized message + negative match against /syntax error/ - dashboard-container tests: 27/27 still pass - E2E: all 5 originally-failing tests now pass locally (20/20)
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776: #779 — Refresh button silently no-op'd dashboard-container.tsx invalidated TanStack Query with a 4-element key (["widget-query", connectionId, query, params]) but useWidgetQuery's actual key is 6 elements (["widget-query", connectionId, database, query, params, staleTime]). Position 2 mismatched (query string vs null/database) so the prefix match failed and no refetch ever fired. Fixed in: e2e/auto-refresh.spec.ts:107 manual per-widget refresh re-fetch e2e/auto-refresh.spec.ts:221 manual refresh, auto-refresh disabled e2e/widget-states.spec.ts:222 showRefreshButton re-fetches e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh Fix: align invalidation prefix to match through `query` slot. Stop at `query` because params/staleTime are merged at hook call time and not reproducible at refresh time. #778 — Write route leaked raw driver error handleRouteError -> sanitizeErrorMessage was deliberately permissive (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax errors echoed user SQL into the response body. Fixed in: e2e/write-permissions.spec.ts:255 "safe 500 message" assertion expected "Write query execution failed", got 'syntax error at or near "THIS"'. Fix: opt-in `safeMessage` flag on handleRouteError that collapses untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise) still get specific handling. Used by /api/query/write only — read routes preserve current behavior so users can debug their own queries. Tests: - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass) - write/route.test.ts: updated leaky-behavior assertion to verify the sanitized message + negative match against /syntax error/ - dashboard-container tests: 27/27 still pass - E2E: all 5 originally-failing tests now pass locally (20/20)
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776: #779 — Refresh button silently no-op'd dashboard-container.tsx invalidated TanStack Query with a 4-element key (["widget-query", connectionId, query, params]) but useWidgetQuery's actual key is 6 elements (["widget-query", connectionId, database, query, params, staleTime]). Position 2 mismatched (query string vs null/database) so the prefix match failed and no refetch ever fired. Fixed in: e2e/auto-refresh.spec.ts:107 manual per-widget refresh re-fetch e2e/auto-refresh.spec.ts:221 manual refresh, auto-refresh disabled e2e/widget-states.spec.ts:222 showRefreshButton re-fetches e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh Fix: align invalidation prefix to match through `query` slot. Stop at `query` because params/staleTime are merged at hook call time and not reproducible at refresh time. #778 — Write route leaked raw driver error handleRouteError -> sanitizeErrorMessage was deliberately permissive (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax errors echoed user SQL into the response body. Fixed in: e2e/write-permissions.spec.ts:255 "safe 500 message" assertion expected "Write query execution failed", got 'syntax error at or near "THIS"'. Fix: opt-in `safeMessage` flag on handleRouteError that collapses untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise) still get specific handling. Used by /api/query/write only — read routes preserve current behavior so users can debug their own queries. Tests: - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass) - write/route.test.ts: updated leaky-behavior assertion to verify the sanitized message + negative match against /syntax error/ - dashboard-container tests: 27/27 still pass - E2E: all 5 originally-failing tests now pass locally (20/20)
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776: #779 — Refresh button silently no-op'd dashboard-container.tsx invalidated TanStack Query with a 4-element key (["widget-query", connectionId, query, params]) but useWidgetQuery's actual key is 6 elements (["widget-query", connectionId, database, query, params, staleTime]). Position 2 mismatched (query string vs null/database) so the prefix match failed and no refetch ever fired. Fixed in: e2e/auto-refresh.spec.ts:107 manual per-widget refresh re-fetch e2e/auto-refresh.spec.ts:221 manual refresh, auto-refresh disabled e2e/widget-states.spec.ts:222 showRefreshButton re-fetches e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh Fix: align invalidation prefix to match through `query` slot. Stop at `query` because params/staleTime are merged at hook call time and not reproducible at refresh time. #778 — Write route leaked raw driver error handleRouteError -> sanitizeErrorMessage was deliberately permissive (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax errors echoed user SQL into the response body. Fixed in: e2e/write-permissions.spec.ts:255 "safe 500 message" assertion expected "Write query execution failed", got 'syntax error at or near "THIS"'. Fix: opt-in `safeMessage` flag on handleRouteError that collapses untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise) still get specific handling. Used by /api/query/write only — read routes preserve current behavior so users can debug their own queries. Tests: - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass) - write/route.test.ts: updated leaky-behavior assertion to verify the sanitized message + negative match against /syntax error/ - dashboard-container tests: 27/27 still pass - E2E: all 5 originally-failing tests now pass locally (20/20)
Two unrelated bugs surfacing as 5 consistent E2E failures across PR #776: #779 — Refresh button silently no-op'd dashboard-container.tsx invalidated TanStack Query with a 4-element key (["widget-query", connectionId, query, params]) but useWidgetQuery's actual key is 6 elements (["widget-query", connectionId, database, query, params, staleTime]). Position 2 mismatched (query string vs null/database) so the prefix match failed and no refetch ever fired. Fixed in: e2e/auto-refresh.spec.ts:107 manual per-widget refresh re-fetch e2e/auto-refresh.spec.ts:221 manual refresh, auto-refresh disabled e2e/widget-states.spec.ts:222 showRefreshButton re-fetches e2e/widget-states.spec.ts:526 cacheMode 'forever' refresh Fix: align invalidation prefix to match through `query` slot. Stop at `query` because params/staleTime are merged at hook call time and not reproducible at refresh time. #778 — Write route leaked raw driver error handleRouteError -> sanitizeErrorMessage was deliberately permissive (only strips bundler internals like __TURBOPACK__) so pg/cypher syntax errors echoed user SQL into the response body. Fixed in: e2e/write-permissions.spec.ts:255 "safe 500 message" assertion expected "Write query execution failed", got 'syntax error at or near "THIS"'. Fix: opt-in `safeMessage` flag on handleRouteError that collapses untyped errors to fallbackMsg. Typed app errors (Queue/Auth/Enterprise) still get specific handling. Used by /api/query/write only — read routes preserve current behavior so users can debug their own queries. Tests: - api-utils.test.ts: 3 new safeMessage cases (44/44 unit pass) - write/route.test.ts: updated leaky-behavior assertion to verify the sanitized message + negative match against /syntax error/ - dashboard-container tests: 27/27 still pass - E2E: all 5 originally-failing tests now pass locally (20/20)
SonarCloud flagged 2 MINOR code smells on PR #771's audit-logs route: the global `parseInt` shadows ES2015's namespaced `Number.parseInt`. 4-min effort total. Same behavior, eslint-friendly, satisfies the "prefer namespaced parse functions" convention.
… name races
Root cause of repeated "strict mode violation: getByText('Neo4j Bar Template',
{ exact: true }) resolved to 2 elements" failures on shard 5 across multiple
PRs (#770, #771): the consumption describe block creates two templates with
hardcoded names ("Neo4j Bar Template", "PostgreSQL Table Template") in
beforeEach. With fullyParallel=true and 2 CI workers, two of these tests'
beforeEach hooks race — both succeed in POSTing — leaving 2 elements with
the same text in the DOM and breaking strict-mode locators.
Fix: declare test.describe.configure({ mode: "serial" }) on the consumption
describe so its tests run sequentially within a worker. Each test's
beforeEach/afterEach now owns the shared template names exclusively.
Verified locally: all 4 consumption tests pass with --workers=2.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR #768 unit suite failed with "Test timed out in 5000ms" on "shows selection count text when rows are selected with pagination active" in data-grid-dynamic-pagination.test.tsx:349. Same root cause as #439 (commit 0ff3419): under coverage instrumentation in CI, rendering 30 rows + userEvent.click + selection state propagation exceeds the default 5s budget. The previous test in the same describe ("can select all rows on the current page") was already bumped to 15000ms for the same reason — this sibling test was missed in that PR. Match the precedent so both selection-related tests have headroom. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The deferred-ready setTimeout in DashboardContainer.openFullscreen could fire after the component unmounted, calling setState on a torn-down tree. In CI (vitest jsdom + coverage) this surfaced as an unhandled "window is not defined" exception originating from dashboard-container-branches.test.tsx, failing the run despite all 2592 tests passing. Track the timer in a ref and clear it on unmount, on close, and when re-arming via openFullscreen. Production behavior unchanged; defensive cleanup prevents the React unmounted-update warning in browsers too.
Add tests for the close, re-arm, and unmount paths of the fullscreen ready-timer ref so SonarCloud's new-coverage check on the prior fix clears the 80% threshold (was 75% on 4 uncovered lines). - close-while-pending → exercises closeFullscreen clearTimeout branch - re-arm openFullscreen → exercises previous-ref clearTimeout branch - unmount-while-pending → exercises useEffect cleanup branch Dialog mock now exposes onOpenChange via a close button so the close path is reachable from tests; vi.useFakeTimers lets us assert the timer was cleared (no setState fires on a torn-down tree).
|
Superseded — switching to per-batch re-implementation on current dev. The release/2.0 cascade (PRs #768–#775) merged successfully, so release/2.0 and release/2.1 now contain identical content (the full v2.1 payload). However, merging that payload into dev would surface 202 file conflicts in a single unreviewable mega-PR — both sides made substantive changes to the same hot files (dashboard-container.tsx, api/query/write, form-widget-renderer.tsx, hooks, etc.) and dev has its own real feature work since the v2.1 branch point (form wizard #165, markdown syntax highlighting #166, percent-stacked bar #167, SVG export #706, HTML-escape security fix in chart tooltips, dozens of test stabilizations). New plan: re-implement each v2.1 batch as a clean PR against current dev, using Branches kept as read-only reference:
They will be deleted once all v2.1 batches have landed cleanly on dev. Re-implementation order (smallest first to validate the workflow):
Each batch will go through |
Closes #757 epic. Closes #767 (Batch 10 swap).
What this is
The
release/2.1branch was originally cut frommainand missed significant refactors that landed ondevandrelease/2.0. This PR brings the reconciledrelease/2.1(now built on top ofrelease/2.0) intodev.The original
release/2.1is preserved asrelease/2.1-archived-2026-05-16.Stacked PRs that built this branch
Plus jest config fix #774 (propagated through the stack).
Excluded from v2.1
Tag
v2.1.0-rc.1points at the swap commit (a4b519d3).Verification
Local (top-of-stack
a4b519d3):npm run build✅npm -w app run test— 2586/2586 ✅npm -w component run test— 1259/1259 ✅npm run lint— 4 pre-existing release/2.0 errors (CI doesn't gate on lint)CI (PR #775, top of stack):
Reconciliation correctness audit:
release/2.0, 52 added, 31 modifiedrelease/2.0's 0004 snapshotcomponent/→app/,connection/→app/) cleanrelease/2.1not brought over: 12 intentional drops (Batch 7 form wizard, generated docs/.astro, query-editor full-screen feature), 1 missed test restored (chart-renderer.test.tsx), 1 already covered at alternate path (rate-limiter test)Follow-ups (not blocking this PR)
0000_initial.sql(no customers yet — see memory)handleRouteErrorraw-error leak in write-permissions responseTest plan
enterprise/package🤖 Generated with Claude Code