|
1 | | -import React from 'react'; |
2 | | -import { Database, Search, Code, MessageSquare, AlertTriangle } from 'lucide-react'; |
| 1 | +import React, { useState } from 'react'; |
| 2 | +import { Database, Search, Code, MessageSquare, AlertTriangle, Copy, Check } from 'lucide-react'; |
3 | 3 | import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; |
4 | 4 | import { Card, CardContent } from '@/components/ui/card'; |
5 | 5 | import { Badge } from '@/components/ui/badge'; |
@@ -36,6 +36,18 @@ interface ChatMessageProps { |
36 | 36 | } |
37 | 37 |
|
38 | 38 | const ChatMessage = ({ type, content, steps, queryData, analysisInfo, confirmationData, progress, user, onConfirm, onCancel }: ChatMessageProps) => { |
| 39 | + const [copied, setCopied] = useState(false); |
| 40 | + |
| 41 | + const handleCopyQuery = async () => { |
| 42 | + try { |
| 43 | + await navigator.clipboard.writeText(content); |
| 44 | + setCopied(true); |
| 45 | + setTimeout(() => setCopied(false), 2000); |
| 46 | + } catch (err) { |
| 47 | + console.error('Failed to copy text:', err); |
| 48 | + } |
| 49 | + }; |
| 50 | + |
39 | 51 | if (type === 'confirmation') { |
40 | 52 | const operationType = (confirmationData?.operationType ?? 'UNKNOWN').toUpperCase(); |
41 | 53 | const isHighRisk = ['DELETE', 'DROP', 'TRUNCATE'].includes(operationType); |
@@ -157,9 +169,24 @@ const ChatMessage = ({ type, content, steps, queryData, analysisInfo, confirmati |
157 | 169 |
|
158 | 170 | {hasSQL && ( |
159 | 171 | <div className="-mx-2 px-2"> |
160 | | - <pre className="bg-gray-900 text-gray-200 p-3 rounded text-sm mb-3 font-mono whitespace-pre-wrap break-words overflow-wrap-anywhere"> |
161 | | - <code className="language-sql">{content}</code> |
162 | | - </pre> |
| 172 | + <div className="relative"> |
| 173 | + <Button |
| 174 | + variant="ghost" |
| 175 | + size="sm" |
| 176 | + onClick={handleCopyQuery} |
| 177 | + className="absolute top-2 right-2 z-10 h-8 w-8 p-0 hover:bg-gray-800" |
| 178 | + title={copied ? "Copied!" : "Copy query"} |
| 179 | + > |
| 180 | + {copied ? ( |
| 181 | + <Check className="w-4 h-4 text-green-400" /> |
| 182 | + ) : ( |
| 183 | + <Copy className="w-4 h-4 text-gray-400" /> |
| 184 | + )} |
| 185 | + </Button> |
| 186 | + <pre className="bg-gray-900 text-gray-200 p-3 rounded text-sm mb-3 font-mono whitespace-pre-wrap break-words overflow-wrap-anywhere"> |
| 187 | + <code className="language-sql">{content}</code> |
| 188 | + </pre> |
| 189 | + </div> |
163 | 190 | </div> |
164 | 191 | )} |
165 | 192 |
|
|
0 commit comments