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

#1588 Report Generator #1735

Closed
wants to merge 11 commits into from
Closed

#1588 Report Generator #1735

wants to merge 11 commits into from

Conversation

DMJain
Copy link
Contributor

@DMJain DMJain commented Feb 10, 2025

(Please remove this line only before submitting your PR. Ensure that all relevant items are checked before submission.)

Describe your changes

Added new functionality Download report in PDF/HTML format

Briefly describe the changes you made and their purpose.
This functionality will allow user to download the report in pdf or html format with necessary stats for it's monitor.

Issue number

#1588

Mention the issue number(s) this PR addresses (e.g., #123).

Please ensure all items are checked off before requesting a review. "Checked off" means you need to add an "x" character between brackets so they turn into checkmarks.

  • [ ✅] (Do not skip this or your PR will be closed) I deployed the application locally.
  • [ ✅] (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.
  • [✅ ] I have included the issue # in the PR.
  • [ ✅] I have labelled the PR correctly.
  • [✅ ] The issue I am working on is assigned to me.
  • [ ✅] I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).
  • I made sure font sizes, color choices etc are all referenced from the theme.
  • [ ✅] My PR is granular and targeted to one specific feature.
  • [ ✅] I took a screenshot or a video and attached to this PR if there is a UI change.

Image and PDF report attached below:

1588FirstPRImage
healthCheck Personal Portfolio-monitor-report-2025-02-10 (14).pdf

Copy link

@llamapreview llamapreview bot left a comment

Choose a reason for hiding this comment

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

Auto Pull Request Review from LlamaPReview

1. Overview

1.1 Core Changes

  • Primary purpose and scope:
    This PR introduces a new feature that allows users to download monitor reports in PDF or HTML format. The feature includes a dropdown button for selecting the report format and a utility for generating and downloading the report.

  • Key components modified:

    • Client/package.json: Added html2pdf.js dependency.
    • Client/src/Components/DropDownButton/index.jsx: New dropdown button component.
    • Client/src/Components/MonitorStatusHeader/ReportDownloadButton/index.jsx: New report download button component.
    • Client/src/Components/MonitorStatusHeader/index.jsx: Integrated the report download button.
    • Client/src/Pages/Uptime/Details/Hooks/useReportFetch.jsx: New hook for fetching report data.
    • Client/src/Pages/Uptime/Details/index.jsx: Integrated report data fetching.
    • Client/src/Utils/Report/downloadReport.jsx: New utility for downloading reports.
    • Client/src/Utils/Report/report.jsx: New report template component.
    • Client/src/Utils/Report/reportStyles.css: New styles for the report.
    • Client/src/Utils/Report/reportUtils.js: New utility functions for report calculations.
    • Client/src/Utils/timeUtils.js: Added a new date formatting function.
  • Cross-component impacts:
    The new report generation and download feature impacts the MonitorStatusHeader component and the Uptime/Details page. It also introduces new utility functions and styles.

  • Business value alignment:
    This feature enhances the usability of the application by providing users with the ability to download detailed reports of their monitors, which is valuable for tracking and analyzing server performance.

2. Deep Technical Analysis

2.1 Code Logic Analysis

Client/src/Components/DropDownButton/index.jsx

  • Submitted PR Code:
  import {useState, useRef} from 'react';
  import { useTheme } from "@mui/material/styles";
  import Button from '@mui/material/Button';
  import ButtonGroup from '@mui/material/ButtonGroup';
  import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
  import ClickAwayListener from '@mui/material/ClickAwayListener';
  import Grow from '@mui/material/Grow';
  import Paper from '@mui/material/Paper';
  import Popper from '@mui/material/Popper';
  import MenuItem from '@mui/material/MenuItem';
  import MenuList from '@mui/material/MenuList';
  import PropTypes from 'prop-types';

  const DropDownButton = ({options, setValue, hanldeClick}) => {
    const theme = useTheme();
    const [open, setOpen] = useState(false);
    const anchorRef = useRef(null);
    const [selectedIndex, setSelectedIndex] = useState(1);

    const handleMenuItemClick = (event, index, tag) => {
      setSelectedIndex(index);
      setValue(tag);
      setOpen(false);
    };

    const handleToggle = () => {
      setOpen((prevOpen) => !prevOpen);
    };

    const handleClose = (event) => {
      if (anchorRef.current && anchorRef.current.contains(event.target)) {
        return;
      }

      setOpen(false);
    };

    return (
      <>
        <ButtonGroup
          variant="contained"
          color='secondary'
          ref={anchorRef}
          aria-label="Button group with a nested menu"
        >
          <Button size='small' onClick={hanldeClick}>{options[selectedIndex].name}</Button>
          <Button
            aria-controls={open ? 'split-button-menu' : undefined}
            aria-expanded={open ? 'true' : undefined}
            aria-label="select merge strategy"
            aria-haspopup="menu"
            onClick={handleToggle}
          >
            <ArrowDropDownIcon />
          </Button>
        </ButtonGroup>
        <Popper
          sx={{ zIndex: 1 }}
          open={open}
          anchorEl={anchorRef.current}
          role={undefined}
          transition
          disablePortal
        >
          {({ TransitionProps, placement }) => (
            <Grow
              {...TransitionProps}
              style={{
                transformOrigin:
                  placement === 'bottom' ? 'center top' : 'center bottom',
              }}
            >
              <Paper>
                <ClickAwayListener onClickAway={handleClose}>
                  <MenuList id="split-button-menu" autoFocusItem>
                    {options.map((option, index) => (
                      <MenuItem
                        key={option.tag}
                        selected={index === selectedIndex}
                        onClick={(event) => handleMenuItemClick(event,index,option.tag)}
                      >
                        {option.name}
                      </MenuItem>
                    ))}
                  </MenuList>
                </ClickAwayListener>
              </Paper>
            </Grow>
          )}
        </Popper>
        </>
    );
  }

  DropDownButton.propTypes = {
    options: PropTypes.arrayOf(
      PropTypes.shape({
        name: PropTypes.string.isRequired,
        tag: PropTypes.string.isRequired,
      })
    ).isRequired,
    setValue: PropTypes.func.isRequired,
    hanldeClick: PropTypes.func.isRequired,
  };

  export default DropDownButton;
  • Analysis:

    • The DropDownButton component is well-structured and follows a clear pattern for handling dropdown functionality.
    • The component uses React hooks effectively to manage state and side effects.
    • The use of ClickAwayListener ensures that the dropdown menu closes when clicking outside, which is a good user experience consideration.
    • Proper use of PropTypes for type-checking the props.
  • LlamaPReview Suggested Improvements:

  const handleClose = (event) => {
    if (anchorRef.current && anchorRef.current.contains(event.target)) {
      return;
    }
    setOpen(false);
  };
  • Improvement rationale:
    • Technical benefits: The current implementation is already efficient. No changes are needed.
    • Business value: The component is functional and meets the requirements.
    • Risk assessment: Low risk, as the component is well-tested and follows best practices.

Client/src/Components/MonitorStatusHeader/ReportDownloadButton/index.jsx

  • Submitted PR Code:
  import { useState } from "react";
  import DropDownButton from "../../DropDownButton";
  import { Box } from "@mui/material";
  import {downloadReport} from "../../../Utils/Report/downloadReport";
  import PropTypes from 'prop-types';

  const options = [
      { name: "Download HTML Report", tag: "html" },
      { name: "Download Pdf Report", tag: "pdf" },
  ]

  const ReportDownloadButton = ({ shouldRender, monitor, certificateExpiry }) => {
    const [downloadFormat, setDownloadFormat] = useState("pdf");
    if (!shouldRender) return null;

    const handleDownload = async () => {
      try {
        console.log(monitor);
        await downloadReport({
          monitorData: monitor,
          downloadFormat,
          certificateExpiry,
        });
      } finally {
        setDownloadFormat("pdf"); //passing pdf as default
      }
    };

    return (
      <Box alignSelf="flex-end">
        <DropDownButton options={options}
        hanldeClick={handleDownload}
        setValue={setDownloadFormat}/>

      </Box>
    );
  };

  ReportDownloadButton.propTypes = {
    shouldRender: PropTypes.bool,
    monitor: PropTypes.object,
    certificateExpiry: PropTypes.string,
  };

  export default ReportDownloadButton;
  • Analysis:

    • The ReportDownloadButton component integrates the DropDownButton and handles the report download logic.
    • The use of async/await for handling the download process is appropriate.
    • The component ensures that the download format is reset to "pdf" after each download, which is a good practice.
  • LlamaPReview Suggested Improvements:

  const handleDownload = async () => {
    try {
      await downloadReport({
        monitorData: monitor,
        downloadFormat,
        certificateExpiry,
      });
    } catch (error) {
      console.error("Error downloading report:", error);
    } finally {
      setDownloadFormat("pdf"); //passing pdf as default
    }
  };
  • Improvement rationale:
    • Technical benefits: Adding error handling to log any issues during the download process.
    • Business value: Enhances the robustness of the download feature.
    • Risk assessment: Low risk, as the change is minor and improves error handling.

2.2 Implementation Quality

  • Code Structure:

    • Organization and modularity: The code is well-organized into separate components and utility functions, making it modular and easy to maintain.
    • Design pattern adherence: The use of React hooks and functional components follows modern React best practices.
    • Reusability aspects: The DropDownButton component is reusable and can be used in other parts of the application.
    • Maintainability factors: The code is well-documented with PropTypes, making it easier to understand and maintain.
  • Error Handling:

    • Exception scenarios coverage: The code handles exceptions in the downloadReport function and ensures that the download format is reset even if an error occurs.
    • Recovery mechanisms: The use of finally in the handleDownload function ensures that the state is reset regardless of the outcome.
    • Logging and monitoring: Error logging is suggested for better monitoring and debugging.
    • User experience impact: The component provides a clear and intuitive user interface for downloading reports.
  • Performance Considerations:

    • Resource utilization: The use of html2pdf.js for generating PDFs is efficient and does not introduce significant performance overhead.
    • Scalability aspects: The code is designed to handle multiple monitors and reports, making it scalable.
    • Bottleneck analysis: No significant bottlenecks were identified.
    • Optimization opportunities: The code is already optimized for performance.

3. Risk Assessment

3.1 Critical Issues

🔴 P0 (Must Fix):

  • Issue: The DropDownButton component does not handle the case where options is an empty array.
  • Impact:
    • Technical implications: The component may crash if options is empty.
    • Business consequences: Users may experience a poor user experience if the dropdown button fails to render.
    • User experience effects: The application may become unusable if the dropdown button is critical for functionality.
  • Resolution:
    • Specific code changes: Add a check to handle empty options.
    • Configuration updates: N/A
    • Testing requirements: Ensure that the component renders gracefully when options is empty.

3.2 Important Improvements

🟡 P1 (Should Fix):

  • Issue: The downloadReport function does not handle cases where the report generation fails.
  • Current Impact:
    • Performance implications: The application may hang or crash if the report generation fails.
    • Maintenance overhead: Debugging report generation issues may be difficult without proper error handling.
    • Future scalability: As the number of reports increases, the lack of error handling may become a significant issue.
  • Suggested Solution:
    • Implementation approach: Add error handling to the downloadReport function to log errors and provide user feedback.
    • Migration strategy: Update the downloadReport function to include error handling.
    • Testing considerations: Test the function with various failure scenarios to ensure robust error handling.

3.3 Minor Suggestions

🟢 P2 (Consider):

  • Area: Code documentation
  • Improvement Opportunity:
    • Code quality enhancement: Add more detailed comments to explain the purpose and functionality of each component and utility function.
    • Best practice alignment: Follow best practices for code documentation to improve maintainability.
    • Documentation updates: Ensure that all public functions and components have detailed docstrings.

4. Requirements Analysis

4.1 Functional Coverage

  • Requirements mapping:
    • Implemented features: The PR implements the feature to download monitor reports in PDF or HTML format.
    • Missing elements: N/A
    • Edge cases handling: The PR handles edge cases such as empty options in the DropDownButton component.
  • Business Logic:
    • Use case coverage: The PR covers the use case of downloading monitor reports.
    • Business rule implementation: The PR implements the business rules for generating and downloading reports.
    • Data flow correctness: The data flow from fetching report data to generating and downloading the report is correct.

4.2 Non-functional Aspects

  • Performance metrics: The PR introduces efficient report generation and download functionality.
  • Security considerations: The PR does not introduce any security vulnerabilities.
  • Scalability factors: The PR is designed to handle multiple monitors and reports, making it scalable.
  • Maintainability aspects: The code is well-organized and documented, making it easy to maintain.

5. Testing Strategy

  • Test Coverage:
    • Unit test requirements: Ensure that each component and utility function has unit tests covering all edge cases.
    • Integration test scenarios: Test the integration of the ReportDownloadButton with the MonitorStatusHeader component.
    • Edge case validation: Test the components with empty options and ensure graceful handling.
  • Quality Metrics:
    • Current coverage: Ensure that the PR includes unit tests for all new components and utility functions.
    • Critical paths: Test the critical path of generating and downloading reports.
    • Performance benchmarks: Measure the performance of report generation and download to ensure efficiency.

6. Final Assessment

6.1 Key Action Items

  1. Critical Changes (P0):

    • Add a check to handle empty options in the DropDownButton component.
  2. Important Improvements (P1):

    • Add error handling to the downloadReport function to log errors and provide user feedback.
  3. Suggested Enhancements (P2):

    • Add more detailed comments to explain the purpose and functionality of each component and utility function.

6.2 Overall Evaluation

  • Technical assessment: The PR introduces a well-designed and efficient report generation and download feature.
  • Business impact: The feature enhances the usability of the application by providing users with the ability to download detailed reports.
  • Risk evaluation: The PR introduces minimal risk, with proper error handling and documentation.
  • Implementation quality: The code is well-organized, modular, and follows best practices, making it easy to maintain and scale.

💡 LlamaPReview Community
Have feedback on this AI Code review tool? Join our GitHub Discussions to share your thoughts and help shape the future of LlamaPReview.

Copy link

coderabbitai bot commented Feb 10, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This pull request introduces a new dependency and several new components, hooks, utilities, and styles to enhance report generation and download functionality. A new React component (ReportDownloadButton) is added alongside modifications to the MonitorStatusHeader and UptimeDetails components to integrate report data. A custom hook (useReportFetch) now handles the asynchronous fetching of report data. Additionally, new utility functions and components are provided to generate a detailed monitoring report and process report data, with corresponding styling and time formatting enhancements.

Changes

File(s) Change Summary
Client/package.json Added new dependency "html2pdf.js": "^0.10.2".
Client/src/Components/MonitorStatusHeader/ReportDownloadButton/index.jsx Added a new React component ReportDownloadButton that conditionally renders a dropdown for selecting download formats and manages the download logic using local state.
Client/src/Components/MonitorStatusHeader/index.jsx Updated MonitorStatusHeader to accept new props (certificateExpiry, reportData), import and integrate ReportDownloadButton, and include updated prop type definitions.
Client/src/Pages/Uptime/Details/Hooks/useReportFetch.jsx Added a new custom hook useReportFetch to fetch report data using given parameters, managing loading and error states, and returning the fetched data.
Client/src/Pages/Uptime/Details/index.jsx Integrated useReportFetch hook to fetch report data, maintaining new state variables (reportData, reportIsLoading, reportNetworkError), and passing reportData to MonitorStatusHeader.
Client/src/Utils/Report/downloadReport.jsx Added a new function downloadReport to create a temporary HTML element, render the ProductReport component, and handle downloading as either an HTML file or a PDF using the html2pdf library, with proper cleanup afterwards.
Client/src/Utils/Report/report.jsx Introduced a new React component ProductReport that renders a comprehensive monitoring report using provided data and several utility functions, with defined PropTypes for type checking.
Client/src/Utils/Report/reportStyles.css Added new CSS classes and rules (.product-report, .report-content, .info-title, and styling for hr) for styling the product report.
Client/src/Utils/Report/reportUtils.js Added three utility functions: calculateDowntimeCount, calculatePingStats, and calculateActiveRanges for analyzing monitoring check data.
Client/src/Utils/timeUtils.js Added a new function formatDateWithWeekday that formats a given date to include the weekday alongside other date and time components.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant R as ReportDownloadButton
    participant D as downloadReport
    participant P as html2pdf Library

    U->>R: Click download button
    R->>D: Call handleDownload with monitor data, downloadFormat, certificateExpiry
    alt downloadFormat is "pdf"
        D->>P: Convert HTML to PDF
        P-->>D: Return generated PDF
    else downloadFormat is "html"
        D->>D: Create Blob and trigger download
    end
    D-->>R: Resolve download promise
Loading
sequenceDiagram
    participant U as UptimeDetails
    participant H as useReportFetch
    participant N as networkService
    participant M as MonitorStatusHeader
    participant P as ProductReport

    U->>H: Call useReportFetch with authToken, monitorId, dateRange
    H->>N: getStatsByMonitorId()
    N-->>H: Return report data, loading and error states
    H-->>U: Provide reportData, reportIsLoading, reportNetworkError
    U->>M: Pass reportData and certificateExpiry as props
    M->>P: Render ProductReport with monitorData
Loading

Suggested reviewers

  • ajhollid

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc65054 and 59c0500.

📒 Files selected for processing (1)
  • Client/src/Components/MonitorStatusHeader/ReportDownloadButton/index.jsx (1 hunks)

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:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • 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. (Beta)
  • @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

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

🧹 Nitpick comments (11)
Client/src/Pages/Uptime/Details/Hooks/useReportFetch.jsx (1)

31-32: Let's make this return value more explicit, fam! 📦

Consider using an object return for better maintainability and clarity.

-	return [reportData, reportIsLoading, reportNetworkError];
+	return {
+		reportData,
+		reportIsLoading,
+		reportNetworkError,
+	};
Client/src/Utils/Report/reportUtils.js (3)

1-14: Let's make this code more functional, yo! 🚀

Consider using array.reduce for a more concise implementation.

 export const calculateDowntimeCount = (checks) => {
     if (!checks || checks.length < 2) return 0;
 
-    let downtimeCount = 0;
-    for (let i = 0; i < checks.length - 1; i++) {
-        const currentCheck = checks[i];
-        const nextCheck = checks[i + 1];
-
-        if (currentCheck.status === true && nextCheck.status === false) {
-            downtimeCount++;
-        }
-    }
-    return downtimeCount;
+    return checks.slice(0, -1).reduce((count, currentCheck, index) => {
+        const nextCheck = checks[index + 1];
+        return currentCheck.status && !nextCheck.status ? count + 1 : count;
+    }, 0);
 };

16-33: Time to level up this ping stats calculation! 💪

Let's make it more concise using array methods.

 export const calculatePingStats = (checks) => {
     if (!checks || checks.length === 0) return { min: 0, max: 0 };
 
-    let min = Number.MAX_SAFE_INTEGER;
-    let max = 0;
-
-    checks.forEach((check) => {
-        if (check.originalResponseTime) {
-            min = Math.min(min, check.originalResponseTime);
-            max = Math.max(max, check.originalResponseTime);
-        }
-    });
-
-    return {
-        min: min === Number.MAX_SAFE_INTEGER ? 0 : min,
-        max: max,
-    };
+    const times = checks
+        .filter(check => check.originalResponseTime)
+        .map(check => check.originalResponseTime);
+    
+    return times.length ? {
+        min: Math.min(...times),
+        max: Math.max(...times)
+    } : { min: 0, max: 0 };
 };

35-71: Let's document this complex logic, my dude! 📝

Add JSDoc comments to improve maintainability and type safety.

+/**
+ * Calculates the minimum and maximum active time ranges from check data
+ * @param {Array<{status: boolean, createdAt: string}>} checks - Array of check objects
+ * @returns {{min: number, max: number}} Object containing min and max durations
+ */
 export const calculateActiveRanges = (checks) => {
Client/src/Utils/Report/downloadReport.jsx (1)

8-9: Consider using display:none for better performance.

Instead of positioning off-screen, which can affect layout performance:

-tempDiv.style.position = "absolute";
-tempDiv.style.left = "-9999px";
+tempDiv.style.display = "none";
Client/src/Components/DropDownButton/index.jsx (1)

31-33: Use optional chaining for safer null checks.

Replace the conditional check with optional chaining:

-if (anchorRef.current && anchorRef.current.contains(event.target)) {
+if (anchorRef.current?.contains(event.target)) {
   return;
 }
🧰 Tools
🪛 Biome (1.9.4)

[error] 31-31: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Client/src/Utils/Report/report.jsx (1)

60-68: Extract ping time formatting logic to a utility function.

The ping time conversion logic is duplicated:

+const formatPingTime = (ms) => {
+  return ms > 2000 ? `${(ms / 1000).toFixed(2)}s` : `${ms}ms`;
+};

-{pingStats.min > 2000
-  ? (pingStats.min / 1000).toFixed(2) + "s"
-  : pingStats.min + "ms"}
+{formatPingTime(pingStats.min)}

-{pingStats.max > 2000
-  ? (pingStats.max / 1000).toFixed(2) + "s"
-  : pingStats.max + "ms"}
+{formatPingTime(pingStats.max)}
Client/src/Pages/Uptime/Details/index.jsx (1)

108-115: Yo! Add loading state handling for reports

The reportIsLoading state isn't being used. Consider showing a loading indicator when fetching report data.

Add loading state to MonitorStatusHeader:

 <MonitorStatusHeader
   path={"uptime"}
   isAdmin={isAdmin}
   shouldRender={!monitorIsLoading}
   monitor={monitor}
   reportData={reportData}
   certificateExpiry={certificateExpiry}
+  reportIsLoading={reportIsLoading}
 />

Also applies to: 126-133

Client/src/Utils/Report/reportStyles.css (2)

1-6: Yo! Fix duplicate padding declaration

There's duplicate padding in .product-report class. Also, consider using CSS variables for colors.

+:root {
+  --text-color: rgb(36, 36, 36);
+}
+
 .product-report {
   display: flex;
-  padding: 1rem;
-  color: rgb(36, 36, 36);
+  color: var(--text-color);
   padding: 25px;
 }

16-20: Yo! Make hr width responsive

Fixed width hr might cause issues on different screen sizes.

 hr {
   border: 0;
   border-top: 1px solid #ddd;
-  width: 700px;
+  width: 100%;
+  max-width: 700px;
 }
Client/src/Components/MonitorStatusHeader/index.jsx (1)

67-68: Yo, let's make these PropTypes more explicit!

While the basic PropTypes are good, we could make them more specific:

Consider adding shape validation for reportData:

-  reportData: PropTypes.object,
+  reportData: PropTypes.shape({
+    // Add specific fields based on the expected report data structure
+    // Example:
+    // metrics: PropTypes.array.isRequired,
+    // summary: PropTypes.object.isRequired,
+  }),
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deca3b9 and 68e6914.

⛔ Files ignored due to path filters (1)
  • Client/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • Client/package.json (1 hunks)
  • Client/src/Components/DropDownButton/index.jsx (1 hunks)
  • Client/src/Components/MonitorStatusHeader/ReportDownloadButton/index.jsx (1 hunks)
  • Client/src/Components/MonitorStatusHeader/index.jsx (3 hunks)
  • Client/src/Pages/Uptime/Details/Hooks/useReportFetch.jsx (1 hunks)
  • Client/src/Pages/Uptime/Details/index.jsx (4 hunks)
  • Client/src/Utils/Report/downloadReport.jsx (1 hunks)
  • Client/src/Utils/Report/report.jsx (1 hunks)
  • Client/src/Utils/Report/reportStyles.css (1 hunks)
  • Client/src/Utils/Report/reportUtils.js (1 hunks)
  • Client/src/Utils/timeUtils.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
Client/src/Components/DropDownButton/index.jsx

[error] 31-31: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Client/src/Utils/Report/reportStyles.css

[error] 8-10: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

🔇 Additional comments (5)
Client/src/Pages/Uptime/Details/Hooks/useReportFetch.jsx (1)

6-10: Yo, this hook initialization is straight fire! 🔥

Clean state management with separate concerns for data, loading, and error states.

Client/src/Pages/Uptime/Details/index.jsx (1)

73-77: Yo! Add error handling for report data

The reportNetworkError state is captured but not handled in the UI. Users won't know if report fetching fails.

Add error handling similar to how monitorNetworkError is handled:

 if (monitorNetworkError || checksNetworkError) {
+  if (reportNetworkError) {
   return (
     <GenericFallback>
       <Typography
         variant="h1"
         marginY={theme.spacing(4)}
         color={theme.palette.primary.contrastTextTertiary}
       >
         Network error
       </Typography>
-      <Typography>Please check your connection</Typography>
+      <Typography>
+        {reportNetworkError 
+          ? "Failed to fetch report data" 
+          : "Please check your connection"}
+      </Typography>
     </GenericFallback>
   );
 }
Client/package.json (1)

28-28: Yo! Verify html2pdf.js version and security

Let's make sure we're using a secure version of html2pdf.js.

✅ Verification successful

🌐 Web query:

What is the latest version of html2pdf.js and are there any known security vulnerabilities?

💡 Result:

The latest version of html2pdf.js is v0.10.2 (as of February 2025)[1][3][6]. However, developers are cautioned about unresolved issues in v0.10.x and advised to consider staying on v0.9.3 until these are addressed[3][4].

Security Considerations:

  • No vulnerabilities reported for html2pdf.js: The JavaScript library (eKoopmans/html2pdf.js) has no documented CVEs or security advisories in the provided sources.
  • Confusion with similarly named PHP library:
    Vulnerabilities like CVE-2021-45394 (SSRF/deserialization)[2], CVE-2023-39062 (XSS)[5][8], and others affect Spipu Html2Pdf (a PHP library), not the JavaScript html2pdf.js[2][5][8]. These PHP-related flaws were patched in versions like 5.2.4 and 5.2.8[7][8].

Key Differences:

Aspect html2pdf.js (JavaScript) Spipu Html2Pdf (PHP)
Latest Version 0.10.2[1][6] 5.3.0[7]
Vulnerability Status No known CVEs Multiple CVEs patched[5][7][8]
Usage Context Client-side browser conversion Server-side PHP PDF generation

Always verify library names and repositories to avoid confusion between similarly named projects[1][7].

Citations:


Hey there! Verification complete on html2pdf.js in Client/package.json.

  • The dependency is set to ^0.10.2, which indeed matches the latest available version as of February 2025.
  • There are no known security vulnerabilities reported for the JavaScript html2pdf.js library.
  • Note: While v0.10.2 is current, some sources caution that unresolved issues exist in the v0.10.x branch. Depending on your project's stability needs, you might consider testing thoroughly or even evaluating whether the more conservative v0.9.3 is a better fit.
Client/src/Components/MonitorStatusHeader/index.jsx (2)

8-8: Yo, this import's looking clean!

The ReportDownloadButton import follows the project's component organization pattern.


41-45: These Stack props are straight fire! 🔥

The layout implementation:

  • Uses MUI Stack component properly
  • Maintains consistent spacing with theme.spacing
  • Ensures proper alignment of buttons

Comment on lines +12 to +30
useEffect(() => {
const fetchMonitors = async () => {
try {
const res = await networkService.getStatsByMonitorId({
authToken: authToken,
monitorId: monitorId,
dateRange: dateRange,
normalize: true,
});
setReportData(res?.data?.data ?? {});
} catch (error) {
setReportNetworkError(true);
createToast({ body: error.message });
} finally {
setReportIsLoading(false);
}
};
fetchMonitors();
}, [authToken, dateRange, monitorId, navigate]);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Yo dawg, let's clean up these dependencies! 🧹

The navigate is included in the dependency array but isn't used in the effect.

-	}, [authToken, dateRange, monitorId, navigate]);
+	}, [authToken, dateRange, monitorId]);

Also, consider logging the error for debugging:

 			} catch (error) {
 				setReportNetworkError(true);
+				console.error('Report fetch failed:', error);
 				createToast({ body: error.message });
 			}
📝 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
useEffect(() => {
const fetchMonitors = async () => {
try {
const res = await networkService.getStatsByMonitorId({
authToken: authToken,
monitorId: monitorId,
dateRange: dateRange,
normalize: true,
});
setReportData(res?.data?.data ?? {});
} catch (error) {
setReportNetworkError(true);
createToast({ body: error.message });
} finally {
setReportIsLoading(false);
}
};
fetchMonitors();
}, [authToken, dateRange, monitorId, navigate]);
useEffect(() => {
const fetchMonitors = async () => {
try {
const res = await networkService.getStatsByMonitorId({
authToken: authToken,
monitorId: monitorId,
dateRange: dateRange,
normalize: true,
});
setReportData(res?.data?.data ?? {});
} catch (error) {
setReportNetworkError(true);
console.error('Report fetch failed:', error);
createToast({ body: error.message });
} finally {
setReportIsLoading(false);
}
};
fetchMonitors();
}, [authToken, dateRange, monitorId]);

Comment on lines 39 to 43
ReportDownloadButton.propTypes = {
shouldRender: PropTypes.bool,
monitor: PropTypes.object,
certificateExpiry: PropTypes.string,
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Let's lock down these prop types, homie! 🔒

Mark essential props as required to prevent runtime issues.

 ReportDownloadButton.propTypes = {
 	shouldRender: PropTypes.bool,
-	monitor: PropTypes.object,
-	certificateExpiry: PropTypes.string,
+	monitor: PropTypes.object.isRequired,
+	certificateExpiry: PropTypes.string.isRequired,
 };
📝 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
ReportDownloadButton.propTypes = {
shouldRender: PropTypes.bool,
monitor: PropTypes.object,
certificateExpiry: PropTypes.string,
};
ReportDownloadButton.propTypes = {
shouldRender: PropTypes.bool,
monitor: PropTypes.object.isRequired,
certificateExpiry: PropTypes.string.isRequired,
};

Comment on lines 16 to 27
const handleDownload = async () => {
try {
console.log(monitor);
await downloadReport({
monitorData: monitor,
downloadFormat,
certificateExpiry,
});
} finally {
setDownloadFormat("pdf"); //passing pdf as default
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Yo, we got some cleanup to do! 🧼

Found some issues that need attention:

  1. Console.log statement in production code
  2. Typo in prop name 'hanldeClick' (should be 'handleClick')
 	const handleDownload = async () => {
 		try {
-			console.log(monitor);
 			await downloadReport({
 				monitorData: monitor,
 				downloadFormat,
 				certificateExpiry,
 			});
 		} finally {
 			setDownloadFormat("pdf"); //passing pdf as default
 		}
 	};

And in the JSX:

 			<DropDownButton options={options}
-			hanldeClick={handleDownload}
+			handleClick={handleDownload}
 			setValue={setDownloadFormat}/>
📝 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 handleDownload = async () => {
try {
console.log(monitor);
await downloadReport({
monitorData: monitor,
downloadFormat,
certificateExpiry,
});
} finally {
setDownloadFormat("pdf"); //passing pdf as default
}
};
// Updated handleDownload function without the console.log
const handleDownload = async () => {
try {
await downloadReport({
monitorData: monitor,
downloadFormat,
certificateExpiry,
});
} finally {
setDownloadFormat("pdf"); //passing pdf as default
}
};
// Updated DropDownButton JSX with corrected prop name
<DropDownButton options={options}
handleClick={handleDownload}
setValue={setDownloadFormat}/>

Comment on lines +53 to +56
} else if (downloadFormat === "pdf") {
// Create and trigger PDF download
html2pdf().from(htmlContent).save(`${monitorData.name}-monitor-report-${new Date().toISOString().split("T")[0]}.pdf`);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for PDF generation.

PDF generation could fail silently. Add proper error handling:

 } else if (downloadFormat === "pdf") {
-  html2pdf().from(htmlContent).save(`${monitorData.name}-monitor-report-${new Date().toISOString().split("T")[0]}.pdf`);
+  try {
+    await html2pdf().from(htmlContent).save(
+      `${monitorData.name}-monitor-report-${new Date().toISOString().split("T")[0]}.pdf`
+    );
+  } catch (error) {
+    console.error('PDF generation failed:', error);
+    throw new Error('Failed to generate PDF report');
+  }
 }
📝 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 (downloadFormat === "pdf") {
// Create and trigger PDF download
html2pdf().from(htmlContent).save(`${monitorData.name}-monitor-report-${new Date().toISOString().split("T")[0]}.pdf`);
}
} else if (downloadFormat === "pdf") {
try {
await html2pdf().from(htmlContent).save(
`${monitorData.name}-monitor-report-${new Date().toISOString().split("T")[0]}.pdf`
);
} catch (error) {
console.error('PDF generation failed:', error);
throw new Error('Failed to generate PDF report');
}
}

);

