Replace Inkeep with keyword-only Algolia search - #6859
Conversation
Greptile SummaryReplaces the Inkeep widget with a client-only, keyword-based Algolia search while retaining compatibility aliases.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx | Implements the client-side Algolia search dialog, request lifecycle, URL filtering, result rendering, accessibility controls, and styling. |
| packages/reflex-site-shared/src/reflex_site_shared/components/algolia.py | Defines the no-SSR frontend component binding and navbar-compatible wrapper. |
| packages/reflex-site-shared/src/reflex_site_shared/components/inkeep.py | Preserves the former Inkeep import surface through aliases to the Algolia implementation. |
| packages/reflex-site-shared/src/reflex_site_shared/plugins.py | Adds the Algolia TypeScript component to the shared plugin’s emitted public assets. |
| packages/reflex-site-shared/src/reflex_site_shared/templates/docs.py | Uses Algolia search as the default docs-navbar search implementation while retaining configurable overrides. |
| docs/app/reflex.lock/package.json | Removes the obsolete Inkeep frontend dependency. |
| docs/app/reflex.lock/bun.lock | Removes Inkeep and its unused transitive dependency graph from the generated lockfile. |
| tests/units/reflex_site_shared/test_algolia.py | Covers the component binding, emitted search asset, request configuration, portal behavior, and result categories. |
Reviews (3): Last reviewed commit: "Add category icons to search results" | Re-trigger Greptile
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0bf59e0fc9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| InkeepSearchBar = AlgoliaSearch | ||
| inkeep = algolia_search |
There was a problem hiding this comment.
Warn before redirecting legacy Inkeep callers
Downstream code that still imports InkeepSearchBar or calls inkeep() now silently receives a different component with the Inkeep chat/support behavior removed. Preserve a migration window or wrap these legacy entry points with the required console.deprecate() warning rather than directly aliasing them, so consumers are notified before the old behavior disappears.
AGENTS.md reference: AGENTS.md:L93-L108
Useful? React with 👍 / 👎.
| <button | ||
| aria-label="Clear search" | ||
| className="ReflexSearch-iconButton" | ||
| onClick={() => setQuery("")} |
There was a problem hiding this comment.
Return focus to the input when clearing
When a keyboard user tabs to the clear button and activates it, setting query to an empty string immediately unmounts the focused button. Focus then falls outside the dialog (typically to body), so the section-level onKeyDown focus trap no longer receives subsequent Tab presses and focus can move into the page behind the modal. Focus inputRef as part of clearing the query or keep the clear control mounted.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
4 issues found across 14 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/units/reflex_site_shared/test_algolia.py">
<violation number="1" location="tests/units/reflex_site_shared/test_algolia.py:68">
P2: These assertions are tightly coupled to the exact whitespace, indentation, and statement ordering of the published AlgoliaSearch.tsx, so any cosmetic reformat (the repo runs Biome) breaks CI even when search behavior is unchanged. Prefer whitespace-normalized substring checks (e.g. token-join the asset once) and assert on behavior-relevant tokens rather than exact multi-line formatting and internal statement ordering.</violation>
</file>
<file name="packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx">
<violation number="1" location="packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx:322">
P3: The command-palette search state isn't reset when the dialog closes. `closeSearch` only flips `isOpen` and restores focus; `query`, `hits`, and `status` are left untouched (and the search effect early-returns while closed without clearing them). As a result, reopening Cmd/Ctrl+K resurrects the previous query and last state — stale cached results, a leftover "Searching…" spinner, or a persistent "Search is temporarily unavailable" error banner — rather than presenting the fresh "Search all of Reflex" idle hero. Consider resetting `query`/`hits`/`status` (to `""`, `[]`, `"idle"`) inside `closeSearch` so each open starts clean, matching the Inkeep behavior being replaced.</violation>
<violation number="2" location="packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx:354">
P3: The `⌘`/`Ctrl` label shown on the Search trigger is derived from `navigator.platform`, which is deprecated and unreliable (it can report the underlying OS instead of the device, and is inconsistent on mobile/tablet user agents). The active shortcut handler already uses the robust `event.metaKey || event.ctrlKey`, so the platform probe only drives cosmetic output. Consider switching the display detection to `window.matchMedia('(hover: none) and (pointer: coarse)')`/`'Mac'`-based user-agent checks or dropping it in favor of a single neutral label to avoid a wrong glyph on some devices.</violation>
<violation number="3" location="packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx:556">
P2: Clicking/activating the clear button sets `query` to an empty string, which unmounts the button itself since it's only rendered when `query` is truthy. If a keyboard user tabbed to and activated this button, focus is dropped outside the dialog (typically to `body`), letting subsequent Tab presses escape the `keepFocusInDialog` trap on the modal. Refocus `inputRef` when clearing the query.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| "ROOT_THEME_SELECTOR = '.radix-themes[data-is-root-theme=\"true\"]'" in source | ||
| ) | ||
| assert ( | ||
| "buttonRef.current?.closest(ROOT_THEME_SELECTOR) ??\n" |
There was a problem hiding this comment.
P2: These assertions are tightly coupled to the exact whitespace, indentation, and statement ordering of the published AlgoliaSearch.tsx, so any cosmetic reformat (the repo runs Biome) breaks CI even when search behavior is unchanged. Prefer whitespace-normalized substring checks (e.g. token-join the asset once) and assert on behavior-relevant tokens rather than exact multi-line formatting and internal statement ordering.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/units/reflex_site_shared/test_algolia.py, line 68:
<comment>These assertions are tightly coupled to the exact whitespace, indentation, and statement ordering of the published AlgoliaSearch.tsx, so any cosmetic reformat (the repo runs Biome) breaks CI even when search behavior is unchanged. Prefer whitespace-normalized substring checks (e.g. token-join the asset once) and assert on behavior-relevant tokens rather than exact multi-line formatting and internal statement ordering.</comment>
<file context>
@@ -0,0 +1,126 @@
+ "ROOT_THEME_SELECTOR = '.radix-themes[data-is-root-theme=\"true\"]'" in source
+ )
+ assert (
+ "buttonRef.current?.closest(ROOT_THEME_SELECTOR) ??\n"
+ " document.querySelector(ROOT_THEME_SELECTOR) ??\n"
+ " document.body"
</file context>
| <button | ||
| aria-label="Clear search" | ||
| className="ReflexSearch-iconButton" | ||
| onClick={() => setQuery("")} |
There was a problem hiding this comment.
P2: Clicking/activating the clear button sets query to an empty string, which unmounts the button itself since it's only rendered when query is truthy. If a keyboard user tabbed to and activated this button, focus is dropped outside the dialog (typically to body), letting subsequent Tab presses escape the keepFocusInDialog trap on the modal. Refocus inputRef when clearing the query.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx, line 556:
<comment>Clicking/activating the clear button sets `query` to an empty string, which unmounts the button itself since it's only rendered when `query` is truthy. If a keyboard user tabbed to and activated this button, focus is dropped outside the dialog (typically to `body`), letting subsequent Tab presses escape the `keepFocusInDialog` trap on the modal. Refocus `inputRef` when clearing the query.</comment>
<file context>
@@ -0,0 +1,1048 @@
+ <button
+ aria-label="Clear search"
+ className="ReflexSearch-iconButton"
+ onClick={() => setQuery("")}
+ type="button"
+ >
</file context>
|
|
||
| useEffect(() => { | ||
| setModifierKey( | ||
| /Mac|iPhone|iPad|iPod/.test(navigator.platform) ? "⌘" : "Ctrl", |
There was a problem hiding this comment.
P3: The ⌘/Ctrl label shown on the Search trigger is derived from navigator.platform, which is deprecated and unreliable (it can report the underlying OS instead of the device, and is inconsistent on mobile/tablet user agents). The active shortcut handler already uses the robust event.metaKey || event.ctrlKey, so the platform probe only drives cosmetic output. Consider switching the display detection to window.matchMedia('(hover: none) and (pointer: coarse)')/'Mac'-based user-agent checks or dropping it in favor of a single neutral label to avoid a wrong glyph on some devices.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx, line 354:
<comment>The `⌘`/`Ctrl` label shown on the Search trigger is derived from `navigator.platform`, which is deprecated and unreliable (it can report the underlying OS instead of the device, and is inconsistent on mobile/tablet user agents). The active shortcut handler already uses the robust `event.metaKey || event.ctrlKey`, so the platform probe only drives cosmetic output. Consider switching the display detection to `window.matchMedia('(hover: none) and (pointer: coarse)')`/`'Mac'`-based user-agent checks or dropping it in favor of a single neutral label to avoid a wrong glyph on some devices.</comment>
<file context>
@@ -0,0 +1,1048 @@
+
+ useEffect(() => {
+ setModifierKey(
+ /Mac|iPhone|iPad|iPod/.test(navigator.platform) ? "⌘" : "Ctrl",
+ );
+ }, []);
</file context>
|
|
||
| const openSearch = useCallback(() => setIsOpen(true), []); | ||
| const closeSearch = useCallback(() => { | ||
| setIsOpen(false); |
There was a problem hiding this comment.
P3: The command-palette search state isn't reset when the dialog closes. closeSearch only flips isOpen and restores focus; query, hits, and status are left untouched (and the search effect early-returns while closed without clearing them). As a result, reopening Cmd/Ctrl+K resurrects the previous query and last state — stale cached results, a leftover "Searching…" spinner, or a persistent "Search is temporarily unavailable" error banner — rather than presenting the fresh "Search all of Reflex" idle hero. Consider resetting query/hits/status (to "", [], "idle") inside closeSearch so each open starts clean, matching the Inkeep behavior being replaced.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-site-shared/src/reflex_site_shared/styles/assets/components/AlgoliaSearch.tsx, line 322:
<comment>The command-palette search state isn't reset when the dialog closes. `closeSearch` only flips `isOpen` and restores focus; `query`, `hits`, and `status` are left untouched (and the search effect early-returns while closed without clearing them). As a result, reopening Cmd/Ctrl+K resurrects the previous query and last state — stale cached results, a leftover "Searching…" spinner, or a persistent "Search is temporarily unavailable" error banner — rather than presenting the fresh "Search all of Reflex" idle hero. Consider resetting `query`/`hits`/`status` (to `""`, `[]`, `"idle"`) inside `closeSearch` so each open starts clean, matching the Inkeep behavior being replaced.</comment>
<file context>
@@ -0,0 +1,1048 @@
+
+ const openSearch = useCallback(() => setIsOpen(true), []);
+ const closeSearch = useCallback(() => {
+ setIsOpen(false);
+ window.requestAnimationFrame(() => buttonRef.current?.focus());
+ }, []);
</file context>
What
@inkeep/cxkit-reactand its OpenAI/AI transitive dependencies from the docs lockfilesinkeepimports for downstream consumers/, Escape, focus trapping/restoration, responsive styling, query debounce/cache, and Algolia attributionWhy
The existing Inkeep integration includes AI chat code and does not reliably surface all current Reflex pages. In particular,
https://reflex.dev/docs/ai/integrations/anthropic/was missing from site search even though it is present in the Algolia page index. This change queries that page index directly and keeps the search experience lexical only—no AI requests or AI search dependency.Impact
The browser sends only standard Algolia keyword queries after a 350 ms debounce and two-character minimum. Results are limited to Reflex-owned URLs and the published search client requests at most 10 hits. Algolia crawler coverage and API-key rate limits are configured separately in the Algolia dashboard.
Verification
pytest -q tests/units/reflex_site_shared— 62 passedpytest -q docs/app/tests/test_docs_navbar.py— 6 passedgit diff --check— passedreflex compile --dry— compiled 1,009 pagesreflex run --env prod --single-port— production build passed and Safari smoke-tested in light and dark modeuv build --directory packages/reflex-site-shared— sdist and wheel passedManual Safari verification confirms
anthropicreturns the Anthropic integration page first.