From a004a1b2ee3066cf3823b0183e26e5347fb92c08 Mon Sep 17 00:00:00 2001 From: Chaitanya045 Date: Fri, 1 Aug 2025 08:20:20 +0530 Subject: [PATCH] issue: add copy functionality to file manager and tool-call side panel --- .../components/thread/file-viewer-modal.tsx | 61 +++++++++++++ .../thread/tool-call-side-panel.tsx | 54 +++++++++++- .../thread/tool-views/GenericToolView.tsx | 88 +++++++++++++++++-- .../file-operation/FileOperationToolView.tsx | 47 ++++++++++ 4 files changed, 243 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/thread/file-viewer-modal.tsx b/frontend/src/components/thread/file-viewer-modal.tsx index ec400fd6..2d6ab3c7 100644 --- a/frontend/src/components/thread/file-viewer-modal.tsx +++ b/frontend/src/components/thread/file-viewer-modal.tsx @@ -21,6 +21,8 @@ import { FileText, ChevronDown, Archive, + Copy, + Check, } from 'lucide-react'; import { ScrollArea } from '@/components/ui/scroll-area'; import { @@ -160,6 +162,10 @@ export function FileViewerModal({ currentFile: string; } | null>(null); + // Add state for copy functionality + const [isCopyingPath, setIsCopyingPath] = useState(false); + const [isCopyingContent, setIsCopyingContent] = useState(false); + // Setup project with sandbox URL if not provided directly useEffect(() => { if (project) { @@ -849,6 +855,43 @@ export function FileViewerModal({ return filePath ? filePath.toLowerCase().endsWith('.md') : false; }, []); + // Copy functions + const copyToClipboard = useCallback(async (text: string) => { + try { + await navigator.clipboard.writeText(text); + return true; + } catch (err) { + console.error('Failed to copy text: ', err); + return false; + } + }, []); + + const handleCopyPath = useCallback(async () => { + if (!textContentForRenderer) return; + + setIsCopyingPath(true); + const success = await copyToClipboard(textContentForRenderer); + if (success) { + toast.success('File content copied to clipboard'); + } else { + toast.error('Failed to copy file content'); + } + setTimeout(() => setIsCopyingPath(false), 500); + }, [textContentForRenderer, copyToClipboard]); + + const handleCopyContent = useCallback(async () => { + if (!textContentForRenderer) return; + + setIsCopyingContent(true); + const success = await copyToClipboard(textContentForRenderer); + if (success) { + toast.success('File content copied to clipboard'); + } else { + toast.error('Failed to copy file content'); + } + setTimeout(() => setIsCopyingContent(false), 500); + }, [textContentForRenderer, copyToClipboard]); + // Handle PDF export for markdown files const handleExportPdf = useCallback( async (orientation: 'portrait' | 'landscape' = 'portrait') => { @@ -1313,6 +1356,24 @@ export function FileViewerModal({
{selectedFilePath && ( <> + {/* Copy content button - only show for text files */} + {textContentForRenderer && ( + + )} +
@@ -185,9 +245,25 @@ export function GenericToolView({ {formattedToolContent && (
-
- - Output +
+
+ + Output +
+
diff --git a/frontend/src/components/thread/tool-views/file-operation/FileOperationToolView.tsx b/frontend/src/components/thread/tool-views/file-operation/FileOperationToolView.tsx index 5707cd57..91419569 100644 --- a/frontend/src/components/thread/tool-views/file-operation/FileOperationToolView.tsx +++ b/frontend/src/components/thread/tool-views/file-operation/FileOperationToolView.tsx @@ -7,6 +7,8 @@ import { Code, Eye, File, + Copy, + Check, } from 'lucide-react'; import { extractFilePath, @@ -68,6 +70,33 @@ export function FileOperationToolView({ const { resolvedTheme } = useTheme(); const isDarkTheme = resolvedTheme === 'dark'; + // Add copy functionality state + const [isCopyingContent, setIsCopyingContent] = useState(false); + + // Copy functions + const copyToClipboard = async (text: string) => { + try { + await navigator.clipboard.writeText(text); + return true; + } catch (err) { + console.error('Failed to copy text: ', err); + return false; + } + }; + + const handleCopyContent = async () => { + if (!fileContent) return; + + setIsCopyingContent(true); + const success = await copyToClipboard(fileContent); + if (success) { + console.log('File content copied to clipboard'); + } else { + console.error('Failed to copy file content'); + } + setTimeout(() => setIsCopyingContent(false), 500); + }; + const operation = getOperationType(name, assistantContent); const configs = getOperationConfigs(); const config = configs[operation]; @@ -284,6 +313,24 @@ export function FileOperationToolView({
+ {/* Copy button - only show when there's file content */} + {fileContent && !isStreaming && ( + + )} {isHtml && htmlPreviewUrl && !isStreaming && (