From 1869da4fcb6721e4d311f4258bad813ed6b84023 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Fri, 13 Feb 2026 09:39:38 -0500 Subject: [PATCH] feat(frontend): add mid-session Copy for Ticket to navigation page Co-Authored-By: Claude Opus 4.6 --- frontend/src/pages/TreeNavigationPage.tsx | 54 ++++++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/frontend/src/pages/TreeNavigationPage.tsx b/frontend/src/pages/TreeNavigationPage.tsx index 7449f4a1..3a11fb20 100644 --- a/frontend/src/pages/TreeNavigationPage.tsx +++ b/frontend/src/pages/TreeNavigationPage.tsx @@ -10,7 +10,8 @@ import { cn, safeGetItem, safeSetItem } from '@/lib/utils' import { MarkdownContent } from '@/components/ui/MarkdownContent' import { CustomStepModal } from '@/components/step-library/CustomStepModal' import { PostStepActionModal, ContinuationModal, ForkTreeModal, ScratchpadSidebar, SessionOutcomeModal } from '@/components/session' -import { Plus, CheckCircle, ArrowRight, Clock, Terminal, Clipboard, Check, HelpCircle } from 'lucide-react' +import { Plus, CheckCircle, ArrowRight, Clock, Terminal, Clipboard, Check, Copy, HelpCircle } from 'lucide-react' +import { toast } from '@/lib/toast' import { Modal } from '@/components/common/Modal' interface LocationState { @@ -45,6 +46,8 @@ export function TreeNavigationPage() { const [copiedCommand, setCopiedCommand] = useState(null) const [shortcutsModalOpen, setShortcutsModalOpen] = useState(false) const [selectingOption, setSelectingOption] = useState(null) + const [copiedForTicket, setCopiedForTicket] = useState(false) + const [isCopyingForTicket, setIsCopyingForTicket] = useState(false) const handleCopyCommand = (text: string) => { navigator.clipboard.writeText(text) @@ -52,6 +55,29 @@ export function TreeNavigationPage() { setTimeout(() => setCopiedCommand(null), 2000) } + const handleCopyForTicket = async () => { + if (!session || isCopyingForTicket) return + setIsCopyingForTicket(true) + try { + const content = await sessionsApi.export(session.id, { + format: 'psa', + include_timestamps: true, + include_tree_info: true, + }) + if (content) { + await navigator.clipboard.writeText(content) + setCopiedForTicket(true) + setTimeout(() => setCopiedForTicket(false), 2000) + toast.success('Copied progress notes to clipboard') + } + } catch (err) { + console.error('Copy for ticket failed:', err) + toast.error('Failed to copy notes') + } finally { + setIsCopyingForTicket(false) + } + } + // Session metadata (prefill from Repeat Last Session) const [ticketNumber, setTicketNumber] = useState(locationState?.prefillTicketNumber || '') const [clientName, setClientName] = useState(locationState?.prefillClientName || '') @@ -549,12 +575,26 @@ export function TreeNavigationPage() {

)} - +
+ + +
{/* Breadcrumb */}