Skip to content
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

debounce modal navigation #5006

Closed
wants to merge 5 commits into from
Closed

Conversation

sashankaryal
Copy link
Contributor

@sashankaryal sashankaryal commented Oct 30, 2024

What changes are proposed in this pull request?

This PR allows modal navigation to be debounced. The first navigation command is immediately executed, whereas subsequent commands are accumulated and executed later. This should reduce the number of network requests incurred when users navigate really fast, and also improve perceived sample navigation speed.

How is this patch tested? If it is not, please explain why.

Unit tests. Local smoke tests. All existing E2E green.

What areas of FiftyOne does this PR affect?

  • App: FiftyOne application changes
  • Build: Build and test infrastructure changes
  • Core: Core fiftyone Python library changes
  • Documentation: FiftyOne documentation changes
  • Other

Summary by CodeRabbit

  • New Features

    • Introduced a debounced navigation mechanism for modal components, enhancing responsiveness.
    • Added optional offset parameters for pagination control in navigation functions.
  • Bug Fixes

    • Improved handling of illegal navigation states in modal navigation.
  • Tests

    • Added unit tests for the new debounced navigation functionality.
  • Documentation

    • Updated method signatures and functionality descriptions for navigation methods.

@sashankaryal sashankaryal added the app Issues related to App features label Oct 30, 2024
@sashankaryal sashankaryal requested review from benjaminpkane and a team October 30, 2024 16:37
@sashankaryal sashankaryal self-assigned this Oct 30, 2024
Copy link
Contributor

coderabbitai bot commented Oct 30, 2024

Walkthrough

The changes introduced in this pull request enhance the modal navigation system by implementing a debounced navigation mechanism. This involves creating a new createDebouncedNavigator function to manage navigation actions with debouncing, ensuring smoother user interactions. Additionally, unit tests for the new navigator are added to validate its functionality. The modal's hooks are updated to maintain referential stability, and pagination functions are modified to include an optional offset parameter, allowing for more flexible navigation through samples.

Changes

File Change Summary
app/packages/core/src/components/Modal/ModalNavigation.tsx Introduced debounced navigation using createDebouncedNavigator. Updated keyboard handling to use debounced functions.
app/packages/core/src/components/Modal/debouncedNavigator.ts Added DebouncedNavigatorOptions interface and createDebouncedNavigator function for debounced navigation control.
app/packages/core/src/components/Modal/debouncedNavigator.test.ts Created unit tests for createDebouncedNavigator, covering various navigation scenarios and behaviors.
app/packages/core/src/components/Modal/hooks.ts Added useRef hooks for jsonPanel and helpPanel to maintain referential stability. Updated onNavigate to utilize these refs.
app/packages/state/src/hooks/useExpandSample.ts Updated next and previous functions to accept an optional offset parameter for dynamic pagination control.
app/packages/state/src/recoil/modal.ts Modified ModalNavigation type to update next and previous method signatures to accept an optional offset parameter.

Possibly related PRs

  • fix modal navigation bug #4803: This PR addresses a bug related to modal navigation, which is directly connected to the changes made in the main PR regarding the navigation mechanism in ModalNavigation.tsx.
  • Fix dynamic groups carousel bug #4863: Although primarily focused on a carousel bug, this PR involves navigation functionality within the modal context, which may relate to the overall navigation improvements introduced in the main PR.

Suggested reviewers

  • benjaminpkane
  • imanjra

Poem

🐰 In the modal's dance, we hop and sway,
With debounced moves, we find our way.
Offsets now guide us, smooth and bright,
Navigating samples, a joyful flight!
So let us leap, with joy and cheer,
For smoother journeys, the time is here! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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 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.

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

@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: 8

🧹 Outside diff range and nitpick comments (5)
app/packages/core/src/components/Modal/debouncedNavigator.ts (1)

8-16: Extract debounce time default as a named constant

Consider extracting the magic number 100 as a named constant at the module level for better maintainability and documentation.

+const DEFAULT_DEBOUNCE_TIME_MS = 100;
+
 export function createDebouncedNavigator({
   isNavigationIllegalWhen,
   navigateFn,
   onNavigationStart,
-  debounceTime = 100,
+  debounceTime = DEFAULT_DEBOUNCE_TIME_MS,
 }: DebouncedNavigatorOptions) {
app/packages/core/src/components/Modal/hooks.ts (1)

11-17: Remove resolved TODO comment

The implementation correctly uses refs to solve the referential stability issue mentioned in the TODO comment. Since the solution is now implemented, the TODO comment can be removed.

-  // todo: jsonPanel and helpPanel are not referentially stable
-  // so use refs here
  const jsonPanelRef = useRef(jsonPanel);
  const helpPanelRef = useRef(helpPanel);
app/packages/state/src/recoil/modal.ts (1)

122-123: LGTM! The type changes align well with the debouncing requirements.

The addition of the optional offset parameter to both navigation methods provides the necessary flexibility for implementing debounced navigation while maintaining type safety. This change enables:

  • Immediate execution of single navigation commands (when offset is undefined)
  • Accumulation of multiple rapid navigation commands (using offset)

Consider documenting the following contract in the type definition:

  • Positive offset values indicate forward navigation
  • Negative offset values indicate backward navigation
  • Undefined offset represents single-step navigation
app/packages/core/src/components/Modal/debouncedNavigator.test.ts (2)

1-27: Consider extracting the debounce time as a constant.

The debounce time of 100ms is used in multiple test cases. Consider extracting it to a constant at the top of the file for better maintainability.

+const DEBOUNCE_TIME_MS = 100;

 describe("createDebouncedNavigator", () => {
   // ...
   debouncedNavigator = createDebouncedNavigator({
     isNavigationIllegalWhen,
     navigateFn,
     onNavigationStart,
-    debounceTime: 100,
+    debounceTime: DEBOUNCE_TIME_MS,
   });

48-54: Consider using the debounce time constant in timing assertions.

The timing values (50ms, 100ms) should use the same constant as the debounce time configuration for better maintainability and clarity.

-vi.advanceTimersByTime(50);
+vi.advanceTimersByTime(DEBOUNCE_TIME_MS / 2);

-vi.advanceTimersByTime(100);
+vi.advanceTimersByTime(DEBOUNCE_TIME_MS);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 95955c9 and 6df55b0.

📒 Files selected for processing (6)
  • app/packages/core/src/components/Modal/ModalNavigation.tsx (5 hunks)
  • app/packages/core/src/components/Modal/debouncedNavigator.test.ts (1 hunks)
  • app/packages/core/src/components/Modal/debouncedNavigator.ts (1 hunks)
  • app/packages/core/src/components/Modal/hooks.ts (1 hunks)
  • app/packages/state/src/hooks/useExpandSample.ts (2 hunks)
  • app/packages/state/src/recoil/modal.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
app/packages/core/src/components/Modal/ModalNavigation.tsx (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/core/src/components/Modal/debouncedNavigator.test.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/core/src/components/Modal/debouncedNavigator.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/core/src/components/Modal/hooks.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/state/src/hooks/useExpandSample.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

app/packages/state/src/recoil/modal.ts (1)

Pattern **/*.{ts,tsx}: Review the Typescript and React code for conformity with best practices in React, Recoil, Graphql, and Typescript. Highlight any deviations.

🔇 Additional comments (14)
app/packages/core/src/components/Modal/debouncedNavigator.ts (1)

18-25: LGTM! Clean implementation of state cleanup

The cleanup function properly handles all state variables and timeout clearing.

app/packages/core/src/components/Modal/hooks.ts (2)

3-3: LGTM: Import addition is appropriate

The addition of useRef import is necessary for the new ref-based implementation.


19-22: Verify integration with debounced navigation

The stable panel references should work well with the debounced navigation mechanism, but we should verify that panel closures are properly debounced when rapid navigation occurs.

✅ Verification successful

Panel closures are properly integrated with debounced navigation

The implementation correctly handles panel closures during navigation:

  • The onNavigate callback (which closes panels) is properly integrated into the debounced navigator as onNavigationStart
  • The debounced navigator calls onNavigationStart at appropriate times:
    • Immediately on the first navigation
    • After the debounce period (150ms) for subsequent rapid navigations
  • Panel closures won't be triggered unnecessarily during rapid navigation due to the debouncing mechanism
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for debounced navigator implementation and its usage with panels
ast-grep --pattern 'createDebouncedNavigator($$$)' 
rg -A 5 'onNavigate.*close'

Length of output: 1923


Script:

#!/bin/bash
# Let's examine the implementation of the debounced navigator and how it handles the onNavigationStart callback
cat app/packages/core/src/components/Modal/debouncedNavigator.ts

# Also check the implementation of onNavigate in the Modal component
cat app/packages/core/src/components/Modal/ModalNavigation.tsx

# And check for any panel-related tests
rg -l "panel.*close" --type ts

Length of output: 6187

app/packages/state/src/hooks/useExpandSample.ts (1)

68-83: Verify integration with debouncing mechanism.

The offset-based navigation support is crucial for the debouncing implementation. Let's verify that the debouncing logic correctly utilizes these offset parameters when accumulating navigation commands.

✅ Verification successful

Debouncing mechanism correctly integrates with offset-based navigation

The implementation is properly integrated:

  • The createDebouncedNavigator correctly accumulates navigation offsets during the debounce period
  • The ModalNavigation component uses two debounced navigators (next/previous) that properly utilize the offset parameter
  • Tests verify that offsets are accumulated and passed correctly to navigation functions
  • The debouncing mechanism is thoroughly tested for various scenarios including offset accumulation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the debouncing implementation that uses these navigation functions
rg -t typescript -l "createDebouncedNavigator|useExpandSample.*offset" 

# Look for tests validating the debounced navigation
rg -t typescript "describe.*[Dd]ebounce.*[Nn]avig" -A 10

Length of output: 201


Script:

#!/bin/bash
# Search for the debouncing implementation that uses these navigation functions
rg "createDebouncedNavigator|useExpandSample.*offset"

# Look for tests validating the debounced navigation
rg "describe.*[Dd]ebounce.*[Nn]avig" -A 10

# Search for files containing both debounce and navigation related terms
rg -l "debounce.*\W+.*next|next.*\W+.*debounce"

# Look for the implementation context around useExpandSample
rg "useExpandSample" -A 10 -B 10

Length of output: 5726


Script:

#!/bin/bash
# Look at the debounced navigator implementation
cat app/packages/core/src/components/Modal/debouncedNavigator.ts

# Check the test file for navigation offset usage
cat app/packages/core/src/components/Modal/debouncedNavigator.test.ts

# Look at the modal navigation implementation
cat app/packages/core/src/components/Modal/ModalNavigation.tsx

Length of output: 11616

app/packages/state/src/recoil/modal.ts (1)

122-123: Verify the impact on existing modal navigation implementations.

The type signature change requires updates to all implementations of ModalNavigation.

✅ Verification successful

Let me gather more specific information about the ModalNavigation interface and its implementations.


Let me try one more search to find any implementations or usages with a different pattern.


The optional offset parameter is already being used correctly in the codebase

The search results show that the existing implementation in app/packages/core/src/components/Modal/ModalNavigation.tsx already uses the offset parameter when calling both next(offset) and previous(offset). Therefore, the type signature change to make the offset parameter optional is actually aligning with the current usage pattern and doesn't require any implementation updates.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for implementations of ModalNavigation interface
ast-grep --pattern 'implements ModalNavigation {
  $$$
}'

# Search for direct usage of next/previous methods
rg -A 2 '\b(next|previous)\s*\(\s*\)' --type ts

Length of output: 1695


Script:

#!/bin/bash
# Search for ModalNavigation interface definition
ast-grep --pattern 'interface ModalNavigation {
  $$$
}'

# Search for classes implementing ModalNavigation with next/previous methods
ast-grep --pattern 'class $_ implements ModalNavigation {
  $$$
  next($$$) {
    $$$
  }
  $$$
}'

# Search for more specific usage of next/previous with offset parameter
rg '\b(next|previous)\s*\(\s*\d+\s*\)' --type ts

Length of output: 210


Script:

#!/bin/bash
# Search for files containing both ModalNavigation and next/previous methods
rg -l "ModalNavigation" --type ts | xargs rg -A 5 "\b(next|previous)\b"

# Search for any imports of ModalNavigation
rg "import.*ModalNavigation" --type ts

# Search for any type annotations using ModalNavigation
rg ": ModalNavigation" --type ts

Length of output: 3186

app/packages/core/src/components/Modal/debouncedNavigator.test.ts (1)

1-181: Well-structured test suite with comprehensive coverage.

The test implementation is solid, following testing best practices with:

  • Clear test organization
  • Proper setup and teardown
  • Comprehensive coverage of main scenarios
  • Good use of mock functions and fake timers
app/packages/core/src/components/Modal/ModalNavigation.tsx (8)

6-6: Imports are appropriate and necessary

The imported React hooks (useCallback, useEffect, useMemo, useRef) are correctly utilized in the component to manage state and performance optimizations.


9-9: Correctly importing createDebouncedNavigator

The createDebouncedNavigator is properly imported from ./debouncedNavigator, enabling the debounced navigation functionality.


71-82: Dependencies for nextNavigator are correctly specified

The dependencies in the useMemo hook for nextNavigator are appropriately set to navigation, onNavigate, and setModal. This ensures that the navigator remains referentially stable and only re-creates when necessary.


84-93: Dependencies for previousNavigator are correctly specified

Similarly, the useMemo hook for previousNavigator has the correct dependencies, ensuring stability and proper functioning of the debounced navigator.


95-100: Proper cleanup of debounced navigators

The useEffect hook effectively cleans up the nextNavigator and previousNavigator when the component unmounts or when the navigators change, preventing potential memory leaks.


116-118: Keyboard navigation handlers correctly updated

The keyboard event handlers now utilize previousNavigator.navigate() and nextNavigator.navigate(), integrating the debounced navigation functionality seamlessly.


121-121: Dependencies for keyboardHandler are accurate

The dependency array for keyboardHandler includes nextNavigator and previousNavigator, ensuring that the handler updates appropriately when these navigators change.


Line range hint 136-146: Arrow click handlers use debounced navigators

The onClick handlers for the navigation arrows are correctly updated to use previousNavigator.navigate and nextNavigator.navigate, providing debounced navigation on user clicks.

Copy link
Contributor

@benjaminpkane benjaminpkane left a comment

Choose a reason for hiding this comment

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

Looks good! Let's wait for the performance patch branch and target that

@findtopher findtopher deleted the branch release/v1.1.0 October 30, 2024 19:00
@findtopher findtopher closed this Oct 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
app Issues related to App features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants