Skip to content

Conversation

Ravishekhar7870
Copy link
Contributor

@Ravishekhar7870 Ravishekhar7870 commented Oct 13, 2025

Testing

tested locally

Summary by CodeRabbit

  • Bug Fixes

    • Prevents upload counters from going negative, ensuring accurate counts during and after file removals.
    • Correctly updates upload count only when a removed file was actively uploading.
  • UI

    • Remove-file buttons are now always enabled, allowing file removal at any time, including during uploads.
  • Reliability

    • Improves cleanup behavior when files are removed, reducing edge-case inconsistencies during uploads.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Walkthrough

Updates ChatBox upload/removal logic to clamp uploading file count at zero, conditionally decrement on removal only when applicable, and enable remove-file buttons. Public API changes: adds optional agentIdFromChatData and requires a user (PublicUser) prop.

Changes

Cohort / File(s) Summary of Changes
Upload count handling
frontend/src/components/ChatBox.tsx
Decrement uses Math.max(prev - 1, 0) to prevent negatives; conditional decrement on file removal only if it was uploading.
UI control state
frontend/src/components/ChatBox.tsx
Remove-file buttons no longer disabled based on uploading state (disabled attr commented out).
Public API updates
frontend/src/components/ChatBox.tsx
ChatBoxProps updated: added optional `agentIdFromChatData?: string

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant CB as ChatBox
  participant FS as FileState

  U->>CB: Remove file
  CB->>FS: Check file.uploading?
  alt uploading === true
    note over CB,FS: Decrement uploadingFilesCount with clamp
    CB->>CB: uploadingFilesCount = max(prev - 1, 0)
  else uploading === false
    note over CB: No decrement
  end
  CB->>FS: Remove file from list
  CB-->>U: UI updates (remove button enabled)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • zereraz
  • shivamashtikar
  • kalpadhwaryu
  • junaid-shirur
  • devesh-juspay

Poem

A bunny counts uploads—never below zero,
Snips files with buttons now ready to go.
Props hop in: a user to know,
An agent’s ID, maybe on show.
Thump-thump, tidy state I keep—
Fuzzy logic, but the bounds run deep. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly identifies that the pull request fixes the attachment removal behavior during upload for issue XYNE-157, reflecting the main change succinctly, though it includes a minor typo in “attachement.”
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/fileRemoval-upload

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Ravishekhar7870, 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!

This pull request implements a fix for issue XYNE-157, which previously prevented users from removing attachments while they were still uploading. The changes ensure that the count of uploading files is correctly maintained and never goes negative, and crucially, it enables the removal of files from the UI regardless of their current upload status. This improves the overall robustness and user experience of the attachment handling feature within the chat interface.

Highlights

  • Attachment Removal: Addressed an issue (XYNE-157) where users were unable to remove attachments that were currently in an uploading state, improving user control over pending uploads.
  • Upload Counter Robustness: Enhanced the logic for uploadingFilesCount to prevent its value from dropping below zero, ensuring accurate tracking of active file uploads under all conditions.
  • User Experience: Modified the UI to allow users to remove files from the chat box even if those files are actively being uploaded, providing a more flexible and responsive interface.
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 by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

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 pull request 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 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. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

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

  1. 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.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly enables the removal of attachments while they are in an uploading state by un-disabling the remove button. However, the implementation for updating the uploadingFilesCount introduces a race condition, which could lead to an incorrect count and subsequent issues with message sending logic. I've provided a detailed comment with a suggested fix to resolve this race condition.

Comment on lines 891 to 893
} finally {
setUploadingFilesCount((prev) => prev - 1)
setUploadingFilesCount((prev) => Math.max(prev - 1, 0))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While adding Math.max is a good defensive measure, there's a more critical race condition here. The new logic in removeFile (around line 1005) decrements uploadingFilesCount when an uploading file is removed. However, this finally block will also run when that same file's upload promise completes, causing the count to be decremented twice.

To fix this, we should only decrement the count here if the file has not been removed by the user in the meantime. We can use selectedFilesRef to check the latest state without adding a dependency to uploadFiles.

          } finally {
            // Only decrement the count if the file hasn't been removed by the user.
            if (selectedFilesRef.current.some(f => f.id === selectedFile.id)) {
              setUploadingFilesCount((prev) => Math.max(prev - 1, 0))
            }
          }

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/components/ChatBox.tsx (1)

2058-2065: Remove dead code: Synchronous check can't respond to async state changes.

The code inside the promise constructor (lines 2061-2064) attempts to check uploadingFilesCount synchronously, but this can't reactively respond to state changes:

if (uploadingFilesCount > 0) {
  await new Promise<void>((resolve) => {
    uploadCompleteResolver.current = resolve
    if(uploadingFilesCount==0){  // This check is effectively dead code
      resolve();
      uploadCompleteResolver.current=null
    }
  })
}

Why this doesn't work:

  1. The promise constructor executes synchronously when the promise is created
  2. At that moment, uploadingFilesCount > 0 (verified by the outer if on line 2058)
  3. The inner check uploadingFilesCount==0 will always be false
  4. Even if it were true, this is a one-time synchronous check - it can't respond to uploadingFilesCount changing later

The useEffect on lines 906-911 is the correct mechanism for resolving the promise when the count reaches zero.

Apply this diff to remove the dead code:

       if (uploadingFilesCount > 0) {
         await new Promise<void>((resolve) => {
           uploadCompleteResolver.current = resolve
-          if(uploadingFilesCount==0){
-            resolve();
-            uploadCompleteResolver.current=null
-          }
         })
-
       }
🧹 Nitpick comments (1)
frontend/src/components/ChatBox.tsx (1)

1004-1006: Code style: Formatting inconsistencies.

This code segment has minor formatting issues:

  1. Missing space after if keyword (should be if (fileToRemove))
  2. Inconsistent indentation (single space instead of standard indentation)
  3. Redundant optional chaining: fileToRemove?.uploading - the ?. is unnecessary since we already verified fileToRemove exists in the if condition

Suggested formatting (note: this code should be removed per the critical issue comment above):

-    if(fileToRemove){
-     setUploadingFilesCount((prev) => Math.max(prev - (fileToRemove?.uploading ? 1 : 0), 0))
-    }
+    if (fileToRemove) {
+      setUploadingFilesCount((prev) => Math.max(prev - (fileToRemove.uploading ? 1 : 0), 0))
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 959357a and 49144cd.

📒 Files selected for processing (1)
  • frontend/src/components/ChatBox.tsx (5 hunks)
🔇 Additional comments (1)
frontend/src/components/ChatBox.tsx (1)

868-868: Good change: Enables file removal during upload.

Commenting out the disabled attribute correctly allows users to remove files while they're uploading, which aligns with the PR objective (XYNE-157).

However, ensure the critical double-decrement bug flagged in the earlier comment is fixed before merging, as it will cause uploadingFilesCount to become incorrect when users remove uploading files.

Also applies to: 924-924

return null
} finally {
setUploadingFilesCount((prev) => prev - 1)
setUploadingFilesCount((prev) => Math.max(prev - 1, 0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Double-decrement bug when removing files during upload.

When a file is removed while uploading, uploadingFilesCount is decremented twice:

  1. In removeFile (line 1005): decrements by 1 if fileToRemove.uploading is true
  2. Here in the finally block: decrements by 1 when the upload promise completes

This causes the count to drop by 2 for a single file, leading to incorrect state and potentially allowing premature message sending.

Solution: Only decrement in the finally block, not in removeFile. The upload promise should be the single source of truth for decrementing the counter.

Apply this diff to fix the issue:

   const removeFile = useCallback(async (id: string) => {
     const fileToRemove = selectedFiles.find((f) => f.id === id)
     
     // If the file has metadata with fileId (meaning it's already uploaded), delete it from the server
     if (fileToRemove?.metadata?.fileId) {
       try {
         const response = await api.files.delete.$post({
           json: {
             attachment: fileToRemove.metadata
           }
         })
         
         if (!response.ok) {
           const errorText = await response.text()
           console.error(`Failed to delete attachment: ${errorText}`)
           // Still remove from UI even if server deletion fails
         }
       } catch (error) {
         console.error('Error deleting attachment:', error)
         // Still remove from UI even if server deletion fails
       }
     }
     
     // Remove from UI
-    if(fileToRemove){
-     setUploadingFilesCount((prev) => Math.max(prev - (fileToRemove?.uploading ? 1 : 0), 0))
-    }
     setSelectedFiles((prev) => {
       if (fileToRemove?.preview) {
         URL.revokeObjectURL(fileToRemove.preview)
       }
       return prev.filter((f) => f.id !== id)
     })
   }, [selectedFiles])

Note: The Math.max(..., 0) clamping here masks the double-decrement issue but doesn't fix the root cause. The upload promise's finally block is sufficient to manage the counter correctly.

📝 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.

Suggested change
setUploadingFilesCount((prev) => Math.max(prev - 1, 0))
const removeFile = useCallback(async (id: string) => {
const fileToRemove = selectedFiles.find((f) => f.id === id)
// If the file has metadata with fileId (meaning it's already uploaded), delete it from the server
if (fileToRemove?.metadata?.fileId) {
try {
const response = await api.files.delete.$post({
json: {
attachment: fileToRemove.metadata
}
})
if (!response.ok) {
const errorText = await response.text()
console.error(`Failed to delete attachment: ${errorText}`)
// Still remove from UI even if server deletion fails
}
} catch (error) {
console.error('Error deleting attachment:', error)
// Still remove from UI even if server deletion fails
}
}
// Remove from UI
setSelectedFiles((prev) => {
if (fileToRemove?.preview) {
URL.revokeObjectURL(fileToRemove.preview)
}
return prev.filter((f) => f.id !== id)
})
}, [selectedFiles])
🤖 Prompt for AI Agents
In frontend/src/components/ChatBox.tsx around line 892 (and related code at
removeFile on line 1005), the uploadingFilesCount is being decremented twice for
a single file: once in removeFile when fileToRemove.uploading is true and again
in the upload promise finally block; remove the decrement in removeFile so the
upload promise's finally is the single source of truth for decrementing
uploadingFilesCount, keep the Math.max clamp in the finally block as a safety
measure, and ensure removeFile still clears the file/abort logic without
touching uploadingFilesCount.

@Ravishekhar7870 Ravishekhar7870 deleted the fix/fileRemoval-upload branch October 15, 2025 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant