- Add a `Copy Thread ID` item to the thread context menu in the sidebar - Copy the selected thread ID via Clipboard API - Show success/error toasts based on copy result
Unified · Split
| @@ -60,6 +60,13 @@ import { isNonEmpty as isNonEmptyString } from "effect/String"; · 59 unmodified lines | ||
| 60 | 60 | |
| 61 | 61 | const EMPTY_KEYBINDINGS: ResolvedKeybindingsConfig = []; |
| 62 | 62 | |
| 63 | +async function copyTextToClipboard(text: string): Promise<void> { | |
| 64 | + if (typeof navigator === "undefined" || navigator.clipboard?.writeText === undefined) { | |
| 65 | + throw new Error("Clipboard API unavailable."); | |
| 66 | + } | |
| 67 | + await navigator.clipboard.writeText(text); | |
| 68 | +} | |
| 69 | + | |
| 63 | 70 | function formatRelativeTime(iso: string): string { |
| 64 | 71 | const diff = Date.now() - new Date(iso).getTime(); |
| 65 | 72 | const minutes = Math.floor(diff / 60_000); |
| @@ -581,6 +588,7 @@ export default function Sidebar() { · 515 unmodified lines | ||
| 581 | 588 | [ |
| 582 | 589 | { id: "rename", label: "Rename thread" }, |
| 583 | 590 | { id: "mark-unread", label: "Mark unread" }, |
| 591 | + { id: "copy-thread-id", label: "Copy Thread ID" }, | |
| 584 | 592 | { id: "delete", label: "Delete", destructive: true }, |
| 585 | 593 | ], |
| 586 | 594 | position, |
| @@ -599,6 +607,23 @@ export default function Sidebar() { · 12 unmodified lines | ||
| 599 | 607 | markThreadUnread(threadId); |
| 600 | 608 | return; |
| 601 | 609 | } |
| 610 | + if (clicked === "copy-thread-id") { | |
| 611 | + try { | |
| 612 | + await copyTextToClipboard(threadId); | |
| 613 | + toastManager.add({ | |
| 614 | + type: "success", | |
| 615 | + title: "Thread ID copied", | |
| 616 | + description: threadId, | |
| 617 | + }); | |
| 618 | + } catch (error) { | |
| 619 | + toastManager.add({ | |
| 620 | + type: "error", | |
| 621 | + title: "Failed to copy thread ID", | |
| 622 | + description: error instanceof Error ? error.message : "An error occurred.", | |
| 623 | + }); | |
| 624 | + } | |
| 625 | + return; | |
| 626 | + } | |
| 602 | 627 | if (clicked !== "delete") return; |
| 603 | 628 | if (appSettings.confirmThreadDelete) { |
| 604 | 629 | const confirmed = await api.dialogs.confirm( |