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

Fix activity pagination, load more functionality #2671

Merged
merged 1 commit into from
Nov 4, 2024

Conversation

gaspergrom
Copy link
Contributor

@gaspergrom gaspergrom commented Nov 4, 2024

Changes proposed ✍️

What

copilot:summary

copilot:poem

Why

How

copilot:walkthrough

Checklist ✅

  • Label appropriately with Feature, Improvement, or Bug.
  • Add screenshots to the PR description for relevant FE changes
  • New backend functionality has been unit-tested.
  • API documentation has been updated (if necessary) (see docs on API documentation).
  • Quality standards are met.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced LfScrollControll component for improved scroll handling in various sections.
    • Enhanced activity loading functionality across contributor and organization detail pages.
    • Added dynamic loading of activities based on user interaction with scroll events.
  • Bug Fixes

    • Simplified rendering logic for activity timelines by refining loading conditions.
  • Documentation

    • Updated references and methods to improve clarity and accessibility for external components.
  • Style

    • Applied new styles to ensure consistent maximum height for scroll containers across components.

@gaspergrom gaspergrom added the Bug Created by Linear-GitHub Sync label Nov 4, 2024
@gaspergrom gaspergrom requested a review from themarolt November 4, 2024 10:46
@gaspergrom gaspergrom self-assigned this Nov 4, 2024
Copy link

coderabbitai bot commented Nov 4, 2024

Walkthrough

The changes in this pull request include the introduction of a new component, LfScrollControll, which enhances scrolling functionality across various components. Modifications to existing components such as activity-timeline, contributor-details-activities, and organization-details-activities enable better loading of activities through improved event handling and state management. The logic for fetching activities has been refined, and several variables and methods have been added or updated to facilitate these changes. Overall, the updates aim to improve user interaction and data loading efficiency within the application.

Changes

File Path Change Summary
frontend/src/modules/activity/components/activity-timeline.vue Modified rendering logic, updated loading button, changed activity limit, and exposed fetchActivities.
frontend/src/modules/contributor/components/details/contributor-details-activities.vue Added loadMore method, created timeline reference, and defined masked computed property.
frontend/src/modules/contributor/pages/contributor-details.page.vue Introduced activities reference and updated controlScroll function for dynamic loading.
frontend/src/modules/data-quality/components/member/data-quality-member-issues.vue Added LfScrollControll component for scroll management and defined .scroll-container style.
frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue Integrated LfScrollControll for merge suggestions with scroll functionality and added .scroll-container style.
frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue Implemented LfScrollControll for displaying merge suggestions with scroll control and added .scroll-container style.
frontend/src/modules/data-quality/pages/data-quality.page.vue Updated <app-page-wrapper> to include a new class for styling adjustments.
frontend/src/modules/organization/components/details/organization-details-activities.vue Added loadMore method and created timeline reference for activity loading.
frontend/src/modules/organization/pages/organization-details.page.vue Introduced activities reference and modified contributors initialization for better state management.
frontend/src/ui-kit/scrollcontroll/ScrollControll.vue Created LfScrollControll component to manage scroll events and emit bottom event.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ActivitiesComponent
    participant ScrollControll

    User->>ActivitiesComponent: Scroll down
    ActivitiesComponent->>ScrollControll: Check scroll position
    ScrollControll-->>ActivitiesComponent: Emit bottom event
    ActivitiesComponent->>ActivitiesComponent: Call loadMore()
    ActivitiesComponent->>ActivitiesComponent: Fetch more activities
    ActivitiesComponent-->>User: Display additional activities
Loading

🐰 "In the meadow where bunnies play,
New features hop in, hip-hip-hooray!
With scrolls that dance and loads that cheer,
Activities bloom, bringing us near!
So let’s fetch more, with a joyful grin,
A world of fun, let the updates begin!" 🐇✨


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.

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

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

🧹 Outside diff range and nitpick comments (13)
frontend/src/ui-kit/scrollcontroll/ScrollControll.vue (1)

1-5: Consider enhancing accessibility and customization options.

The scrollable container should have proper ARIA attributes for better accessibility. Also, consider making the scroll threshold configurable.

 <template>
-  <div class="relative overflow-auto" v-bind="$attrs" @scroll="controlScroll">
+  <div
+    class="relative overflow-auto"
+    role="region"
+    aria-label="Scrollable content"
+    v-bind="$attrs"
+    @scroll="controlScroll"
+  >
     <slot />
   </div>
 </template>
frontend/src/modules/data-quality/pages/data-quality.page.vue (1)

Line range hint 2-39: Consider implementing virtual scrolling for better performance.

Given that this PR focuses on pagination and load more functionality, and this component serves as a parent for data-heavy views (People and Organizations), it might benefit from virtual scrolling implementation.

Consider:

  1. Using a virtual scrolling library like vue-virtual-scroller for the child components
  2. Implementing pagination state management at this level to share common pagination logic between tabs
  3. Adding a loading state indicator for better UX during data fetching

Would you like assistance in implementing any of these suggestions?

frontend/src/modules/organization/components/details/organization-details-activities.vue (1)

46-54: Consider extracting pagination logic into a composable

Since this pagination pattern is being implemented across multiple components (organization-details-activities, contributor-details-activities), consider creating a reusable composable.

Example approach:

// useActivityPagination.ts
import { ref } from 'vue'
import type { AppActivityTimeline } from '@/modules/activity/components/activity-timeline.vue'

export function useActivityPagination() {
  const timeline = ref<AppActivityTimeline | null>(null)
  const loading = ref(false)

  const loadMore = async () => {
    if (!timeline.value || loading.value) return
    
    try {
      loading.value = true
      await timeline.value.fetchActivities()
    } catch (error) {
      console.error('Failed to load more activities:', error)
    } finally {
      loading.value = false
    }
  }

  return {
    timeline,
    loading,
    loadMore
  }
}

This would:

  • Reduce code duplication
  • Ensure consistent behavior across components
  • Make it easier to maintain and modify pagination logic
frontend/src/modules/contributor/components/details/contributor-details-activities.vue (2)

57-57: Add type safety to timeline ref

Consider adding type safety to the timeline ref for better TypeScript integration.

-const timeline = ref(null);
+const timeline = ref<InstanceType<typeof AppActivityTimeline> | null>(null);

67-69: Consider exposing loading state

The loading state should be exposed to parent components for better UX coordination.

 defineExpose({
   loadMore,
+  isLoading,
 });
frontend/src/modules/data-quality/components/member/data-quality-member-issues.vue (2)

148-152: Consider improving the scroll container styles.

A few suggestions to enhance maintainability and prevent potential issues:

  1. Add scoping to prevent style conflicts
  2. Document the magic number (228px) calculation
  3. Consider using CSS variables for better maintainability
-<style lang="scss">
+<style lang="scss" scoped>
+// Height calculation:
+// 228px = Header height (64px) + Padding (40px) + Tabs (48px) + Additional spacing (76px)
+$header-offset: 228px;
+
 .scroll-container{
-  max-height: calc(100vh - 228px);
+  max-height: calc(100vh - #{$header-offset});
 }
 </style>

Line range hint 6-39: Consider adding error handling for load more functionality.

While the implementation works well, it might benefit from error handling to improve user experience when loading fails.

Consider adding error state handling:

 <lf-scroll-controll v-else-if="members.length > 0" class="scroll-container -mb-4" @bottom="loadMore()">
+  <div v-if="error" class="text-red-500 text-sm text-center py-2">
+    Failed to load more items. Please try again.
+  </div>
   <!-- existing content -->
 </lf-scroll-controll>

And in the script:

const error = ref(false);

const loadDataIssues = () => {
  error.value = false;
  loading.value = true;
  // ... existing code ...
    .catch(() => {
      error.value = true;
    })
    .finally(() => {
      loading.value = false;
    });
};
frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue (2)

Line range hint 6-28: Consider adding loading state for infinite scroll.

While there's a loading indicator for the initial load, there's no visual feedback when loading more items through scrolling. This might confuse users about whether more content is being loaded.

Consider adding a loading indicator at the bottom of the scroll container:

     <lf-scroll-controll v-else-if="mergeSuggestions.length > 0" class="scroll-container -mb-4" @bottom="loadMore()">
       <!-- ... existing content ... -->
+      <div v-if="loadingMore" class="flex justify-center py-4">
+        <lf-spinner size="small" />
+      </div>
     </lf-scroll-controll>

136-140: Improve scroll container height calculation.

The current implementation uses a magic number (228px) which makes maintenance difficult and might not work well across different screen sizes and layouts.

Consider these improvements:

  1. Use CSS custom properties for better maintainability:
-  max-height: calc(100vh - 228px);
+  max-height: calc(100vh - var(--header-height) - var(--padding-top) - var(--padding-bottom));
  1. Add responsive behavior:
 .scroll-container {
-  max-height: calc(100vh - 228px);
+  max-height: calc(100vh - 228px);
+  @media (max-width: 768px) {
+    max-height: calc(100vh - 180px);
+  }
 }
  1. Scope the styles to prevent conflicts:
-<style lang="scss">
+<style lang="scss" scoped>
frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue (1)

153-157: Document the magic number in the height calculation.

The calc(100vh - 228px) uses a magic number that should be documented. Consider:

  1. Adding a comment explaining how 228px was calculated
  2. Using CSS variables for better maintainability

Here's a suggested improvement:

 <style lang="scss">
+/* 228px breakdown:
+ * - Header height: XXpx
+ * - Padding: XXpx
+ * - Other elements: XXpx
+ */
+:root {
+  --header-offset: 228px;
+}
 .scroll-container{
-  max-height: calc(100vh - 228px);
+  max-height: calc(100vh - var(--header-offset));
 }
 </style>
frontend/src/modules/contributor/pages/contributor-details.page.vue (2)

136-136: Consider using proper type instead of 'any'

Replace any with the proper component type for better type safety and IDE support.

-const activities = ref<any>(null);
+const activities = ref<InstanceType<typeof LfContributorDetailsActivities> | null>(null);

82-82: Consider decoupling scroll handling from parent component

The current implementation couples scroll handling with the parent component. Consider:

  1. Moving scroll handling to individual tab components
  2. Using a reusable scroll container component
  3. Implementing an event-based approach for load more functionality

This would improve component reusability and maintain better separation of concerns.

Also applies to: 136-136, 158-159

frontend/src/modules/organization/pages/organization-details.page.vue (1)

139-140: Consider adding TypeScript types for refs.

While the ref initialization is correct, consider adding explicit types for better type safety:

-const contributors = ref(null);
-const activities = ref(null);
+const contributors = ref<InstanceType<typeof LfOrganizationDetailsContributors> | null>(null);
+const activities = ref<InstanceType<typeof LfOrganizationDetailsActivities> | null>(null);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6875221 and 1e0b557.

📒 Files selected for processing (10)
  • frontend/src/modules/activity/components/activity-timeline.vue (8 hunks)
  • frontend/src/modules/contributor/components/details/contributor-details-activities.vue (3 hunks)
  • frontend/src/modules/contributor/pages/contributor-details.page.vue (3 hunks)
  • frontend/src/modules/data-quality/components/member/data-quality-member-issues.vue (4 hunks)
  • frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue (4 hunks)
  • frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue (4 hunks)
  • frontend/src/modules/data-quality/pages/data-quality.page.vue (1 hunks)
  • frontend/src/modules/organization/components/details/organization-details-activities.vue (2 hunks)
  • frontend/src/modules/organization/pages/organization-details.page.vue (3 hunks)
  • frontend/src/ui-kit/scrollcontroll/ScrollControll.vue (1 hunks)
🔇 Additional comments (19)
frontend/src/ui-kit/scrollcontroll/ScrollControll.vue (1)

1-21: Verify consistent usage across the application.

Let's ensure this component is being used consistently across all implementations.

✅ Verification successful

Let me gather more information about the actual usage patterns in these files.


Let me try a different approach using case-insensitive search and template syntax:


Component usage is consistent across all implementations

The verification shows consistent usage patterns across all three implementations:

  • All components use kebab-case lf-scroll-controll in templates
  • All implementations correctly use the @bottom event handler
  • All components consistently bind it to a loadMore() function
  • All have the same conditional rendering pattern with v-else-if and class scroll-container
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage patterns of LfScrollControll component
# Expected: Consistent usage of @bottom event and proper attribute passing

# Search for component usage
echo "Checking component usage patterns..."
rg -A 3 "LfScrollControll" frontend/src/modules/

# Check for potential scroll handling in other components that might need migration
echo "Checking for other scroll handlers that might need migration..."
ast-grep --pattern 'onScroll($$$) { $$$ }' frontend/src/modules/

Length of output: 1856


Script:

#!/bin/bash
# Check the actual implementation and usage in the identified files
echo "Checking data-quality-member-merge-suggestions.vue..."
rg -A 10 "<LfScrollControll" frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue

echo -e "\nChecking data-quality-organization-merge-suggestions.vue..."
rg -A 10 "<LfScrollControll" frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue

echo -e "\nChecking data-quality-member-issues.vue..."
rg -A 10 "<LfScrollControll" frontend/src/modules/data-quality/components/member/data-quality-member-issues.vue

Length of output: 728


Script:

#!/bin/bash
# Search for component usage with different possible template syntaxes
echo "Checking component usage with various syntaxes..."
rg -i -A 10 "<(lf-scroll-controll|lfscrollcontroll)" frontend/src/modules/data-quality/components/

# Also check for kebab-case usage in template
echo -e "\nChecking for kebab-case event handling..."
rg -i "@bottom" frontend/src/modules/data-quality/components/

# Check template section specifically
echo -e "\nChecking template sections..."
rg -p "<template>[\s\S]*?</template>" frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue
rg -p "<template>[\s\S]*?</template>" frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue
rg -p "<template>[\s\S]*?</template>" frontend/src/modules/data-quality/components/member/data-quality-member-issues.vue

Length of output: 6043

frontend/src/modules/data-quality/pages/data-quality.page.vue (1)

2-2: Verify the impact of padding removal on scroll functionality.

The removal of bottom padding using !pb-0 might be related to fixing scroll detection issues, but using the !important modifier (via Tailwind's ! prefix) could make the styling harder to maintain or override when needed.

Consider these alternatives:

  1. If this is for scroll detection, consider handling it in the scroll controller component instead of modifying padding
  2. If padding adjustment is necessary, consider using a more specific selector or a CSS custom property for better maintainability

Let's verify if other components have similar padding adjustments:

✅ Verification successful

Let me gather more context about the usage of these components and their scroll-related functionality.


The padding removal is intentional and correctly implemented

The !pb-0 class on app-page-wrapper is a necessary change that works in conjunction with the LfScrollControll component used in child components. The scroll containers in child components (data-quality-member-issues, data-quality-member-merge-suggestions, and data-quality-organization-merge-suggestions) all use a negative margin bottom (-mb-4) and have a calculated max height. Removing the parent's padding ensures proper scroll detection and consistent spacing.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar padding modifications in other components
rg -g '*.vue' '!pb-0' 

Length of output: 251


Script:

#!/bin/bash
# Check for scroll-related code in these components and their parent directories
rg -g '*.vue' -B 2 -A 2 'scroll' frontend/src/modules/automation frontend/src/modules/data-quality

# Look for LfScrollControl usage as mentioned in PR context
rg -g '*.vue' 'LfScrollControl' frontend/src/modules/automation frontend/src/modules/data-quality

Length of output: 8457

frontend/src/modules/organization/components/details/organization-details-activities.vue (1)

25-25: LGTM: Timeline ref properly integrated

The ref addition to app-activity-timeline is correctly implemented, enabling proper access to the component instance for pagination control.

frontend/src/modules/contributor/components/details/contributor-details-activities.vue (2)

30-30: LGTM: Timeline ref properly configured

The ref addition to AppActivityTimeline is correctly implemented, enabling proper interaction with the timeline component instance.


67-69: Verify parent component integration

The loadMore method is correctly exposed, but let's verify its integration with the parent component's scroll handling.

✅ Verification successful

Integration with parent component is properly implemented

The exposed loadMore method is correctly integrated in the parent component contributor-details.page.vue. The parent implements a scroll handler that calls activities.value.loadMore() when the 'activities' tab is active and the scroll reaches the bottom. This matches the expected integration pattern mentioned in the review.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of loadMore in parent components
rg -l "loadMore.*contributor-details-activities" frontend/src/modules/contributor/

Length of output: 84


Script:

#!/bin/bash
# Let's try a broader search for the component name and potential parent components
rg -l "contributor-details-activities" frontend/src/modules/contributor/

# Also search for loadMore usage in potential parent components
rg "loadMore" frontend/src/modules/contributor/ -A 3 -B 3

Length of output: 4372

frontend/src/modules/data-quality/components/member/data-quality-member-issues.vue (2)

67-67: LGTM! Import statement is correctly placed.

The LfScrollControll component is properly imported and integrates well with the existing load more functionality.


Line range hint 6-39: LGTM! Verify the negative margin's impact.

The scroll control implementation looks good and properly integrates with the existing member issues list. The infinite scroll trigger is correctly implemented using the @bottom event.

Please verify if the negative margin (-mb-4) affects the visual layout:

✅ Verification successful

Negative margin usage is consistent with similar components

The -mb-4 class is consistently used with lf-scroll-controll components across similar data quality views, including organization and member merge suggestions. This establishes a clear pattern for scroll container spacing in the application.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other instances of negative margins in similar components
rg -l "class=\".*-mb-4.*\"" "frontend/src/modules/**/*.vue"

Length of output: 129


Script:

#!/bin/bash
# Let's try searching without the glob pattern which might not be supported
# Search for negative margins in the frontend directory
rg -l "class=\".*-mb-4.*\"" frontend/

Length of output: 382


Script:

#!/bin/bash
# Let's examine the context of -mb-4 usage in these files to understand the pattern
rg "class=\".*-mb-4.*\"" frontend/src/modules/data-quality/components/ -C 2

Length of output: 2230

frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue (1)

6-6: Verify ScrollControll component implementation.

Let's ensure the ScrollControll component is implemented correctly and used consistently across the application.

Also applies to: 65-65

✅ Verification successful

ScrollControll component is correctly implemented and consistently used

The verification confirms:

  • The ScrollControll component is properly implemented in frontend/src/ui-kit/scrollcontroll/ScrollControll.vue with correct scroll event handling and bottom emission
  • It's consistently used across data quality components for both organization and member sections
  • The component name 'LfScrollControll' matches the usage in the reviewed code
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check ScrollControll component implementation
echo "Checking ScrollControll component implementation..."
cat frontend/src/ui-kit/scrollcontroll/ScrollControll.vue || echo "ScrollControll component not found at expected location"

# Check for consistent usage across the application
echo -e "\nChecking usage patterns..."
rg -l "LfScrollControll" frontend/src/

Length of output: 1052

frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue (2)

71-71: LGTM!

The import is correctly placed and follows the project's component organization pattern.


Line range hint 6-31: LGTM! Consider edge cases for scroll behavior.

The implementation of LfScrollControll looks good, providing both scroll-based and button-based loading. However, let's verify the scroll behavior in edge cases.

Please verify these scenarios:

  1. Rapid scrolling doesn't trigger multiple simultaneous requests
  2. Loading state is properly handled during scroll-triggered loads
  3. The component behaves correctly with different viewport sizes
✅ Verification successful

Scroll behavior implementation is properly handled

After reviewing the LfScrollControll component implementation, I can confirm that:

  1. The scroll logic is simple and robust, using a 10px threshold to trigger the bottom event
  2. The component emits the 'bottom' event only when actually reaching the bottom, preventing multiple simultaneous requests
  3. The implementation is viewport-size independent as it uses relative measurements (scrollTop + clientHeight vs scrollHeight)

The scroll behavior is well-implemented and doesn't require any modifications. The original review comment's concerns about edge cases are addressed by the clean implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for LfScrollControll implementation to understand how it handles these edge cases
ast-grep --pattern 'export default {
  $$$
  methods: {
    $$$
    onScroll($_) {
      $$$
    }
    $$$
  }
  $$$
}'

Length of output: 121


Script:

#!/bin/bash
# Let's try to find the LfScrollControll component implementation
fd -e vue -e js "scroll-controll" -X cat

# Also search for any file containing scroll-related logic
rg -i "onscroll|scrollcontroll" --type vue --type js -C 3

Length of output: 128


Script:

#!/bin/bash
# Let's try different variations of the component name and fix the file type for rg
fd "scroll|Scroll" -e vue -e js -X cat

# Search with correct file extension
rg -i "onscroll|scrollcontrol" -t js -t vue -C 3

Length of output: 1547

frontend/src/modules/contributor/pages/contributor-details.page.vue (1)

82-82: LGTM: Ref properly added to activities component

The ref addition enables proper interaction with the activities component for load more functionality.

frontend/src/modules/organization/pages/organization-details.page.vue (2)

94-94: LGTM: Template ref addition is correct.

The addition of ref="activities" to the activities component enables proper integration with the scroll-based load more functionality.


166-167: Verify loadMore implementation consistency.

Let's verify that the loadMore method is properly implemented in the activities component and follows the same pattern as other components.

✅ Verification successful

Based on the search results, I can see that the loadMore() method is consistently implemented across various components in the codebase, including:

  1. Organization details page uses it for loading more activities and contributors
  2. Member merge suggestions page uses it for pagination
  3. Data quality components use it for member and organization merge suggestions
  4. Contributor details page uses it for notes and activities

The implementation follows a common pattern where loadMore() is used with infinite scroll or "Load more" buttons to fetch additional data by incrementing the page number and maintaining the existing items.

The implementation is consistent with the codebase patterns. The usage in organization-details.page.vue for loading more activities follows the same pattern as other components.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check loadMore implementation in related components
echo "Checking loadMore implementation in activities component..."
ast-grep --pattern 'loadMore() {
  $$$
}'

