146 lines
5.0 KiB
TypeScript
146 lines
5.0 KiB
TypeScript
"use client";
|
|
|
|
import { memo, useCallback, useEffect, useRef, useState, type ReactNode } from "react";
|
|
import { useSettingsData } from "@/hooks/domains/settings/use-settings-data";
|
|
import { type ChatInputContainerHandle } from "@/components/task/chat/chat-input-container";
|
|
import { MessageList } from "@/components/task/chat/message-list";
|
|
import { useChatPanelState } from "@/components/task/chat/use-chat-panel-state";
|
|
import {
|
|
ChatInputArea,
|
|
useSubmitHandler,
|
|
useChatPanelHandlers,
|
|
} from "@/components/task/chat/chat-input-area";
|
|
import { ClarificationPanelSection } from "@/components/task/chat/clarification-panel-section";
|
|
import { getSessionWorkspacePath } from "@/lib/session-workspace-path";
|
|
import { routePanelMouseDown } from "@/components/task/chat/route-panel-mouse-down";
|
|
import { useQuickChatInitialPrompt } from "./use-quick-chat-initial-prompt";
|
|
|
|
type QuickChatContentProps = {
|
|
sessionId: string;
|
|
minimalToolbar?: boolean;
|
|
placeholderOverride?: string;
|
|
initialPrompt?: string;
|
|
onInitialPromptAttempted?: () => void;
|
|
recoveryContent?: ReactNode;
|
|
recoveryRevealKey?: string | null;
|
|
};
|
|
|
|
function useQuickChatState(sessionId: string) {
|
|
const chatInputRef = useRef<ChatInputContainerHandle>(null);
|
|
|
|
useSettingsData(true);
|
|
const panelState = useChatPanelState({
|
|
sessionId,
|
|
onOpenFile: undefined,
|
|
onOpenFileAtLine: undefined,
|
|
});
|
|
const { isSending, handleSubmit } = useSubmitHandler(panelState, undefined);
|
|
const { handleCancelTurn } = useChatPanelHandlers(panelState.resolvedSessionId, chatInputRef);
|
|
|
|
return {
|
|
chatInputRef,
|
|
panelState,
|
|
isSending,
|
|
handleSubmit,
|
|
handleCancelTurn,
|
|
};
|
|
}
|
|
|
|
export const QuickChatContent = memo(function QuickChatContent({
|
|
sessionId,
|
|
minimalToolbar,
|
|
placeholderOverride,
|
|
initialPrompt,
|
|
onInitialPromptAttempted,
|
|
recoveryContent,
|
|
recoveryRevealKey,
|
|
}: QuickChatContentProps) {
|
|
const [clarificationKey, setClarificationKey] = useState(0);
|
|
const shortcutScopeRef = useRef<HTMLDivElement>(null);
|
|
const state = useQuickChatState(sessionId);
|
|
const { chatInputRef, panelState, isSending, handleSubmit, handleCancelTurn } = state;
|
|
const { taskId, pendingClarification, pendingClarificationGroup } = panelState;
|
|
|
|
useEffect(() => {
|
|
const timer = setTimeout(() => chatInputRef.current?.focusInput(), 50);
|
|
return () => clearTimeout(timer);
|
|
}, [chatInputRef]);
|
|
|
|
const restoreRejectedPrompt = useCallback(
|
|
(rejectedSessionId: string, prompt: string) => {
|
|
const input = chatInputRef.current;
|
|
if (rejectedSessionId === sessionId && input && !input.getValue())
|
|
input.insertText(prompt, 0, 0);
|
|
},
|
|
[chatInputRef, sessionId],
|
|
);
|
|
|
|
useQuickChatInitialPrompt({
|
|
sessionId,
|
|
taskId,
|
|
prompt: initialPrompt,
|
|
blocked: panelState.planCommentMigration?.isBlocking ?? false,
|
|
submit: handleSubmit,
|
|
onAttempted: onInitialPromptAttempted,
|
|
onRejected: restoreRejectedPrompt,
|
|
});
|
|
|
|
const handleClarificationResolved = useCallback(() => setClarificationKey((k) => k + 1), []);
|
|
const handleShortcutScopeMouseDown = useCallback(
|
|
(event: React.MouseEvent<HTMLDivElement>) => routePanelMouseDown(event, shortcutScopeRef),
|
|
[],
|
|
);
|
|
|
|
return (
|
|
<div
|
|
ref={shortcutScopeRef}
|
|
data-testid="quick-chat-content"
|
|
tabIndex={-1}
|
|
onMouseDown={handleShortcutScopeMouseDown}
|
|
className="flex flex-col flex-1 min-h-0 outline-none"
|
|
>
|
|
<div className="flex-1 min-h-0 overflow-hidden bg-popover" data-testid="quick-chat-messages">
|
|
<MessageList
|
|
items={panelState.groupedItems}
|
|
messages={panelState.allMessages}
|
|
permissionsByToolCallId={panelState.permissionsByToolCallId}
|
|
childrenByParentToolCallId={panelState.childrenByParentToolCallId}
|
|
taskId={taskId ?? undefined}
|
|
sessionId={panelState.resolvedSessionId}
|
|
messagesLoading={panelState.messagesLoading}
|
|
isWorking={panelState.isWorking}
|
|
sessionState={panelState.session?.state}
|
|
worktreePath={getSessionWorkspacePath(panelState.session)}
|
|
onOpenFile={undefined}
|
|
prependContent={recoveryContent}
|
|
recoveryRevealKey={recoveryRevealKey}
|
|
/>
|
|
</div>
|
|
<ClarificationPanelSection
|
|
key={sessionId}
|
|
pending={Boolean(pendingClarification)}
|
|
messages={pendingClarificationGroup}
|
|
onResolved={handleClarificationResolved}
|
|
shortcutScopeRef={shortcutScopeRef}
|
|
maxHeightVh={35}
|
|
/>
|
|
<ChatInputArea
|
|
chatInputRef={chatInputRef}
|
|
clarificationKey={clarificationKey}
|
|
onClarificationResolved={handleClarificationResolved}
|
|
handleSubmit={handleSubmit}
|
|
handleCancelTurn={handleCancelTurn}
|
|
showRequestChangesTooltip={false}
|
|
onRequestChangesTooltipDismiss={undefined}
|
|
panelState={panelState}
|
|
isSending={isSending}
|
|
hideSessionsDropdown={true}
|
|
minimalToolbar={minimalToolbar}
|
|
hidePlanMode={true}
|
|
placeholderOverride={placeholderOverride}
|
|
surfaceClassName="bg-popover"
|
|
/>
|
|
</div>
|
|
);
|
|
});
|