forked from scratchfoundation/scratch-gui
-
-
Notifications
You must be signed in to change notification settings - Fork 16
Add Google Drive file upload functionality with custom dialog #429
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
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This commit implements the ability to save Scratch 3.0 projects (.sb3) to Google Drive with a custom dialog for specifying the filename and save location, complementing the existing "Load from Google Drive" functionality. ## New Features - **Menu Integration**: Added "Save to Google Drive" menu item in File menu - **Save Dialog**: Custom dialog with filename input and save location selection - **Folder Selection**: Users can save to My Drive root or select a specific folder - **File Upload**: Multipart upload using Google Drive Files API v3 ## Implementation ### New Components 1. **google-drive-saver-hoc.jsx**: HOC for Google Drive save functionality - Manages save dialog state and upload process - Converts Ruby code to blocks before saving - Provides error handling and user feedback 2. **google-drive-save-dialog.jsx**: Custom save dialog component - Filename input with .sb3 extension validation - Save location dropdown (My Drive or folder selection) - Cancel, Reset, and Save buttons 3. **google-drive-save-dialog.css**: Dialog styling ### Modified Files 1. **google-drive-api.js**: Added upload functionality - uploadFile(): Multipart upload to Google Drive - showFolderPicker(): Folder selection via Google Picker - handleFolderPickerResponse(): Handle folder picker callback 2. **menu-bar.jsx**: Integrated save functionality - Added "Save to Google Drive" menu item - Integrated GoogleDriveSaverHOC - Added GoogleDriveSaveDialog component 3. **ja.js**: Added Japanese translations for all new UI elements ## Technical Details - Uses existing OAuth 2.0 authentication from GoogleDriveLoaderHOC - Leverages drive.file scope (already configured) - Multipart upload with metadata and file content - Base64 encoding for binary file data - Folder picker using Google Picker API ## Testing - ✅ Lint checks pass: npm run test:lint - Dialog UI follows app.diagrams.net design patterns - Supports both My Drive root and folder selection ## Related - Implements feature request from Issue #428 - Built on top of PR #427 (Google Drive load functionality) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Changed from undefined $motion-primary-transparent to $motion-tertiary to match existing button patterns in the codebase. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Moved 'Save to Google Drive' menu item to appear after 'Load from Google Drive' as requested, making the menu order more logical with related operations grouped together. Menu order: - Load from your computer - Save to your computer - Load from URL - Load from Google Drive - Save to Google Drive (moved here) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixed three issues based on user feedback: 1. **Removed file type field**: Removed unnecessary 'タイプ:' field showing 'Scratch 3.0 Project (.sb3)' as it's redundant 2. **Changed 'Where:' label to 'フォルダ:'**: More intuitive Japanese label for folder selection 3. **Fixed select dropdown display**: Changed from FormattedMessage to intl.formatMessage in option tags to properly display folder options instead of '[object Object]' 4. **Added white background**: Set dialog body background to white (was transparent before) These changes improve the dialog's usability and visual clarity. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Removed 'Google ドライブ –' prefix from folder selection options for cleaner, more concise UI: Before: - Google ドライブ – My Drive - Google ドライブ – フォルダを選択する... After: - My Drive - フォルダを選択する... 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Changed 'My Drive' to 'マイドライブ' in Japanese locale for better user experience with native speakers. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
aba5b78 to
4638cbc
Compare
Added .setParent('root') to Google Picker DocsView to enable
hierarchical folder navigation instead of showing all folders
in a flat list.
Now the folder picker:
- Starts from root (top-level folders only)
- Allows users to navigate into subfolders by double-clicking
- Provides a cleaner, more intuitive folder selection experience
This matches the expected behavior shown in the reference screenshot.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added .setParent('root') to Google Picker DocsView in showPicker
method to enable hierarchical folder navigation when loading files
from Google Drive.
Now the file picker:
- Starts from root (top-level folders and files only)
- Allows users to navigate into subfolders by double-clicking
- Provides consistent UX with the folder picker for saving
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed menu label from 'Google ドライブに保存' to 'Googleドライブに名前をつけて保存...' to better indicate that a save dialog will appear. Changes: - Japanese: 'Googleドライブに名前をつけて保存...' - English: 'Save to Google Drive...' The ellipsis (...) indicates that user interaction is required before the action completes, following standard UI conventions. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed menu label from "Save to Google Drive..." to "Save as to Google Drive..." - Aligns with Japanese label "Googleドライブに名前をつけて保存..." 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Updated dialog title and header to "Save as to Google Drive" - Internationalized all labels with proper English defaults: - Filename label: "Save as:" (ja: "名前を付けて保存:") - Folder label: "Folder:" (ja: "フォルダ:") - Internationalized all buttons with English defaults: - Cancel button: "Cancel" (ja: "キャンセル") - Reset button: "Reset" (ja: "リセット") - Save button: "Save" (ja: "保存") - Internationalized folder selection option: - "Select folder..." (ja: "フォルダを選択する...") - Updated Japanese translations for title/header to "Googleドライブに名前をつけて保存" 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…Drive" - Updated menu label from "Save as to Google Drive..." to "Save a copy to Google Drive..." - Updated dialog title and header to match new label - Updated Japanese translations to "Googleドライブにコピーを保存" - Aligns with scratch.mit.edu UI conventions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Removed redundant header content at top of dialog body - Dialog title in modal is sufficient, no need for duplicate header - Removed unused 'gui.googleDriveSaveDialog.header' translation from ja.js 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replaced alert dialog with inline save status display in menu bar
- Added loading spinner during save with "Saving project..." message
- Show "Project saved." message for 3 seconds after successful save
- Changed saveStatus state management from boolean to string enum ('idle' | 'saving' | 'saved')
- Added Spinner component to menu bar with proper styling
- Matches scratch.mit.edu UI/UX patterns
English messages:
- Saving: "Saving project..."
- Saved: "Project saved."
Japanese messages:
- Saving: "プロジェクトを保存中..."
- Saved: "プロジェクトが保存されました。"
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The MenuBar component now uses GoogleDriveSaverHOC, which wraps it with RubyToBlocksConverterHOC. This HOC requires `targets` and `rubyCode` state slices in the Redux store. The test's mock store was missing these state slices, causing the tests to fail with: TypeError: Cannot read properties of undefined (reading 'editingTarget') Added the missing state slices with their initial values from the respective reducers: - targets: sprites, stage, editingTarget, highlightedTargetId, highlightedTargetTime - rubyCode: target, code, modified, errors, markers This fixes the CI failures in PR #429. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
github-actions bot
pushed a commit
that referenced
this pull request
Dec 14, 2025
…e-drive-upload Add Google Drive file upload functionality with custom dialog
takaokouji
added a commit
that referenced
this pull request
Dec 14, 2025
Add GOOGLE_CLIENT_ID and GOOGLE_API_KEY environment variables to all production build steps in the GitHub Actions workflow. This enables the Google Drive integration features (file loading and saving) in deployed environments. Changes: - Added environment variables to "Run Build" step (line 66-67) - Added environment variables to "Rebuild for smalruby3-gui GitHub Pages" step (line 127-128) - Added environment variables to "Rebuild for branch GitHub Pages" step (line 155-156) These variables will be sourced from GitHub Secrets and injected into the webpack build process via webpack.DefinePlugin. Deployment targets: - smalruby.app (main production site) - smalruby.github.io/smalruby3-gui/ (GitHub Pages) - Branch-specific deployments Related: #428, #429 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This was referenced Dec 14, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Implements the ability to save Scratch 3.0 projects (.sb3) to Google Drive with a custom dialog for specifying the filename and save location, addressing issue #428.
Key Features
Implementation Details
New Files
src/containers/google-drive-saver-hoc.jsxsrc/components/google-drive-save-dialog/google-drive-save-dialog.jsxsrc/components/google-drive-save-dialog/google-drive-save-dialog.cssModified Files
src/lib/google-drive-api.jsuploadFile()method for multipart upload to Google DriveshowFolderPicker()method for folder selectionhandleFolderPickerResponse()for handling folder picker callbackssrc/components/menu-bar/menu-bar.jsxsrc/locales/ja.jsTechnical Approach
Reuses Existing Infrastructure
drive.filescope (already configured in PR Add Google Drive file loading functionality #427)Upload Flow
parents: ["root"])vm.saveProjectSb3()Multipart Upload
Uses Google Drive Files API v3 with multipart upload format:
Error Handling
UI/UX Reference
The dialog design follows app.diagrams.net's save dialog:
See Issue #428 for reference screenshots.
Testing
Manual Testing
Tested the following scenarios:
Lint and Build
npm run test:lintBreaking Changes
None. This is a new feature that doesn't affect existing functionality.
Configuration
Uses the same environment variables as the load functionality:
GOOGLE_CLIENT_ID: OAuth 2.0 Client IDGOOGLE_API_KEY: API Key for Google Picker APISee
docs/google-drive-setup.mdfor setup instructions.Related Work
Future Enhancements
Possible improvements for future PRs:
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com