Skip to content

Commit f6a1e1d

Browse files
committed
Rebase fallout and Self-review
1 parent 4e61076 commit f6a1e1d

File tree

17 files changed

+318
-277
lines changed

17 files changed

+318
-277
lines changed

packages/shared/src/tasks/api.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ const deleteTask = defineRequest<TaskActionParams, void>("deleteTask");
4747
const pauseTask = defineRequest<TaskActionParams, void>("pauseTask");
4848
const resumeTask = defineRequest<TaskActionParams, void>("resumeTask");
4949
const downloadLogs = defineRequest<{ taskId: string }, void>("downloadLogs");
50+
const sendTaskMessage = defineRequest<
51+
{ taskId: string; message: string },
52+
void
53+
>("sendTaskMessage");
5054

5155
const viewInCoder = defineCommand<{ taskId: string }>("viewInCoder");
5256
const viewLogs = defineCommand<{ taskId: string }>("viewLogs");
53-
const sendTaskMessage = defineCommand<{
54-
taskId: string;
55-
message: string;
56-
}>("sendTaskMessage");
5757

5858
const taskUpdated = defineNotification<Task>("taskUpdated");
5959
const tasksUpdated = defineNotification<Task[]>("tasksUpdated");
@@ -73,10 +73,10 @@ export const TasksApi = {
7373
pauseTask,
7474
resumeTask,
7575
downloadLogs,
76+
sendTaskMessage,
7677
// Commands
7778
viewInCoder,
7879
viewLogs,
79-
sendTaskMessage,
8080
// Notifications
8181
taskUpdated,
8282
tasksUpdated,

packages/tasks/src/App.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ export default function App() {
4949
const { onNotification } = useIpc();
5050
useEffect(() => {
5151
return onNotification(TasksApi.showCreateForm, () => {
52-
deselectTask();
5352
setCreateOpen(true);
5453
});
55-
}, [onNotification, setCreateOpen, deselectTask]);
54+
}, [onNotification, setCreateOpen]);
5655

