-
Notifications
You must be signed in to change notification settings - Fork 510
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
feat: export as markdown #245
base: develop
Are you sure you want to change the base?
Conversation
WalkthroughThe changes introduce new functionality to the Changes
Poem
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (1)
src/components/molecules/RunContent.tsx (1)
167-171
: Improve accessibility and consistency of download optionsThe Markdown download option should follow accessibility best practices and maintain consistency with other download options.
-<Typography - onClick={downloadMarkdown} -> - <a style={{ textDecoration: 'none', cursor: 'pointer' }}>Download as Markdown</a> -</Typography> +<Typography> + <Button + component="a" + onClick={downloadMarkdown} + sx={{ textDecoration: 'none' }} + aria-label="Download data as Markdown" + > + Download as Markdown + </Button> +</Typography>Consider:
- Using Material-UI Button component for better accessibility
- Adding proper ARIA labels
- Maintaining consistent styling with other download options
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
src/components/molecules/RunContent.tsx
(4 hunks)
🔇 Additional comments (1)
src/components/molecules/RunContent.tsx (1)
Line range hint 61-171
: Verify table data handling consistency
Let's verify that the table data handling is consistent across all export formats.
✅ Verification successful
Table data handling is consistent across export formats
The code review shows that:
- The table data is consistently sourced from
row.serializableOutput
for all export formats (JSON, CSV, and Markdown) - The conversion functions (
convertToCSV
andconvertToMarkdown
) handle the data uniformly:- Both use the same
columns
array for headers - Both handle empty/undefined values appropriately
- Both properly escape special characters (CSV uses JSON.stringify, Markdown escapes pipe characters)
- Both use the same
- The download implementations follow the same secure pattern using
Blob
andURL.createObjectURL
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for table data handling patterns across the codebase
echo "Checking table data handling patterns..."
rg -A 5 "serializableOutput" --type typescript
# Look for similar download implementations
echo "Checking download implementations..."
rg -A 10 "download.*Blob" --type typescript
Length of output: 336
Script:
#!/bin/bash
# Search for table data handling patterns across the codebase
echo "Checking table data handling patterns..."
rg -A 5 "serializableOutput"
# Look for similar download implementations
echo "Checking download implementations..."
rg -A 10 "download.*Blob"
# Look for CSV and Markdown conversion functions
echo "Checking data conversion implementations..."
rg -A 10 "convertTo(CSV|Markdown)"
Length of output: 15309
const downloadMarkdown = () => { | ||
const markdownContent = convertToMarkdown(tableData, columns); | ||
const blob = new Blob([markdownContent], { type: 'text/markdown;charset=utf-8;' }); | ||
const url = URL.createObjectURL(blob); | ||
|
||
const link = document.createElement("a"); | ||
link.href = url; | ||
link.setAttribute("download", "data.md"); | ||
document.body.appendChild(link); | ||
link.click(); | ||
document.body.removeChild(link); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add cleanup and error handling to downloadMarkdown function
The current implementation might cause memory leaks and doesn't handle potential errors.
const downloadMarkdown = () => {
- const markdownContent = convertToMarkdown(tableData, columns);
- const blob = new Blob([markdownContent], { type: 'text/markdown;charset=utf-8;' });
- const url = URL.createObjectURL(blob);
+ try {
+ const markdownContent = convertToMarkdown(tableData, columns);
+ const blob = new Blob([markdownContent], { type: 'text/markdown;charset=utf-8;' });
+ const url = URL.createObjectURL(blob);
- const link = document.createElement("a");
- link.href = url;
- link.setAttribute("download", "data.md");
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
+ const link = document.createElement("a");
+ link.href = url;
+ link.setAttribute("download", "data.md");
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ URL.revokeObjectURL(url);
+ } catch (error) {
+ console.error('Failed to download markdown:', error);
+ // Consider adding user feedback here
+ }
};
The changes:
- Add error handling with try-catch
- Clean up the URL object to prevent memory leaks
- Consider adding user feedback for errors
📝 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.
const downloadMarkdown = () => { | |
const markdownContent = convertToMarkdown(tableData, columns); | |
const blob = new Blob([markdownContent], { type: 'text/markdown;charset=utf-8;' }); | |
const url = URL.createObjectURL(blob); | |
const link = document.createElement("a"); | |
link.href = url; | |
link.setAttribute("download", "data.md"); | |
document.body.appendChild(link); | |
link.click(); | |
document.body.removeChild(link); | |
}; | |
const downloadMarkdown = () => { | |
try { | |
const markdownContent = convertToMarkdown(tableData, columns); | |
const blob = new Blob([markdownContent], { type: 'text/markdown;charset=utf-8;' }); | |
const url = URL.createObjectURL(blob); | |
const link = document.createElement("a"); | |
link.href = url; | |
link.setAttribute("download", "data.md"); | |
document.body.appendChild(link); | |
link.click(); | |
document.body.removeChild(link); | |
URL.revokeObjectURL(url); | |
} catch (error) { | |
console.error('Failed to download markdown:', error); | |
// Consider adding user feedback here | |
} | |
}; |
const convertToMarkdown = (data: any[], columns: string[]): string => { | ||
|
||
const headerRow = `| ${columns.join(' | ')} |`; | ||
|
||
// Create separator row for Markdown tables | ||
const separatorRow = `| ${columns.map(() => '---').join(' | ')} |`; | ||
|
||
|
||
const dataRows = data.map(row => | ||
`| ${columns.map(col => { | ||
|
||
const value = row[col]; | ||
return value === undefined || value === "" ? "-" : | ||
|
||
String(value).replace(/\|/g, '\\|').replace(/\n/g, ' '); | ||
}).join(' | ')} |` | ||
); | ||
|
||
|
||
return [headerRow, separatorRow, ...dataRows].join('\n'); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance the robustness of Markdown conversion
The implementation needs improvements in type safety and data handling:
-const convertToMarkdown = (data: any[], columns: string[]): string => {
+interface TableData {
+ [key: string]: string | number | boolean | null | undefined;
+}
+
+const convertToMarkdown = (data: TableData[], columns: string[]): string => {
const headerRow = `| ${columns.join(' | ')} |`;
const separatorRow = `| ${columns.map(() => '---').join(' | ')} |`;
const dataRows = data.map(row =>
`| ${columns.map(col => {
const value = row[col];
- return value === undefined || value === "" ? "-" :
- String(value).replace(/\|/g, '\\|').replace(/\n/g, ' ');
+ if (value === null || value === undefined || value === "") {
+ return "-";
+ }
+ return String(value)
+ .replace(/\|/g, '\\|')
+ .replace(/\n/g, ' ')
+ .replace(/\[/g, '\\[')
+ .replace(/\]/g, '\\]')
+ .replace(/\*/g, '\\*')
+ .replace(/_/g, '\\_');
}).join(' | ')} |`
);
return [headerRow, separatorRow, ...dataRows].join('\n');
};
The changes:
- Add proper TypeScript interface for table data
- Handle null values explicitly
- Escape additional Markdown special characters
- Remove unnecessary empty lines
📝 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.
const convertToMarkdown = (data: any[], columns: string[]): string => { | |
const headerRow = `| ${columns.join(' | ')} |`; | |
// Create separator row for Markdown tables | |
const separatorRow = `| ${columns.map(() => '---').join(' | ')} |`; | |
const dataRows = data.map(row => | |
`| ${columns.map(col => { | |
const value = row[col]; | |
return value === undefined || value === "" ? "-" : | |
String(value).replace(/\|/g, '\\|').replace(/\n/g, ' '); | |
}).join(' | ')} |` | |
); | |
return [headerRow, separatorRow, ...dataRows].join('\n'); | |
}; | |
interface TableData { | |
[key: string]: string | number | boolean | null | undefined; | |
} | |
const convertToMarkdown = (data: TableData[], columns: string[]): string => { | |
const headerRow = `| ${columns.join(' | ')} |`; | |
const separatorRow = `| ${columns.map(() => '---').join(' | ')} |`; | |
const dataRows = data.map(row => | |
`| ${columns.map(col => { | |
const value = row[col]; | |
if (value === null || value === undefined || value === "") { | |
return "-"; | |
} | |
return String(value) | |
.replace(/\|/g, '\\|') | |
.replace(/\n/g, ' ') | |
.replace(/\[/g, '\\[') | |
.replace(/\]/g, '\\]') | |
.replace(/\*/g, '\\*') | |
.replace(/_/g, '\\_'); | |
}).join(' | ')} |` | |
); | |
return [headerRow, separatorRow, ...dataRows].join('\n'); | |
}; |
Summary by CodeRabbit