Skip to content

added infinite scroll in search results #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

MayankBansal2004
Copy link
Contributor

@MayankBansal2004 MayankBansal2004 commented Apr 13, 2025

Description

added the infinite scroll in the search results.

Testing

i have tested visually it's working well.

Additional Notes

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Introduced infinite scrolling for search results, enabling automatic loading of additional content as you scroll.
    • Replaced the "load more" button with a dynamic loading indicator to enhance the user experience.
    • Added a loading state to improve feedback during data fetching.

Copy link

coderabbitai bot commented Apr 13, 2025

Walkthrough

The changes integrate infinite scrolling into the Search component. A new isLoading state tracks loading status during pagination. An IntersectionObserver monitors a sentinel div at the bottom of the results list, triggering additional data fetches when it becomes visible and more results are available. The previous manual "More Results" button is removed and replaced by this automatic loading mechanism. The handleNext function is moved earlier in the code without changing its logic. Loading state resets upon new results arrival or fetch errors. Minor cleanup includes removal of unused imports and reordering of related variables.

Changes

File Change Summary
frontend/src/routes/_authenticated/search.tsx - Replaced manual pagination button with infinite scroll using IntersectionObserver.
- Added isLoading state and bottomRef sentinel.
- Moved handleNext function earlier, unchanged logic.
- Removed unused imports and ChevronDown icon.
- Adjusted loading state management and conditional rendering of loader.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SearchComp as Search Component
    participant Observer as IntersectionObserver
    participant API as Server API

    User->>SearchComp: Scrolls down
    SearchComp->>Observer: Observe bottom sentinel div
    Observer-->>SearchComp: Sentinel visible & more results available
    SearchComp->>SearchComp: Set isLoading = true
    SearchComp->>API: Fetch next page of results
    API-->>SearchComp: Return additional results
    SearchComp->>SearchComp: Append results and set isLoading = false
    SearchComp->>Observer: Disconnect if no more results
Loading

Poem

🐇 I’m a rabbit swift and keen,
Watching scrolls on every screen.
When the end comes into sight,
I fetch more results with delight.
No buttons slow my hopping pace,
Just endless scroll in endless space!
Happy coding, keep the race! 🚀


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 952d34d and 0604802.

📒 Files selected for processing (1)
  • frontend/src/routes/_authenticated/search.tsx (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/routes/_authenticated/search.tsx
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Hello @MayankBansal2004, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Summary of Changes

This pull request by MayankBansal2004 introduces infinite scrolling to the search results page. The primary goal is to enhance the user experience by automatically loading more results as the user scrolls down, eliminating the need for manual pagination. The changes involve adding an intersection observer to detect when the user reaches the bottom of the result list, triggering the loading of additional results. The PR also includes logic to manage the loading state and prevent redundant requests.

Highlights

  • Infinite Scroll Implementation: Implemented infinite scrolling using an Intersection Observer to detect when the user reaches the bottom of the search results.
  • Loading State Management: Added a loading state to indicate when more results are being fetched and prevent multiple simultaneous requests.
  • Conditional Rendering of Loading Indicator: Implemented conditional rendering of a loading indicator at the bottom of the search results while new data is being fetched.
  • Filter-Aware Pagination: Ensured that the infinite scroll functionality respects the applied filters and only loads more results within the filtered subset.

Changelog

  • frontend/src/routes/_authenticated/search.tsx
    • Removed unused ChevronDown import from line 39.
    • Added bottomRef to track the bottom of the search results for the intersection observer on line 122.
    • Added isLoading state to manage the loading state during infinite scroll on line 123.
    • Implemented a useEffect hook with an Intersection Observer to trigger loading more results when the bottom of the list is visible, with checks to ensure results are available, the filter page size is greater than the current page, the results length is less than the filter page size, and that loading is not already in progress, starting on line 153.
    • Added logic to reset the loading state after results are received on line 374.
    • Added logic to reset the loading state in case of an error during the search request on line 392.
    • Removed totalCount and filterPageSize declarations from the main component body and moved them to the top of the component on lines 113 and 114.
    • Replaced the 'More Results' button with a loading indicator that appears during infinite scroll on lines 541-550.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


The scroll extends, a boundless quest,
For data sought, put to the test.
No click required,
New knowledge acquired,
Infinite content, truly blessed.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request introduces infinite scrolling to the search results page, which should improve the user experience. The implementation appears to be well-structured, utilizing IntersectionObserver for efficient loading. However, there are a few areas that could be improved for clarity and robustness.

Summary of Findings

  • Potential Race Condition: There's a potential race condition where handleNext might be called multiple times in quick succession if the intersection observer triggers rapidly. This could lead to multiple requests being fired off before the isLoading state has a chance to update, potentially causing unexpected behavior or data duplication.
  • Error Handling in Intersection Observer: The intersection observer's callback doesn't have explicit error handling. If handleNext fails, the isLoading state might not be reset, preventing further loading. This could lead to a broken infinite scroll experience.
  • Redundant Condition in Loading Indicator: The loading indicator's visibility condition includes filterPageSize > page, which seems redundant since results.length < filterPageSize already implies that page is not yet at the maximum.

Merge Readiness

The pull request is a good step towards improving the search results page. However, the potential race condition and lack of error handling in the intersection observer should be addressed before merging. I am unable to approve this pull request, and recommend that others review and approve this code before merging. At a minimum, the high severity issues should be addressed before merging.

Comment on lines +167 to +168
setIsLoading(true)
handleNext()
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Consider adding a check within handleNext to see if isLoading is already true to prevent multiple calls in quick succession. This can prevent race conditions where multiple requests are fired off before the state has a chance to update.

          if (isLoading) {
            return; // Prevent multiple calls
          }
          setIsLoading(true)
          handleNext()

) {
// Load more results when bottom is visible
setIsLoading(true)
handleNext()
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Add a .finally() block to handleNext to ensure setIsLoading(false) is always called, even if there's an error. This prevents the loading indicator from getting stuck if the request fails.

          setIsLoading(true)
          handleNext()
          .finally(() => setIsLoading(false));

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
frontend/src/routes/_authenticated/search.tsx (2)

113-119: Consider using useMemo for derived values

The variables totalCount and filterPageSize are calculated on every render. Since they're used in the IntersectionObserver effect's dependency array and might be expensive to recalculate, consider memoizing them.

-const totalCount = searchMeta?.totalCount || 0
-const filterPageSize =
-  filter.app && filter.entity
-    ? groups
-      ? groups[filter.app][filter.entity]
-      : totalCount
-    : totalCount
+const totalCount = useMemo(() => searchMeta?.totalCount || 0, [searchMeta])
+const filterPageSize = useMemo(() => {
+  if (filter.app && filter.entity) {
+    return groups ? groups[filter.app][filter.entity] : totalCount
+  }
+  return totalCount
+}, [filter.app, filter.entity, groups, totalCount])

541-551: Add feedback when all results are loaded

The infinite scroll implementation works well, but consider adding a message when all results have been loaded to provide better feedback to users.

{/* Infinite scroll loading indicator and bottom reference */}
{results.length > 0 && (
  <div ref={bottomRef} className="py-4 flex justify-center">
    {isLoading && filterPageSize > page && results.length < filterPageSize ? (
      <div className="flex items-center space-x-2">
        <div className="w-4 h-4 rounded-full border-2 border-t-transparent border-blue-500 animate-spin"></div>
        <span className="text-gray-500">Loading more results...</span>
      </div>
+   ) : results.length >= filterPageSize ? (
+     <div className="text-gray-500">All results loaded</div>
    ) : null}
  </div>
)}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ca5109 and e5a0234.

📒 Files selected for processing (1)
  • frontend/src/routes/_authenticated/search.tsx (6 hunks)
🔇 Additional comments (3)
frontend/src/routes/_authenticated/search.tsx (3)

121-123: LGTM! Good implementation of infinite scroll state variables

The approach of using useRef for the bottom element reference and useState for loading state is appropriate for implementing infinite scroll functionality.


373-375: LGTM! Proper loading state management

Good addition to reset the loading state after results are successfully received.


392-392: LGTM! Error state handling

Good addition to reset the loading state when an error occurs, preventing the UI from being stuck in a loading state.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
frontend/src/routes/_authenticated/search.tsx (2)

545-545: Simplify the loading indicator condition.

The condition for showing the loading indicator can be simplified for better readability.

-{isLoading && filterPageSize > page && results.length < filterPageSize ? (
+{isLoading && results.length < filterPageSize ? (

If results.length < filterPageSize, it already implies that there are more results to load, making the filterPageSize > page check redundant.


172-174: ⚠️ Potential issue

Prevent race conditions in loading logic.

The current implementation could trigger multiple requests if the user scrolls quickly or the network is slow.

Implement proper loading state management by adding a check before triggering handleNext and ensuring loading state is always reset:

-          setIsLoading(true)
-          handleNext()
+          if (isLoading) {
+            return; // Prevent multiple calls
+          }
+          setIsLoading(true)
+          handleNext()
+            .finally(() => setIsLoading(false));

Since handleNext doesn't return a Promise, consider modifying it as suggested in the previous comment so that .finally() works correctly.

🧹 Nitpick comments (1)
frontend/src/routes/_authenticated/search.tsx (1)

158-177: Inconsistency in the IntersectionObserver threshold comment.

The comment states "Trigger when 10% of the element is visible" but the threshold is set to 0.5 (50%).

-  { threshold: 0.5 } // Trigger when 10% of the element is visible
+  { threshold: 0.5 } // Trigger when 50% of the element is visible
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e5a0234 and 8348c2b.

📒 Files selected for processing (1)
  • frontend/src/routes/_authenticated/search.tsx (6 hunks)
🔇 Additional comments (5)
frontend/src/routes/_authenticated/search.tsx (5)

113-124: Good job centralizing key variables for better readability!

Moving totalCount and filterPageSize calculations to the top of the component makes the code more maintainable, and adding clear comments about the purpose of the new variables helps with code clarity.


158-186: Missing handleNext in the useEffect dependency array.

The dependency array for the IntersectionObserver useEffect should include handleNext to avoid potential stale closure issues.

Good job including handleNext in the dependency array! This prevents stale closure issues if handleNext references state that changes over time.


378-381: Good practice setting loading state after success.

Explicitly resetting the loading state after results are received is a good practice to ensure the UI accurately reflects the application state.


397-397: Good error handling with loading state reset.

Resetting the loading state in the error case is crucial to prevent the UI from being stuck in a loading state when errors occur.


542-552: Well-implemented infinite scroll UI element.

The loading indicator is clearly visible and provides good feedback to users. The implementation with a separate div element for the observer reference is clean.

@zereraz zereraz requested a review from kalpadhwaryu April 21, 2025 11:23
<div ref={bottomRef} className="py-4 flex justify-center">
{isLoading && filterPageSize > page && results.length < filterPageSize ? (
<div className="flex items-center space-x-2">
<div className="w-4 h-4 rounded-full border-2 border-t-transparent border-blue-500 animate-spin"></div>
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of this div, use LoaderContent component from common.tsx

) // State for debug info visibility, initialized from env var
const [traceData, setTraceData] = useState<any | null>(null) // State for trace data
// close autocomplete if clicked outside
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we removing important comments and todos? Add them again everywhere.

observerRef.current = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && !isLoading) {
const totalCount = searchMeta?.totalCount || 0
Copy link
Contributor

Choose a reason for hiding this comment

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

totalCount and filterPageSize consts are derived twice in this file. Just derive them once.

const autocompleteRef = useRef<HTMLDivElement | null>(null)
const [autocompleteQuery, setAutocompleteQuery] = useState("")
const observerRef = useRef<IntersectionObserver | null>(null)
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't use ref for the observer itself. Go back to the previous version what you had done before.

/>
))}
</div>
{results.length > 0 && results.length < filterPageSize && (
<div ref={loadMoreRef} className="h-10"></div>
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we sure we want to remove Loading animation? What happens when user has reached the bottom of search results and still the next page results are being fetched. Check with slow internet.

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