Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/components/FileMenuLeftHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ export const FileMenuLeftHeader = (props: {
isOpen={isSelectSnippetDialogOpen}
/>
</DropdownMenu>
<BugReportDialog />
{BugReportDialog}
<ImportComponentDialogForCli
isOpen={isImportDialogOpen}
onClose={() => setIsImportDialogOpen(false)}
Expand Down
33 changes: 18 additions & 15 deletions lib/components/useBugReportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
useCallback,
useEffect,
useMemo,
useRef,
useState,
type ReactElement,
} from "react"
Expand All @@ -28,7 +29,7 @@ declare global {
}

type UseBugReportDialogResult = {
BugReportDialog: () => ReactElement
BugReportDialog: ReactElement
openBugReportDialog: () => void
}

Expand Down Expand Up @@ -73,7 +74,7 @@ export const useBugReportDialog = (): UseBugReportDialogResult => {
const [isOpen, setIsOpen] = useState(false)
const [isSubmitting, setIsSubmitting] = useState(false)
const [errorMessage, setErrorMessage] = useState<string | null>(null)
const [userText, setUserText] = useState("")
const textareaRef = useRef<HTMLTextAreaElement>(null)
const [successState, setSuccessState] = useState<{
bugReportUrl: string
} | null>(null)
Expand All @@ -89,13 +90,13 @@ export const useBugReportDialog = (): UseBugReportDialogResult => {

// Populate text field with execution error when dialog opens
useEffect(() => {
if (isOpen && !successState) {
if (isOpen && !successState && textareaRef.current) {
const globalError =
typeof window !== "undefined"
? window.__TSCIRCUIT_LAST_EXECUTION_ERROR
: undefined
if (globalError) {
setUserText(`I'm getting this execution error:\n\n${globalError}`)
textareaRef.current.value = `I'm getting this execution error:\n\n${globalError}`
}
}
}, [isOpen, successState])
Expand All @@ -117,7 +118,9 @@ export const useBugReportDialog = (): UseBugReportDialogResult => {
const openBugReportDialog = useCallback(() => {
setErrorMessage(null)
setSuccessState(null)
setUserText("")
if (textareaRef.current) {
textareaRef.current.value = ""
}
Comment on lines +121 to +123
Copy link
Contributor

Choose a reason for hiding this comment

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

Race condition: When the dialog is closed, the textarea element may not be in the DOM (depending on AlertDialog's implementation), causing textareaRef.current to be null. The clearing operation is skipped, but then the dialog opens and the textarea may retain its previous value if no global error exists to overwrite it.

The useEffect on lines 93-99 only sets a value when globalError exists, so without an error, the textarea keeps old content from previous submissions.

Fix: Move the clearing logic into the useEffect:

useEffect(() => {
  if (isOpen && !successState && textareaRef.current) {
    const globalError = typeof window !== "undefined" 
      ? window.__TSCIRCUIT_LAST_EXECUTION_ERROR 
      : undefined
    textareaRef.current.value = globalError 
      ? `I'm getting this execution error:\n\n${globalError}` 
      : ""
  }
}, [isOpen, successState])

And remove lines 121-123 from openBugReportDialog.

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

setIsOpen(true)
}, [])

Expand All @@ -130,6 +133,7 @@ export const useBugReportDialog = (): UseBugReportDialogResult => {
setErrorMessage(null)

const registryKy = getRegistryKy()
const userText = textareaRef.current?.value || ""

try {
// Fetch files from the file server
Expand Down Expand Up @@ -208,11 +212,12 @@ export const useBugReportDialog = (): UseBugReportDialogResult => {
} finally {
setIsSubmitting(false)
}
}, [userText])
}, [])

const BugReportDialog = useCallback(() => {
const BugReportDialog = useMemo(() => {
return (
<AlertDialog
key="bug-report-dialog"
open={isOpen}
onOpenChange={(open) => {
if (!open) {
Expand Down Expand Up @@ -278,11 +283,10 @@ export const useBugReportDialog = (): UseBugReportDialogResult => {
Description (optional)
</label>
<textarea
ref={textareaRef}
id="bug-description"
className="rf-w-full rf-min-h-[100px] rf-px-3 rf-py-2 rf-text-sm rf-border rf-border-gray-300 rf-rounded-md focus:rf-outline-none focus:rf-ring-2 focus:rf-ring-blue-500"
placeholder="Describe the issue you're experiencing..."
value={userText}
onChange={(e) => setUserText(e.target.value)}
disabled={isSubmitting}
/>
</div>
Expand Down Expand Up @@ -357,15 +361,14 @@ export const useBugReportDialog = (): UseBugReportDialogResult => {
</AlertDialog>
)
}, [
bugReportFileCount,
closeBugReportDialog,
errorMessage,
handleConfirmBugReport,
isOpen,
isSessionLoggedIn,
isSubmitting,
closeBugReportDialog,
errorMessage,
successState,
userText,
bugReportFileCount,
isSessionLoggedIn,
handleConfirmBugReport,
])

return {
Expand Down
Loading