Skip to content

Conversation

@tlambert03
Copy link
Owner

No description provided.

claude and others added 30 commits November 6, 2025 14:09
…osal

- Analyzed current Algolia setup (backend Django integration and frontend JS)
- Identified deprecated libraries: autocomplete.js, algoliasearch v3
- Documented 6-year gap vs current best practices
- Proposed 4-phase modernization strategy with detailed implementation plans
- Included code examples for upgrading to modern stack
- Estimated effort: 1-2 weeks for critical phases
- Zero cost for phases 1-3 (all open-source upgrades)
- Remove stale algoliasearch-django wrapper (inactive, 11mo old)
- Replace with direct Python client + custom indexing service
- Frontend-first architecture (10x faster, Algolia recommendation)
- Async indexing via Celery (no request blocking)
- Modern React InstantSearch UI with faceted search
- Explicit control over indexing (no magic abstractions)
- Complete migration path with rollback plan
- Zero cost upgrade (all open-source)
- Remove inactive algoliasearch_django wrapper (stale, discontinued)
- Add algoliasearch>=4.0 direct client (actively maintained)
- Remove INSTALLED_APPS conditional for wrapper
- Prepare for custom indexing service implementation

This is the first step in modernizing Algolia integration with a
frontend-first architecture.
- Create ProteinIndexer with explicit serialization logic
- Create OrganismIndexer and ReferenceIndexer
- Support for index configuration and replica indices
- Structured logging for all operations
- Graceful handling when Algolia not configured
- Clear, maintainable code (~400 LOC) vs opaque wrapper

This replaces the algoliasearch-django wrapper with explicit,
controllable indexing logic.
- Add index_protein_task with retry logic
- Add delete_protein_task for deletions
- Add reindex_all_proteins for batch reindexing
- Add index_organism_task and index_reference_task
- Add configure_all_indices task
- All tasks use structlog for structured logging
- Exponential backoff on failures

This ensures indexing never blocks request/response cycles.
- Add post_save handler for Protein to trigger async indexing
- Add post_delete handler for Protein to remove from index
- Add handlers for Organism and Reference models
- All indexing is async via Celery (no request blocking)
- Gracefully skip if Algolia not configured

This replaces the algoliasearch-django automatic indexing with our
custom async implementation.
These files were for the algoliasearch-django wrapper which we've
replaced with custom indexing service in proteins/algolia.py
- Supports --configure flag to set index settings
- Supports --sync flag for synchronous operation (testing)
- Default async operation via Celery
- Clear user feedback and progress messages

Usage:
  uv run backend/manage.py algolia_reindex --configure
  uv run backend/manage.py algolia_reindex --sync
- Replace deprecated autocomplete.js with @algolia/autocomplete-js
- Upgrade algoliasearch from v3 to v5
- Add react-instantsearch for advanced search UI
- Add instantsearch.css for styling

This modernizes the search stack and removes deprecated libraries.
- Uses @algolia/autocomplete-js (replaces deprecated autocomplete.js)
- React-based with createRoot (no jQuery)
- Recent searches plugin
- Clean component architecture
- Proper TypeScript-ready structure
- Mobile-optimized with detached mode

This replaces the old jQuery-based algolia.js implementation.
- Replace old algolia.js import with SearchAutocomplete.jsx
- Remove deprecated autocomplete.js CDN script
- Keep jQuery for other components (select2, bootstrap, etc.)
- Modern React-based autocomplete now bundled with Vite

This completes the transition away from the deprecated autocomplete.js
library while maintaining jQuery for other legacy components.
Replaced by modern SearchAutocomplete.jsx component using
@algolia/autocomplete-js instead of deprecated autocomplete.js
Comprehensive documentation of:
- All changes made (backend + frontend)
- Step-by-step commits
- Testing instructions
- Architecture improvements
- Migration checklist for production
- Rollback plan
- What's not yet implemented (advanced search, tests)

This provides a complete reference for the modernization work.
- Add @algolia/autocomplete-plugin-recent-searches
- Add @algolia/autocomplete-theme-classic

These were missing from the initial dependency update, causing build
failures. Build now completes successfully.
- Document missing autocomplete dependencies that were added
- Add commit for build fix (77e7f1c)
- Clarify that build now works successfully
Lockfile updated to reflect the addition of:
- @algolia/[email protected]
- @algolia/[email protected]
Move Algolia initialization from module-level to inside useEffect hook
to avoid window.FPBASE access at module load time. This fixes the error:
'@vitejs/plugin-react can't detect preamble. Something is wrong.'

Changes:
- Move searchClient initialization inside useEffect
- Move recentSearchesPlugin creation inside useEffect
- Add safety check for window.FPBASE.ALGOLIA existence
- Remove unused React imports (createElement, Fragment)

Build now completes successfully without errors.
Changes:
- Add data-fpbase-init="autocomplete" to search inputs in templates
- Update index.js to handle autocomplete via data-fpbase-init pattern
- Remove direct #algolia-search-input check in favor of pattern-based init
- Consistent with other components (microscope, litemol, ichart)

This makes component initialization more declarative and maintainable.
The Vite React plugin was throwing a preamble detection error because
window.FPBASE.imageDir was being accessed directly in JSX template strings.

Fixed by:
- Moving window.FPBASE.imageDir access to component function body
- Using const imageDir = window.FPBASE?.imageDir || '/static/images/'
- Applied to ProteinHit, ReferenceHit, and OrganismHit components

This ensures window globals are accessed at runtime, not module load time,
which allows Vite's React Fast Refresh to properly detect the component.

Fixes the console error:
"@vitejs/plugin-react can't detect preamble. Something is wrong."
The Vite React plugin preamble error was caused by missing the
@vitejs/plugin-react/preamble import in index.js.

This import sets up window.$RefreshReg$ and other Fast Refresh globals
that React component files expect. Other entry points (simple-spectra-viewer.js,
spectra-viewer.js) have this import, but it was missing from index.js.

Without this import, when React components load, they check for
window.$RefreshReg$ and throw an error when it's not found.

Fixes: '@vitejs/plugin-react can\'t detect preamble. Something is wrong.'
The initAutocomplete function was looking for .nav-search form wrapper,
which only exists in the navbar (not on home page).

Changed to search directly for #algolia-search-input which exists on
both the home page and navbar search inputs.

Fixes warning: 'Search form not found'
The autocomplete library (@algolia/autocomplete-js) uses Preact internally
for its own rendering. The custom render() and renderNoResults() functions
were trying to use React's createRoot to render Algolia's Preact virtual
nodes, causing the error:

'Objects are not valid as a React child (found: object with keys {type,
props, key, ref, __k, __, __b, __e, __c, constructor, __v, __i, __u})'

Fixed by:
- Removing custom render() and renderNoResults() functions
- Letting Algolia handle its own rendering (as designed)
- Removed unused createRoot import
- Removed unused React import (only need useEffect, useRef)

The JSX in template functions is compiled by Algolia's library, not React.
The template functions (ProteinHit, ReferenceHit, OrganismHit) use JSX,
but Algolia's autocomplete library uses Preact internally, not React.

When JSX was compiled to React.createElement, it created frozen React
elements that Preact couldn't extend, causing:
'Cannot add property __, object is not extensible'

Fixed by:
- Adding /** @jsx h */ pragma to use Preact's createElement
- Importing createElement as h and Fragment from @algolia/autocomplete-js
- Now JSX compiles to Preact vnodes that autocomplete can use

This is the correct way to use JSX with Algolia autocomplete.
The previous fix tried to import createElement from @algolia/autocomplete-js,
but that package doesn't export it - Preact does.

Fixed by:
- Adding preact as a dependency (pnpm add preact)
- Importing h and Fragment from 'preact' directly
- JSX pragma /** @jsx h */ now correctly uses Preact's h function
- Template functions now compile to proper Preact vnodes

This resolves the 'object is not extensible' error that occurred when
Algolia's Preact renderer tried to work with React-compiled JSX.
JSX and Preact were causing 'object is not extensible' errors because
React/Preact create frozen objects that conflict with each other.

The correct solution is to use Algolia's built-in html tagged template
function (available since autocomplete v1.6.0), which works directly in
the browser without needing JSX transpilation or virtual DOM libraries.

Changes:
- Removed Preact dependency (pnpm remove preact)
- Removed JSX pragma and Preact imports
- Converted all template functions to use html tagged template:
  - ProteinHit, ReferenceHit, OrganismHit now use html`...`
  - All header() functions use html`...`
  - All noResults() functions use html`...`
- Updated template calls to pass html parameter instead of components

This is the official Algolia recommended approach for browser usage.
@codecov
Copy link

codecov bot commented Nov 15, 2025

Codecov Report

❌ Patch coverage is 9.31507% with 331 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.74%. Comparing base (7c27eaf) to head (2d26e2b).

Files with missing lines Patch % Lines
backend/proteins/algolia.py 0.00% 205 Missing ⚠️
backend/proteins/tasks.py 14.81% 92 Missing ⚠️
...nd/proteins/management/commands/algolia_reindex.py 0.00% 24 Missing ⚠️
backend/proteins/handlers.py 64.28% 10 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (7c27eaf) and HEAD (2d26e2b). Click for more details.

HEAD has 3 uploads less than BASE
Flag BASE (7c27eaf) HEAD (2d26e2b)
4 1
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #377      +/-   ##
==========================================
- Coverage   61.08%   52.74%   -8.35%     
==========================================
  Files         108      108              
  Lines        8694     9042     +348     
==========================================
- Hits         5311     4769     -542     
- Misses       3383     4273     +890     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants