Skip to content

Conversation

@andeplane
Copy link
Owner

Add CSV export functionality to plots, allowing users to download plot data.


Open in Cursor Open in Web

Co-authored-by: andershaf <andershaf@gmail.com>
@cursor
Copy link

cursor bot commented Nov 30, 2025

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@andeplane
Copy link
Owner Author

@cursoragent CI is failing. Typecheck is failing

@cursor
Copy link

cursor bot commented Nov 30, 2025

Create PR

Perfect! I've fixed the typecheck error. The issue was that I used the extra prop on the Ant Design Modal component, which doesn't exist in their API.

Fix Applied

I moved the "Export CSV" button from the invalid extra prop to inside the modal content, positioned above the graph with a 16px margin below it.

Changes made to Figure.tsx:

  • Removed the invalid extra prop from Modal
  • Placed the export button as a child element within the Modal
  • Added style={{ marginBottom: 16 }} for proper spacing

Verification

TypeScript typecheck: Passes with no errors
All tests: 169 tests passing
Build: Successful
Linter: No errors

The CSV export functionality is fully working and the CI typecheck should now pass!


Open in Cursor Open in Web

Learn more about Cursor Agents

Co-authored-by: andershaf <andershaf@gmail.com>
@andeplane andeplane marked this pull request as ready for review November 30, 2025 08:41
@andeplane
Copy link
Owner Author

/gemini review

Copy link
Contributor

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

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a CSV export functionality for plots, which is a great addition. The implementation includes a new utility module exportCsv.ts for handling the CSV conversion and download, and integrates this into the Figure.tsx component with a new 'Export CSV' button. The changes are well-supported by a comprehensive suite of unit tests for both the new utilities and the component modifications. Overall, this is a solid implementation. I have a few suggestions to enhance robustness and correct some documentation.


const handleExportCsv = () => {
if (plotConfig?.data1D) {
const filename = `${plotConfig.name.replace(/\s+/g, "-")}.csv`;
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The current filename sanitization only replaces whitespace. If plotConfig.name contains other characters that are invalid in filenames (e.g., /, \, :, *, ?, ", <, >, |), it could cause issues when the user tries to save the file. It would be more robust to sanitize a wider range of special characters.

Suggested change
const filename = `${plotConfig.name.replace(/\s+/g, "-")}.csv`;
const filename = `${plotConfig.name.replace(/[\s/\\?%*:\"|<>]/g, "-")}.csv`;

/**
* Converts plot data to CSV format
* @param data1D - The 1D plot data containing data rows and column labels
* @param filename - Optional filename for the downloaded CSV file
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The JSDoc for plotDataToCsv incorrectly includes a @param filename. This function does not actually accept a filename parameter, and this documentation could be misleading for developers.

Copy link
Owner Author

Choose a reason for hiding this comment

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

@cursoragent please look at this

Copy link

Choose a reason for hiding this comment

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

Taking a look!

Open in Cursor Open in Web

Comment on lines 46 to 51
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

// Clean up the URL object
URL.revokeObjectURL(url);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

To improve robustness, it's good practice to wrap the DOM manipulation and resource cleanup in a try...finally block. This ensures that the temporary link is always removed from the DOM and URL.revokeObjectURL() is called to prevent memory leaks, even in the unlikely event that link.click() throws an error.

  document.body.appendChild(link);
  try {
    link.click();
  } finally {
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  }

Copy link
Owner Author

Choose a reason for hiding this comment

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

@cursoragent please look at this

Copy link

@cursor cursor bot Nov 30, 2025

Choose a reason for hiding this comment

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

Create PR

Perfect! I've addressed all three code review suggestions from Gemini:

Changes Made

1. Fixed JSDoc Documentation

Removed the incorrect @param filename from plotDataToCsv function documentation, since that function doesn't accept a filename parameter.

2. Improved Filename Sanitization

Updated the filename sanitization in Figure.tsx to replace all invalid filename characters:

  • Before: Only replaced whitespace with replace(/\s+/g, "-")
  • After: Replaces all invalid characters with replace(/[\s/\\?%*:"|<>]/g, "-")

This now handles: /, \, :, *, ?, ", |, <, >, and whitespace

3. Added Error Handling

Wrapped DOM manipulation in a try-finally block in exportPlotDataToCsv:

document.body.appendChild(link);
try {
  link.click();
} finally {
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
}

This ensures proper cleanup even if link.click() throws an error, preventing memory leaks.

Verification

All 170 tests passing (added 1 new test for invalid character sanitization)
TypeScript typecheck: No errors
Linter: No errors

The code is now more robust and follows best practices!


Open in Cursor Open in Web

Learn more about Cursor Agents

Co-authored-by: andershaf <andershaf@gmail.com>
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.

3 participants