5756
useEffect(() => {
5857
if (data) {

packages/tasks/src/components/AgentChatHistory.tsx

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef, useCallback } from "react";
1+
import { useEffect, useRef } from "react";
22

33
import type { LogsStatus, TaskLogEntry } from "@repo/shared";
44

@@ -26,34 +26,20 @@ export function AgentChatHistory({
2626
}: AgentChatHistoryProps) {
2727
const containerRef = useRef<HTMLDivElement>(null);
2828
const isAtBottomRef = useRef(true);
29-
const isInitialMountRef = useRef(true);
3029

31-
const checkIfAtBottom = useCallback(() => {
30+
const handleScroll = () => {
3231
const container = containerRef.current;
33-
if (!container) return true;
32+
if (!container) return;
3433
const distanceFromBottom =
3534
container.scrollHeight - container.scrollTop - container.clientHeight;
36-
return distanceFromBottom <= 50;
37-
}, []);
38-
39-
const handleScroll = useCallback(() => {
40-
isAtBottomRef.current = checkIfAtBottom();
41-
}, [checkIfAtBottom]);
42-
43-
useEffect(() => {
44-
if (isInitialMountRef.current && containerRef.current) {
45-
containerRef.current.scrollTop = containerRef.current.scrollHeight;
46-
isInitialMountRef.current = false;
47-
}
48-
}, []);
35+
isAtBottomRef.current = distanceFromBottom <= 50;
36+
};
4937

5038
useEffect(() => {
5139
if (containerRef.current && isAtBottomRef.current) {
5240
containerRef.current.scrollTop = containerRef.current.scrollHeight;
5341
}
54-
}, [logs]);
55-
56-
const emptyMessage = getEmptyMessage(logsStatus);
42+
}, [logs, isThinking]);
5743

5844
return (
5945
<div className="agent-chat-history">
@@ -65,21 +51,24 @@ export function AgentChatHistory({
6551
>
6652
{logs.length === 0 ? (
6753
<div
68-
className={`chat-history-empty ${logsStatus === "error" ? "chat-history-error" : ""}`}
54+
className={[
55+
"chat-history-empty",
56+
logsStatus === "error" && "chat-history-error",
57+
]
58+
.filter(Boolean)
59+
.join(" ")}
6960
>
70-
{emptyMessage}
61+
{getEmptyMessage(logsStatus)}
7162
</div>
7263
) : (
7364
logs.map((log) => (
74-
<div key={log.id} className={`log-entry log-entry-${log.type}`}>
65+
<div key={log.id} className="log-entry">
7566
{log.content}
7667
</div>
7768
))
7869
)}
7970
{isThinking && (
80-
<div className="log-entry log-entry-thinking">
81-
<span className="log-content">*Thinking...</span>
82-
</div>
71+
<div className="log-entry log-entry-thinking">Thinking...</div>
8372
)}
8473
</div>
8574
</div>

packages/tasks/src/components/CreateTaskSection.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export function CreateTaskSection({ templates }: CreateTaskSectionProps) {
4747
onChange={setPrompt}
4848
onSubmit={handleSubmit}
4949
loading={isPending}
50+
actionIcon="send"
51+
actionLabel="Send"
52+
actionDisabled={!canSubmit}
5053
/>
5154
{error && <div className="create-task-error">{error.message}</div>}
5255
<div className="create-task-options">

packages/tasks/src/components/ErrorBanner.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { VscodeIcon } from "@vscode-elements/react-elements";
2-
import { useCallback } from "react";
32

43
import { useTasksApi } from "../hooks/useTasksApi";
54

@@ -11,17 +10,17 @@ interface ErrorBannerProps {
1110

1211
export function ErrorBanner({ task }: ErrorBannerProps) {
1312
const api = useTasksApi();
14-
const message = task.current_state?.message || "Build failed";
15-
16-
const handleViewLogs = useCallback(() => {
17-
void api.viewLogs(task.id);
18-
}, [api, task.id]);
13+
const message = task.current_state?.message || "Task failed";
1914

2015
return (
2116
<div className="error-banner">
2217
<VscodeIcon name="warning" />
23-
<span className="error-banner-message">{message}.</span>
24-
<button type="button" className="text-link" onClick={handleViewLogs}>
18+
<span>{message}</span>
19+
<button
20+
type="button"
21+
className="text-link"
22+
onClick={() => api.viewLogs(task.id)}
23+
>
2524
View logs <VscodeIcon name="link-external" />
2625
</button>
2726
</div>

packages/tasks/src/components/PromptInput.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ interface PromptInputProps {
1212
disabled?: boolean;
1313
loading?: boolean;
1414
placeholder?: string;
15+
actionIcon: "send" | "debug-pause";
16+
actionLabel: string;
17+
actionDisabled: boolean;
1518
}
1619

1720
export function PromptInput({
@@ -21,9 +24,10 @@ export function PromptInput({
2124
disabled = false,
2225
loading = false,
2326
placeholder = "Prompt your AI agent to start a task...",
27+
actionIcon,
28+
actionLabel,
29+
actionDisabled,
2430
}: PromptInputProps) {
25-
const canSubmit = value.trim().length > 0 && !disabled && !loading;
26-
2731
return (
2832
<div className="prompt-input-container">
2933
<textarea
@@ -34,7 +38,7 @@ export function PromptInput({
3438
onKeyDown={(e) => {
3539
if (isSubmit(e)) {
3640
e.preventDefault();
37-
if (canSubmit) {
41+
if (!actionDisabled) {
3842
onSubmit();
3943
}
4044
}
@@ -47,10 +51,10 @@ export function PromptInput({
4751
) : (
4852
<VscodeIcon
4953
actionIcon
50-
name="send"
51-
label="Send"
52-
onClick={() => canSubmit && onSubmit()}
53-
className={canSubmit ? "" : "disabled"}
54+
name={actionIcon}
55+
label={actionLabel}
56+
onClick={() => !actionDisabled && onSubmit()}
57+
className={actionDisabled ? "disabled" : ""}
5458
/>
5559
)}
5660
</div>

packages/tasks/src/components/TaskDetailHeader.tsx

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
import { getTaskLabel, type Task } from "@repo/shared";
22
import { VscodeIcon } from "@vscode-elements/react-elements";
33

4-
import { ActionMenu, type ActionMenuItem } from "./ActionMenu";
4+
import { getActionLabel } from "../utils/taskLoadingState";
5+
6+
import { ActionMenu } from "./ActionMenu";
57
import { StatusIndicator } from "./StatusIndicator";
8+
import { useTaskMenuItems } from "./useTaskMenuItems";
69

710
interface TaskDetailHeaderProps {
811
task: Task;
9-
menuItems: ActionMenuItem[];
1012
onBack: () => void;
11-
loadingAction?: string | null;
1213
}
1314

14-
export function TaskDetailHeader({
15-
task,
16-
menuItems,
17-
onBack,
18-
loadingAction,
19-
}: TaskDetailHeaderProps) {
20-
const displayName = getTaskLabel(task);
15+
export function TaskDetailHeader({ task, onBack }: TaskDetailHeaderProps) {
16+
const label = getTaskLabel(task);
17+
const { menuItems, action } = useTaskMenuItems({ task });
18+
const loadingAction = getActionLabel(action);
2119

2220
return (
2321
<div className="task-detail-header">
@@ -28,8 +26,8 @@ export function TaskDetailHeader({
2826
onClick={onBack}
2927
/>
3028
<StatusIndicator task={task} />
31-
<span className="task-detail-title" title={displayName}>
32-
{displayName}
29+
<span className="task-detail-title" title={label}>
30+
{label}
3331
{loadingAction && (
3432
<span className="task-action-label">{loadingAction}</span>
3533
)}
Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import { getTaskActions, type TaskDetails } from "@repo/shared";
2-
3-
import { getActionLabel } from "../utils/taskAction";
4-
51
import { AgentChatHistory } from "./AgentChatHistory";
62
import { ErrorBanner } from "./ErrorBanner";
73
import { TaskDetailHeader } from "./TaskDetailHeader";
8-
import { TaskInput } from "./TaskInput";
9-
import { useTaskMenuItems } from "./useTaskMenuItems";
4+
import { TaskMessageInput } from "./TaskMessageInput";
5+
6+
import type { TaskDetails } from "@repo/shared";
107

118
interface TaskDetailViewProps {
129
details: TaskDetails;
@@ -15,30 +12,22 @@ interface TaskDetailViewProps {
1512

1613
export function TaskDetailView({ details, onBack }: TaskDetailViewProps) {
1714
const { task, logs, logsStatus } = details;
18-
const { canPause } = getTaskActions(task);
1915

20-
const isWorking =
16+
const isThinking =
2117
task.status === "active" &&
2218
task.current_state?.state === "working" &&
2319
task.workspace_agent_lifecycle === "ready";
2420

25-
const { menuItems, action } = useTaskMenuItems({ task });
26-
2721
return (
2822
<div className="task-detail-view">
29-
<TaskDetailHeader
30-
task={task}
31-
menuItems={menuItems}
32-
onBack={onBack}
33-
loadingAction={getActionLabel(action)}
34-
/>
23+
<TaskDetailHeader task={task} onBack={onBack} />
3524
{task.status === "error" && <ErrorBanner task={task} />}
3625
<AgentChatHistory
3726
logs={logs}
3827
logsStatus={logsStatus}
39-
isThinking={isWorking}
28+
isThinking={isThinking}
4029
/>
41-
<TaskInput taskId={task.id} task={task} canPause={canPause} />
30+
<TaskMessageInput task={task} />
4231
</div>
4332
);
4433
}

0 commit comments

Comments
 (0)