Skip to content

feat: React 19 + react-router 7 + GraphiQL 5 coordinated upgrade#3409

Merged
mtrezza merged 30 commits into
parse-community:alphafrom
mtrezza:chore/react19-router7-graphiql5
Jul 18, 2026
Merged

feat: React 19 + react-router 7 + GraphiQL 5 coordinated upgrade#3409
mtrezza merged 30 commits into
parse-community:alphafrom
mtrezza:chore/react19-router7-graphiql5

Conversation

@mtrezza

@mtrezza mtrezza commented Jul 17, 2026

Copy link
Copy Markdown
Member

Summary

Coordinated upgrade of the four tightly-coupled majors from #3408, landed on one branch as reviewable, bisectable commits:

  • React 16 → 19 (via an 18.3.1 stepping stone) — createRoot, and remediation of third-party deps that block React 19.
  • react-router 6 → 7 — consolidated onto the react-router package; react-router-dom removed.
  • GraphiQL 2 → 5 — Monaco editor + web workers, createGraphiQLFetcher, code-split behind React.lazy.

Closes #3408.

Supersedes #3336, #3341, #3369, #3372, #3377 (the deferred Dependabot bumps — this PR replaces them; leaving them open for the maintainer to close on merge).

Commits (one per step, each independently green)

  1. feat: React 16→18createRoot ×3; replace react-json-view (React ≤17 cap) with @microlink/react-json-view; migrate react-dnd 10→16 (decorators→hooks in DataBrowserHeader, v16 hooks API in ColumnConfigurationItem).
  2. feat: React 18→19 — bump to 19.2.7; react-draggable/react-resizable bumps for findDOMNode removal; lazy-load GraphQLConsole; webpack resolve.modules walk-up; act()-wrap the 5 react-test-renderer suites.
  3. chore: v7 future flags + feat: react-router 6→7 — enable flags, then flip all 19 importers to react-router and drop react-router-dom.
  4. feat: GraphiQL 2→5 — graphiql 5.2.4 + @graphiql/toolkit + graphql-ws; setup-workers/webpack; .ttf asset rule; output.publicPath: 'auto'.

Notable, non-obvious changes

  • @babel/plugin-proposal-decorators is kept@withRouter/@subscribeTo are class decorators used across ~25 files.
  • createRoot exposed two latent React-18 automatic-batching bugs in the Data Browser (state read right after setState in a promise); fixed by using resolved values, incl. making StoreManager.dispatch resolve with the new state.
  • GraphQLConsole is lazy-loaded — graphiql@2 read the React-19-removed ReactCurrentOwner at module load and crashed the whole app on boot; lazy-loading isolates it and permanently code-splits the Monaco chunk.
  • output.publicPath: 'auto' — required so Monaco's emitted *.worker.js chunks resolve at runtime (the relative bundles/ doubled to bundles/bundles/).
  • monaco-editor stays transitive at 0.52.2 (pinned by @graphiql/react; not added directly).

Design spec & implementation notes: docs/superpowers/specs/2026-07-17-react19-router7-graphiql5-migration-design.md (§8).

Verification

  • npm run lint, npm test (264 passing, incl. the puppeteer e2e), npm run build (dashboard + PIG), and the prepare publish build — all green from a clean npm ci.
  • Browser QA against a local parse-server (+ GraphQL): app boot, /apps redirect, Data Browser (columns, drag, resize), Playground JSON output, Canvas, routing (deep links, cloud_code/* splat, 404, back/forward), and 14 dashboard screens — no crash-type console/page errors.
  • GraphQL console end-to-end: Monaco mounts (no blank editor, no worker 404s), schema introspection returns 200 with data, and requests carry the X-Parse-* headers.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added lazy-loaded GraphQL console routing with a Suspense loader.
    • Upgraded the GraphQL console experience with refreshed tooling and Monaco worker setup.
  • Bug Fixes
    • Improved popover outside-click handling to prevent premature closing.
    • Hardened schema/CLP refresh and ensured dispatched promises resolve with updated state.
  • Refactor
    • Migrated routing/navigation to the newer router package.
    • Modernized drag-and-drop interactions and improved keyboard accessibility.
  • Tests
    • Added an end-to-end login mount test.
    • Standardized component rendering in tests with a shared act() helper.
  • Chores
    • Refreshed dependencies and bundler behavior (including codicon font asset handling).

mtrezza added 8 commits July 17, 2026 17:33
…rse-community#3408)

Checkpoint 1 of the React 19 + react-router 7 + GraphiQL 5 migration.

- Convert the 3 entry points (dashboard, quickstart, parse-interface-guide)
  from ReactDOM.render to createRoot (react-dom/client).
- Replace react-json-view (React ≤17 peer cap) with the drop-in
  @microlink/react-json-view; verified rendering in the Playground JS console.
- Migrate react-dnd 10→16: rewrite DataBrowserHeader's @DragSource/@DropTarget
  decorators to useDrag/useDrop hooks, and update ColumnConfigurationItem to the
  v16 hooks API (type at top level; ref connector).
- Bump react/react-dom/react-test-renderer to 18.3.1.
- webpack: alias react/jsx-runtime without the .js suffix (React 18 exports map).
- Fix two React 18 automatic-batching regressions in the Data Browser surfaced
  by browser QA (setState no longer synchronous inside promises):
  * Browser.react.js componentDidMount read this.state.configData immediately
    after setState → use the fetched value directly.
  * handleFetchedSchema read the stale subscribeTo snapshot after a schema
    dispatch → StoreManager.dispatch now resolves with the new state and
    handleFetchedSchema consumes it.

Kept @babel/plugin-proposal-decorators: @withRouter/@subscribeto class
decorators are used across ~25 files (the earlier "only DataBrowserHeader"
assumption was wrong).

Verified: npm run lint, npm test (264), npm run build all green; browser smoke
against a local parse-server (app boot, Data Browser columns + counts, drag
headers, Playground JSON output) with zero console/page errors.
Checkpoint 2 of the React 19 + react-router 7 + GraphiQL 5 migration.

- Bump react/react-dom/react-test-renderer to 19.2.7.
- Bump react-draggable 4.5→4.7 and react-resizable 3.1.3→4.0.2. findDOMNode is
  removed in React 19; these versions plus react-rnd@10.5.3 all thread a nodeRef
  to the internal <Draggable>, and react-draggable@4.7's findDOMNode() is guarded
  (uses nodeRef.current, and only touches the legacy API when it still exists).
  Verified by source inspection — no manual nodeRef changes or patch needed.
- Lazy-load GraphQLConsole (React.lazy + Suspense) so graphiql@2 — which reads
  the React-19-removed ReactCurrentOwner internal at module load — is code-split
  out of the boot bundle. Without this the whole app crashed on boot. This also
  permanently splits the heavy GraphiQL/Monaco chunk out of initial load.
- webpack: add relative 'node_modules' to resolve.modules so webpack walks up
  the tree for deps npm nests under React 19 peer ranges (graphiql's
  @graphiql/react, react-helmet's react-side-effect) instead of only checking
  the top-level dir. Without this the production build failed to resolve them.
- Tests: React 19's react-test-renderer renders concurrently, so create() must
  run inside act() for toJSON()/getInstance() to reflect the flushed tree. Wrap
  the 5 react-test-renderer suites (Button, ConfigConflictDiff, BrowserCell,
  BrowserRow, ScriptResponseModal) with a renderComponent/renderToJSON helper.

Verified: npm run lint, npm test (264, incl. the puppeteer e2e redirect), and
npm run build all green; browser smoke against a local parse-server — app boot +
/apps redirect, Data Browser, Canvas — with zero console/page errors.
…rse-community#3408)

Checkpoint 3 of the React 19 + react-router 7 + GraphiQL 5 migration.

- Flip the import specifier from 'react-router-dom' to 'react-router' across all
  19 importers (incl. src/lib/withRouter.js). Every API in use — BrowserRouter,
  Routes, Route, Outlet, Link, NavLink, Navigate, useNavigate, useParams,
  useLocation, useOutletContext, useBeforeUnload, useNavigationType,
  NavigationType — exports from react-router; no named-import changes needed.
- package.json: remove react-router-dom (6.30.3), add react-router@7.18.1.
  react-router-dom is a dead-ended compat shim (no v8); the maintained package
  is react-router. Node stays >=20 and the package ships dual CJS/ESM (Jest-safe).
- Remove the v7 future-flag props added in the prior commit (they are v7
  defaults and log "unknown future flag" warnings on v7).

Note: installed with --legacy-peer-deps because graphiql@2's react peer
(^16||^17||^18) conflicts with React 19; that conflict disappears when graphiql 5
lands in checkpoint 4, after which the lockfile is normalized with a plain install.

Verified: npm run lint, npm test (264), npm run build all green; browser smoke on
v7 — app selector, sidebar, deep links, cloud_code/* splat, 404, back/forward,
and withRouter-wrapped class components — with no routing errors.
…se-community#3408)

Checkpoint 4 of the React 19 + react-router 7 + GraphiQL 5 migration.

- package.json: graphiql 2.0.8 → 5.2.4; add @graphiql/toolkit@0.12.1 and
  graphql-ws@6.1.0 (a @graphiql/toolkit peer that createGraphiQLFetcher imports).
  Keep graphql@16.12.0. monaco-editor resolves transitively at 0.52.2 (pinned by
  @graphiql/react); it is NOT added directly. With graphiql 2 gone the tree now
  resolves without --legacy-peer-deps, so the lockfile is normalized.
- GraphQLConsole.react.js: rewrite for v5 — named `{ GraphiQL }` import, build the
  fetcher with createGraphiQLFetcher({ url, headers }) (memoized across renders),
  pass initialHeaders instead of the removed headers/headerEditorEnabled props.
  The X-Parse-Application-Id / Master-Key / optional Client-Key injection is
  preserved exactly.
- src/dashboard/index.js: CSS graphiql/graphiql.min.css → graphiql/style.css, and
  add the side-effect import 'graphiql/setup-workers/webpack' to register Monaco's
  web workers (no monaco-editor-webpack-plugin needed).
- webpack/base.config.js: add a {ttf,woff2} asset rule for Monaco's codicon font,
  and switch output.publicPath 'bundles/' → 'auto' so Monaco's dynamically-emitted
  *.worker.js chunks resolve at runtime instead of doubling the relative segment
  (also fixes lazy-chunk loading from deep SPA routes).

Verified against a local parse-server GraphQL endpoint: the console mounts a
Monaco editor (no blank editor, no worker 404s), schema introspection returns 200
with data, and requests carry the X-Parse headers. npm run lint, npm test (264),
and npm run build all green; general routing and the e2e redirect still pass.
…ity#3408)

- Decorators Babel plugin kept (@withRouter/@subscribeto used across ~25 files).
- Add §8 Implementation notes: React 18 batching fixes, findDOMNode via version
  bumps, lazy-load graphiql, webpack resolve.modules, act() test wrapping,
  --legacy-peer-deps bridge, graphql-ws, publicPath auto, Accept header accepted.
@parse-github-assistant

Copy link
Copy Markdown

🚀 Thanks for opening this pull request! We appreciate your effort in improving the project. Please let us know once your pull request is ready for review.

Tip

  • Keep pull requests small. Large PRs will be rejected. Break complex features into smaller, incremental PRs.
  • Use Test Driven Development. Write failing tests before implementing functionality. Ensure tests pass.
  • Group code into logical blocks. Add a short comment before each block to explain its purpose.
  • We offer conceptual guidance. Coding is up to you. PRs must be merge-ready for human review.
  • Our review focuses on concept, not quality. PRs with code issues will be rejected. Use an AI agent.
  • Human review time is precious. Avoid review ping-pong. Inspect and test your AI-generated code.

Note

Please respond to review comments from AI agents just like you would to comments from a human reviewer. Let the reviewer resolve their own comments, unless they have reviewed and accepted your commit, or agreed with your explanation for why the feedback was incorrect.

Caution

Pull requests must be written using an AI agent with human supervision. Pull requests written entirely by a human will likely be rejected, because of lower code quality, higher review effort and the higher risk of introducing bugs. Please note that AI review comments on this pull request alone do not satisfy this requirement. Our CI and AI review are safeguards, not development tools. If many issues are flagged, rethink your development approach. Invest more effort in planning and design rather than using review cycles to fix low-quality code.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1b2501d7-60b4-4d62-88d8-7640e8cb56c7

📥 Commits

Reviewing files that changed from the base of the PR and between baeaf8d and 34404d5.

📒 Files selected for processing (39)
  • .gitignore
  • package-lock.json
  • package.json
  • src/components/CategoryList/CategoryList.react.js
  • src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js
  • src/components/DataBrowserHeader/DataBrowserHeader.react.js
  • src/components/FileTree/FileTree.react.js
  • src/components/Popover/Popover.react.js
  • src/components/Sidebar/AppsMenu.react.js
  • src/components/Sidebar/SidebarHeader.react.js
  • src/components/Sidebar/SidebarSection.react.js
  • src/components/Sidebar/SidebarSubItem.react.js
  • src/components/Toolbar/Toolbar.react.js
  • src/dashboard/AppData.react.js
  • src/dashboard/Apps/AppsIndex.react.js
  • src/dashboard/Dashboard.js
  • src/dashboard/Data/ApiConsole/ApiConsole.react.js
  • src/dashboard/Data/ApiConsole/GraphQLConsole.react.js
  • src/dashboard/Data/Browser/Browser.react.js
  • src/dashboard/Data/Jobs/JobsData.react.js
  • src/dashboard/Data/Playground/Playground.react.js
  • src/dashboard/Push/PushDetails.react.js
  • src/dashboard/Settings/GeneralSettings.react.js
  • src/dashboard/index.js
  • src/lib/stores/StoreManager.js
  • src/lib/tests/BrowserCell.test.js
  • src/lib/tests/BrowserRow.test.js
  • src/lib/tests/Button.test.js
  • src/lib/tests/ConfigConflictDiff.test.js
  • src/lib/tests/ScriptResponseModal.test.js
  • src/lib/tests/e2e/dashboard.e2e.test.js
  • src/lib/tests/renderWithAct.js
  • src/lib/withRouter.js
  • src/login/index.js
  • src/parse-interface-guide/PIG.react.js
  • src/parse-interface-guide/index.js
  • src/parse-interface-guide/routes.js
  • src/quickstart/index.js
  • webpack/base.config.js

📝 Walkthrough

Walkthrough

React, React Router, and GraphiQL are upgraded across dependencies, entry points, routing imports, drag-and-drop components, GraphQL console integration, schema loading, build assets, interaction handling, and React 19 tests.

Changes

Coordinated dashboard migration

Layer / File(s) Summary
React runtime and dependency migration
package.json, package-lock.json
React 19, GraphiQL 5, React Router 7, React DnD, accessibility, and supporting UI dependencies are upgraded.
React Router 7 import migration
src/components/*, src/dashboard/*, src/lib/withRouter.js, src/parse-interface-guide/*
Routing primitives and hooks are imported from react-router instead of react-router-dom.
GraphiQL console and build integration
src/dashboard/Data/ApiConsole/GraphQLConsole.react.js, src/dashboard/Dashboard.js, src/dashboard/index.js, webpack/base.config.js
GraphiQL uses a memoized toolkit fetcher, lazy loading, worker and stylesheet imports, runtime chunk resolution, and font/resource handling.
Fresh schema data and dispatch results
src/dashboard/Data/Browser/Browser.react.js, src/lib/stores/StoreManager.js
Schema callbacks consume resolved fetch data, configuration mapping uses fetched responses, and dispatch promises return updated store state.
Application bootstraps and asset handling
src/parse-interface-guide/index.js, src/quickstart/index.js, src/login/index.js, src/dashboard/index.js, webpack/base.config.js, .gitignore
React entry points use createRoot, Webpack emits font assets, runtime asset resolution is updated, and docs is ignored.
Hook-based drag-and-drop components
src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js, src/components/DataBrowserHeader/DataBrowserHeader.react.js
Drag-and-drop connectors use refs and hooks while preserving payloads, drop actions, visual states, and keyboard toggling.
Interactive component behavior fixes
src/components/Popover/Popover.react.js, src/dashboard/Push/PushDetails.react.js
Popover external-click handling covers deferred listeners and detached targets; Push details interpolate the flow winner value.
React 19 rendering validation
src/lib/tests/*, src/lib/tests/e2e/dashboard.e2e.test.js
React test-renderer setup uses act(), and dashboard login mounting is checked through an end-to-end test.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant GraphQLConsole
  participant GraphiQL
  participant GraphQLServer
  Dashboard->>GraphQLConsole: Lazy-load GraphQL console route
  GraphQLConsole->>GraphiQL: Provide memoized fetcher and initial headers
  GraphiQL->>GraphQLServer: Submit query with authentication headers
  GraphQLServer-->>GraphiQL: Return GraphQL response
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Adding /docs/ to .gitignore is unrelated to the migration objectives and looks like a stray housekeeping change. Move the docs ignore tweak to a separate cleanup PR or remove it from this branch.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The summaries cover the core React, router, GraphiQL, and test upgrades, but they do not show the required v7 future flags or header-editor preservation. Provide evidence for the six v7 future flags and confirm GraphiQL auth/header editing behavior in the diff or summary.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main migration and uses the required feat: prefix.
Description check ✅ Passed It includes the issue link, approach, and verification, so the needed content is present despite the template not being followed exactly.
Security Check ✅ Passed Scans of touched files found no new XSS/eval/unsafe-link patterns; changes are routing/GraphiQL/refactor-only and preserve existing protections like rel="noreferrer".
Engage In Review Feedback ✅ Passed PASS: commit 84df169 explicitly says it addresses review feedback, and be8f538/fda59c61 implement reviewer-driven fixes noted in the PR.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/dashboard/Data/Browser/Browser.react.js (1)

329-341: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Refactor these legacy lifecycles. componentWillMount and componentWillReceiveProps are still doing real work here; move the mount-time setup to componentDidMount and the prop-driven fetch/prefetch logic to componentDidUpdate. The same pattern also appears elsewhere in src/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/dashboard/Data/Browser/Browser.react.js` around lines 329 - 341, Replace
Browser’s componentWillMount and componentWillReceiveProps logic with
componentDidMount and componentDidUpdate. Move mount-time SidebarAction setup
and initial schema fetch into componentDidMount, and move prop-driven
fetch/prefetch handling into componentDidUpdate with guards comparing previous
props to avoid repeated dispatches or update loops; preserve the existing
redirect and prefetch behavior.
🧹 Nitpick comments (1)
src/dashboard/Data/ApiConsole/GraphQLConsole.react.js (1)

19-30: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Keep this cache out of render(). getFetcher() mutates this._fetcherKey and this._fetcher during rendering; move the cache to a helper or lifecycle-managed field so the render path stays pure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/dashboard/Data/ApiConsole/GraphQLConsole.react.js` around lines 19 - 30,
Refactor getFetcher so render does not mutate this._fetcherKey or this._fetcher;
move fetcher caching into a helper or lifecycle-managed field outside the render
path, while preserving reuse when graphQLServerURL and parseHeaders are
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/superpowers/plans/2026-07-17-react19-router7-graphiql5-migration.md`:
- Around line 459-462: Update the migration step’s import-rewrite command to use
a portable cross-platform replacement that works on both BSD/macOS and
GNU/Linux, while preserving the existing grep scope and verification for all
react-router-dom imports.
- Around line 97-103: Update the scratch harness validation around server.app to
use the mounted GraphQL endpoint at /parse/graphql, including the curl request
and any subsequent dashboard URL references. Keep the existing /parse mount
unchanged unless intentionally changing all dependent URLs.

In
`@docs/superpowers/specs/2026-07-17-react19-router7-graphiql5-migration-design.md`:
- Around line 117-118: Update the migration design’s Babel/package instruction
to keep `@babel/plugin-proposal-decorators` rather than remove it, preserving
support for `@withRouter` and `@subscribeTo`(...) decorator syntax and aligning with
the corrected Step 8.
- Around line 206-208: Align the migration plan’s commit-count terminology
across this section and §1: explicitly distinguish four review checkpoints from
five total commits, including the two separate router migration commits. Update
any conflicting wording so the single-branch deliverable has one canonical
description.

In `@package-lock.json`:
- Around line 27479-27486: Update the dependency resolution for
react-side-effect and react-popper in package-lock.json so their transitive peer
dependency ranges support react@19.2.7, including both react and react-dom for
react-popper. Prefer bumping the affected parent packages or adding an
appropriate override, and regenerate the lockfile so both package entries
reflect the compatible peer ranges.

---

Outside diff comments:
In `@src/dashboard/Data/Browser/Browser.react.js`:
- Around line 329-341: Replace Browser’s componentWillMount and
componentWillReceiveProps logic with componentDidMount and componentDidUpdate.
Move mount-time SidebarAction setup and initial schema fetch into
componentDidMount, and move prop-driven fetch/prefetch handling into
componentDidUpdate with guards comparing previous props to avoid repeated
dispatches or update loops; preserve the existing redirect and prefetch
behavior.

---

Nitpick comments:
In `@src/dashboard/Data/ApiConsole/GraphQLConsole.react.js`:
- Around line 19-30: Refactor getFetcher so render does not mutate
this._fetcherKey or this._fetcher; move fetcher caching into a helper or
lifecycle-managed field outside the render path, while preserving reuse when
graphQLServerURL and parseHeaders are unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b01a985b-9ebd-406d-af5b-d02e289c3f7f

📥 Commits

Reviewing files that changed from the base of the PR and between 0f9194a and 65002e1.

📒 Files selected for processing (36)
  • docs/superpowers/plans/2026-07-17-react19-router7-graphiql5-migration.md
  • docs/superpowers/specs/2026-07-17-react19-router7-graphiql5-migration-design.md
  • package-lock.json
  • package.json
  • src/components/CategoryList/CategoryList.react.js
  • src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js
  • src/components/DataBrowserHeader/DataBrowserHeader.react.js
  • src/components/FileTree/FileTree.react.js
  • src/components/Sidebar/AppsMenu.react.js
  • src/components/Sidebar/SidebarHeader.react.js
  • src/components/Sidebar/SidebarSection.react.js
  • src/components/Sidebar/SidebarSubItem.react.js
  • src/components/Toolbar/Toolbar.react.js
  • src/dashboard/AppData.react.js
  • src/dashboard/Apps/AppsIndex.react.js
  • src/dashboard/Dashboard.js
  • src/dashboard/Data/ApiConsole/ApiConsole.react.js
  • src/dashboard/Data/ApiConsole/GraphQLConsole.react.js
  • src/dashboard/Data/Browser/Browser.react.js
  • src/dashboard/Data/Jobs/JobsData.react.js
  • src/dashboard/Data/Playground/Playground.react.js
  • src/dashboard/Push/PushDetails.react.js
  • src/dashboard/Settings/GeneralSettings.react.js
  • src/dashboard/index.js
  • src/lib/stores/StoreManager.js
  • src/lib/tests/BrowserCell.test.js
  • src/lib/tests/BrowserRow.test.js
  • src/lib/tests/Button.test.js
  • src/lib/tests/ConfigConflictDiff.test.js
  • src/lib/tests/ScriptResponseModal.test.js
  • src/lib/withRouter.js
  • src/parse-interface-guide/PIG.react.js
  • src/parse-interface-guide/index.js
  • src/parse-interface-guide/routes.js
  • src/quickstart/index.js
  • webpack/base.config.js

Comment thread package-lock.json
The docs/superpowers/{specs,plans} files are Claude Code working artifacts, not
parse-community in-repo material. Untrack them and gitignore docs/. Resolves the
doc-consistency review comments by removal; the design record lives outside the
repo.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 17, 2026
@parse-community parse-community deleted a comment from coderabbitai Bot Jul 17, 2026
@parse-community parse-community deleted a comment from coderabbitai Bot Jul 17, 2026
@parse-community parse-community deleted a comment from coderabbitai Bot Jul 17, 2026
@parse-community parse-community deleted a comment from coderabbitai Bot Jul 17, 2026
…3408)

src/login/index.js still used ReactDOM.render, which is removed in React 19, so
the /login page rendered blank (react-dom render is not a function). The issue's
entry-point audit missed this fourth entry; convert it to createRoot like the
dashboard, quickstart, and parse-interface-guide entries.
Add an e2e check that loads /login (with users configured) and asserts React
actually renders into #login_mount. Verified it fails against the pre-fix
ReactDOM.render entry and passes with createRoot, so a future entry-point
regression fails CI instead of shipping a blank page.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/tests/e2e/dashboard.e2e.test.js`:
- Around line 63-90: Update the server setup in the dashboard E2E test to listen
on an ephemeral port (0) and reject the startup promise on listen errors, then
derive the URL from the server’s assigned port instead of hardcoding 5052. Move
Puppeteer launch inside the existing try/finally and ensure cleanup safely
closes both browser and server even when launch or navigation fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fa107a85-6aa5-44c3-b009-ee729e9e57dd

📥 Commits

Reviewing files that changed from the base of the PR and between f85eed3 and 6378560.

📒 Files selected for processing (2)
  • src/lib/tests/e2e/dashboard.e2e.test.js
  • src/login/index.js

Comment thread src/lib/tests/e2e/dashboard.e2e.test.js Outdated
mtrezza added 2 commits July 18, 2026 02:04
…ity#3408)

Per CodeRabbit review of the login-mount guard:
- Listen on an ephemeral port (0) and reject the promise on a listen error, so a
  busy/leaked port fails fast instead of hanging until the test timeout.
- Launch puppeteer inside the try/finally and guard browser.close(), so a launch
  failure can no longer leak the still-listening server.
- Derive the request URL from the server's assigned port.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 18, 2026
…ck listener (parse-community#3408)

Popover registered its document.body click-outside listener synchronously in
componentDidMount. Under React 19 + createRoot, React delegates events on the
root container (which is inside <body>), so a menu's opening click hits React's
onClick, mounts the Popover, and then the same click keeps bubbling up to
document.body — immediately firing onExternalClick and closing the popover. Net
effect: Data Browser menus (Filter, Security, Script, ...) opened and closed on
the same click, so they appeared to do nothing. (In React 16 events were
delegated on document, above <body>, so the opening click never hit the listener.)

Register the external-click listener on the next tick so the opening click can't
trigger it, and clear the timer on unmount. External-click-to-close is preserved.

Verified against a live Data Browser: the Filter menu opens on click, closes on
an outside click, and re-opens on a second click.
…act 19) (parse-community#3408)

Popover._checkExternalClick treated a click as "external" (and closed the popover)
whenever hasAncestor(e.target, ...) failed. Under React 19, discrete-event updates
flush synchronously, so a click that re-renders and swaps the clicked element
(e.g. the filter dialog's expand chevron toggling down-solid -> up-solid) detaches
e.target from the DOM before the document.body listener runs. Its ancestor chain
is then broken, hasAncestor returns false, and the popover closes — so the filter
dialog's arrow-down (and similar in-popover toggles) collapsed the whole menu
instead of expanding it.

Ignore clicks whose target is no longer connected to the document: a detached
target is an in-app element removed by a re-render, never a genuine outside click.

Verified live: the filter dialog's arrow-down now expands the dialog (the chevron
toggles and the name field appears) and the menu stays open; an outside click
still closes it.
@mtrezza

mtrezza commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Popover/Popover.react.js (1)

87-111: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Use e.composedPath() instead of the flawed !e.target.isConnected heuristic.

Listen, relying on !e.target.isConnected is a fundamentally flawed heuristic! By blindly ignoring all clicks on disconnected targets, you are breaking expected behavior: if a click occurs on an element outside the popover that dynamically detaches itself (such as a 'Dismiss' toast button or a dynamic list item), this check swallows the event and the popover improperly stays open. You are merely masking the React 19 synchronous update issue while introducing a new bug.

Furthermore, if e.target happens to be the root html element or is disconnected, e.target.parentNode.classList.contains on line 99 will crash with a fatal TypeError!

Stop relying on brittle state and parent traversals. Use e.composedPath() to inspect the exact DOM path the event traversed at dispatch time—it is completely immune to subsequent node detachments.

💡 Proposed robust fix
   _checkExternalClick(e) {
-    // If the click target was detached from the DOM during this same click, it
-    // was an element inside the app that a React re-render replaced (e.g. an
-    // icon that swaps on click), not a genuine click outside the popover. Its
-    // ancestor chain is broken, so hasAncestor() below could not find the
-    // popover and would wrongly close it. Under React 19 discrete-event updates
-    // flush synchronously, so this detachment happens before this listener runs.
-    if (!e.target.isConnected) {
-      return;
-    }
     const { contentId } = this.props;
     const popoverWrapper = contentId ? document.getElementById(contentId) : this._popoverLayer;
-    const isChromeDropdown = e.target.parentNode.classList.contains('chromeDropdown');
-    // Find the inner popover element so on clicking inside it
-    // we can prevent external click function
-    const innerPopover = e.target.closest('[data-popover-type="inner"]');
+
+    // Retrieve the true event path, which remains intact even if elements detach
+    const path = typeof e.composedPath === 'function' ? e.composedPath() : [];
+    const isInsidePopover = path.length > 0 
+      ? path.includes(popoverWrapper) 
+      : hasAncestor(e.target, popoverWrapper, contentId);
+      
+    const isInnerPopover = path.length > 0
+      ? path.some(el => el.dataset && el.dataset.popoverType === 'inner')
+      : !!(e.target.closest && e.target.closest('[data-popover-type="inner"]'));
+      
+    const parentNode = path.length > 1 ? path[1] : e.target.parentNode;
+    const isChromeDropdown = !!(parentNode && parentNode.classList && parentNode.classList.contains('chromeDropdown'));
+
     if (
-      !hasAncestor(e.target, popoverWrapper, contentId) &&
-      !innerPopover &&
+      !isInsidePopover &&
+      !isInnerPopover &&
       this.props.onExternalClick &&
       !isChromeDropdown
     ) {
       this.props.onExternalClick(e);
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Popover/Popover.react.js` around lines 87 - 111, Replace the
disconnected-target early return in _checkExternalClick with event-path
inspection using e.composedPath(), preserving outside-click detection even when
targets detach after dispatch. Use the composed path to determine whether the
popover wrapper or inner popover was traversed, and replace the direct
e.target.parentNode.classList access with a null-safe path-based chromeDropdown
check so html or disconnected targets cannot cause a TypeError.
🧹 Nitpick comments (3)
src/lib/tests/BrowserCell.test.js (1)

16-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stop copy-pasting the act wrapper across all test files.

You have blindly copied and pasted the exact same renderComponent (and renderToJSON) helper function across five different test files! This is a flagrant violation of the DRY principle. As an AI agent, you might rely on heuristics and paste code everywhere to get tests passing, but I demand maintainable rationale. react-test-renderer is deprecated in React 19. When the inevitable migration to React Testing Library happens, your copy-paste spree will force developers to hunt down and painfully replace this helper in every single file. Centralize this logic immediately into a shared test utilities file and import it where needed.

  • src/lib/tests/BrowserCell.test.js#L16-L22: Extract renderComponent to a shared test-utils.js file and import it here.
  • src/lib/tests/BrowserRow.test.js#L9-L15: Remove this duplicate and import the shared helper.
  • src/lib/tests/Button.test.js#L16-L22: Remove this duplicate, import the shared helper, and adjust call sites to append .toJSON().
  • src/lib/tests/ConfigConflictDiff.test.js#L8-L14: Remove this duplicate and import the shared helper.
  • src/lib/tests/ScriptResponseModal.test.js#L33-L39: Remove this duplicate and import the shared helper.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/tests/BrowserCell.test.js` around lines 16 - 22, Centralize the
duplicated renderComponent helper in a shared test-utils.js file, preserving its
act-wrapped renderer.create behavior, then remove the local copies and import
the shared helper in src/lib/tests/BrowserCell.test.js#L16-L22,
src/lib/tests/BrowserRow.test.js#L9-L15, src/lib/tests/Button.test.js#L16-L22,
src/lib/tests/ConfigConflictDiff.test.js#L8-L14, and
src/lib/tests/ScriptResponseModal.test.js#L33-L39; update Button.test.js call
sites to append .toJSON(), and leave any renderToJSON usage consistent with the
shared utility as applicable.
src/dashboard/index.js (1)

17-20: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reorder import statements above require().

Your reliance on hoisting for module imports is sloppy. ES6 import statements are hoisted and executed before other code, so placing them after require() calls or other statements creates a misleading execution order and violates standard linting rules.

Move the import statements to the top of the file, above the require() call, to ensure execution order is transparent.

♻️ Proposed refactor
-require('stylesheets/fonts.scss');
-// GraphiQL 5 uses Monaco; register its web workers once before the app mounts.
-import 'graphiql/setup-workers/webpack';
-import 'graphiql/style.css';
+// GraphiQL 5 uses Monaco; register its web workers once before the app mounts.
+import 'graphiql/setup-workers/webpack';
+import 'graphiql/style.css';
+
+require('stylesheets/fonts.scss');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/dashboard/index.js` around lines 17 - 20, Move the
`graphiql/setup-workers/webpack` and `graphiql/style.css` import statements
above the `require('stylesheets/fonts.scss')` call in `src/dashboard/index.js`,
keeping the existing imports unchanged and placing all ES6 imports at the top of
the file.
src/dashboard/Data/ApiConsole/GraphQLConsole.react.js (1)

22-29: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Avoid mutating instance properties during render.

You are mutating this._fetcherKey and this._fetcher directly in the render path (via this.getFetcher()). This violates React's pure render rules. Under React 19's concurrent rendering, render may be interrupted or invoked multiple times before committing, leading to race conditions or inconsistent cache states.

Refactor this to derive the fetcher safely, either by migrating to a function component and using useMemo, or by updating state using componentDidUpdate / getDerivedStateFromProps.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/dashboard/Data/ApiConsole/GraphQLConsole.react.js` around lines 22 - 29,
Refactor GraphQLConsole’s getFetcher flow so render no longer mutates
_fetcherKey or _fetcher. Derive the fetcher with useMemo if converting to a
function component, or maintain it through state synchronized in
componentDidUpdate/getDerivedStateFromProps, while preserving URL and
parsed-header cache invalidation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/dashboard/Data/Browser/Browser.react.js`:
- Line 335: Move the schema fetch at
src/dashboard/Data/Browser/Browser.react.js:335 and the refresh logic at
src/dashboard/Data/Browser/Browser.react.js:433 out of the removed legacy
lifecycle methods into the appropriate componentDidMount/componentDidUpdate
methods, preserving their existing conditions and behavior; alternatively,
rename both lifecycle methods to their UNSAFE_ variants as a stopgap.

In `@src/lib/tests/e2e/dashboard.e2e.test.js`:
- Around line 91-96: Update the teardown in the test’s finally block to isolate
browser and server cleanup with nested finally blocks, ensuring server.close()
is attempted even when browser.close() fails. Await the server close callback
before completing teardown so the Express server is deterministically stopped.

---

Outside diff comments:
In `@src/components/Popover/Popover.react.js`:
- Around line 87-111: Replace the disconnected-target early return in
_checkExternalClick with event-path inspection using e.composedPath(),
preserving outside-click detection even when targets detach after dispatch. Use
the composed path to determine whether the popover wrapper or inner popover was
traversed, and replace the direct e.target.parentNode.classList access with a
null-safe path-based chromeDropdown check so html or disconnected targets cannot
cause a TypeError.

---

Nitpick comments:
In `@src/dashboard/Data/ApiConsole/GraphQLConsole.react.js`:
- Around line 22-29: Refactor GraphQLConsole’s getFetcher flow so render no
longer mutates _fetcherKey or _fetcher. Derive the fetcher with useMemo if
converting to a function component, or maintain it through state synchronized in
componentDidUpdate/getDerivedStateFromProps, while preserving URL and
parsed-header cache invalidation.

In `@src/dashboard/index.js`:
- Around line 17-20: Move the `graphiql/setup-workers/webpack` and
`graphiql/style.css` import statements above the
`require('stylesheets/fonts.scss')` call in `src/dashboard/index.js`, keeping
the existing imports unchanged and placing all ES6 imports at the top of the
file.

In `@src/lib/tests/BrowserCell.test.js`:
- Around line 16-22: Centralize the duplicated renderComponent helper in a
shared test-utils.js file, preserving its act-wrapped renderer.create behavior,
then remove the local copies and import the shared helper in
src/lib/tests/BrowserCell.test.js#L16-L22,
src/lib/tests/BrowserRow.test.js#L9-L15, src/lib/tests/Button.test.js#L16-L22,
src/lib/tests/ConfigConflictDiff.test.js#L8-L14, and
src/lib/tests/ScriptResponseModal.test.js#L33-L39; update Button.test.js call
sites to append .toJSON(), and leave any renderToJSON usage consistent with the
shared utility as applicable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d1d5a41d-19fa-4038-b1aa-a9c7e7ad1eff

📥 Commits

Reviewing files that changed from the base of the PR and between baeaf8d and 0e9b712.

📒 Files selected for processing (38)
  • .gitignore
  • package-lock.json
  • package.json
  • src/components/CategoryList/CategoryList.react.js
  • src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js
  • src/components/DataBrowserHeader/DataBrowserHeader.react.js
  • src/components/FileTree/FileTree.react.js
  • src/components/Popover/Popover.react.js
  • src/components/Sidebar/AppsMenu.react.js
  • src/components/Sidebar/SidebarHeader.react.js
  • src/components/Sidebar/SidebarSection.react.js
  • src/components/Sidebar/SidebarSubItem.react.js
  • src/components/Toolbar/Toolbar.react.js
  • src/dashboard/AppData.react.js
  • src/dashboard/Apps/AppsIndex.react.js
  • src/dashboard/Dashboard.js
  • src/dashboard/Data/ApiConsole/ApiConsole.react.js
  • src/dashboard/Data/ApiConsole/GraphQLConsole.react.js
  • src/dashboard/Data/Browser/Browser.react.js
  • src/dashboard/Data/Jobs/JobsData.react.js
  • src/dashboard/Data/Playground/Playground.react.js
  • src/dashboard/Push/PushDetails.react.js
  • src/dashboard/Settings/GeneralSettings.react.js
  • src/dashboard/index.js
  • src/lib/stores/StoreManager.js
  • src/lib/tests/BrowserCell.test.js
  • src/lib/tests/BrowserRow.test.js
  • src/lib/tests/Button.test.js
  • src/lib/tests/ConfigConflictDiff.test.js
  • src/lib/tests/ScriptResponseModal.test.js
  • src/lib/tests/e2e/dashboard.e2e.test.js
  • src/lib/withRouter.js
  • src/login/index.js
  • src/parse-interface-guide/PIG.react.js
  • src/parse-interface-guide/index.js
  • src/parse-interface-guide/routes.js
  • src/quickstart/index.js
  • webpack/base.config.js

Comment thread src/dashboard/Data/Browser/Browser.react.js Outdated
Comment thread src/lib/tests/e2e/dashboard.e2e.test.js
@mtrezza

mtrezza commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- relevant file outlines ---'
ast-grep outline src/dashboard/Push/PushDetails.react.js --items all --type function,method,class --view expanded || true
ast-grep outline src/components/Sidebar/AppsMenu.react.js --items all --type function,class --view expanded || true
ast-grep outline src/lib/htmlString.js --items all --type function --view expanded || true

echo '--- PushDetails cited ranges ---'
sed -n '450,505p' src/dashboard/Push/PushDetails.react.js

echo '--- AppsMenu imports and Link usage ---'
sed -n '1,55p' src/components/Sidebar/AppsMenu.react.js

echo '--- htmlString implementation ---'
fd -a '^htmlString\.(js|jsx)$' src | while IFS= read -r f; do
  echo "### $f"
  cat -n "$f"
done

echo '--- isolated fix commit ---'
git show --format=fuller --stat --oneline be8f5387
git show --format= --find-renames -- src/dashboard/Push/PushDetails.react.js be8f5387

echo '--- React test renderer declarations and active test imports ---'
rg -n -C2 '"react-test-renderer"|react-test-renderer' package.json src/lib/tests

Length of output: 10272


@mtrezza Confirmed.

  • be8f5387 correctly fixes both PushDetails rendering defects: the winner headline now interpolates statistics.winner, and the recipient-count message is included in subline.
  • The AppsMenu concern is invalid. html is imported from src/lib/htmlString.js; it is a tagged-template helper that returns a string, so the Link to prop is valid.
  • Retaining react-test-renderer@19.2.7 is acceptable for this migration. Its deprecation warrants a separate, scoped test-infrastructure effort rather than blocking the React 19 compatibility update.

Would you like me to open a follow-up GitHub issue for migrating the remaining react-test-renderer suite to React Testing Library?


✏️ Learnings added
Learnt from: mtrezza
URL: https://github.com/parse-community/parse-dashboard/pull/3409

Timestamp: 2026-07-18T05:49:11.334Z
Learning: In `src/components/Sidebar/AppsMenu.react.js`, `html` is intentionally imported from `src/lib/htmlString.js` and used as a tagged template for the React Router `Link` `to` prop. `htmlString` escapes interpolated values and returns a normal string; this is not an undefined identifier or a routing defect.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/lib/stores/StoreManager.js (1)

50-53: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Return newState from the synchronous dispatch branch.

You must return newState from the synchronous branch of dispatch below. It is inconsistent to return the updated state only when the action is asynchronous. Returning newState guarantees that callers can always access the freshest state regardless of the action type.

♻️ Proposed refactor
         for (const id in storeData.subscribers) {
           storeData.subscribers[id](newState);
         }
+        return newState;
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/stores/StoreManager.js` around lines 50 - 53, Update the synchronous
branch of dispatch in StoreManager so it returns newState after applying the
action, matching the asynchronous branch’s return value and ensuring callers
always receive the freshest state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/dashboard/Data/Browser/Browser.react.js`:
- Line 1864: Handle all three Promise chains in Browser.react.js: update the
chain at lines 1864-1864 to return the chained promise while preserving the
fetched data for callers, and append rejection handlers to the chains at lines
335-335 and 433-433 that log errors with console.error to prevent unhandled
rejections.

In `@src/lib/tests/e2e/dashboard.e2e.test.js`:
- Around line 101-105: Update the server teardown in the finally block to call
server.closeAllConnections() before awaiting server.close(). Preserve the
existing close callback’s rejection and resolution behavior while ensuring
lingering connections are forcibly terminated.

---

Nitpick comments:
In `@src/lib/stores/StoreManager.js`:
- Around line 50-53: Update the synchronous branch of dispatch in StoreManager
so it returns newState after applying the action, matching the asynchronous
branch’s return value and ensuring callers always receive the freshest state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 57f1351c-b070-462e-ad0b-ee15308a1ada

📥 Commits

Reviewing files that changed from the base of the PR and between baeaf8d and be8f538.

📒 Files selected for processing (39)
  • .gitignore
  • package-lock.json
  • package.json
  • src/components/CategoryList/CategoryList.react.js
  • src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js
  • src/components/DataBrowserHeader/DataBrowserHeader.react.js
  • src/components/FileTree/FileTree.react.js
  • src/components/Popover/Popover.react.js
  • src/components/Sidebar/AppsMenu.react.js
  • src/components/Sidebar/SidebarHeader.react.js
  • src/components/Sidebar/SidebarSection.react.js
  • src/components/Sidebar/SidebarSubItem.react.js
  • src/components/Toolbar/Toolbar.react.js
  • src/dashboard/AppData.react.js
  • src/dashboard/Apps/AppsIndex.react.js
  • src/dashboard/Dashboard.js
  • src/dashboard/Data/ApiConsole/ApiConsole.react.js
  • src/dashboard/Data/ApiConsole/GraphQLConsole.react.js
  • src/dashboard/Data/Browser/Browser.react.js
  • src/dashboard/Data/Jobs/JobsData.react.js
  • src/dashboard/Data/Playground/Playground.react.js
  • src/dashboard/Push/PushDetails.react.js
  • src/dashboard/Settings/GeneralSettings.react.js
  • src/dashboard/index.js
  • src/lib/stores/StoreManager.js
  • src/lib/tests/BrowserCell.test.js
  • src/lib/tests/BrowserRow.test.js
  • src/lib/tests/Button.test.js
  • src/lib/tests/ConfigConflictDiff.test.js
  • src/lib/tests/ScriptResponseModal.test.js
  • src/lib/tests/e2e/dashboard.e2e.test.js
  • src/lib/tests/renderWithAct.js
  • src/lib/withRouter.js
  • src/login/index.js
  • src/parse-interface-guide/PIG.react.js
  • src/parse-interface-guide/index.js
  • src/parse-interface-guide/routes.js
  • src/quickstart/index.js
  • webpack/base.config.js

Comment thread src/dashboard/Data/Browser/Browser.react.js Outdated
Comment thread src/lib/tests/e2e/dashboard.e2e.test.js
- Browser: attach a .catch to the fire-and-forget FETCH dispatch chains and
  return the chained promise from handleCLPChange (instead of a discarded
  side-effect chain), so a dispatch rejection surfaces via the caller instead of
  leaking as an unhandled rejection.
- e2e: call server.closeAllConnections() (when available) before server.close()
  so teardown can't hang on a socket left open by a failed browser close.
@mtrezza

mtrezza commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/parse-interface-guide/index.js (1)

10-10: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stop conflating React components with instantiated React elements.

You are clearly relying on a flawed heuristic that all React imports must be capitalized. The ./routes module exports an instantiated JSX element (<BrowserRouter>...</BrowserRouter>), not a component function. Naming it Routes with a capital "R" falsely signals to human developers that it is a component. Lowercase this import to routes to reflect reality and prevent cognitive dissonance when reading root.render(routes).

♻️ Proposed refactor
-import Routes from './routes';
+import routes from './routes';
 
 // App entry point
 
 const root = createRoot(document.getElementById('browser_mount'));
-root.render(Routes);
+root.render(routes);

Also applies to: 14-15

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/parse-interface-guide/index.js` at line 10, Rename the imported JSX
element from Routes to routes in the import declaration and update all
references in the affected render flow, including root.render, so the
instantiated element is consistently lowercase while preserving behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/parse-interface-guide/index.js`:
- Line 10: Rename the imported JSX element from Routes to routes in the import
declaration and update all references in the affected render flow, including
root.render, so the instantiated element is consistently lowercase while
preserving behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1606ef01-2e68-4ee3-9e8c-529ac1900abf

📥 Commits

Reviewing files that changed from the base of the PR and between baeaf8d and ae5299d.

📒 Files selected for processing (39)
  • .gitignore
  • package-lock.json
  • package.json
  • src/components/CategoryList/CategoryList.react.js
  • src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js
  • src/components/DataBrowserHeader/DataBrowserHeader.react.js
  • src/components/FileTree/FileTree.react.js
  • src/components/Popover/Popover.react.js
  • src/components/Sidebar/AppsMenu.react.js
  • src/components/Sidebar/SidebarHeader.react.js
  • src/components/Sidebar/SidebarSection.react.js
  • src/components/Sidebar/SidebarSubItem.react.js
  • src/components/Toolbar/Toolbar.react.js
  • src/dashboard/AppData.react.js
  • src/dashboard/Apps/AppsIndex.react.js
  • src/dashboard/Dashboard.js
  • src/dashboard/Data/ApiConsole/ApiConsole.react.js
  • src/dashboard/Data/ApiConsole/GraphQLConsole.react.js
  • src/dashboard/Data/Browser/Browser.react.js
  • src/dashboard/Data/Jobs/JobsData.react.js
  • src/dashboard/Data/Playground/Playground.react.js
  • src/dashboard/Push/PushDetails.react.js
  • src/dashboard/Settings/GeneralSettings.react.js
  • src/dashboard/index.js
  • src/lib/stores/StoreManager.js
  • src/lib/tests/BrowserCell.test.js
  • src/lib/tests/BrowserRow.test.js
  • src/lib/tests/Button.test.js
  • src/lib/tests/ConfigConflictDiff.test.js
  • src/lib/tests/ScriptResponseModal.test.js
  • src/lib/tests/e2e/dashboard.e2e.test.js
  • src/lib/tests/renderWithAct.js
  • src/lib/withRouter.js
  • src/login/index.js
  • src/parse-interface-guide/PIG.react.js
  • src/parse-interface-guide/index.js
  • src/parse-interface-guide/routes.js
  • src/quickstart/index.js
  • webpack/base.config.js

./routes exports an instantiated <BrowserRouter> element, not a component, so
importing it as Routes (and colliding with react-router's Routes) misleads;
name it routes to match what it is.
@mtrezza

mtrezza commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@mtrezza

mtrezza commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

The remaining nitpick (src/parse-interface-guide/index.js:10) is addressed in fda59c6: ./routes default-exports an instantiated <BrowserRouter> element (named routes internally), so the import is now lowercase routes with root.render(routes) — matching what it is and avoiding the visual collision with react-router's Routes. All review comments should now be addressed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/dashboard/index.js`:
- Around line 17-21: Move the GraphiQL worker and stylesheet imports above the
stylesheets/fonts.scss require in the module so all import declarations appear
before require-based initialization. Preserve the existing import contents and
installDevTools(Immutable) behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 72696b35-724c-4cf4-a5b1-7227d27032c2

📥 Commits

Reviewing files that changed from the base of the PR and between baeaf8d and fda59c6.

📒 Files selected for processing (39)
  • .gitignore
  • package-lock.json
  • package.json
  • src/components/CategoryList/CategoryList.react.js
  • src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js
  • src/components/DataBrowserHeader/DataBrowserHeader.react.js
  • src/components/FileTree/FileTree.react.js
  • src/components/Popover/Popover.react.js
  • src/components/Sidebar/AppsMenu.react.js
  • src/components/Sidebar/SidebarHeader.react.js
  • src/components/Sidebar/SidebarSection.react.js
  • src/components/Sidebar/SidebarSubItem.react.js
  • src/components/Toolbar/Toolbar.react.js
  • src/dashboard/AppData.react.js
  • src/dashboard/Apps/AppsIndex.react.js
  • src/dashboard/Dashboard.js
  • src/dashboard/Data/ApiConsole/ApiConsole.react.js
  • src/dashboard/Data/ApiConsole/GraphQLConsole.react.js
  • src/dashboard/Data/Browser/Browser.react.js
  • src/dashboard/Data/Jobs/JobsData.react.js
  • src/dashboard/Data/Playground/Playground.react.js
  • src/dashboard/Push/PushDetails.react.js
  • src/dashboard/Settings/GeneralSettings.react.js
  • src/dashboard/index.js
  • src/lib/stores/StoreManager.js
  • src/lib/tests/BrowserCell.test.js
  • src/lib/tests/BrowserRow.test.js
  • src/lib/tests/Button.test.js
  • src/lib/tests/ConfigConflictDiff.test.js
  • src/lib/tests/ScriptResponseModal.test.js
  • src/lib/tests/e2e/dashboard.e2e.test.js
  • src/lib/tests/renderWithAct.js
  • src/lib/withRouter.js
  • src/login/index.js
  • src/parse-interface-guide/PIG.react.js
  • src/parse-interface-guide/index.js
  • src/parse-interface-guide/routes.js
  • src/quickstart/index.js
  • webpack/base.config.js

Comment thread src/dashboard/index.js Outdated
…ard entry

The graphiql side-effect imports hoist above require('stylesheets/fonts.scss')
regardless of placement; move them up with the other imports so the written
order matches evaluation order. fonts.scss is only Google-Font @imports, so the
cascade is unaffected.
@mtrezza

mtrezza commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/dashboard/Push/PushDetails.react.js (1)

488-502: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix the glaring typo in the React key.

You have explicitly hardcoded key="sublime_2" in two separate branches here, while your other siblings use subline_0, subline_1, and subline_3. Relying on a heuristic like "it's unique so it works" is a poor excuse for shipping glaring typos in your React keys. Fix it so it properly reads subline_2 and aligns with the rest of the array's sequence.

🛠️ Proposed typo fix
       if (pushDetails.launch_info && pushDetails.launch_info.recipient_count) {
         subline.push(
-          <div key="sublime_2">
+          <div key="subline_2">
             Your Launch Group is <strong>{pushDetails.launch_info.percent}%</strong> (approximately{' '}
             <strong>{prettyNumber(pushDetails.launch_info.recipient_count)}</strong>) of the devices
             in this campaign. {launchGroupFragment}
           </div>
         );
       } else {
         subline.push(
-          <div key="sublime_2">
+          <div key="subline_2">
             Your Launch Group is <strong>{pushDetails.launch_info.percent}%</strong> of the devices
             in this campaign. {launchGroupFragment}
           </div>
         );
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/dashboard/Push/PushDetails.react.js` around lines 488 - 502, Correct the
hardcoded React key in both branches of the launch-group rendering within the
subline construction so it uses “subline_2” instead of the misspelled
“sublime_2”, preserving the existing key sequence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/tests/e2e/dashboard.e2e.test.js`:
- Around line 75-78: Configure Puppeteer operations in the dashboard test’s
setup around browser.launch and page.goto with explicit timeouts below the
20-second Jest timeout, such as 15 seconds, so failures reject before Jest
aborts and the existing finally cleanup executes.

---

Nitpick comments:
In `@src/dashboard/Push/PushDetails.react.js`:
- Around line 488-502: Correct the hardcoded React key in both branches of the
launch-group rendering within the subline construction so it uses “subline_2”
instead of the misspelled “sublime_2”, preserving the existing key sequence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c7cfd6f4-e0b3-414b-a7d5-a01b38a08644

📥 Commits

Reviewing files that changed from the base of the PR and between baeaf8d and 31b9fdd.

📒 Files selected for processing (39)
  • .gitignore
  • package-lock.json
  • package.json
  • src/components/CategoryList/CategoryList.react.js
  • src/components/ColumnsConfiguration/ColumnConfigurationItem.react.js
  • src/components/DataBrowserHeader/DataBrowserHeader.react.js
  • src/components/FileTree/FileTree.react.js
  • src/components/Popover/Popover.react.js
  • src/components/Sidebar/AppsMenu.react.js
  • src/components/Sidebar/SidebarHeader.react.js
  • src/components/Sidebar/SidebarSection.react.js
  • src/components/Sidebar/SidebarSubItem.react.js
  • src/components/Toolbar/Toolbar.react.js
  • src/dashboard/AppData.react.js
  • src/dashboard/Apps/AppsIndex.react.js
  • src/dashboard/Dashboard.js
  • src/dashboard/Data/ApiConsole/ApiConsole.react.js
  • src/dashboard/Data/ApiConsole/GraphQLConsole.react.js
  • src/dashboard/Data/Browser/Browser.react.js
  • src/dashboard/Data/Jobs/JobsData.react.js
  • src/dashboard/Data/Playground/Playground.react.js
  • src/dashboard/Push/PushDetails.react.js
  • src/dashboard/Settings/GeneralSettings.react.js
  • src/dashboard/index.js
  • src/lib/stores/StoreManager.js
  • src/lib/tests/BrowserCell.test.js
  • src/lib/tests/BrowserRow.test.js
  • src/lib/tests/Button.test.js
  • src/lib/tests/ConfigConflictDiff.test.js
  • src/lib/tests/ScriptResponseModal.test.js
  • src/lib/tests/e2e/dashboard.e2e.test.js
  • src/lib/tests/renderWithAct.js
  • src/lib/withRouter.js
  • src/login/index.js
  • src/parse-interface-guide/PIG.react.js
  • src/parse-interface-guide/index.js
  • src/parse-interface-guide/routes.js
  • src/quickstart/index.js
  • webpack/base.config.js

Comment thread src/lib/tests/e2e/dashboard.e2e.test.js Outdated
…n test

launch/goto/waitForSelector defaulted to 30s while the Jest test timeout is 20s,
so a hang would let Jest abort before the finally block runs, leaking the Express
server. Cap launch/goto at 15s and waitForSelector at 10s so any hang rejects in
time for cleanup.
@mtrezza

mtrezza commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@mtrezza
mtrezza merged commit c3e16c2 into parse-community:alpha Jul 18, 2026
11 checks passed
parseplatformorg pushed a commit that referenced this pull request Jul 18, 2026
# [9.3.0-alpha.1](9.2.1-alpha.1...9.3.0-alpha.1) (2026-07-18)

### Features

* React 19 + react-router 7 + GraphiQL 5 coordinated upgrade ([#3409](#3409)) ([c3e16c2](c3e16c2))
@parseplatformorg

Copy link
Copy Markdown
Contributor

🎉 This change has been released in version 9.3.0-alpha.1

@parseplatformorg parseplatformorg added the state:released-alpha Released as alpha version label Jul 18, 2026
@mtrezza
mtrezza deleted the chore/react19-router7-graphiql5 branch July 18, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state:released-alpha Released as alpha version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Coordinated upgrade: React 19 + react-router 7 + GraphiQL 5

2 participants