mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-05 04:52:12 +00:00
fix: simplify agent thread layout to match reference chat UI (#1388)
Replace the floating absolute-positioned prompt bar (gradient overlay + 128px bottomInset) with a plain flex column: MessageView as flex-1 with a shrink-0 prompt bar beneath it, matching open-swe-app's ChatView. Also remove the redundant always-on 'Files Changed' panel — MessageView already renders an inline TurnChangedFilesCard per agent turn, and the duplicate was being clipped by the floating prompt bar. This eliminates the large whitespace gap and the broken files-changed box.
This commit is contained in:
parent
c8a997c125
commit
9e3406bd29
1 changed files with 10 additions and 64 deletions
|
|
@ -1,13 +1,8 @@
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { ChevronDown } from "lucide-react";
|
|
||||||
|
|
||||||
import { AgentPromptBar } from "@/components/agents/AgentPromptBar";
|
import { AgentPromptBar } from "@/components/agents/AgentPromptBar";
|
||||||
import { AgentsShell } from "@/components/agents/AgentsSidebar";
|
import { AgentsShell } from "@/components/agents/AgentsSidebar";
|
||||||
import {
|
import { MessageView } from "@/components/agents/ported";
|
||||||
MessageView,
|
|
||||||
summarizeChangedFiles,
|
|
||||||
type MessageViewScrollControl,
|
|
||||||
} from "@/components/agents/ported";
|
|
||||||
import type { SessionUser } from "@/lib/api";
|
import type { SessionUser } from "@/lib/api";
|
||||||
import type { AgentThread, Message } from "@/lib/agents/types";
|
import type { AgentThread, Message } from "@/lib/agents/types";
|
||||||
import { useSendAgentMessage } from "@/lib/agents/queries";
|
import { useSendAgentMessage } from "@/lib/agents/queries";
|
||||||
|
|
@ -24,13 +19,9 @@ interface AgentThreadViewProps {
|
||||||
thread: AgentThread;
|
thread: AgentThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PROMPT_OVERLAY_INSET = 128;
|
|
||||||
|
|
||||||
export function AgentThreadView({ user, thread }: AgentThreadViewProps) {
|
export function AgentThreadView({ user, thread }: AgentThreadViewProps) {
|
||||||
const sendMessage = useSendAgentMessage(thread.id);
|
const sendMessage = useSendAgentMessage(thread.id);
|
||||||
useAgentThreadStream(thread.id, thread.status === "running");
|
useAgentThreadStream(thread.id, thread.status === "running");
|
||||||
const scrollControlRef = useRef<MessageViewScrollControl | null>(null);
|
|
||||||
const [showScrollToBottom, setShowScrollToBottom] = useState(false);
|
|
||||||
const [pendingPrompts, setPendingPrompts] = useState<PendingPrompt[]>(() =>
|
const [pendingPrompts, setPendingPrompts] = useState<PendingPrompt[]>(() =>
|
||||||
getPendingPrompts(thread.id),
|
getPendingPrompts(thread.id),
|
||||||
);
|
);
|
||||||
|
|
@ -92,12 +83,6 @@ export function AgentThreadView({ user, thread }: AgentThreadViewProps) {
|
||||||
return result;
|
return result;
|
||||||
}, [thread.messages, pendingPrompts]);
|
}, [thread.messages, pendingPrompts]);
|
||||||
|
|
||||||
const changedFiles = useMemo(() => {
|
|
||||||
const agentMessages = thread.messages.filter((m) => m.author === "agent");
|
|
||||||
const allChunks = agentMessages.flatMap((m) => m.chunks);
|
|
||||||
return summarizeChangedFiles(allChunks);
|
|
||||||
}, [thread.messages]);
|
|
||||||
|
|
||||||
const hasMessages = displayMessages.length > 0;
|
const hasMessages = displayMessages.length > 0;
|
||||||
const isStreaming = thread.status === "running" || pendingPrompts.length > 0;
|
const isStreaming = thread.status === "running" || pendingPrompts.length > 0;
|
||||||
|
|
||||||
|
|
@ -106,53 +91,14 @@ export function AgentThreadView({ user, thread }: AgentThreadViewProps) {
|
||||||
<div className="flex min-w-0 flex-1 flex-col">
|
<div className="flex min-w-0 flex-1 flex-col">
|
||||||
<div className="flex min-h-0 flex-1 flex-col">
|
<div className="flex min-h-0 flex-1 flex-col">
|
||||||
{hasMessages ? (
|
{hasMessages ? (
|
||||||
<div className="relative flex min-h-0 flex-1 flex-col">
|
<div className="relative flex min-h-0 flex-1 flex-col overflow-hidden">
|
||||||
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
|
<MessageView
|
||||||
<MessageView
|
messages={displayMessages}
|
||||||
messages={displayMessages}
|
isStreaming={isStreaming}
|
||||||
isStreaming={isStreaming}
|
contentWidthClass="max-w-3xl"
|
||||||
contentWidthClass="max-w-3xl"
|
/>
|
||||||
bottomInset={PROMPT_OVERLAY_INSET}
|
<div className="shrink-0 px-4 pb-4">
|
||||||
scrollButtonSlot="external"
|
<div className="mx-auto w-full min-w-0 max-w-3xl">
|
||||||
scrollControlRef={scrollControlRef}
|
|
||||||
onShowScrollToBottomChange={setShowScrollToBottom}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{changedFiles.length > 0 && (
|
|
||||||
<div className="mx-auto mt-4 w-full max-w-3xl shrink-0 px-6">
|
|
||||||
<div className="rounded-lg border border-[var(--ui-border)] bg-[var(--ui-panel)] p-3">
|
|
||||||
<div className="mb-2 text-xs font-medium text-[var(--ui-text-muted)]">
|
|
||||||
{changedFiles.length} Files Changed
|
|
||||||
</div>
|
|
||||||
<div className="space-y-1">
|
|
||||||
{changedFiles.map((file) => (
|
|
||||||
<div
|
|
||||||
key={file.filePath}
|
|
||||||
className="flex items-center justify-between rounded px-2 py-1 text-xs hover:bg-[var(--ui-panel-2)]"
|
|
||||||
>
|
|
||||||
<span className="font-mono text-[var(--ui-text)]">{file.filePath}</span>
|
|
||||||
<span className="text-[var(--ui-success)]">+{file.additions}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 px-6 pb-4">
|
|
||||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-16 bg-gradient-to-t from-[var(--ui-bg)] via-[var(--ui-bg)]/80 to-transparent" />
|
|
||||||
<div className="pointer-events-auto relative mx-auto max-w-3xl">
|
|
||||||
{showScrollToBottom && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => scrollControlRef.current?.scrollToBottom()}
|
|
||||||
aria-label="Scroll to bottom"
|
|
||||||
className="absolute bottom-full left-1/2 z-30 mb-2 inline-flex h-8 w-8 -translate-x-1/2 items-center justify-center rounded-full bg-[var(--ui-panel-2)] text-[color:var(--ui-text-muted)] shadow-md transition-colors hover:bg-[var(--ui-panel)] hover:text-[color:var(--ui-text)]"
|
|
||||||
>
|
|
||||||
<ChevronDown className="h-3.5 w-3.5" />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<AgentPromptBar
|
<AgentPromptBar
|
||||||
placeholder="Add a follow up"
|
placeholder="Add a follow up"
|
||||||
compact
|
compact
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue