140 lines
4.8 KiB
TypeScript
140 lines
4.8 KiB
TypeScript
'use client';
|
|
|
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
import '@git-diff-view/react/styles/diff-view.css';
|
|
import { TooltipProvider } from '@kandev/ui/tooltip';
|
|
import { TaskTopBar } from '@/components/task/task-top-bar';
|
|
import { TaskLayout } from '@/components/task/task-layout';
|
|
import { DebugOverlay } from '@/components/debug-overlay';
|
|
import type { Task } from '@/lib/types/http';
|
|
import { DEBUG_UI } from '@/lib/config';
|
|
import { getWebSocketClient } from '@/lib/ws/connection';
|
|
import { useRepositories } from '@/hooks/use-repositories';
|
|
import { useTaskAgent } from '@/hooks/use-task-agent';
|
|
import { useTaskMessages } from '@/hooks/use-task-messages';
|
|
import { useAppStore } from '@/components/state-provider';
|
|
|
|
type TaskPageClientProps = {
|
|
task: Task | null;
|
|
sessionId?: string | null;
|
|
};
|
|
|
|
export default function TaskPage({ task: initialTask, sessionId = null }: TaskPageClientProps) {
|
|
const [isMounted, setIsMounted] = useState(false);
|
|
const kanbanTask = useAppStore((state) =>
|
|
initialTask?.id ? state.kanban.tasks.find((item) => item.id === initialTask.id) ?? null : null
|
|
);
|
|
const task = useMemo(() => {
|
|
if (!initialTask) return null;
|
|
if (!kanbanTask) return initialTask;
|
|
return {
|
|
...initialTask,
|
|
title: kanbanTask.title ?? initialTask.title,
|
|
description: kanbanTask.description ?? initialTask.description,
|
|
column_id: (kanbanTask.columnId as string | undefined) ?? initialTask.column_id,
|
|
position: kanbanTask.position ?? initialTask.position,
|
|
state: (kanbanTask.state as Task['state'] | undefined) ?? initialTask.state,
|
|
repositories: initialTask.repositories,
|
|
};
|
|
}, [initialTask, kanbanTask]);
|
|
const connectionStatus = useAppStore((state) => state.connection.status);
|
|
|
|
// Custom hooks for state management
|
|
const {
|
|
isAgentRunning,
|
|
isAgentLoading,
|
|
worktreePath,
|
|
worktreeBranch,
|
|
taskSessionId,
|
|
taskSessionState,
|
|
handleStartAgent,
|
|
handleStopAgent,
|
|
} = useTaskAgent(task);
|
|
const activeSessionId = sessionId ?? taskSessionId;
|
|
const isAgentWorking =
|
|
taskSessionState !== null
|
|
? taskSessionState === 'STARTING' || taskSessionState === 'RUNNING'
|
|
: isAgentRunning && (task?.state === 'IN_PROGRESS' || task?.state === 'SCHEDULING');
|
|
const { isLoading: isLoadingMessages } = useTaskMessages(task?.id ?? null, activeSessionId);
|
|
|
|
useEffect(() => {
|
|
queueMicrotask(() => setIsMounted(true));
|
|
}, []);
|
|
|
|
|
|
const { repositories } = useRepositories(task?.workspace_id ?? null, Boolean(task?.workspace_id));
|
|
const repository = useMemo(
|
|
() => repositories.find((item) => item.id === task?.repositories?.[0]?.repository_id) ?? null,
|
|
[repositories, task?.repositories]
|
|
);
|
|
|
|
const handleSendMessage = useCallback(async (content: string) => {
|
|
if (!task?.id) return;
|
|
|
|
const client = getWebSocketClient();
|
|
if (!client) return;
|
|
|
|
if (!activeSessionId) {
|
|
console.error('No active agent session. Start an agent before sending a message.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await client.request(
|
|
'message.add',
|
|
{ task_id: task.id, task_session_id: activeSessionId, content },
|
|
10000
|
|
);
|
|
} catch (error) {
|
|
console.error('Failed to send message:', error);
|
|
}
|
|
}, [activeSessionId, task]);
|
|
|
|
if (!isMounted) {
|
|
return <div className="h-screen w-full bg-background" />;
|
|
}
|
|
|
|
return (
|
|
<TooltipProvider>
|
|
<div className="h-screen w-full flex flex-col bg-background">
|
|
{DEBUG_UI && (
|
|
<DebugOverlay
|
|
title="Task Debug"
|
|
entries={{
|
|
ws_status: connectionStatus,
|
|
task_id: task?.id ?? null,
|
|
task_session_id: activeSessionId ?? null,
|
|
task_state: task?.state ?? null,
|
|
task_session_state: taskSessionState ?? null,
|
|
is_agent_working: isAgentWorking,
|
|
}}
|
|
/>
|
|
)}
|
|
<TaskTopBar
|
|
taskId={task?.id ?? null}
|
|
activeSessionId={activeSessionId ?? null}
|
|
taskTitle={task?.title}
|
|
taskDescription={task?.description}
|
|
baseBranch={task?.repositories?.[0]?.base_branch ?? undefined}
|
|
onStartAgent={handleStartAgent}
|
|
onStopAgent={handleStopAgent}
|
|
isAgentRunning={isAgentRunning}
|
|
isAgentLoading={isAgentLoading}
|
|
worktreePath={worktreePath}
|
|
worktreeBranch={worktreeBranch}
|
|
repositoryPath={repository?.local_path ?? null}
|
|
repositoryName={repository?.name ?? null}
|
|
/>
|
|
|
|
<TaskLayout
|
|
taskId={task?.id ?? null}
|
|
taskDescription={task?.description}
|
|
isLoadingMessages={isLoadingMessages}
|
|
isAgentWorking={isAgentWorking}
|
|
onSendMessage={handleSendMessage}
|
|
/>
|
|
</div>
|
|
</TooltipProvider>
|
|
);
|
|
}
|