vogievetsky opened a new pull request, #20448:
URL: https://github.com/apache/druid/pull/20448

   ### A note from the human
   
   So after looking at how well Claude Code running Opus 5.5 performed on 
https://github.com/apache/druid/pull/20421 I was sufficiently impressed to 
attempt an ambitious goal: update the console to all the latest dependencies as 
if the project was started today. I asked Claude to make me a "Command and 
Conquer" tech tree of updates that need to be made.
   
   <img width="458" height="326" alt="image" 
src="https://github.com/user-attachments/assets/95ccce29-c515-43c7-bb0d-de287e699242";
 />
   
   I then had Claude work through them one by one (see the order of the commits 
in this PR). I am extremely pleased with the result. The styling was all kept 
pixel perfect. Claude even fixed some bugs along the way. Maybe in a subsequent 
PR we can relax the style overrides and lean in more into the new Blueprint v6 
style but for this PR I wanted pixel perfection as a goal for Claude.
   
   I decided to combine all these changes into one mega PR because a lot of 
these changes were huge on their own and this mega PR is not that much more 
complex in aggregate. I realize this will create a huge merge conflict if 
someone (like me!) has a fork or feature branch with web console changes in it, 
I have therefore **included a prompt** at the bottom of the description that 
you should use to agenticaly migrate your feature branch to the new stuff. If 
you use Opus 5.5 I am confident it will one-shot it.
   
   > Human out
   
   ---
   
   ### Description
   
   This PR moves the web console onto the current major versions of its 
framework and tooling: React 19, Blueprint 6, TypeScript 6, Ace 1.44, Prettier 
3 and Node 24. It also replaces the libraries that have no React 19 support: 
React Router, react-table v6, react-shallow-renderer and react-diff-viewer. 
Blueprint 6 is restyled to look exactly like the Blueprint 5 console, so none 
of this should be visible to users, apart from the bug fixes listed at the end.
   
   The branch is a series of self-contained commits, one per migration, and 
each one builds and passes the tests on its own. Reviewing commit by commit is 
recommended.
   
   #### React 19
   
   - `react` / `react-dom` / types 18.3 → 19.3; the `@types/react` npm override 
is gone.
   - `forwardRef` removed in favor of `ref` as a prop (`SqlInput`, 
`FlexibleQueryInput`, `FilterPane`, `DroppableContainer`); `useRef` calls get 
an explicit initial value; ref callbacks no longer return a value; `<Context 
value>` instead of `<Context.Provider value>`.
   - The React Compiler lint rules `react-hooks/refs` and 
`react-hooks/set-state-in-effect` (disabled with TODOs in the previous upgrade) 
are back on, and the hooks (`useConstant`, `useLastDefined`, 
`useLastDefinedDeep`, `useMemoWithPrevious`, `useQueryManager`) and components 
no longer read refs during render or set state in effects.
   - Every `react-hooks/exhaustive-deps` suppression and warning is replaced 
with `useEffectEvent` or with the correct dependencies. There are no lint 
suppressions left.
   
   #### Libraries replaced because they do not support React 19
   
   - **react-table v6 → `ConsoleTable`** (`src/components/console-table`), 
built on TanStack Table v9. Its props are a drop-in replacement for how the 
console used react-table (`Header`, `accessor`, `Cell`, `Aggregated`, `show`, 
`pivotBy`, `SubComponent`, `manual`, `sorted`, `filtered`, `page`…). The 
rendered DOM keeps react-table's structure with `.ReactTable` / `rt-*` renamed 
to `.console-table` / `ct-*` (`rt-noData` → `ct-no-data`). Cell render props 
are now typed with the row type, expanded groups no longer collapse whenever 
the parent re-renders, and changes to `defaultPageSize` are now applied. 
`bootstrapReactTable` is gone.
   - **React Router 5 → a small hash router** (`src/utils/hash-routing.ts`, 
routing in `ConsoleApplication.renderView`). React Router 6+ has no "noslash" 
hash mode and decodes route params, so upgrading would have changed every 
console URL and broken table filters containing an encoded `&`, `%` or `/`. The 
existing semantics are kept: `#view/param` URLs, `decodeURI` of the path, 
case-insensitive views, `#/view` normalized to `#view`, the ingestion and query 
redirects, and capability-gated views.
   - **react-shallow-renderer → React Testing Library.** The 36 specs that used 
