-
Notifications
You must be signed in to change notification settings - Fork 69
[LG-5455] feat(code-editor): add download functionality with smart file extensions #3066
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
base: integration/code-editor
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 249a6d5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Size Change: +1.3 kB (+0.06%) Total Size: 2.07 MB
ℹ️ View Unchanged
|
} | ||
|
||
// Determine file extension based on language | ||
const extension = |
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.
Can someone pass in a language that isn't included in LANGUAGE_EXTENSION_MAP
?
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.
No, this is a great point. I'll also update the LANGUAGE_EXTENSION_MAP
to enforce this.
packages/code-editor/README.md
Outdated
// Downloads as 'code.py' (default filename with Python extension) | ||
editorRef.current.downloadContent(); // No filename provided | ||
|
||
// Downloads as 'document.txt' (fallback for unsupported/no language) |
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.
Is this missing a code snippet?
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.
Good catch. I removed this completely since I'm no longer defaulting to .txt
at the moment
@@ -115,6 +116,13 @@ export function Panel({ | |||
onRedoClick?.(); | |||
}; | |||
|
|||
const handleDownloadClick = () => { | |||
if (downloadContent) { | |||
downloadContent(); |
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.
If you're downloading from the panel, will the file name always be code
?
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.
Currently yes, but I think this is a good point. I'm going to add an optional prop on Panel
that allows the setting of it.
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.
I also decided I'm going to update handleDownloadContent
in CodeEditor, to only add an extension if an acceptable extension is already added to the filename provided. This feels intuitive to me. So if I have js
selected and pass in a filename of index.js
it doesn't download as index.js.js
but if my filename is just index
it will download as index.js
intelligently.
I also think I'm going to get rid of the default .txt
because its probably not a fair assumption. When no language is selected, just no extension will be added.
Curious to hear your thoughts on this.
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.
I'm backtracking on this lol. I'm now thinking that a filename provided should override the extension. It just gives the consumer more control over the download. Still curious what you think here though
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.
if no extension is specified, what will the format be?
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.
I was just testing out preview on mac, https://jmp.sh/EWQKXqlV. I'm not sure if these are relatable but if you don't add an extention, it adds one by default, and if you type in an extension, it treats it as part of the name.
08f40b0
to
d1d676f
Compare
520ebd1
to
e68010b
Compare
0568216
to
878344d
Compare
@shaneeza The git history got all messed up on this one again when I merged the branch 2 ahead of this 😭. I'm going to wait to fix this until I can get the one in front of it merged. Sorry for the craziness. |
- Introduced a new method to download the current editor content as a file, with the extension determined by the selected programming language. - Updated the CodeEditorHandle and CodeEditorContext interfaces to include the new downloadContent method. - Added a mapping of language names to their corresponding file extensions to facilitate the download process.
- Added a new handleDownloadClick method to the Panel component to trigger the downloadContent function from the CodeEditorContext. - Updated the onClick handler for the Download menu item to use the new method, enhancing the user experience by allowing content downloads directly from the panel.
…and Panel - Implemented comprehensive tests for the download feature in the CodeEditor, verifying correct filename generation based on language and handling of empty content. - Enhanced Panel tests to ensure the downloadContent function is called when the download menu item is clicked, including handling cases where the function is not available. - Improved test coverage for the download functionality, ensuring robustness and reliability in the editor's user experience.
… content - Introduced a `downloadContent` method to the CodeEditor ref for programmatic file downloads, supporting various file extensions based on the editor's language. - Integrated a download button in the Panel's secondary menu for direct content downloads, with proper filename handling. - Enhanced context support for child components via `CodeEditorContext`, allowing custom UI implementations for downloads. - Implemented content validation to prevent downloads of empty or whitespace-only content, providing user-friendly warnings. - Updated TypeScript definitions and added extensive tests to ensure robust functionality and user experience.
…ctionality details - Enhanced the description of the Panel component to include the new download button and its integration with the CodeEditor's functionality. - Updated the properties table to reflect the addition of the download feature, including the `onDownloadClick` callback and its behavior. - Added a new section detailing the `downloadContent` method, including examples and supported file extensions for improved documentation clarity.
- Updated Panel tests to utilize the new renderPanel utility, improving clarity and reducing redundancy. - Simplified test cases for the downloadContent function, ensuring proper handling when the function is undefined. - Enhanced test maintainability by integrating default context functions for download actions.
- Extracted the LANGUAGE_EXTENSION_MAP from CodeEditor.tsx to a new constants.ts file for better organization and maintainability. - Simplified the extension determination logic in CodeEditor.tsx by directly referencing the imported LANGUAGE_EXTENSION_MAP.
…filenames - Introduced the `downloadFileName` property to the Panel component, allowing users to specify a custom filename for downloaded editor content. - Updated the download handling logic to utilize the provided filename, enhancing the flexibility of the download functionality. - Added tests to ensure correct behavior when the `downloadFileName` is specified or omitted.
31e1961
to
249a6d5
Compare
// Downloads as 'code' (uses filename exactly as provided, even though it's "code") | ||
editorRef.current.downloadContent('code'); | ||
|
||
// Downloads as 'code.py' (default behavior - no filename parameter provided) |
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.
Is the extension in the comment correct?
✍️ Proposed changes
This PR adds comprehensive download functionality to the CodeEditor component, allowing users to download their code with appropriate file extensions based on the selected language. The implementation includes both imperative API access and Panel UI integration.
Key Features:
.js
,.ts
,.py
,.css
, etc.) with.txt
fallbackdownloadContent(filename?)
method on CodeEditor ref handleThe implementation uses browser-native Blob API and maintains full backward compatibility while extending the component's capabilities. Supports 16+ languages including JavaScript, TypeScript, Python, Java, Go, Rust, and more.
🎟️ Jira ticket: LG-5455
✅ Checklist
For bug fixes, new features & breaking changes
npm run build:ts
and there are no errorsnpm test
and there are no errorsnpm run lint:eslint
and there are no errorsnpm run lint:stylelint
and there are no errorsnpx changeset
)🧪 How to test changes
Testing Download Functionality
Basic Download Test:
<CodeEditor defaultValue="console.log('test');" language="javascript" />
ref.current.downloadContent('my-script')
or use Panel download buttonmy-script.js
with correct contentLanguage Extension Mapping:
.js
), TypeScript (.ts
), Python (.py
), etc..txt
Edge Cases:
Panel Integration:
<Panel showSecondaryMenuButton />
componentImperative API:
ref.current.downloadContent()
without filename (uses 'code' default)ref.current.downloadContent('custom-name')
with custom filenameTesting in Storybook