Skip to content

SCIX-871 fix: gate SortStats and YearHistogramSlider on searchStatus#861

Closed
thostetler wants to merge 5 commits intoadsabs:masterfrom
thostetler:fix/SCIX-871-gate-numfound-yearhistogram-on-search-status
Closed

SCIX-871 fix: gate SortStats and YearHistogramSlider on searchStatus#861
thostetler wants to merge 5 commits intoadsabs:masterfrom
thostetler:fix/SCIX-871-gate-numfound-yearhistogram-on-search-status

Conversation

@thostetler
Copy link
Copy Markdown
Member

NumFound's SortStats sub-component and YearHistogramSlider both read latestQuery
directly and fire API requests when the main search has errored, showing stale
citation stats and histogram data from the previous query.

  • Gate SortStats rendering in NumFound on searchStatus === 'success' so the
    citation stats call never fires on stale latestQuery
  • Add searchStatus === 'success' to the enabled condition in YearHistogramSlider
    so histogram data is not fetched against a stale query

thostetler added 5 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
- 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.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 5, 2026

Codecov Report

❌ Patch coverage is 90.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.6%. Comparing base (5a4245b) to head (fd3ac97).

Files with missing lines Patch % Lines
src/components/SearchFacet/YearHistogramSlider.tsx 0.0% 2 Missing ⚠️
src/test-utils.tsx 91.4% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           master    #861     +/-   ##
========================================
- Coverage    62.7%   62.6%   -0.0%     
========================================
  Files         323     323             
  Lines       38011   38031     +20     
  Branches     1723    1720      -3     
========================================
- Hits        23802   23794      -8     
- Misses      14169   14197     +28     
  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/components/SearchFacet/YearHistogramSlider.tsx 27.7% <0.0%> (-0.2%) ⬇️
src/test-utils.tsx 89.2% <91.4%> (+0.2%) ⬆️

... and 6 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 thostetler marked this pull request as ready for review May 5, 2026 03:32
@thostetler thostetler requested review from Copilot and shinyichen May 5, 2026 03:32
@thostetler
Copy link
Copy Markdown
Member Author

Folded into #860.

@thostetler thostetler closed this May 5, 2026
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

This PR introduces a centralized searchStatus in the Zustand search slice and uses it to prevent secondary “dependent” UI (citation sort stats + year histogram + facet queries) from firing API requests when the primary search is not in a good/successful state, avoiding stale requests against latestQuery.

Changes:

  • Add searchStatus (idle/loading/success/empty/error) to the global search store and drive it from the primary search query lifecycle on /search.
  • Gate rendering/fetching for NumFound’s SortStats and YearHistogramSlider behind searchStatus === 'success'.
  • Gate facet data fetching behind searchStatus and add tests around the new gating behavior; adjust facet loading UI to account for primary-search loading.

Risk summary

Medium risk: changes affect search-page state semantics and can indirectly influence when/if facet requests fire and what store state is considered “current”.

Findings (priority order)

medium

  • Facet queries can re-enable for whitespace/empty q

    • Impact: Facet requests may fire for invalid or effectively-empty queries (e.g., whitespace-only), potentially causing unnecessary/invalid /search/query calls and inconsistent UI behavior.
    • Location: src/components/SearchFacet/useGetFacetData.ts:63
    • Minimal fix: Include a non-empty/trimmed q guard in isQueryEnabled (in addition to searchStatus === 'success').
    • Confidence: high
  • Empty-results path leaves stale docs.current in store

    • Impact: When a search succeeds with numFound === 0, the UI indicates empty results but state.docs.current can still contain bibcodes from the prior successful search, leaking stale state into selection/telemetry/other store consumers.
    • Location: src/pages/search/index.tsx:279-286
    • Minimal fix: In the numFound === 0 branch, clear current docs in the store (e.g., setDocs([])), and ensure related selection flags are consistent.
    • Confidence: medium

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/test-utils.tsx Switch test store setup to createStore to avoid Zustand singleton leakage across tests; refactor formatting.
src/store/slices/search.ts Add SearchStatus, searchStatus state, and setSearchStatus action to the search slice.
src/pages/search/index.tsx Drive searchStatus from primary search query lifecycle via an isomorphic layout effect.
src/components/SearchFacet/YearHistogramSlider.tsx Gate histogram facet fetch on searchStatus === 'success'.
src/components/SearchFacet/useGetFacetData.ts Gate facet fetch + exposed facet state on searchStatus; add isSearchLoading.
src/components/SearchFacet/useGetFacetData.test.ts Update/add tests validating facet fetch gating by searchStatus.
src/components/SearchFacet/store/FacetStore.ts Adjust provider props typing (explicit children?: ReactNode).
src/components/SearchFacet/SearchFacetModal/SearchFacetModal.tsx Fix prop typing collision by omitting children from inherited props.
src/components/SearchFacet/FacetList.tsx Update facet loading UI to reflect primary-search loading and simplify loader rendering.
src/components/NumFound/NumFound.tsx Gate SortStats rendering on searchStatus === 'success' to prevent stale stats requests.

}, [prefix, searchTerm, sortDir]);

const isQueryEnabled = enabled && isNonEmptyString(searchQuery?.q?.trim());
const isQueryEnabled = enabled && searchStatus === 'success';
Comment on lines +279 to +286
if (data.response.numFound === 0) {
setSearchStatus('empty');
} else {
setDocs(data.response.docs.map((d) => d.bibcode));
setQuery(searchParams);
submitQuery();
setSearchStatus('success');
}
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.

2 participants