refactor(website/client): Modernize Vue.js architecture with composables#642
refactor(website/client): Modernize Vue.js architecture with composables#642
Conversation
- Create usePackOptions composable for pack configuration state - Create usePackRequest composable for request lifecycle management - Refactor TryIt.vue to use composables, reducing complexity from 19 refs to 2 composables - Improve type safety with PackOptions interface and InputMode type - Enable better reusability and testability of state logic 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Create useFileUpload composable for unified drag/drop, validation, and file processing - Create useZipProcessor composable for ZIP file operations - Refactor TryItFileUpload.vue: reduce from 213 to 105 lines (50% reduction) - Refactor TryItFolderUpload.vue: reduce from 342 to 115 lines (66% reduction) - Eliminate code duplication while maintaining all existing functionality - Improve type safety with configurable validation and preprocessing pipelines - Enable better reusability and testability of upload logic 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis change refactors file and folder upload handling in the UI by introducing new composables ( Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant TryIt.vue
participant usePackRequest
participant useFileUpload
participant useZipProcessor
participant API
User->>TryIt.vue: Select input mode (url/file/folder)
TryIt.vue->>usePackRequest: setMode(mode)
User->>TryIt.vue: Enter URL or upload file/folder
TryIt.vue->>useFileUpload: handleFileSelect / handleDrop
useFileUpload->>useZipProcessor: (if folder) createZipFromFiles
useFileUpload-->>TryIt.vue: Emit uploadedFile (File)
User->>TryIt.vue: Click "Submit"
TryIt.vue->>usePackRequest: submitRequest()
usePackRequest->>API: handlePackRequest (with params & uploadedFile)
API-->>usePackRequest: Response (result or error)
usePackRequest-->>TryIt.vue: Update result/error state
Possibly related PRs
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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
Documentation and Community
|
There was a problem hiding this comment.
Pull Request Overview
This PR modernizes the Vue.js architecture by refactoring state management into composables and unifying file upload logic.
- Refactored state management with new composables (usePackOptions, usePackRequest)
- Consolidated file upload logic for both ZIP file uploads and folder drops via useFileUpload and useZipProcessor
- Simplified component code in TryIt.vue and related upload components
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| website/client/composables/useZipProcessor.ts | Added ZIP creation and validation functions using JSZip |
| website/client/composables/usePackRequest.ts | Centralized request logic with timeout handling and state management refactor |
| website/client/composables/usePackOptions.ts | Consolidated pack option state and computed request options |
| website/client/composables/useFileUpload.ts | Unified file/folder upload functionality with improved validation and asynchronous processing |
| website/client/components/Home/TryItFolderUpload.vue | Updated folder upload component to leverage new composables, reducing duplicate code |
| website/client/components/Home/TryItFileUpload.vue | Updated file upload component to use new ZIP validation and upload handling logic |
| website/client/components/Home/TryIt.vue | Integrated the new composable-based state management and file upload handling |
There was a problem hiding this comment.
Hello @yamadashy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
Summary of Changes
Hello team,
Gemini here, providing a summary for this pull request authored by yamadashy.
This PR focuses on modernizing the Vue.js architecture within the website/client directory by leveraging Vue 3's Composition API and creating reusable composables. The primary goals are to extract state management and complex logic (specifically file/folder upload) out of components, reduce code duplication, enhance type safety, and improve overall maintainability.
The changes involve creating dedicated composables (usePackOptions, usePackRequest, useFileUpload, useZipProcessor) and refactoring existing components (TryIt.vue, TryItFileUpload.vue, TryItFolderUpload.vue) to utilize these new composables. This significantly reduces the complexity and line count in the components themselves, centralizing logic in the composables.
Highlights
- State Management Refactoring: State related to pack options and the pack request lifecycle has been extracted into
usePackOptionsandusePackRequestcomposables, respectively. This centralizes state logic and improves type safety. - Unified File/Folder Upload Logic: A new generic
useFileUploadcomposable has been created to handle common file/folder selection, drag-and-drop, and basic validation logic. AuseZipProcessorcomposable handles ZIP-specific operations like creating a ZIP from folder contents. - Component Simplification: The
TryIt.vue,TryItFileUpload.vue, andTryItFolderUpload.vuecomponents have been significantly simplified by offloading their state and logic to the new composables, leading to substantial reductions in their code size. - Code Reduction and Duplication Elimination: By consolidating shared logic into composables, the PR eliminates duplicated code across the file and folder upload components and reduces the overall lines of code in the refactored components.
- Improved Maintainability and Testability: Separating concerns into composables makes the logic easier to understand, maintain, and potentially test independently from the components.
Changelog
Click here to see the changelog
- .gitignore
- Added
website/client/.vitepress/dist/to ignore the VitePress build output directory.
- Added
- website/client/components/Home/TryIt.vue
- Removed numerous individual
refdeclarations for input and processing states (lines 99-118). - Replaced manual state management and request handling logic with properties and methods from the new
usePackRequestcomposable (lines 97-121, 123-124). - Updated
TryItPackOptionsbindings to use thepackOptionsobject from the composable instead of individual refs (lines 61-70). - Removed the local
handleFileUploadfunction (lines 202-204).
- Removed numerous individual
- website/client/components/Home/TryItFileUpload.vue
- Removed local state (
fileInput,dragActive,selectedFile,errorMessage) and constants (MAX_FILE_SIZE) (lines 17-20, 6). - Removed local file validation and event handling logic (lines 22-53).
- Imported and integrated the
useFileUploadanduseZipProcessorcomposables (lines 3-4, 16-42). - Updated template bindings and event handlers to use the state and methods provided by
useFileUpload(lines 67-72, 81, 89, 96).
- Removed local state (
- website/client/components/Home/TryItFolderUpload.vue
- Removed local state (
fileInput,dragActive,selectedFolder,errorMessage) and constants (MAX_FILE_SIZE) (lines 18-21, 7). - Removed extensive local logic for folder validation, ZIP creation, file collection, and event handling (lines 23-172).
- Imported and integrated the
useFileUploadanduseZipProcessorcomposables (lines 3-4, 16-52). - Updated template bindings and event handlers to use the state and methods provided by
useFileUpload(lines 77-88, 91, 99, 112).
- Removed local state (
- website/client/composables/useFileUpload.ts
- New file: Implements a generic Vue composable for handling file and folder uploads.
- Manages drag/drop state, selected item, error messages, and processing status.
- Includes default validation for file size and accepted types, with options for custom validation and preprocessing.
- Provides methods for handling file input changes, drag/drop events, and triggering the file input.
- Includes specialized logic for handling folder drops using
webkitGetAsEntry.
- website/client/composables/usePackOptions.ts
- New file: Implements a Vue composable to manage the state of pack configuration options.
- Uses a reactive object to hold all options.
- Provides a computed property to easily format options for the pack request API.
- Includes methods to update individual options and reset to default values.
- website/client/composables/usePackRequest.ts
- New file: Implements a Vue composable to manage the state and logic related to the pack request lifecycle.
- Integrates
usePackOptionsto access pack configuration. - Manages input states (URL, mode, uploaded file) and request states (loading, error, result, execution status).
- Includes logic for submitting the request, handling timeouts, and cancellation.
- Provides a computed property to check if the current input is valid for submission.
- website/client/composables/useZipProcessor.ts
- New file: Implements a Vue composable for ZIP file processing.
- Includes a method (
createZipFromFiles) to generate a ZIP file from an array of File objects. - Includes a method (
validateZipFile) for basic validation of a single file to check if it's a ZIP.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
Deploying repomix with
|
| Latest commit: |
135e535
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://e268a566.repomix.pages.dev |
| Branch Preview URL: | https://feat-refact-website.repomix.pages.dev |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #642 +/- ##
=======================================
Coverage 90.32% 90.32%
=======================================
Files 96 96
Lines 4962 4962
Branches 1042 1042
=======================================
Hits 4482 4482
Misses 480 480 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request introduces a significant and well-executed refactor of the Vue.js components, primarily by leveraging composables for state management and file upload logic. The changes lead to much cleaner, more maintainable, and reusable code. The reduction in component complexity in TryIt.vue, TryItFileUpload.vue, and TryItFolderUpload.vue is particularly noteworthy.
The new composables (usePackOptions, usePackRequest, useFileUpload, useZipProcessor) are thoughtfully designed and effectively encapsulate their respective functionalities. This is a great step forward for the codebase.
Summary of Findings
- Architectural Improvement: The refactoring to use Vue composables has significantly improved code organization, reduced component complexity, and enhanced reusability. This is a major positive change.
- Timeout Error Handling: In
usePackRequest.ts, throwing an error directly within asetTimeoutcallback for request timeouts might lead to unhandled promise rejections. Relying onAbortController.abort()with a reason is generally a safer way to handle this, allowing the error to propagate through thefetchpromise chain. - File Upload Logic: The
useFileUpload.tscomposable provides a robust and flexible way to handle file and folder uploads, including drag/drop, validation, and preprocessing. The type assertions for validators, while functional, could be slightly refactored for enhanced clarity inprocessFiles(lines 114-124), but this is a minor point and not a functional issue. (Not commented due to review settings).
Merge Readiness
This pull request represents a significant improvement to the codebase. The refactoring is well done and the new composable-based architecture is much cleaner.
There is one medium-severity issue identified regarding timeout error handling in usePackRequest.ts that should be addressed before merging to prevent potential unhandled errors. Once that is resolved, and after the planned manual testing is completed, this PR should be in good shape for merging.
As an AI, I am not authorized to approve pull requests. Please ensure other reviewers approve these changes before merging.
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (4)
website/client/composables/useZipProcessor.ts (1)
16-21: Consider more robust ZIP validation.The current validation only checks MIME type and file extension, which can be unreliable or spoofed. For better security, consider validating the actual file content.
Would you like me to implement a more robust validation that checks the ZIP file signature (magic bytes)?
- function validateZipFile(file: File): { valid: boolean; error?: string } { - if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) { - return { valid: false, error: 'Please upload a ZIP file' }; - } - return { valid: true }; - } + async function validateZipFile(file: File): Promise<{ valid: boolean; error?: string }> { + // Quick check for type/extension + if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) { + return { valid: false, error: 'Please upload a ZIP file' }; + } + + // Check ZIP magic bytes (PK\x03\x04 or PK\x05\x06) + try { + const buffer = await file.slice(0, 4).arrayBuffer(); + const bytes = new Uint8Array(buffer); + const isZip = (bytes[0] === 0x50 && bytes[1] === 0x4B && + (bytes[2] === 0x03 || bytes[2] === 0x05) && + (bytes[3] === 0x04 || bytes[3] === 0x06)); + + if (!isZip) { + return { valid: false, error: 'Invalid ZIP file format' }; + } + return { valid: true }; + } catch { + // Fallback to basic validation if reading fails + return { valid: true }; + } + }website/client/components/Home/TryIt.vue (1)
123-125: Remove unnecessary wrapper function.The
handleSubmitfunction is now just a wrapper aroundsubmitRequest. You can directly usesubmitRequestin the template and event handlers.-async function handleSubmit() { - await submitRequest(); -}Then update the template and event handlers:
- <form class="try-it-container" @submit.prevent="handleSubmit"> + <form class="try-it-container" @submit.prevent="submitRequest">if (event.key === 'Enter' && mode.value === 'url' && isSubmitValid.value && !loading.value) { - handleSubmit(); + submitRequest(); }nextTick(() => { - handleSubmit(); + submitRequest(); });website/client/composables/useFileUpload.ts (2)
11-11: Consider clarifying thepreprocessFilesreturn type.The function accepts an array of files but returns a single file. While this makes sense for scenarios like zipping multiple files into one, consider making the intent clearer through documentation or a more specific type name.
Add a JSDoc comment to clarify the purpose:
+ /** + * Preprocesses multiple files into a single file (e.g., creating a ZIP archive) + */ preprocessFiles?: (files: File[], folderName?: string) => Promise<File>;
114-124: Improve type safety in validator selection.The current implementation uses type casting which reduces type safety. Consider restructuring to maintain proper typing.
- const validator = - config.mode === 'folder' || multiple - ? validateFiles || defaultValidateFiles - : validateFile || defaultValidateFile; - - let validationResult: { valid: boolean; error?: string }; - if (config.mode === 'folder' || multiple) { - validationResult = (validator as typeof defaultValidateFiles)(files); - } else { - validationResult = (validator as typeof defaultValidateFile)(files[0]); - } + let validationResult: { valid: boolean; error?: string }; + if (config.mode === 'folder' || multiple) { + const validator = validateFiles || defaultValidateFiles; + validationResult = validator(files); + } else { + const validator = validateFile || defaultValidateFile; + validationResult = validator(files[0]); + }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
.gitignore(1 hunks)website/client/components/Home/TryIt.vue(3 hunks)website/client/components/Home/TryItFileUpload.vue(3 hunks)website/client/components/Home/TryItFolderUpload.vue(4 hunks)website/client/composables/useFileUpload.ts(1 hunks)website/client/composables/usePackOptions.ts(1 hunks)website/client/composables/usePackRequest.ts(1 hunks)website/client/composables/useZipProcessor.ts(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (20)
- GitHub Check: Build and run (macos-latest, 18.x)
- GitHub Check: Build and run (macos-latest, 18.0.0)
- GitHub Check: Test (ubuntu-latest, 18.0.0)
- GitHub Check: Build and run (windows-latest, 22.x)
- GitHub Check: Build and run (ubuntu-latest, 18.0.0)
- GitHub Check: Build and run (windows-latest, 18.0.0)
- GitHub Check: Build and run (windows-latest, 18.x)
- GitHub Check: Build and run (windows-latest, 21.x)
- GitHub Check: Test (windows-latest, 18.0.0)
- GitHub Check: Test (windows-latest, 24.x)
- GitHub Check: Test (macos-latest, 22.x)
- GitHub Check: Test (macos-latest, 18.x)
- GitHub Check: Test (windows-latest, 22.x)
- GitHub Check: Test (ubuntu-latest, 19.x)
- GitHub Check: Test (windows-latest, 20.x)
- GitHub Check: Test (windows-latest, 23.x)
- GitHub Check: Test (windows-latest, 21.x)
- GitHub Check: Test (windows-latest, 19.x)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Cloudflare Pages
🔇 Additional comments (11)
.gitignore (1)
6-6: Ignore generated VitePress build outputThe added
website/client/.vitepress/dist/entry prevents tracking of the VitePress build artifacts. Confirm that this path matches your actual output directory and clean up any already committed files with:git rm -r --cached website/client/.vitepress/dist/website/client/components/Home/TryIt.vue (1)
97-121: Excellent refactoring with composables!The migration to using
usePackRequestcomposable significantly improves code organization and reduces component complexity. The destructuring is clean and well-structured.website/client/components/Home/TryItFileUpload.vue (4)
1-5: Well-structured composable imports.The refactoring properly separates concerns by importing dedicated composables for file upload and ZIP processing functionality.
16-42: Excellent composable configuration and destructuring.The
useFileUploadcomposable is properly configured with file-specific options, including appropriate file size limits, type restrictions, and validation delegation touseZipProcessor. The destructured properties provide clean access to all necessary state and methods.
44-60: Clean async event handler implementation.The event handlers properly await composable methods and only emit upload events on successful validation. The result checking pattern (
result.success && result.result) ensures robust error handling.
67-77: Proper drag-and-drop event handling.The template correctly binds all drag-and-drop event handlers from the composable, with appropriate event modifiers (
.prevent) to handle default browser behavior.website/client/composables/usePackRequest.ts (2)
26-27: Good request cancellation implementation.The AbortController pattern is properly implemented with automatic cancellation of pending requests and proper cleanup. The timeout constant is clearly defined.
Also applies to: 56-63
30-40: Comprehensive validation logic.The computed validation correctly handles all input modes with appropriate checks: URL validation for URL mode and file presence for upload modes.
website/client/components/Home/TryItFolderUpload.vue (2)
33-52: Well-configured folder upload with appropriate validation and preprocessing.The composable is properly configured for folder mode with:
- Correct
webkitdirectoryattribute for folder selection- Empty folder validation
- ZIP creation preprocessing with proper error handling for missing folder names
73-115: Consistent template implementation with file upload component.The template properly mirrors the file upload component's structure while maintaining folder-specific UI elements. All event handlers and state bindings correctly use the composable's exposed properties.
website/client/composables/useFileUpload.ts (1)
275-311: Well-structured composable API!The return statement provides a clean and comprehensive API surface. The
inputAttributescomputed property correctly handles cross-browser directory selection attributes, and all necessary state and methods are properly exposed.
…handled promise rejection
Summary
Changes Made
Phase 1: State Management Refactoring
Phase 2: Upload Logic Consolidation
Technical Improvements
Test Plan
🤖 Generated with Claude Code