|
| 1 | +# Backend fuzzy search integration |
| 2 | + |
| 3 | +## Reference |
| 4 | + |
| 5 | +**Quickstarts service API:** See the quickstarts repo documentation for the fuzzy search contract, examples, and configuration: |
| 6 | + |
| 7 | +- **Fuzzy Search (service):** `docs/developers/FUZZY_SEARCH.md` in [RedHatInsights/quickstarts](https://github.com/RedHatInsights/quickstarts) |
| 8 | + |
| 9 | +That doc describes: |
| 10 | +- Query params: `display-name=<term>` and `fuzzy=true` |
| 11 | +- Ranking: match count (DESC) → total Levenshtein distance (ASC) |
| 12 | +- Config: `FUZZY_SEARCH_DISTANCE_THRESHOLD` (server-side; default 3) |
| 13 | +- Tag filters work together with fuzzy (e.g. `bundle=ansible`) |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Overview |
| 18 | + |
| 19 | +Integrate the quickstarts service fuzzy search (Levenshtein, `fuzzy` query param from PR #436) so the help panel Search panel and the catalog use server-side fuzzy matching on `spec.displayName` instead of or in addition to client-side behavior. Replace the Search panel's Fuse.js-based quickstart search with the backend API; enable fuzzy for the catalog "Find by name" filter. |
| 20 | + |
| 21 | +## Context |
| 22 | + |
| 23 | +The quickstarts service supports optional fuzzy search via [PR #436](https://github.com/RedHatInsights/quickstarts/pull/436): |
| 24 | + |
| 25 | +- **Query params:** `display-name` (existing) and **`fuzzy`** (boolean, default `false`). |
| 26 | +- **Behavior:** When `fuzzy=true`, backend uses Levenshtein distance on **spec.displayName** (word-by-word), with typo tolerance configurable via `FUZZY_SEARCH_DISTANCE_THRESHOLD` (server-side env). |
| 27 | +- **Scope:** Search is only on `spec.displayName` for now; extending to `spec.description` or `spec.tasks` is a possible future backend change. |
| 28 | + |
| 29 | +In this app: |
| 30 | + |
| 31 | +- **Search panel** ([`SearchPanel.tsx`](src/components/HelpPanel/HelpPanelTabs/SearchPanel/SearchPanel.tsx)): Previously fetched all quickstarts via `fetchAllData(getUser, {})` and ran **Fuse.js** over quickstarts + services + API docs. Fuse.js has been removed and replaced by the backend fuzzy search: the search path now calls `fetchAllData(getUser, { 'display-name': query.trim(), fuzzy: true })` for quickstarts and filters services and API docs client-side. |
| 32 | +- **Learn panel** ([`LearnPanel.tsx`](src/components/HelpPanel/HelpPanelTabs/LearnPanel.tsx)): No free-text search today (only bundle, content type, bookmarks). No change unless we add a "search by name" input later. |
| 33 | +- **Catalog** ([`GlobalLearningResourcesPage`](src/components/GlobalLearningResourcesPage/GlobalLearningResourcesPage.tsx), filters): Uses `loaderOptions['display-name']` when the user types in "Find by name". Pass `fuzzy: true` when a display-name filter is present so catalog search is typo-tolerant. |
| 34 | + |
| 35 | +--- |
| 36 | + |
| 37 | +## 1. API layer: add `fuzzy` support |
| 38 | + |
| 39 | +**File:** [`src/utils/fetchQuickstarts.ts`](src/utils/fetchQuickstarts.ts) |
| 40 | + |
| 41 | +- Add **`fuzzy?: boolean`** to `FetchQuickstartsOptions`. |
| 42 | +- In the `axios.get` params, when `fuzzy === true` and there is a non-empty `display-name`, pass **`fuzzy: true`** in the request (query param name from the API is `fuzzy`). |
| 43 | +- Keep existing behavior when `fuzzy` is omitted or `false`. |
| 44 | + |
| 45 | +**File:** [`src/utils/fetchAllData.ts`](src/utils/fetchAllData.ts) |
| 46 | + |
| 47 | +- No signature change; it already forwards `FetchQuickstartsOptions` to `fetchQuickstarts`. |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## 2. Search panel: use backend fuzzy for quickstarts |
| 52 | + |
| 53 | +**File:** [`src/components/HelpPanel/HelpPanelTabs/SearchPanel/SearchPanel.tsx`](src/components/HelpPanel/HelpPanelTabs/SearchPanel/SearchPanel.tsx) |
| 54 | + |
| 55 | +- **`performSearch(query)`:** Call `fetchAllData(chrome.auth.getUser, { 'display-name': query.trim(), fuzzy: true })` for quickstarts; fetch bundles and bundleInfo for services and API docs. Build quickstart SearchResults from returned quickstarts. Filter services and API docs client-side by query. Combine: quickstarts first (backend order), then filtered services, then filtered API docs. |
| 56 | +- **No Fuse.js:** Fuse.js is not used. Services and API docs are filtered with simple substring (case-insensitive) matching; there is no global Fuse index and no `fuse.js` dependency in the codebase. |
| 57 | + |
| 58 | +--- |
| 59 | + |
| 60 | +## 3. Catalog: enable fuzzy when "Find by name" is used |
| 61 | + |
| 62 | +**Files:** [`GlobalLearningResourcesFilters.tsx`](src/components/GlobalLearningResourcesPage/GlobalLearningResourcesFilters.tsx), [`GlobalLearningResourcesFiltersMobile.tsx`](src/components/GlobalLearningResourcesPage/GlobalLearningResourcesFiltersMobile.tsx) |
| 63 | + |
| 64 | +- When updating `loaderOptions` for the display-name input, set **`fuzzy: true`** whenever **`'display-name'`** is non-empty. |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +## 4. Learn panel |
| 69 | + |
| 70 | +- No code change: LearnPanel has no display-name search field. Add later if product wants "search by name" there. |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## 5. Tests and mocks |
| 75 | + |
| 76 | +- Add tests for `fuzzy: true` in request params when display-name is set. |
| 77 | +- Update quickstarts API mocks to accept optional `fuzzy` query parameter (e.g. in `helpPanelJourneyHelpers.ts` and Storybook/Cypress intercepts). |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +## 6. Cleanup (done) |
| 82 | + |
| 83 | +- **`fuse.js`** has been removed and is no longer a project dependency. |
| 84 | +- Typo tolerance for quickstart search is controlled by the backend env **`FUZZY_SEARCH_DISTANCE_THRESHOLD`** (no frontend configuration). |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## Out of scope (future) |
| 89 | + |
| 90 | +- Backend extending fuzzy to **spec.description** or **spec.tasks** (backend change; frontend keeps passing `fuzzy=true`). |
| 91 | +- Frontend configuration for Levenshtein distance (server env only). |
0 commit comments