({
session,
initialProjectPath = "",
className,
onStreamingChange,
onProjectPathChange,
})
| 69 | * <ClaudeCodeSession onBack={() => setView('projects')} /> |
| 70 | */ |
| 71 | export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({ |
| 72 | session, |
| 73 | initialProjectPath = "", |
| 74 | className, |
| 75 | onStreamingChange, |
| 76 | onProjectPathChange, |
| 77 | }) => { |
| 78 | const [projectPath] = useState(initialProjectPath || session?.project_path || ""); |
| 79 | const [messages, setMessages] = useState<ClaudeStreamMessage[]>([]); |
| 80 | const [isLoading, setIsLoading] = useState(false); |
| 81 | const [error, setError] = useState<string | null>(null); |
| 82 | const [rawJsonlOutput, setRawJsonlOutput] = useState<string[]>([]); |
| 83 | const [copyPopoverOpen, setCopyPopoverOpen] = useState(false); |
| 84 | const [isFirstPrompt, setIsFirstPrompt] = useState(!session); |
| 85 | const [totalTokens, setTotalTokens] = useState(0); |
| 86 | const [extractedSessionInfo, setExtractedSessionInfo] = useState<{ sessionId: string; projectId: string } | null>(null); |
| 87 | const [claudeSessionId, setClaudeSessionId] = useState<string | null>(null); |
| 88 | const [showTimeline, setShowTimeline] = useState(false); |
| 89 | const [timelineVersion, setTimelineVersion] = useState(0); |
| 90 | const [showSettings, setShowSettings] = useState(false); |
| 91 | const [showForkDialog, setShowForkDialog] = useState(false); |
| 92 | const [showSlashCommandsSettings, setShowSlashCommandsSettings] = useState(false); |
| 93 | const [forkCheckpointId, setForkCheckpointId] = useState<string | null>(null); |
| 94 | const [forkSessionName, setForkSessionName] = useState(""); |
| 95 | |
| 96 | // Queued prompts state |
| 97 | const [queuedPrompts, setQueuedPrompts] = useState<Array<{ id: string; prompt: string; model: "sonnet" | "opus" }>>([]); |
| 98 | |
| 99 | // New state for preview feature |
| 100 | const [showPreview, setShowPreview] = useState(false); |
| 101 | const [previewUrl, setPreviewUrl] = useState(""); |
| 102 | const [showPreviewPrompt, setShowPreviewPrompt] = useState(false); |
| 103 | const [splitPosition, setSplitPosition] = useState(50); |
| 104 | const [isPreviewMaximized, setIsPreviewMaximized] = useState(false); |
| 105 | |
| 106 | // Add collapsed state for queued prompts |
| 107 | const [queuedPromptsCollapsed, setQueuedPromptsCollapsed] = useState(false); |
| 108 | |
| 109 | const parentRef = useRef<HTMLDivElement>(null); |
| 110 | const unlistenRefs = useRef<UnlistenFn[]>([]); |
| 111 | const hasActiveSessionRef = useRef(false); |
| 112 | const floatingPromptRef = useRef<FloatingPromptInputRef>(null); |
| 113 | const queuedPromptsRef = useRef<Array<{ id: string; prompt: string; model: "sonnet" | "opus" }>>([]); |
| 114 | const isMountedRef = useRef(true); |
| 115 | const isListeningRef = useRef(false); |
| 116 | const sessionStartTime = useRef<number>(Date.now()); |
| 117 | |
| 118 | // Session metrics state for enhanced analytics |
| 119 | const sessionMetrics = useRef({ |
| 120 | firstMessageTime: null as number | null, |
| 121 | promptsSent: 0, |
| 122 | toolsExecuted: 0, |
| 123 | toolsFailed: 0, |
| 124 | filesCreated: 0, |
| 125 | filesModified: 0, |
| 126 | filesDeleted: 0, |
| 127 | codeBlocksGenerated: 0, |
| 128 | errorsEncountered: 0, |
nothing calls this directly
no test coverage detected