echo "\nChecking for similar pagination implementations..."
rg -A 10 'loadMore\(\)' --type vue

Length of output: 352


Script:

#!/bin/bash
# Let's try a different approach to find loadMore implementations
echo "Searching for loadMore method implementations..."
rg -A 10 'loadMore\(\)'

echo "\nSearching for files containing 'loadMore'..."
rg -l 'loadMore'

echo "\nChecking for pagination-related patterns..."
rg -A 5 'pagination|pageSize|currentPage'

Length of output: 167499

frontend/src/modules/activity/components/activity-timeline.vue (6)

87-87: LGTM: Simplified rendering condition

The simplified condition for rendering timeline items is more maintainable and correctly handles the empty state elsewhere in the template.


220-226: LGTM: Migrated to design system button component

The change from el-button to lf-button maintains functionality while improving UI consistency with the design system.

Also applies to: 264-264


346-348: LGTM: Added safety guard against concurrent fetches

The loading check prevents race conditions and duplicate requests, improving reliability.


453-456: LGTM: Clean component interface exposure

Exposing fetchActivities enables the load more functionality required by the PR objectives while maintaining a minimal public interface.


379-384: Consider handling activities older than one month

The one-month window for fetching activities might limit access to historical data. Consider:

  1. Making the time window configurable
  2. Adding a warning when older activities exist but aren't shown