shallow rendering now do full renders. A DOM snapshot serializer 
(`src/test-utils/snapshot-serializer.ts`) and component stubs 
(`src/test-utils/stub-component.tsx`, including `consoleTableStub`) keep 
snapshots roughly as small as the shallow ones. `script/mkcomp` generates RTL 
specs.
   - **react-diff-viewer → react-diff-viewer-continued**, pinned to `~4.0.6`: 
4.1+ pulls in `js-yaml`/`argparse` (Python-2.0 license, not in the allowlist), 
and 4.4 adds syntax highlighting, a web worker and lazy chunks (+109 KB).
   - **Popover → PopoverNext.** The legacy Blueprint `Popover` is built on 
react-popper, which does not support React 19. All 80 usages move to 
`PopoverNext` (`position` → `placement`, `minimal` → `animation="minimal" 
arrow={false}`). They keep `lazy` and `shouldReturnFocusOnClose={false}`, the 
legacy defaults the console relies on.
   
   #### Blueprint 6
   
   - `@blueprintjs/core`, `icons`, `select` and `datetime` → 6. `datetime2` is 
removed (`DateRangePicker3` → `DateRangePicker`).
   - The CSS namespace changes from `bp5` to `bp6`.
   - `AppToaster.show` stays synchronous even though `OverlayToaster.create` is 
now async.
   - Blueprint 6's CSS design tokens are mapped onto the console palette and 
typography. The mapping is generated by 
`script/generate-blueprint-token-overrides.mjs`.
   - `src/blueprint-overrides/_blueprint5-look.scss` restores the Blueprint 5 
metrics and dark theme the console was designed with. It was checked against 
the previous build with computed-style and screenshot diffs.
   - Deprecated props are migrated:
     - `minimal` → `variant="minimal"`
     - `small` / `large` → `size`
     - `rightIcon` → `endIcon`
     - `Alignment.LEFT` / `RIGHT` → `START` / `END`
     - `Keys` / `keyCode` → `key`
   - `@typescript-eslint/no-deprecated` is now on, so new usages of deprecated 
APIs fail the lint.
   
   #### Ace 1.5 → 1.44, react-ace 10 → 15
   
   - Completers are now created once and read the latest props. Ace only uses 
the first completers it is given, so completions used to be stuck with the 
props of the first render. For example, the workbench offered no column 
completions after column metadata loaded.
   - The `dsql` and `hjson` modes are now classes built on Ace's `TextMode` and 
registered once. `initAceDsqlMode` resets the cached mode so later editors get 
the cluster's functions.
   - Functions with several signatures use the completion caption. Sub-query 
gutter markers work whatever element is under the mouse. The doc tooltip keeps 
its look.
   - Snapshots describe each Ace editor (mode, value, placeholder) instead of 
Ace's DOM.
   
   #### TypeScript, Sass, Prettier, Node
   
   - **TypeScript 5.5 → 6.0**:
     - `moduleResolution` is `bundler` instead of `node`.
     - `types` is `["jest"]`.
     - `target` is es2022.
     - `lib` is `dom` + `esnext`.
     - `experimentalDecorators` is removed.
     - `regenerator-runtime` is removed.
   - **Sass `@import` → `@use`:**
     - Components `@use` the `variables` module, which forwards the palette and 
the Blueprint variable overrides.
     - Blueprint's own sources still use `@import`, so they are loaded with 
`meta.load-css()` (`src/blueprint-overrides/_blueprint.scss`).
     - The compiled CSS is unchanged, and the build no longer prints Sass 
warnings.
   - **Prettier 2 → 3.9** with `@awesome-code-style/prettier-config` 5. The 
code is reformatted with the new defaults (for example, nested ternaries are 
now indented).
   - **Node 22.23.3 → 24.21.0 and npm 10.9.9 → 11.19.0** in `pom.xml` and 
`volta`, with `engines` set to `>=24`.
     - `license-checker-rseidelsohn` is replaced by its successor 
`@lizenz/checker`. `licenses.yaml` is unchanged by that switch.
     - An npm 11 `allowScripts` entry allows `playwright-chromium`, and denies 
