Skip to content
Open
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
36 changes: 33 additions & 3 deletions src/components/studyroom/LiveCodeRunner.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from "react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Play, Code, Share, Loader2 } from "lucide-react";
import { Play, Code, Share, Loader2, Clipboard, Trash2 } from "lucide-react";
import { toast } from "sonner";
import { env } from "@/env";

Expand Down Expand Up @@ -80,7 +80,18 @@ export function LiveCodeRunner({ onShare }: LiveCodeRunnerProps) {
onShare(code, language.id, output);
setIsOpen(false);
};

const handleCopyOutput = () => {
if (!output) { toast.error("No output to copy"); return; }
navigator.clipboard.writeText(output).then(
() => toast.success("Output copied!"),
() => toast.error("Failed to copy output")
);
};
Comment on lines +83 to +89

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

MDN Clipboard API: is navigator.clipboard available only in secure contexts, and what are the main browser support caveats for Clipboard.writeText?

💡 Result:

Yes, the navigator.clipboard property is available only in secure contexts (HTTPS) [1][2][3]. If accessed in an insecure context (such as HTTP or local files, excluding localhost), navigator.clipboard will be undefined, and attempts to call methods like writeText will result in an error [4]. Beyond the secure context requirement, the main browser support caveats for Clipboard.writeText include the following: 1. Transient User Activation: Most browsers require the call to be made in response to a user-initiated action (such as a click or keypress) [2][5]. Attempting to write to the clipboard on page load or without a direct user gesture often fails or triggers browser security prompts [5][4]. 2. Focus Requirements: For Chromium-based browsers, the script must typically be running in the active, focused tab to successfully write to the clipboard [5][4]. 3. Permission Policies: The browser may require explicit permission (e.g., the clipboard-write permission) or display a prompt to the user before allowing the operation [2][5]. Behavior can vary between browsers, particularly concerning whether transient activation is required or if a persistent permission grant is available [2][5]. 4. Browser Interoperability: While widely supported, specific implementation details regarding user gestures and permission prompts can differ between browsers (e.g., Firefox and Safari vs. Chromium-based browsers) [5]. Developers should always wrap these calls in try-catch blocks to handle scenarios where the operation is denied or unavailable [6][4].

Citations:


🏁 Script executed:

cd /tmp && find . -type f -name "LiveCodeRunner.tsx" 2>/dev/null | head -5

Repository: durdana3105/peer-learning

Length of output: 51


🏁 Script executed:

rg -l "LiveCodeRunner" --type=tsx 2>/dev/null | head -3

Repository: durdana3105/peer-learning

Length of output: 51


🏁 Script executed:

git ls-files | grep -i livecode | head -10

Repository: durdana3105/peer-learning

Length of output: 113


🏁 Script executed:

wc -l src/components/studyroom/LiveCodeRunner.tsx

Repository: durdana3105/peer-learning

Length of output: 117


🏁 Script executed:

cat -n src/components/studyroom/LiveCodeRunner.tsx | sed -n '75,140p'

Repository: durdana3105/peer-learning

Length of output: 3038


🏁 Script executed:

cat -n src/components/studyroom/LiveCodeRunner.tsx | sed -n '140,185p'

Repository: durdana3105/peer-learning

Length of output: 2293


Guard navigator.clipboard before calling writeText to handle unavailability in non-secure contexts.

The Clipboard API is undefined in HTTP contexts and may throw synchronously before your .then() handler runs. Wrap this in a try/catch block with an optional chaining check as shown below.

Proposed fix
-  const handleCopyOutput = () => {
-    if (!output) { toast.error("No output to copy"); return; }
-    navigator.clipboard.writeText(output).then(
-      () => toast.success("Output copied!"),
-      () => toast.error("Failed to copy output")
-    );
-  };
+  const handleCopyOutput = async () => {
+    if (!output) {
+      toast.error("No output to copy");
+      return;
+    }
+    if (!navigator.clipboard?.writeText) {
+      toast.error("Clipboard is not available in this browser/context");
+      return;
+    }
+    try {
+      await navigator.clipboard.writeText(output);
+      toast.success("Output copied!");
+    } catch {
+      toast.error("Failed to copy output");
+    }
+  };
📝 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
const handleCopyOutput = () => {
if (!output) { toast.error("No output to copy"); return; }
navigator.clipboard.writeText(output).then(
() => toast.success("Output copied!"),
() => toast.error("Failed to copy output")
);
};
const handleCopyOutput = async () => {
if (!output) {
toast.error("No output to copy");
return;
}
if (!navigator.clipboard?.writeText) {
toast.error("Clipboard is not available in this browser/context");
return;
}
try {
await navigator.clipboard.writeText(output);
toast.success("Output copied!");
} catch {
toast.error("Failed to copy output");
}
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/studyroom/LiveCodeRunner.tsx` around lines 83 - 89, The
handleCopyOutput function calls navigator.clipboard.writeText without guarding
against unavailability in non-secure contexts (HTTP), which can cause
synchronous errors before the promise handler executes. Add a try/catch block
around the clipboard operation and use optional chaining to check if
navigator.clipboard exists before calling writeText. This ensures the code
gracefully handles environments where the Clipboard API is undefined or
unavailable, displaying an appropriate error toast instead of crashing.


const handleClearCode = () => {
setCode("");
setOutput("");
};
return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
Expand Down Expand Up @@ -113,6 +124,14 @@ export function LiveCodeRunner({ onShare }: LiveCodeRunnerProps) {
</select>

<div className="flex gap-2">
<button
type="button"
onClick={handleClearCode}
disabled={isRunning}
className="flex items-center gap-2 bg-gray-700 text-white px-4 py-2 rounded-lg font-medium hover:bg-gray-600 transition disabled:opacity-50"
>
<Trash2 size={16} /> Clear
</button>
<button
onClick={runCode}
disabled={isRunning}
Expand Down Expand Up @@ -142,7 +161,18 @@ export function LiveCodeRunner({ onShare }: LiveCodeRunnerProps) {
/>
</div>
<div className="flex flex-col gap-2 h-full">
<label className="text-sm font-medium text-gray-400">Output</label>
<div className="flex items-center justify-between">
+ <label className="text-sm font-medium text-gray-400">Output</label>
{output && (
<button
onClick={handleCopyOutput}
disabled={isRunning}
className="flex items-center gap-1 text-xs text-gray-400 hover:text-gray-200 disabled:opacity-50"
>
<Clipboard size={13} /> Copy
</button>
)}
</div>
<div className="w-full h-full bg-black text-green-400 font-mono text-sm p-4 rounded-xl border border-gray-800 overflow-y-auto whitespace-pre-wrap">
{output || "Output will appear here..."}
</div>
Expand Down