Skip to content

SCIX-871 fix: gate facets on searchStatus to prevent stale data#860

Open
thostetler wants to merge 6 commits intoadsabs:masterfrom
thostetler:fix/SCIX-871-search-status-facet-gating
Open

SCIX-871 fix: gate facets on searchStatus to prevent stale data#860
thostetler wants to merge 6 commits intoadsabs:masterfrom
thostetler:fix/SCIX-871-search-status-facet-gating

Conversation

@thostetler
Copy link
Copy Markdown
Member

@thostetler thostetler commented May 5, 2026

Facets were showing stale data from the previous search when a new search returned zero results or errored. The root cause: latestQuery (what facets use to build their requests) only updated when docs.length > 0, and facets had no signal for whether the main search was still in flight, empty, or failed.

  • Add SearchStatus union type to the Zustand search slice ('idle' | 'loading' | 'success' | 'empty' | 'error')
  • Drive status transitions from the search page using isLoading/isSuccess/isError — uses isLoading rather than isFetching to avoid toggling facets off during background refetches of the same query
  • Switch status effect to useLayoutEffect so facets start loading in the same frame as search results
  • Gate facet fetches (enabled) and returned data (treeData, totalResults, canLoadMore) on searchStatus === 'success' — explicit data gate required because enabled: false alone does not clear React Query cached values
  • Show a spinner in open facets while the main search is loading instead of incorrectly showing No Results
  • Fix store singleton in test-utils that was leaking Zustand state between tests
  • Fix TS errors in SearchFacetModal (children render prop type conflict) and FacetStoreProvider

@codecov
Copy link
Copy Markdown

codecov Bot commented May 5, 2026

Codecov Report

❌ Patch coverage is 85.71429% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.6%. Comparing base (5a4245b) to head (245c2b3).

Files with missing lines Patch % Lines
src/components/SearchFacet/YearHistogramSlider.tsx 0.0% 4 Missing ⚠️
src/test-utils.tsx 91.4% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           master    #860     +/-   ##
========================================
- Coverage    62.7%   62.6%   -0.0%     
========================================
  Files         323     323             
  Lines       38011   38031     +20     
  Branches     1723    1720      -3     
========================================
- Hits        23802   23797      -5     
- Misses      14169   14194     +25     
  Partials       40      40             
Files with missing lines Coverage Δ
src/components/SearchFacet/store/FacetStore.ts 85.9% <100.0%> (ø)
src/components/SearchFacet/useGetFacetData.ts 76.7% <100.0%> (+0.3%) ⬆️
src/store/slices/search.ts 91.6% <100.0%> (+0.6%) ⬆️
src/test-utils.tsx 89.2% <91.4%> (+0.2%) ⬆️
src/components/SearchFacet/YearHistogramSlider.tsx 27.7% <0.0%> (-0.2%) ⬇️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

thostetler added 3 commits May 4, 2026 20:10
SCIX-871 test: add searchStatus facet gating integration tests

SCIX-871 feat: gate facets on searchStatus to prevent stale data after empty/failed searches

SCIX-871 fix: drive searchStatus from search page to gate facets

SCIX-871 perf: use useLayoutEffect to start facets in same frame as search results
SCIX-871 fix: use varied two-column skeleton rows in facets during search loading

SCIX-871 fix: use spinner instead of skeleton rows in facets during search loading
@thostetler thostetler changed the title SCIX-871 fix: gate facets on searchStatus to prevent stale data after empty/failed searches SCIX-871 fix: gate facets on searchStatus to prevent stale data May 5, 2026
@thostetler thostetler force-pushed the fix/SCIX-871-search-status-facet-gating branch from 78b4903 to 6f40e80 Compare May 5, 2026 00:10
@thostetler thostetler marked this pull request as ready for review May 5, 2026 00:55
@thostetler thostetler requested review from Copilot and shinyichen May 5, 2026 00:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Risk summary: High — the new search-status gating moves the stale-facet fix in the right direction, but there are still stale latestQuery paths and an error-state regression in the facet UI.

This PR adds an explicit main-search status to the shared search store so facet-related UI can stop showing cached data from an earlier query when the primary search is loading, empty, or errored. It also tightens test setup around Zustand store creation and fixes a couple of TypeScript prop-type issues in facet components.

Changes:

  • Add searchStatus to the search slice and drive its transitions from /search.
  • Gate facet requests/rendered facet data on successful main-search completion and show loading spinners in facet UIs.
  • Update test utilities to create fresh stores per test and fix TS typing conflicts in facet provider/modal components.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/test-utils.tsx Test wrapper now builds a fresh app store instead of reusing the cached client store helper.
src/store/slices/search.ts Adds SearchStatus state and setter to the global search slice.
src/pages/search/index.tsx Drives search-status changes from the main search query lifecycle.
src/components/SearchFacet/useGetFacetData.ts Gates facet fetching/data exposure on main-search success.
src/components/SearchFacet/useGetFacetData.test.ts Adds hook tests for status-based facet gating.
src/components/SearchFacet/store/FacetStore.ts Adjusts facet store provider typing for children.
src/components/SearchFacet/SearchFacetModal/SearchFacetModal.tsx Resolves the modal children render-prop typing conflict.
src/components/SearchFacet/FacetList.tsx Updates facet loading UI to show spinners for both facet-fetch and main-search loading states.

Comment thread src/pages/search/index.tsx Outdated
Comment thread src/components/SearchFacet/useGetFacetData.ts
Comment thread src/pages/search/index.tsx Outdated
Comment thread src/pages/search/index.tsx Outdated
thostetler added 2 commits May 4, 2026 22:40
- Replace useLayoutEffect with useIsomorphicLayoutEffect (falls back to
  useEffect on the server) to eliminate the React SSR warning that fires
  when useLayoutEffect is used on a server-rendered page.
- Move setQuery/submitQuery inside the numFound > 0 branch so empty-result
  searches do not open a Sentry performance span that can never close
  (providers.tsx only closes spans when docs.current is non-empty).
NumFound's SortStats sub-component and YearHistogramSlider both read
latestQuery directly and fire API requests even when the main search
has errored, showing stale data from the previous query. Gate both
on searchStatus === 'success' so they stay quiet until the search
completes successfully.
enabled:false stops new requests but React Query keeps the cached
data in memory. Gate histogramData derivation on searchStatus so
the stale histogram clears immediately when the search transitions
away from success.
<Center data-testid="search-facet-loading">
<Spinner size="sm" />
<Center py="4" data-testid="search-facet-loading">
<Spinner size="sm" color="gray.400" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hard coded color here might be an accessibility issue (although it doesn't stay on screen that long). I believe gray.400 doesn't have enough contrast on white background, and also considering we also have dark mode, maybe it's best to specify the color using the useColorModeColor hook.

<Skeleton h="24px" />
</Stack>
<Center py="4" data-testid="search-facet-loading">
<Spinner size="sm" color="gray.400" />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

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