#!/bin/bash
# Check if there are any existing issues or discussions about activity history limitations
rg -i "activity.*history|older.*activities" .github/

Also applies to: 417-421


308-313: Verify impact of reduced page size on user experience

The changes to initialization values look good, but the reduction in page size from 50 to 10 items might affect user experience:

  • ✅ Faster initial page load
  • ❓ More frequent pagination requests
✅ Verification successful

Let me analyze the pagination implementation to better understand the impact of reducing the page size.


Reducing page size from 50 to 10 is safe and beneficial

The implementation in activity-list.vue shows a robust pagination system with:

  • Load more button that appears when more items are available
  • Proper handling of append operations for smooth infinite scroll
  • Default fetch limit of 50 in the component, making the timeline's reduced limit of 10 a performance optimization

The change is beneficial because:

  • Faster initial page load with smaller data set
  • Load more functionality ensures users can still access all activities
  • No risk of degraded UX as pagination is properly implemented
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any performance-related comments or issues
rg -i "performance|slow|pagination" .github/

Length of output: 54


Script:

#!/bin/bash
# Check activity timeline component for pagination and loading logic
rg -A 5 -B 5 "loadMore|pagination|scroll" frontend/src/modules/activity/components/activity-timeline.vue

# Check for any existing activity list size or performance related tests
rg -i "activity.*items.*length|activity.*limit" frontend/src/modules/activity/

