149 lines
4.3 KiB
TypeScript
149 lines
4.3 KiB
TypeScript
"use client";
|
|
|
|
import { GridSpinner } from "@/components/grid-spinner";
|
|
import type { Message, TaskSessionState, TaskState } from "@/lib/types/http";
|
|
import type { RenderItem } from "@/hooks/use-processed-messages";
|
|
import { MessageRenderer } from "@/components/task/chat/message-renderer";
|
|
import { TurnGroupMessage } from "@/components/task/chat/messages/turn-group-message";
|
|
import { PrepareProgress } from "@/components/session/prepare-progress";
|
|
|
|
export type MessageListProps = {
|
|
items: RenderItem[];
|
|
messages: Message[];
|
|
/** Action messages rendered after the env prep error status in the footer. */
|
|
footerActionMessages?: Message[];
|
|
permissionsByToolCallId: Map<string, Message>;
|
|
childrenByParentToolCallId: Map<string, Message[]>;
|
|
taskId?: string;
|
|
sessionId: string | null;
|
|
messagesLoading: boolean;
|
|
isWorking: boolean;
|
|
sessionState?: TaskSessionState;
|
|
taskState?: TaskState;
|
|
worktreePath?: string;
|
|
onOpenFile?: (path: string) => void;
|
|
};
|
|
|
|
export function getItemKey(item: RenderItem): string {
|
|
if (item.type === "turn_group" || item.type === "prepare_progress") return item.id;
|
|
return item.message.id;
|
|
}
|
|
|
|
export function getSessionRunningState(sessionState: string | null | undefined) {
|
|
return sessionState === "CREATED" || sessionState === "STARTING" || sessionState === "RUNNING";
|
|
}
|
|
|
|
export function getLastTurnGroupId(items: RenderItem[]) {
|
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
const item = items[i];
|
|
if (item.type === "turn_group") return item.id;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function MessageListStatus({
|
|
isLoadingMore,
|
|
hasMore,
|
|
showLoadingState,
|
|
messagesLoading,
|
|
isInitialLoading,
|
|
messagesCount,
|
|
}: {
|
|
isLoadingMore: boolean;
|
|
hasMore: boolean;
|
|
showLoadingState: boolean;
|
|
messagesLoading: boolean;
|
|
isInitialLoading: boolean;
|
|
messagesCount: number;
|
|
}) {
|
|
return (
|
|
<>
|
|
{isLoadingMore && hasMore && (
|
|
<div className="text-center text-xs text-muted-foreground py-2">
|
|
Loading older messages...
|
|
</div>
|
|
)}
|
|
{showLoadingState && (
|
|
<div className="flex items-center justify-center py-8 text-muted-foreground">
|
|
<GridSpinner className="text-primary mr-2" />
|
|
<span>Loading messages...</span>
|
|
</div>
|
|
)}
|
|
{!messagesLoading && !isInitialLoading && messagesCount === 0 && (
|
|
<div className="flex items-center justify-center py-8 text-muted-foreground">
|
|
<span>No messages yet. Start the conversation!</span>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function MessageItem({
|
|
item,
|
|
sessionId,
|
|
permissionsByToolCallId,
|
|
childrenByParentToolCallId,
|
|
taskId,
|
|
worktreePath,
|
|
onOpenFile,
|
|
isLastGroup,
|
|
isTurnActive,
|
|
messages,
|
|
sessionState,
|
|
taskState,
|
|
onScrollToMessage,
|
|
}: {
|
|
item: RenderItem;
|
|
sessionId: string | null;
|
|
permissionsByToolCallId: Map<string, Message>;
|
|
childrenByParentToolCallId: Map<string, Message[]>;
|
|
taskId?: string;
|
|
worktreePath?: string;
|
|
onOpenFile?: (path: string) => void;
|
|
isLastGroup: boolean;
|
|
isTurnActive: boolean;
|
|
messages: Message[];
|
|
sessionState?: TaskSessionState;
|
|
taskState?: TaskState;
|
|
onScrollToMessage: (id: string) => void;
|
|
}) {
|
|
if (item.type === "prepare_progress") {
|
|
return <PrepareProgress sessionId={item.sessionId} />;
|
|
}
|
|
if (item.type === "turn_group") {
|
|
return (
|
|
<TurnGroupMessage
|
|
group={item}
|
|
sessionId={sessionId}
|
|
permissionsByToolCallId={permissionsByToolCallId}
|
|
childrenByParentToolCallId={childrenByParentToolCallId}
|
|
taskId={taskId}
|
|
worktreePath={worktreePath}
|
|
onOpenFile={onOpenFile}
|
|
isLastGroup={isLastGroup}
|
|
isTurnActive={isTurnActive}
|
|
allMessages={messages}
|
|
sessionState={sessionState}
|
|
taskState={taskState}
|
|
onScrollToMessage={onScrollToMessage}
|
|
/>
|
|
);
|
|
}
|
|
return (
|
|
<MessageRenderer
|
|
comment={item.message}
|
|
isTaskDescription={item.message.id === "task-description"}
|
|
sessionState={sessionState}
|
|
taskState={taskState}
|
|
taskId={taskId}
|
|
permissionsByToolCallId={permissionsByToolCallId}
|
|
childrenByParentToolCallId={childrenByParentToolCallId}
|
|
worktreePath={worktreePath}
|
|
sessionId={sessionId ?? undefined}
|
|
onOpenFile={onOpenFile}
|
|
allMessages={messages}
|
|
onScrollToMessage={onScrollToMessage}
|
|
/>
|
|
);
|
|
}
|