the prebuilt-binary fallbacks of `@parcel/watcher` and `unrs-resolver`.
   
   #### Housekeeping
   
   - **Upgraded:**
     - memoize-one 6
     - copy-to-clipboard 4 (clipboard writes go through a `copyToClipboard` 
helper that keeps the prompt fallback)
     - @flatten-js/interval-tree 2
     - zustand 5
     - uuid 14
     - globals 17
     - postcss-preset-env 11
   - **Removed as unused:**
     - `date-fns`
     - `@types/enzyme*`
     - `ts-node`
     - `fs-extra`
   - **Gitignore:** top-level `*.jpeg` files (the e2e tests write their error 
screenshots there) are now ignored.
   
   #### Bug fixes that came out of the migrations
   
   - Workbench SQL completions now include columns once their metadata loads 
(the stale Ace completers described above).
   - Pie chart: a second click on a slice now closes its bubble. The click 
handler used to read a stale highlight.
   - Explore grouping table: it now re-runs when the module filter changes 
(`moduleWhere` was missing from the memo dependencies).
   - Tables: expanded groups no longer collapse on unrelated re-renders.
   - Execution stages: a missing React `key` in the sort stats cell is fixed.
   
   #### Not upgraded
   
   - ESLint 10 is blocked by `eslint-plugin-react`.
   - stylelint 17 is blocked by the Blueprint stylelint plugin.
   - TypeScript 7 is blocked by typescript-eslint and ts-jest.
   - react-diff-viewer-continued stays on 4.0.x for the license and bundle size 
reasons above.
   
   #### Testing
   
   - `npm test` passes: typecheck, ESLint (0 warnings), Prettier and stylelint, 
plus 162 suites with 806 tests and 248 snapshots.
   - The production build has no warnings, and `npm run check-licenses` passes.
   - E2E against a local Druid through the dev server: all 5 specs pass. 
`multi-stage-query` can fail when run alongside the other specs with a "not 
enough task slots" dialog, because of their concurrent ingestion tasks. It 
passes on its own and fails the same way against the master console.
   - Every view was compared against the master console with computed-style and 
screenshot diffs, in addition to manual testing of tables (sorting, filtering, 
pivoting, pagination, resizing), popovers and menus, the SQL editor and 
completions, the data loaders and the Explore charts.
   
   <hr>
   
   This PR has:
   
   - [x] been self-reviewed.
   - [x] added or updated version, license, or notice information in 
[licenses.yaml](https://github.com/apache/druid/blob/master/dev/license.md)
   - [x] added comments explaining the "why" and the intent of the code 
wherever would not be obvious for an unfamiliar reader.
   - [x] added unit tests or modified existing tests to cover new code paths, 
ensuring the threshold for [code 
coverage](https://github.com/apache/druid/blob/master/dev/code-review/code-coverage.md)
 is met.
   - [x] been tested in a test Druid cluster.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   
   ---
   
   ## Prompt for migrating a fork or feature branch
   
   > Copy everything below into a Claude Code session opened at the root of the 
fork's Druid checkout.
   
   You are migrating the Apache Druid web console code in this repository 
(`web-console/`) so it builds on top of an upstream change that moved the 
console to React 19, Blueprint 6, TypeScript 6, Ace 1.44, Prettier 3, Sass 
modules, a custom hash router, a custom `ConsoleTable` (instead of react-table 
v6), React Testing Library (instead of shallow rendering) and Node 24. The fork 
or feature branch adds its own code (for example new views, components, dialogs 
or Explore modules) that was written against the old stack. Your job is to 
bring that code up to the new stack with **no visual or behavioral changes**, 
and without changing the upstream code except where the feature genuinely needs 
a hook into it.
   
   **Getting set up**
   
   1. Find the upstream merge commit of the migration (search `git log` on 
upstream master for "feat: Web console: upgrade to the latest and greatest" and 
the neighboring "Web console:" commits). Read the upstream 
`web-console/CLAUDE.md` and the PR description for that change. List the fork's 
own web-console changes with `git diff <merge-base> <fork-branch> -- 
web-console` so you know exactly which files are the fork's.
   2. Merge or rebase onto the new upstream. For conflicts in files the fork 
only touched lightly, take upstream and re-apply the fork's intent on top; do 
not try to keep the old versions of upstream files.
   3. Use Node 24 (`volta pin [email protected] [email protected]` inside `web-console/` 
if Volta is used; never `volta install`, which changes the user's global 
default). Run `npm ci`. If the fork added dependencies, check that they support 
React 19; if they need install scripts, npm 11 requires them to be listed in 
`allowScripts` in `package.json`.
   
   **Migration checklist (apply to every fork-owned file)**
   
   - **Tables:** `react-table` is gone. Replace `ReactTable` with 
`ConsoleTable` from `src/components` (`console-table/console-table.tsx`). The 
props deliberately mirror react-table v6 (`data`, `columns`, `Header`, 
`accessor`, `Cell`, `Aggregated`, `Filter`, `filterMethod`, `sortMethod`, 
`show`, `width`, `pivotBy`, `SubComponent`, `manual`, `pages`, 
`sorted`/`onSortedChange`, `filtered`/`onFilteredChange`, 
`page`/`onPageChange`, `pageSize`/`onPageSizeChange`, `defaultPageSize`, 
`noDataText`…), so most conversions are a rename plus types: use 
`ConsoleTableColumn<Row>` and `ConsoleTableCellInfo<Row>` instead of 
`Column`/`CellInfo`/`RowInfo`, and drop `any` in cell render props. Props that 
`ConsoleTable` does not support (for example `getTrProps`/`getTdProps`) need a 
different approach; read the component before adding anything to it. In SCSS 
and e2e selectors, `.ReactTable` → `.console-table`, `.rt-*` → `.ct-*` 
(`rt-tbody` → `ct-tbody`, `rt-tr-group` → `ct-tr-group`, `rt-noDa
 ta` → `ct-no-data`, …), while react-table's `-odd`, `-padRow`, `-sort-asc`, 
`-filters`, `-pagination`… modifier classes keep their names. Anything that 
used `bootstrapReactTable` or react-table defaults should rely on the defaults 
built into `ConsoleTable`.
   - **Routing:** `react-router` / `react-router-dom` are gone. A new top-level 
view is a `case '<view>':` in `ConsoleApplication.renderView()` 
(`src/console-application.tsx`), gated on capabilities like its neighbors, and 
it gets its URL param (if any) as a prop from `parseHashRoute(hashPath).param`. 
Do not add `RouteComponentProps`, `Link`, `useHistory`, `withRouter` or 
`useParams`; navigate by setting `location.hash` (for example `location.hash = 
'my-view/' + param`) the way the existing views do. The URL format is unchanged 
(`#view/param`, no leading slash, case-insensitive view, `decodeURI` applied to 
the path). New redirects go in `REDIRECTS`. Add a header bar entry if the view 
needs one (`src/components/header-bar`).
   - **React 19:**
     - Replace `forwardRef` with `ref` as a regular prop.
     - Give every `useRef` an initial value (`useRef<T>(undefined)`).
     - Ref callbacks must not return a value, so use `el => { x = el; }`.
     - Use `<SomeContext value={…}>` instead of `<SomeContext.Provider 
value={…}>`.
     - Drop `defaultProps` on function components and remove string refs.
     - The React Compiler lint rules are on:
       - Do not read `ref.current` during render.
       - Do not call `setState` synchronously in an effect body. Derive the 
value during render, move the update to the event handler, or use the existing 
hooks (`useLastDefined`, `useMemoWithPrevious`, `useQueryManager`…).
       - Where an effect needs the latest props or state without re-running, 
wrap that logic in `useEffectEvent` and call it from the effect, or from a 
callback the effect registers (as the Explore chart modules do for ECharts 
handlers).
     - Fix `react-hooks/exhaustive-deps` warnings properly instead of 
suppressing them. Upstream has zero suppressions, so keep it that way.
   - **Blueprint 6:**
     - Class names are `bp6-*`. In SCSS use `#{$bp-ns}`, never a hard-coded 
`bp5`.
     - Replace `Popover` with `PopoverNext`, keeping the console defaults: 
`lazy` and `shouldReturnFocusOnClose={false}`. `position` becomes `placement`, 
and `minimal` becomes `animation="minimal" arrow={false}`. Copy the props from 
an existing upstream usage.
     - Button, tag and input props:
       - `minimal` → `variant="minimal"`
       - `small` / `large` → `size="small"` / `"large"`
       - `rightIcon` → `endIcon`
     - `Alignment.LEFT` / `RIGHT` → `START` / `END`.
     - `DateRangePicker3` from `@blueprintjs/datetime2` → `DateRangePicker` 
from `@blueprintjs/datetime`.
     - Use `event.key` instead of `Keys` / `keyCode`.
     - `@typescript-eslint/no-deprecated` is an error, so the linter will find 
the leftovers.
     - Toasts still go through `AppToaster.show(...)` synchronously.
     - Don't restyle Blueprint components locally to make them "look right". 
The Blueprint 5 look is restored globally in 
`src/blueprint-overrides/_blueprint5-look.scss`, so fix a mismatch there, and 
only if it's a genuine gap that affects upstream components too.
   - **Sass:**
     - `@import` is gone. Start each component stylesheet with `@use '<relative 
path>/variables' as *;` (see any upstream component `.scss`), and add `@use 
'sass:math';` etc. for built-in modules (`math.div` instead of `/`).
     - Blueprint variables and mixins that used to leak in as globals come from 
the `variables` module (it forwards the colors, color aliases and Blueprint 
variable overrides). If one is missing, add it to 
`src/blueprint-overrides/common/` rather than redefining it locally.
     - The build must produce no Sass warnings.
   - **Ace:**
     - The editor is ace-builds 1.44 with react-ace 15. Remove `editorProps={{ 
$blockScrolling: … }}` and the `any` casts around Ace types.
     - Custom completers must be created once and read the current props 
through a ref or `useEffectEvent`, because Ace keeps only the first completers 
it is given. Reuse the upstream SQL completer setup instead of writing a 
parallel one.
     - Custom modes follow the class-based pattern in `src/ace-modes/`.
   - **Other upgraded libraries:**
     - `uuid` 14 is ESM only; import `{ v4 as uuidv4 }`.
     - `zustand` 5 uses named imports (upstream uses `createStore` plus 
`useStore(store, selector)`), and has no default export.
     - `memoize-one` 6 is a default import.
     - Clipboard writes go through the upstream `copyToClipboard` helper, not 
`copy-to-clipboard` directly.
     - `date-fns` is no longer a dependency. Use the existing `src/utils/date` 
helpers or `instanceof Date`.
     - For diffs, use `react-diff-viewer-continued` (keep it on `~4.0.6`).
     - Import `saveAs` from `file-saver` as a named import.
   - **Tests:**
     - Shallow rendering is gone. Specs use `render` from 
`@testing-library/react` and snapshot `container.firstChild`. Mock heavy 
children with `jest.mock(path, () => 
jest.requireActual('<rel>/test-utils/stub-component').consoleTableStub)` or 
`stubComponent('Name')`.
     - The global DOM snapshot serializer reduces icons to their names and 
collapses padding rows.
     - Ace modes are registered in `src/setup-tests.ts`.
     - Tests that depend on time must fake the clock, and tests that trigger 
network requests must mock them, so full renders stay quiet and deterministic.
     - Regenerate the fork's snapshots with `npm run update-snapshots`, then 
read the snapshot diffs to confirm only the expected structure changed.
     - In e2e (Playwright), use `fill` instead of `type` and the new 
`bp6-`/`ct-` selectors.
   - **TypeScript 6 and formatting:**
     - `moduleResolution: bundler` needs explicit file extensions only for 
non-TS assets; side-effect style imports are type-checked through the existing 
module declarations.
     - `target` is es2022, so class fields use define semantics. A subclass 
that re-declares a field set by its parent constructor must use `declare`.
     - Run `npm run autofix` for Prettier 3 formatting instead of fixing the 
format by hand.
   
   **Verification (do all of it, report honestly)**
   
   1. `npm test` passes in `web-console/`, which runs the typecheck, ESLint (0 
warnings), Prettier, stylelint and all Jest suites. `npm run build` (or 
`script/build`) must also compile with no warnings, and `npm run 
check-licenses` must pass. For any new dependency, update `licenses.yaml` at 
the repo root.
   2. Start the dev server on a free port (`npx webpack serve --port <port> 
--no-open`) against a Druid cluster. Don't touch dev servers other people 
started, and only kill processes you started.
   3. For every fork-owned view, dialog and component, compare the migrated 
build against the fork's pre-migration build, side by side. Use Playwright to 
check computed styles and take screenshots, and exercise the interactions by 
hand: tables (sort, filter, pivot, paginate, resize, expand), popovers and 
menus (open, close, focus), keyboard handling, editors and completions, and URL 
deep links, including params with encoded `&`, `%` and `/`.
   4. Report any visual or behavioral difference you could not remove, along 
with its cause. Don't commit or push unless asked.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to