fix(block-editor): server-side search for content-type & contentlet pickers - #36488
Conversation
…ntentlet pickers (#36487) The slash-menu content-type picker fetched only the first 40 types (perPage:40, name ASC) and filtered that set client-side, hiding every content type past the alphabetical cap ("list ends after Image Asset") — unreachable by scroll or search. The contentlet drill-down had the same one-shot-fetch + client-filter limitation. Restore the legacy editor's behavior: re-query the server (debounced) on each keystroke, so results aren't capped by a page size and scale to 2000+ content types. - SlashMenuService: add openAsyncSubmenu() — 250ms debounce, stale-response token guard, query dedupe, timer/level-switch teardown; filterItems routes to the server search in async mode. Remove the now-dead openSubmenu()/setItems() (one-shot path). - slash-menu-catalog: both picker levels use openAsyncSubmenu. buildContentletByTypeQuery now takes the search term and builds a Lucene-escaped, tokenized query (ported from the legacy getContentlets, including UUID handling). Reported via Freshdesk #38277. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @rjvelazco's task in 13m 8s —— View job Code ReviewReviewed the full diff against One non-blocking gap below. New Issues
Notes (non-blocking)
Everything else — the token/ • |
The content-type / contentlet sub-menu discarded the fresh caret rect on each keystroke — update() set items but not clientRectFn in sub-menu mode — so the overlay kept the ROOT menu's original suggestion decoration node. Once the query text changes during a search, that node detaches and getBoundingClientRect() returns ~(0,0), stranding the menu at the top-left of the editor. Refresh clientRectFn in the sub-menu branch too (still preserving the sub-menu's own commandFn) so the overlay follows the caret exactly like the root menu. Pre-existing bug surfaced by the new server-side search, which turns the sub-menu into a real search box where longer queries are typed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@claude can you review this code, pretty please |
Addresses the PR review's one actionable finding (missing coverage for the parts most prone to silent regression). First specs in new-block-editor. - slash-menu-catalog.spec.ts: buildContentletByTypeQuery — empty, single/multi-word, hyphenated, UUID, Lucene-escaping, and trimming cases (mirrors the legacy suggestions.service spec). Exported the builder for direct testing. - slash-menu.service.spec.ts: openAsyncSubmenu — initial search, 250ms debounce coalescing, consecutive-query dedupe, stale-response token guard (out-of-order resolution), and close() dropping a late response. 12 tests, all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the review. Addressed the one actionable finding — added the first specs in
Re your notes: agreed on all — query-builder parity, escaping, and the async state machine were the design intent, and the |
…spec Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per review feedback — use braces on if statements even when the body is one line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Tick the box to add this pull request to the merge queue (same as
|
…esolution) The slash-menu service spec imported from @ngneat/spectator/jest, which is no longer a declared dependency — the workspace migrated to the @openng/spectator fork. It passed locally only because a stale @ngneat package lingered in node_modules; CI's clean install has only @OpenNg, so the suite failed to run with 'Cannot find module @ngneat/spectator/jest'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Proposed Changes
Fixes #36487 — the new Block Editor's content-type picker only showed the first 40 content types (alphabetical) and couldn't find the rest by scroll or search; the contentlet drill-down had the same limitation.
Root cause: the slash-menu submenu fetched once with an empty query (
perPage: 40) and filtered client-side. The legacy editor re-queried the server on each keystroke, so any record was findable. This restores that behavior.What changed:
SlashMenuService— newopenAsyncSubmenu(search, commandFn): rows come from a debounced (250ms) server search that re-runs on every keystroke. Includes a stale-response token guard, consecutive-query dedupe, and timer/level-switch/close teardown.filterItemsroutes to the server search when in async mode. Removed the now-deadopenSubmenu()/setItems()(the one-shot-fetch + client-filter path).slash-menu-catalog— both picker levels useopenAsyncSubmenu.buildContentletByTypeQuerynow accepts the search term and builds a Lucene-escaped, tokenized query (ported from the legacygetContentlets, incl. UUID handling), so contentlet search is server-side too.update()now refreshes the caret anchor (clientRectFn) in sub-menu mode too. Previously it was discarded there, so once the query text changed while searching, the overlay stayed pinned to the root menu's now-detached suggestion decoration node (getBoundingClientRect()→ ~0,0) and the menu jumped to the top-left of the editor. A pre-existing bug that the new search box surfaced (multi-word queries in the sub-menu).No fixed page-size cap → scales to instances with 2000+ content types. Empty/error/loading states, keyboard nav, and node insertion are preserved.
Checklist
nx run new-block-editor:lintpasses (type-checked)/→ Content → confirm the full type list searches server-side (types past the old 40-cap, e.g.MM…/RTL…, are findable)nx serve, no seeded backend.)Additional info
🤖 Generated with Claude Code
This PR fixes: #36487