Length of output: 187


Script:

#!/bin/bash
# Search for the loadActivities method implementation
ast-grep --pattern 'async loadActivities() {
  $$$
}'

# Look for infinite scroll or load more implementation
ast-grep --pattern 'onScroll($$$) {
  $$$
}'

# Check for any API endpoints or services related to activities
rg -l "activities.*limit|per_page" frontend/src/

Length of output: 255


Script:

#!/bin/bash
# Check the content of activity-list.vue for pagination implementation
cat frontend/src/modules/activity/components/activity-list.vue

# Check the content of github config for any pagination defaults
cat frontend/src/integrations/github/config.js

# Look for any scroll or intersection observer implementation in the timeline
rg -A 5 "IntersectionObserver|scroll" frontend/src/modules/activity/components/activity-timeline.vue

Length of output: 7083

Comment on lines +7 to +15
<script setup lang="ts">
const emit = defineEmits<{(e: 'bottom'): void}>();

const controlScroll = (e: any) => {
if (e.target.scrollTop + e.target.clientHeight >= e.target.scrollHeight - 10) {
emit('bottom');
}
};
</script>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve type safety and scroll handling efficiency.

The current implementation has several areas for improvement:

  1. The event type should be properly typed instead of 'any'
  2. Scroll events should be debounced to prevent performance issues
  3. The scroll threshold should be configurable
 <script setup lang="ts">
-const emit = defineEmits<{(e: 'bottom'): void}>();
+interface Props {
+  threshold?: number;
+  debounceMs?: number;
+}
 
-const controlScroll = (e: any) => {
-  if (e.target.scrollTop + e.target.clientHeight >= e.target.scrollHeight - 10) {
-    emit('bottom');
-  }
+const props = withDefaults(defineProps<Props>(), {
+  threshold: 10,
+  debounceMs: 200
+});
+
+const emit = defineEmits<{(e: 'bottom'): void}>();
+
+const controlScroll = (e: UIEvent) => {
+  const target = e.target as HTMLElement;
+  if (
+    Math.ceil(target.scrollTop + target.clientHeight) >=
+    target.scrollHeight - props.threshold
+  ) {
+    debounce(() => emit('bottom'), props.debounceMs)();
+  }
 };
 </script>

You'll need to import the debounce utility:

import { debounce } from 'lodash-es';

Comment on lines +17 to +21
<script lang="ts">
export default {
name: 'LfScrollControll',
};
</script>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix component naming and modernize component definition.

  1. The component name has a typo ('Controll' should be 'Control')
  2. In Vue 3 with <script setup>, the separate script block for defining the component name is unnecessary
-<script lang="ts">
-export default {
-  name: 'LfScrollControll',
-};
-</script>
+<script setup lang="ts">
+defineOptions({
+  name: 'LfScrollControl'
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<script lang="ts">
export default {
name: 'LfScrollControll',
};
</script>
<script setup lang="ts">
defineOptions({
name: 'LfScrollControl'
});
</script>

Comment on lines +46 to +54
const timeline = ref<AppActivityTimeline | null>(null);

const loadMore = () => {
timeline.value.fetchActivities();
};

defineExpose({
loadMore,
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and null checks to loadMore method

While the implementation is functional, it could benefit from additional safeguards to prevent runtime errors and improve user experience.

Consider applying these improvements:

 const timeline = ref<AppActivityTimeline | null>(null);
 
-const loadMore = () => {
-  timeline.value.fetchActivities();
-};
+const loading = ref(false);
+
+const loadMore = async () => {
+  if (!timeline.value || loading.value) return;
+  
+  try {
+    loading.value = true;
+    await timeline.value.fetchActivities();
+  } catch (error) {
+    console.error('Failed to load more activities:', error);
+    // Consider adding user feedback for the error
+  } finally {
+    loading.value = false;
+  }
+};

 defineExpose({
   loadMore,
 });

This implementation:

  • Prevents calls when the timeline isn't ready or already loading
  • Adds proper error handling
  • Manages loading state to prevent duplicate calls
  • Makes the method async to properly handle the Promise
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const timeline = ref<AppActivityTimeline | null>(null);
const loadMore = () => {
timeline.value.fetchActivities();
};
defineExpose({
loadMore,
});
const timeline = ref<AppActivityTimeline | null>(null);
const loading = ref(false);
const loadMore = async () => {
if (!timeline.value || loading.value) return;
try {
loading.value = true;
await timeline.value.fetchActivities();
} catch (error) {
console.error('Failed to load more activities:', error);
// Consider adding user feedback for the error
} finally {
loading.value = false;
}
};
defineExpose({
loadMore,
});

Comment on lines +63 to +65
const loadMore = () => {
timeline.value.fetchActivities();
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and loading state

The loadMore method should include error handling and loading state management.

+const isLoading = ref(false);
+
 const loadMore = async () => {
+  if (isLoading.value) return;
+  
+  try {
+    isLoading.value = true;
     timeline.value.fetchActivities();
+  } catch (error) {
+    console.error('Failed to load more activities:', error);
+    // Consider adding user notification here
+  } finally {
+    isLoading.value = false;
+  }
 };

Committable suggestion skipped: line range outside the PR's diff.

@@ -62,6 +62,7 @@ import AppOrganizationMergeSuggestionsDialog
from '@/modules/organization/components/organization-merge-suggestions-dialog.vue';
import { storeToRefs } from 'pinia';
import { useLfSegmentsStore } from '@/modules/lf/segments/store';
import LfScrollControll from '@/ui-kit/scrollcontroll/ScrollControll.vue';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prevent race conditions in loadMore function.

The current implementation doesn't prevent multiple simultaneous calls to loadMore(), which could occur when rapidly scrolling or clicking the load more button while a request is in progress.

Consider adding a guard clause:

 const loadMore = () => {
+  if (loading.value) return;
   offset.value = mergeSuggestions.value.length;
   loadMergeSuggestions();
 };

Also applies to: 108-112

Comment on lines +158 to +159
} else if (tabs.value === 'activities') {
activities.value.loadMore();
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add safeguards to the scroll handling

The current implementation could benefit from additional safeguards:

  1. Add null check before calling loadMore
  2. Add debounce/throttle to prevent excessive calls
  3. Add loading state check to prevent simultaneous calls
+import { debounce } from 'lodash-es';

-const controlScroll = (e) => {
+const controlScroll = debounce((e) => {
   if (e.target.scrollTop + e.target.clientHeight >= e.target.scrollHeight - 10) {
     if (tabs.value === 'notes') {
-      notes.value.loadMore();
+      notes.value?.loadMore?.();
     } else if (tabs.value === 'activities') {
-      activities.value.loadMore();
+      activities.value?.loadMore?.();
     }
   }
-};
+}, 200);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +166 to +167
} else if (tabs.value === 'activities') {
activities.value.loadMore();
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for loadMore calls.

The scroll control logic should handle potential errors when calling loadMore:

    } else if (tabs.value === 'activities') {
-      activities.value.loadMore();
+      try {
+        activities.value?.loadMore();
+      } catch (error) {
+        console.error('Failed to load more activities:', error);
+        // Consider showing a user-friendly error message
+      }

This ensures:

  1. Null safety with the optional chaining
  2. Graceful error handling
  3. Better debugging capability
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} else if (tabs.value === 'activities') {
activities.value.loadMore();
} else if (tabs.value === 'activities') {
try {
activities.value?.loadMore();
} catch (error) {
console.error('Failed to load more activities:', error);
// Consider showing a user-friendly error message
}

@gaspergrom gaspergrom merged commit 66ef96a into main Nov 4, 2024
7 checks passed
@gaspergrom gaspergrom deleted the bug/activities-filtering branch November 4, 2024 10:54
@coderabbitai coderabbitai bot mentioned this pull request Nov 13, 2024
5 tasks
@coderabbitai coderabbitai bot mentioned this pull request Dec 19, 2024
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Created by Linear-GitHub Sync
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants