({ chatId, subChatId, format, isRemote = false }: ExportOptions)
| 160 | * Copy chat or sub-chat content to clipboard. |
| 161 | */ |
| 162 | export async function copyChat({ chatId, subChatId, format, isRemote = false }: ExportOptions): Promise<void> { |
| 163 | try { |
| 164 | let exportData: { content: string; filename: string } |
| 165 | |
| 166 | if (isRemote) { |
| 167 | // Remote chat export - fetch from remote API and format locally |
| 168 | const chat = await remoteApi.getAgentChat(chatId) |
| 169 | const subChat = subChatId |
| 170 | ? chat.subChats.find(sc => sc.id === subChatId) |
| 171 | : chat.subChats[0] |
| 172 | |
| 173 | if (!subChat) { |
| 174 | throw new Error("No chat data found") |
| 175 | } |
| 176 | |
| 177 | const messages = (subChat.messages || []) as Message[] |
| 178 | const chatName = subChat.name || chat.name || "remote-chat" |
| 179 | exportData = formatMessages(messages, format, chatName) |
| 180 | } else { |
| 181 | // Local chat export - use existing tRPC endpoint |
| 182 | exportData = await trpcClient.chats.exportChat.query({ |
| 183 | chatId, |
| 184 | subChatId, |
| 185 | format, |
| 186 | }) |
| 187 | } |
| 188 | |
| 189 | try { |
| 190 | await navigator.clipboard.writeText(exportData.content) |
| 191 | } catch { |
| 192 | // Fallback using Electron clipboard API |
| 193 | if (window.desktopApi?.clipboardWrite) { |
| 194 | await window.desktopApi.clipboardWrite(exportData.content) |
| 195 | } else { |
| 196 | throw new Error("Clipboard not available") |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | toast.success("Copied to clipboard") |
| 201 | } catch (error) { |
| 202 | console.error("[copyChat] Error:", error) |
| 203 | toast.error("Copy failed", { |
| 204 | description: error instanceof Error ? error.message : "Unable to copy chat", |
| 205 | }) |
| 206 | } |
| 207 | } |
no test coverage detected