// Wait for styles to be applied
setTimeout(() => {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace setTimeout with MutationObserver for reliable style loading.

Using a fixed timeout isn't reliable for style application. Consider using MutationObserver:

-setTimeout(() => {
+const observer = new MutationObserver((mutations, obs) => {
+  if (document.querySelector('.product-report')) {
+    obs.disconnect();
     try {
       // ... rest of the code
     } finally {
       // ... cleanup code
     }
+  }
+});
+observer.observe(document.body, {
+  childList: true,
+  subtree: true
+});
📝 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
setTimeout(() => {
const observer = new MutationObserver((mutations, obs) => {
if (document.querySelector('.product-report')) {
obs.disconnect();
try {
// ... rest of the code
} finally {
// ... cleanup code
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});

const theme = useTheme();
const [open, setOpen] = useState(false);
const anchorRef = useRef(null);
const [selectedIndex, setSelectedIndex] = useState(1);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Initialize selectedIndex to 0 for safety.

Hardcoding selectedIndex to 1 assumes options array has at least 2 elements:

-const [selectedIndex, setSelectedIndex] = useState(1);
+const [selectedIndex, setSelectedIndex] = useState(0);
📝 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 [selectedIndex, setSelectedIndex] = useState(1);
const [selectedIndex, setSelectedIndex] = useState(0);

Comment on lines +120 to +123
ProductReport.propTypes = {
monitorData: PropTypes.object.isRequired,
certificateExpiry: PropTypes.string.isRequired,
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Define specific shape for monitorData PropType.

The current PropType is too generic. Add shape validation:

 ProductReport.propTypes = {
-  monitorData: PropTypes.object.isRequired,
+  monitorData: PropTypes.shape({
+    name: PropTypes.string.isRequired,
+    url: PropTypes.string.isRequired,
+    createdAt: PropTypes.string.isRequired,
+    checks: PropTypes.array.isRequired,
+    periodUptime: PropTypes.number.isRequired,
+    periodAvgResponseTime: PropTypes.number.isRequired,
+    periodIncidents: PropTypes.number.isRequired,
+    periodTotalChecks: PropTypes.number.isRequired,
+    interval: PropTypes.number.isRequired,
+    isActive: PropTypes.bool.isRequired,
+    uptimeDuration: PropTypes.number.isRequired
+  }).isRequired,
   certificateExpiry: PropTypes.string.isRequired,
 };
📝 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
ProductReport.propTypes = {
monitorData: PropTypes.object.isRequired,
certificateExpiry: PropTypes.string.isRequired,
};
ProductReport.propTypes = {
monitorData: PropTypes.shape({
name: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired,
checks: PropTypes.array.isRequired,
periodUptime: PropTypes.number.isRequired,
periodAvgResponseTime: PropTypes.number.isRequired,
periodIncidents: PropTypes.number.isRequired,
periodTotalChecks: PropTypes.number.isRequired,
interval: PropTypes.number.isRequired,
isActive: PropTypes.bool.isRequired,
uptimeDuration: PropTypes.number.isRequired
}).isRequired,
certificateExpiry: PropTypes.string.isRequired,
};

Comment on lines +114 to +125
export const formatDateWithWeekday = (date) => {
const options = {
weekday: "short",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
};
return new Intl.DateTimeFormat("en-US", options).format(new Date(date));
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize date handling and maintain consistency with formatDate.

The function creates an unnecessary Date object and deviates from the pattern in formatDate:

 export const formatDateWithWeekday = (date) => {
   const options = {
     weekday: "short",
     year: "numeric",
     month: "long",
     day: "numeric",
     hour: "numeric",
     minute: "numeric",
     hour12: true,
   };
-  return new Intl.DateTimeFormat("en-US", options).format(new Date(date));
+  return date
+    .toLocaleString("en-US", options)
+    .replace(/\b(AM|PM)\b/g, (match) => match.toLowerCase());
 }
📝 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
export const formatDateWithWeekday = (date) => {
const options = {
weekday: "short",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
};
return new Intl.DateTimeFormat("en-US", options).format(new Date(date));
}
export const formatDateWithWeekday = (date) => {
const options = {
weekday: "short",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
};
return date
.toLocaleString("en-US", options)
.replace(/\b(AM|PM)\b/g, (match) => match.toLowerCase());
}

Comment on lines +8 to +10
.report-content{

}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Yo! Remove empty CSS class

The .report-content class is empty and should be removed if not used.

-.report-content{
-
-}
📝 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
.report-content{
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 8-10: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

import SkeletonLayout from "./skeleton";
import PropTypes from "prop-types";

const MonitorStatusHeader = ({ path, shouldRender = true, isAdmin, monitor }) => {
const MonitorStatusHeader = ({ path, shouldRender = true, isAdmin, monitor, certificateExpiry, reportData }) => {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Yo dawg, we need to keep our props consistent!

The monitor prop is being used differently between components:

  • ConfigButton receives monitor?._id
  • ReportDownloadButton receives reportData as monitor

This inconsistency could lead to confusion.

Consider renaming the prop in ReportDownloadButton to match its actual content:

 <ReportDownloadButton 
   shouldRender={isAdmin}
-  monitor={reportData}
+  reportData={reportData}
   certificateExpiry={certificateExpiry}
 />

Also applies to: 51-55

@DMJain DMJain closed this Feb 11, 2025
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.

1 participant