-
-
Notifications
You must be signed in to change notification settings - Fork 95
Pull Request: Implement File Handling Capabilities for chat0 #28
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: main
Are you sure you want to change the base?
Conversation
|
@Prasannajaga is attempting to deploy a commit to the Harsh's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThe changes introduce file attachment support to the chat input component, enabling users to add files via drag-and-drop, paste, or file selection. New hooks and components manage file state and previews, and the message display now renders attached files. The Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ChatInput
participant useFileHandler
participant FilePreview
participant Message
User->>ChatInput: Drag/drop, paste, or select file
ChatInput->>useFileHandler: Handle file event
useFileHandler-->>ChatInput: Update file state (URLs, types, list)
ChatInput->>FilePreview: Render file preview(s)
User->>ChatInput: Submit message
ChatInput->>Message: Send message with experimental_attachments
Message->>FilePreview: Render attached file previews
Possibly related issues
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
frontend/components/ChatInput.tsxOops! Something went wrong! :( ESLint: 9.28.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.28.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. frontend/components/Message.tsxOops! Something went wrong! :( ESLint: 9.28.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.28.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting. frontend/hooks/useFileHandler.tsxOops! Something went wrong! :( ESLint: 9.28.0 ESLint couldn't find the plugin "eslint-plugin-react-hooks". (The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".) It's likely that the plugin isn't installed correctly. Try reinstalling by running the following: The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.2_eslint@9.28.0_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js". If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.
✨ Finishing Touches
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
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: 15
🧹 Nitpick comments (1)
.gitignore (1)
44-44: Remove trailing whitespace.-#cloudflare -.open-next +#cloudflare +.open-next
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
.gitignore(1 hunks)frontend/components/ChatInput.tsx(8 hunks)frontend/components/Message.tsx(2 hunks)frontend/components/filePreview.tsx(1 hunks)frontend/hooks/useFileHandler.tsx(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
frontend/components/ChatInput.tsx (1)
frontend/hooks/useFileHandler.tsx (1)
useFileHandler(3-84)
frontend/components/Message.tsx (1)
frontend/components/filePreview.tsx (1)
TextFilePreview(12-37)
🔇 Additional comments (1)
.gitignore (1)
45-45: Reconsider ignoringpackage-lock.json.The
package-lock.jsonfile should typically be committed to version control to ensure reproducible builds and consistent dependency versions across all environments. Ignoring it can lead to "works on my machine" issues.Consider keeping
package-lock.jsonin version control unless there's a specific reason to exclude it (e.g., if you're using Yarn and haveyarn.lockinstead).
| alt={attachment.name} | ||
| /> | ||
| : attachment.contentType?.startsWith("text/") ? | ||
| <TextFilePreview fileList={undefined} /> : |
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.
Fix TextFilePreview receiving undefined fileList.
The TextFilePreview component is being passed undefined as the fileList prop, which will always render empty content. You need to pass the actual file data from the attachment.
The attachment object likely contains the file data or URL that should be used here. Consider either:
- Modifying
TextFilePreviewto accept a URL and fetch the content - Storing the actual File object in the attachment data structure
🤖 Prompt for AI Agents
In frontend/components/Message.tsx at line 83, the TextFilePreview component is
incorrectly receiving undefined for its fileList prop, causing it to render
empty content. To fix this, pass the actual file data from the attachment object
to the fileList prop. This may involve accessing the file or URL stored in the
attachment and providing it directly to TextFilePreview, or updating the
attachment structure to include the necessary file information.
| /> | ||
| : attachment.contentType?.startsWith("text/") ? | ||
| <TextFilePreview fileList={undefined} /> : | ||
| <iframe src={attachment.url} className="w-20 h-20 overflow-hidden" scrolling="no"></iframe> |
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.
Security concern: Validate iframe source URLs.
Rendering arbitrary URLs in an iframe without validation could pose security risks. Consider implementing a whitelist of allowed domains or file types.
Add proper sandboxing attributes to the iframe and validate the URL source:
-<iframe src={attachment.url} className="w-20 h-20 overflow-hidden" scrolling="no"></iframe>
+<iframe
+ src={attachment.url}
+ className="w-20 h-20 overflow-hidden"
+ scrolling="no"
+ sandbox="allow-scripts allow-same-origin"
+ title={attachment.name}
+></iframe>📝 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.
| <iframe src={attachment.url} className="w-20 h-20 overflow-hidden" scrolling="no"></iframe> | |
| <iframe | |
| src={attachment.url} | |
| className="w-20 h-20 overflow-hidden" | |
| scrolling="no" | |
| sandbox="allow-scripts allow-same-origin" | |
| title={attachment.name} | |
| ></iframe> |
🤖 Prompt for AI Agents
In frontend/components/Message.tsx at line 84, the iframe src attribute is set
directly from attachment.url without validation, posing a security risk. Fix
this by implementing a whitelist check to ensure the URL domain or file type is
allowed before rendering. Additionally, add sandbox attributes to the iframe
element to restrict its capabilities and enhance security.
| <div className='flex flex-col gap-2'> | ||
| {message.experimental_attachments | ||
| ?.map((attachment, index) => ( | ||
| <section key={attachment.name}> |
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
Use a unique key for attachment rendering.
Using attachment.name as the React key could cause rendering issues if multiple files have the same name.
-<section key={attachment.name}>
+<section key={`${message.id}-attachment-${index}`}>📝 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.
| <section key={attachment.name}> | |
| <section key={`${message.id}-attachment-${index}`}> |
🤖 Prompt for AI Agents
In frontend/components/Message.tsx at line 75, the React key for the attachment
section is set to attachment.name, which may not be unique if multiple
attachments share the same name. Update the key to use a unique identifier for
each attachment, such as a combination of attachment name and a unique property
like an ID or index, to ensure stable and correct rendering by React.
| append(userMessage, { experimental_attachments: fileList }) | ||
| setInput(''); | ||
| clearFiles(); | ||
| adjustHeight(true); |
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 file validation before appending message.
Consider validating file size and type before sending to prevent issues with large files or unsupported formats.
+// Add validation before append
+if (fileList) {
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
+ const file = fileList[0];
+ if (file.size > MAX_FILE_SIZE) {
+ // Show error to user
+ return;
+ }
+}
append(userMessage, { experimental_attachments: fileList })📝 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.
| append(userMessage, { experimental_attachments: fileList }) | |
| setInput(''); | |
| clearFiles(); | |
| adjustHeight(true); | |
| // Add validation before append | |
| if (fileList) { | |
| const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB | |
| const file = fileList[0]; | |
| if (file.size > MAX_FILE_SIZE) { | |
| // Show error to user | |
| return; | |
| } | |
| } | |
| append(userMessage, { experimental_attachments: fileList }) | |
| setInput(''); | |
| clearFiles(); | |
| adjustHeight(true); |
🤖 Prompt for AI Agents
In frontend/components/ChatInput.tsx around lines 106 to 109, before calling
append(userMessage, { experimental_attachments: fileList }), add validation
logic to check each file's size and type in fileList. Filter out or reject files
that exceed size limits or are of unsupported formats, and only append messages
with valid files. This prevents issues caused by large or unsupported files
being sent.
| <div className="flex gap-2 items-center"> | ||
| <input onChange={handleFileChange} className='hidden' type="file" name="" id="fileChange" /> | ||
| <label htmlFor="fileChange"> | ||
| <Plus /> | ||
| </label> |
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
Improve file input UI accessibility and styling.
The Plus icon button lacks proper styling and accessibility attributes.
-<label htmlFor="fileChange">
- <Plus />
-</label>
+<label
+ htmlFor="fileChange"
+ className="cursor-pointer p-2 hover:bg-muted rounded-md transition-colors"
+ aria-label="Attach file"
+>
+ <Plus className="w-5 h-5" />
+</label>📝 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.
| <div className="flex gap-2 items-center"> | |
| <input onChange={handleFileChange} className='hidden' type="file" name="" id="fileChange" /> | |
| <label htmlFor="fileChange"> | |
| <Plus /> | |
| </label> | |
| <div className="flex gap-2 items-center"> | |
| <input onChange={handleFileChange} className='hidden' type="file" name="" id="fileChange" /> | |
| <label | |
| htmlFor="fileChange" | |
| className="cursor-pointer p-2 hover:bg-muted rounded-md transition-colors" | |
| aria-label="Attach file" | |
| > | |
| <Plus className="w-5 h-5" /> | |
| </label> |
🤖 Prompt for AI Agents
In frontend/components/ChatInput.tsx around lines 183 to 187, the file input UI
lacks proper accessibility and styling. Add appropriate ARIA attributes to the
label or input for better accessibility, such as aria-label or role. Also,
enhance the styling of the Plus icon button to make it visually clear and
interactive, for example by adding cursor pointer and focus styles to the label
element.
| setContentTypes(types); | ||
| console.log("type" , types , fileUrls , fileList); | ||
|
|
||
| }, []); |
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.
Fix useCallback dependency array.
The empty dependency array is incorrect since the callback uses fileUrls and fileList in the console.log.
-}, []);
+}, [fileUrls]);Note: After removing the console.log, the empty array would be correct.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 17, the useCallback hook has an
empty dependency array but uses fileUrls and fileList inside its callback, which
is incorrect. To fix this, either add fileUrls and fileList to the dependency
array to ensure the callback updates when these values change, or remove the
console.log statement that references them, allowing the empty array to be
correct.
| const [contentTypes, setContentTypes] = useState<string[]>([]); | ||
|
|
||
| const processFiles = useCallback((files: FileList) => { | ||
| const urls = Array.from(files).map((file) => URL.createObjectURL(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.
Prevent memory leaks by revoking object URLs.
Object URLs created with URL.createObjectURL must be revoked to prevent memory leaks.
Store the URLs and revoke them when clearing or before creating new ones:
const processFiles = useCallback((files: FileList) => {
+ // Revoke previous URLs
+ fileUrls.forEach(url => URL.revokeObjectURL(url));
+
const urls = Array.from(files).map((file) => URL.createObjectURL(file));Also update clearFiles:
const clearFiles = useCallback(() =>{
+ fileUrls.forEach(url => URL.revokeObjectURL(url));
setFileList(undefined);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 9, the code creates object URLs
with URL.createObjectURL but does not revoke them, causing potential memory
leaks. Modify the code to store the generated URLs in a variable or state, and
ensure that before creating new URLs or when clearing files, you call
URL.revokeObjectURL on each stored URL to release the memory. Also update the
clearFiles function to revoke all stored URLs before clearing them.
| // Optional: handle pasted text if needed | ||
| const text = event.clipboardData.getData('text/plain'); | ||
| if (text) { | ||
| document.execCommand('insertText', false, text); |
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
Replace deprecated document.execCommand.
document.execCommand is deprecated and should not be used. Consider using the modern Clipboard API or letting the browser handle text paste naturally.
-document.execCommand('insertText', false, text);
+// Let the default paste behavior handle text insertion
+// or use: navigator.clipboard.writeText(text);📝 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.
| document.execCommand('insertText', false, text); | |
| // Let the default paste behavior handle text insertion | |
| // or use: navigator.clipboard.writeText(text); |
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 44, replace the deprecated
document.execCommand('insertText', false, text) with a modern approach. Use the
Clipboard API's navigator.clipboard.writeText(text) if you want to
programmatically copy text, or alternatively, allow the browser to handle text
insertion naturally without forcing it via execCommand. Adjust the code to avoid
using execCommand and adopt the Clipboard API or native input handling.
| setFileUrls(urls); | ||
| setFileList(files); | ||
| setContentTypes(types); | ||
| console.log("type" , types , fileUrls , fileList); |
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.
Remove console.log statement.
Debug logging should not be included in production code.
-console.log("type" , types , fileUrls , fileList);📝 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.
| console.log("type" , types , fileUrls , fileList); | |
| // (Remove the debug log; no replacement needed) |
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 15, remove the console.log
statement that outputs "type", types, fileUrls, and fileList to eliminate debug
logging from production code.
| const processFiles = useCallback((files: FileList) => { | ||
| const urls = Array.from(files).map((file) => URL.createObjectURL(file)); | ||
| const types = Array.from(files).map((file) => file.type); | ||
|
|
||
| setFileUrls(urls); | ||
| setFileList(files); | ||
| setContentTypes(types); | ||
| console.log("type" , types , fileUrls , fileList); | ||
|
|
||
| }, []); |
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 file validation for size and quantity.
The file processing should validate file size and limit the number of files to prevent performance issues.
const processFiles = useCallback((files: FileList) => {
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
+ const MAX_FILES = 5;
+
+ if (files.length > MAX_FILES) {
+ console.error(`Maximum ${MAX_FILES} files allowed`);
+ return;
+ }
+
+ for (const file of Array.from(files)) {
+ if (file.size > MAX_FILE_SIZE) {
+ console.error(`File ${file.name} exceeds maximum size of 10MB`);
+ return;
+ }
+ }
+
const urls = Array.from(files).map((file) => URL.createObjectURL(file));📝 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 processFiles = useCallback((files: FileList) => { | |
| const urls = Array.from(files).map((file) => URL.createObjectURL(file)); | |
| const types = Array.from(files).map((file) => file.type); | |
| setFileUrls(urls); | |
| setFileList(files); | |
| setContentTypes(types); | |
| console.log("type" , types , fileUrls , fileList); | |
| }, []); | |
| const processFiles = useCallback((files: FileList) => { | |
| const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB | |
| const MAX_FILES = 5; | |
| if (files.length > MAX_FILES) { | |
| console.error(`Maximum ${MAX_FILES} files allowed`); | |
| return; | |
| } | |
| for (const file of Array.from(files)) { | |
| if (file.size > MAX_FILE_SIZE) { | |
| console.error(`File ${file.name} exceeds maximum size of 10MB`); | |
| return; | |
| } | |
| } | |
| const urls = Array.from(files).map((file) => URL.createObjectURL(file)); | |
| const types = Array.from(files).map((file) => file.type); | |
| setFileUrls(urls); | |
| setFileList(files); | |
| setContentTypes(types); | |
| console.log("type", types, fileUrls, fileList); | |
| }, []); |
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx around lines 8 to 17, add validation to the
processFiles function to check each file's size against a defined maximum limit
and ensure the total number of files does not exceed a set quantity limit. If
any file is too large or the number of files is too many, prevent further
processing and optionally provide feedback. Implement these checks before
creating object URLs and updating state to avoid performance issues.
|
this looks good, but we will first need a way to store these somewhere(S3 or somewhere), since we can't fill indexxed db with large files. |
|
@senbo1 any update on this ? |
Changes Made
Testing
ScreenShots
Notes for Reviewers
Summary by CodeRabbit