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

analytics: update to data download and add location modules #2256

Merged
merged 2 commits into from
Nov 26, 2024

Conversation

OchiengPaul442
Copy link
Contributor

@OchiengPaul442 OchiengPaul442 commented Nov 26, 2024

Summary of Changes (What does this PR do?)

  • removed general online status to be specific for a given component i.e. add location component

Status of maturity (all need to be checked before merging):

  • I've tested this locally
  • I consider this code done
  • This change ready to hit production in its current state

Screenshots (optional)

image
image

Summary by CodeRabbit

  • New Features

    • Enhanced the AddLocations component to filter and display only online sites.
    • Improved data handling for selected sites based on the updated filtering logic.
    • Introduced a mechanism for manual data refetching in the analytics data fetching process.
  • Bug Fixes

    • Streamlined logic for initializing selected sites and sidebar sites, ensuring accurate data representation.
  • Chores

    • Updated the SITES_SUMMARY_URL to remove unnecessary query parameters for a cleaner API call.
    • Adjusted the target URL in the API proxy to align with the updated sites summary URL.

@OchiengPaul442 OchiengPaul442 self-assigned this Nov 26, 2024
Copy link

coderabbitai bot commented Nov 26, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

The changes in this pull request involve modifications to the AddLocations component to filter site data, ensuring only online sites are considered. This is achieved through the introduction of a memoized variable, filteredSites, which updates the logic for managing selected sites. Additionally, the SITES_SUMMARY_URL constant in the analytics URL file is updated to remove an unnecessary query parameter, and the API proxy handler is adjusted to reflect this change, ensuring requests are made without the online status filter.

Changes

File Path Change Summary
platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx Updated AddLocations component to filter site data, introducing filteredSites for managing selected sites and updating the DataTable component accordingly.
platform/src/core/urls/analytics.js Modified SITES_SUMMARY_URL to remove the ?online_status=online query parameter, resulting in a cleaner URL.
platform/src/pages/api/proxy/sites.js Altered handler function to remove the online_status=online query parameter from targetUrl, affecting the API request for site data.
platform/src/core/utils/useFetchAnalyticsData.jsx Added fetchAnalytics function for improved data fetching logic, updated fetchAnalyticsData to accept a signal for cancellation, and introduced refetchId for manual refetching.

Possibly related PRs

Suggested labels

ready for review

Suggested reviewers

  • Baalmart
  • Codebmk

🎉 In the land of code where logic flows,
Filtering sites, as everyone knows.
With filteredSites, we now can see,
Only the online, as bright as can be!
URLs cleaned, and requests refined,
A smoother experience, perfectly aligned! 🌟


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 or @coderabbitai title 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: 0

🧹 Outside diff range and nitpick comments (4)
platform/src/core/urls/analytics.js (1)

10-10: Consider adding JSDoc documentation.

Since this is a shared URL constant, it would be helpful to add JSDoc documentation explaining its purpose and noting that filtering should be handled at the component level.

+/**
+ * URL for fetching sites summary.
+ * Note: Filtering (e.g., by online status) should be handled at the component level.
+ */
 export const SITES_SUMMARY_URL = `${BASE_AUTH_URL}/devices/sites/summary`;
platform/src/pages/api/proxy/sites.js (1)

9-9: Consider caching strategy for performance optimization

Since we're now fetching all sites instead of just online ones, the response payload might be larger. Consider implementing caching at the API proxy level to optimize performance.

Example implementation:

+import { cacheData, getCachedData } from '../../../utils/cache';
+
+const CACHE_KEY = 'sites_summary';
+const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
+
 export default async function handler(req, res) {
   if (req.method !== 'GET') {
     return res.status(405).json({ error: 'Method Not Allowed' });
   }
+
+  const cachedData = getCachedData(CACHE_KEY);
+  if (cachedData) {
+    return res.status(200).json(cachedData);
+  }
+
   const targetUrl = 'https://analytics.airqo.net/api/v2/devices/sites/summary';
   
   try {
     const response = await axios.get(targetUrl, {
       headers: {
         Authorization: req.headers.authorization,
       },
     });
+    cacheData(CACHE_KEY, response.data, CACHE_TTL);
     res.status(response.status).json(response.data);
platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx (2)

52-55: Consider adding null safety to the isOnline check

The current implementation might filter out sites where isOnline is undefined but should be considered valid.

Consider this more robust implementation:

  const filteredSites = useMemo(() => {
-   return (sitesSummaryData || []).filter((site) => site.isOnline === true);
+   return (sitesSummaryData || []).filter((site) => site?.isOnline !== false);
  }, [sitesSummaryData]);

74-81: Optimize the useEffect dependencies and add cleanup

The effect might run unnecessarily when selectedSiteIds changes but filteredSites is still loading.

Consider this optimization:

  useEffect(() => {
-   if (filteredSites && selectedSiteIds.length) {
+   if (!filteredSites?.length) return;
+   
+   if (selectedSiteIds.length) {
      const initialSelectedSites = filteredSites.filter((site) =>
        selectedSiteIds.includes(site._id),
      );
      setSelectedSites(initialSelectedSites);
      setSidebarSites(initialSelectedSites);
    }
+   
+   return () => {
+     // Cleanup function to prevent memory leaks
+     setSelectedSites([]);
+     setSidebarSites([]);
+   };
  }, [filteredSites, selectedSiteIds]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6d8811b and f4c7c15.

📒 Files selected for processing (3)
  • platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx (3 hunks)
  • platform/src/core/urls/analytics.js (1 hunks)
  • platform/src/pages/api/proxy/sites.js (1 hunks)
🔇 Additional comments (4)
platform/src/core/urls/analytics.js (1)

10-10: LGTM! Let's verify API compatibility.

The removal of the online_status query parameter makes the endpoint more generic and reusable, which is good. This aligns well with moving the filtering logic to the component level.

Let's verify the API handler changes mentioned in the summary:

✅ Verification successful

API handler is compatible with the URL change

The API handler in platform/src/pages/api/proxy/sites.js is already designed to pass through requests without processing query parameters, making it fully compatible with the removal of online_status parameter. The handler simply forwards the request to the analytics endpoint with authentication headers, which is exactly what we want.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the API handler has been updated to handle the URL without the online_status parameter
# Expected: Find the corresponding handler file and check for related changes

# Search for the API handler file
rg -l "sites/summary" "platform/src/pages/api/proxy"

Length of output: 88


Script:

#!/bin/bash
# Let's examine the handler file to see how it processes the sites/summary endpoint
rg -A 10 "sites/summary" "platform/src/pages/api/proxy/sites.js"

# Also check for any online_status related code
rg "online_status" "platform/src/pages/api/proxy/sites.js"

Length of output: 427

platform/src/pages/api/proxy/sites.js (1)

9-9: Architectural change: Filter responsibility shifted to client

The removal of the online_status filter from the API endpoint aligns with the PR objective of making online status handling specific to the AddLocations component. This is a good architectural decision as it:

  1. Provides more flexibility in how different components can filter the data
  2. Reduces the coupling between the API and specific UI requirements

However, we should verify the impact of this change.

Let's verify the usage of this endpoint across the codebase:

✅ Verification successful

Removal of online_status filter is safe to proceed

The codebase analysis reveals that the removal of the online_status filter from the sites summary endpoint is architecturally sound because:

  1. The endpoint is used through a centralized API service (getSitesSummaryApi)
  2. No components are directly relying on pre-filtered online status in the response
  3. The change aligns with the separation of concerns, letting client components handle their own filtering needs

The implementation maintains proper error handling and authorization, while the architectural change provides more flexibility for different components to apply their own filtering logic.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other components that might be affected by this change

# Search for references to the sites summary endpoint
rg -l "devices/sites/summary" --type js --type jsx --type ts --type tsx

# Search for components that might be relying on pre-filtered online status
rg -l "online_status.*online" --type js --type jsx --type ts --type tsx

Length of output: 201


Script:

#!/bin/bash
# Let's try a different approach using more basic commands

# Search for references to the sites summary endpoint
rg "devices/sites/summary" -g "*.{js,ts,tsx}"

# Search for components that might be relying on pre-filtered online status
rg "online_status.*online" -g "*.{js,ts,tsx}"

# Also check for the specific URL
rg "analytics.airqo.net/api/v2/devices/sites/summary" -g "*.{js,ts,tsx}"

Length of output: 514


Script:

#!/bin/bash
# Let's check how this URL is being used in the codebase

# Check the analytics.js file to understand the URL usage
cat platform/src/core/urls/analytics.js

# Look for imports of SITES_SUMMARY_URL
rg "SITES_SUMMARY_URL" -g "*.{js,ts,tsx}"

# Check for any query parameter handling related to online_status
rg -B2 -A2 "SITES_SUMMARY_URL" -g "*.{js,ts,tsx}"

Length of output: 1721


Script:

#!/bin/bash
# Let's check how getSitesSummaryApi is being used

# Look for usages of getSitesSummaryApi
rg -B2 -A2 "getSitesSummaryApi" -g "*.{js,ts,tsx}"

# Also check for any components that might be handling site filtering
rg "filterSites|filteredSites" -g "*.{js,ts,tsx}"

Length of output: 3546

platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx (2)

230-230: LGTM! Consistent use of filtered sites

The update to use filteredSites in the DataTable component maintains consistency with the PR's objective of showing only online sites.


Line range hint 52-230: Verify the impact on user experience

The changes successfully implement site filtering at the component level, but let's verify the user experience.

✅ Verification successful

Implementation maintains consistent UX and aligns with existing patterns

The filtering implementation is safe and consistent with the codebase's existing patterns:

  • The isOnline === true filter is already used in other components (e.g., Preferences.js)
  • Error handling and loading states are properly maintained in the Modal components
  • The filtering logic is isolated to this component and doesn't affect other site status displays
  • The implementation follows the same pattern as other components in the Modal directory
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential UX impact by analyzing related components and tests

# Look for any existing tests that might need updates
rg -A 5 "test\(.*AddLocations" 

# Check for other components that might be affected by the filtering change
rg -A 5 "sitesSummaryData.*online_status"

# Look for any error handling or loading states related to site filtering
ast-grep --pattern 'loading || error'

Length of output: 116


Script:

#!/bin/bash
# Let's try a different approach to verify the UX impact

# Check for test files related to AddLocations
fd "AddLocations.*test" --type f

# Look for components that might be consuming the filtered sites
rg -A 3 "filteredSites.*=" 

# Check for any existing filtering logic for online sites
rg -A 3 "isOnline.*=.*true" 

# Look for any UI components that display site status
rg -A 3 "site\.isOnline" 

# Check for any error messages or loading states in the Modal directory
fd . "platform/src/common/components/Modal" -t f -x rg -l "loading|error"

Length of output: 4694

Copy link
Contributor

New next-platform changes available for preview here

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

🧹 Outside diff range and nitpick comments (1)
platform/src/core/utils/useFetchAnalyticsData.jsx (1)

87-87: Limit logging of error details to prevent exposing sensitive information

Logging entire error objects may inadvertently expose sensitive data. Consider logging only the error message or relevant information.

Apply this diff to refine the logging:

-console.error('Error fetching analytics data:', err);
+console.error('Error fetching analytics data:', err.message);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f4c7c15 and d2fc234.

📒 Files selected for processing (1)
  • platform/src/core/utils/useFetchAnalyticsData.jsx (2 hunks)

Comment on lines +64 to +65
const token = localStorage.getItem('token');
if (!token) throw new Error('Authorization token is missing.');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid storing tokens in localStorage for security reasons

Storing authentication tokens in localStorage can expose them to XSS attacks. Consider using secure cookies (with HttpOnly and Secure flags) or leveraging more secure storage mechanisms like Redux or Context API to enhance security.

Comment on lines +21 to +27
if (response.status === 200 && response.data?.status === 'success') {
return response.data.data || [];
} else {
throw new Error(
response.data?.message || 'Failed to fetch analytics data.',
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure consistent response handling in fetchAnalytics

The response handling logic differs between development and production environments. In development, you're checking:

if (response.status === 200 && response.data?.status === 'success')

While in production, you have:

if (response.status === 'success' && Array.isArray(response.data))

Align the response validation criteria to ensure consistent behavior across environments, which will help avoid unexpected issues when switching between development and production.

Also applies to: 34-38

const data = await fetchAnalytics(requestBody, token, signal);
setAllSiteData(data);
} catch (err) {
if (err.name === 'CanceledError' || err.name === 'AbortError') return; // Request was cancelled
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update Axios cancellation error handling

When handling canceled requests with Axios, the error code is 'ERR_CANCELED' or you can use axios.isCancel(err). Modify the error check to accurately detect canceled requests.

Apply this diff to update the error handling:

-if (err.name === 'CanceledError' || err.name === 'AbortError') return; // Request was cancelled
+if (err.code === 'ERR_CANCELED' || axios.isCancel(err)) return; // Request was cancelled
📝 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
if (err.name === 'CanceledError' || err.name === 'AbortError') return; // Request was cancelled
if (err.code === 'ERR_CANCELED' || axios.isCancel(err)) return; // Request was cancelled

Copy link
Contributor

New next-platform changes available for preview here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants