diff --git a/apps/web/src/components/ChatView.browser.tsx b/apps/web/src/components/ChatView.browser.tsx index ec07053a..245c0d77 100644 --- a/apps/web/src/components/ChatView.browser.tsx +++ b/apps/web/src/components/ChatView.browser.tsx @@ -2456,7 +2456,7 @@ describe("ChatView timeline estimator parity (full app)", () => { } }); - it("keeps source control closed by default on wide draft thread routes before first send", async () => { + it("defaults source control open on wide draft thread routes before first send", async () => { const draftId = DraftId.make("draft-source-control-before-start"); useComposerDraftStore.setState({ draftThreadsByThreadKey: { @@ -2494,18 +2494,19 @@ describe("ChatView timeline estimator parity (full app)", () => { "Unable to find source control toggle.", ); expect(sourceControlToggle.disabled).toBe(false); - expect(sourceControlToggle.hasAttribute("data-pressed")).toBe(false); - await expect - .element(page.getByRole("heading", { name: "Source Control" })) - .not.toBeInTheDocument(); + expect(sourceControlToggle.hasAttribute("data-pressed")).toBe(true); + expect(document.body.textContent).not.toContain("Explain this codebase"); + expect(document.body.textContent).not.toContain("Review my uncommitted changes"); + expect(document.body.textContent).not.toContain("Fix a bug"); + await expect.element(page.getByRole("heading", { name: "Source Control" })).toBeVisible(); sourceControlToggle.click(); await vi.waitFor( () => { - expect(mounted.router.state.location.search).toMatchObject({ sourceControl: "1" }); - expect(sourceControlToggle.hasAttribute("data-pressed")).toBe(true); - expect(document.querySelector('h2[aria-label="Source Control"]')).not.toBeNull(); + expect(mounted.router.state.location.search).toMatchObject({ sourceControl: "0" }); + expect(sourceControlToggle.hasAttribute("data-pressed")).toBe(false); + expect(document.querySelector('h2[aria-label="Source Control"]')).toBeNull(); }, { timeout: 8_000, interval: 16 }, ); diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index e8f3dbe9..3e3c601e 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -47,7 +47,6 @@ import { isElectron } from "../env"; import { ensureLocalApi, readLocalApi } from "../localApi"; import { closeRightPanelSearchParams, - isDraftSourceControlPanelOpen, isSourceControlPanelOpen, parseDiffRouteSearch, preserveRightPanelSearchParamsForDraftNavigation, @@ -1263,12 +1262,9 @@ export default function ChatView(props: ChatViewProps) { composerInteractionMode ?? activeThread?.interactionMode ?? DEFAULT_INTERACTION_MODE; const isLocalDraftThread = !isServerThread && localDraftThread !== undefined; const canCheckoutPullRequestIntoThread = isLocalDraftThread; - // Mirror the owning route's panel default: server threads open on wide - // viewports, drafts stay closed until explicitly opened. - const sourceControlOpen = - routeKind === "server" - ? isSourceControlPanelOpen(rawSearch, { defaultOpen: !shouldUseRightPanelSheet }) - : isDraftSourceControlPanelOpen(rawSearch); + const sourceControlOpen = isSourceControlPanelOpen(rawSearch, { + defaultOpen: !shouldUseRightPanelSheet, + }); // The diff panel is a drill-in of source control, so the header toggle // treats the right panel as one unit: it stays pressed while a diff is // open and pressing it closes the whole panel. @@ -1323,15 +1319,6 @@ export default function ChatView(props: ChatViewProps) { // General Chat threads run in a hidden scratch workspace: source-control, // scripts, and open-in affordances stay hidden even though a project exists. const isGeneralChatThread = activeProject?.kind === "general-chat"; - const insertDraftStarterPrompt = useCallback( - (text: string) => { - setComposerDraftPrompt(composerDraftTarget, text); - window.requestAnimationFrame(() => { - composerRef.current?.focusAtEnd(); - }); - }, - [composerDraftTarget, composerRef, setComposerDraftPrompt], - ); const draftTimelineEmptyState = useMemo( () => isLocalDraftThread && draftThread ? ( @@ -1339,14 +1326,12 @@ export default function ChatView(props: ChatViewProps) { currentProjectRef={scopeProjectRef(draftThread.environmentId, draftThread.projectId)} currentProjectName={activeProject?.name ?? null} isGeneralChat={isGeneralChatThread} - onInsertPrompt={insertDraftStarterPrompt} /> ) : undefined, [ activeProject?.name, draftThread?.environmentId, draftThread?.projectId, - insertDraftStarterPrompt, isGeneralChatThread, isLocalDraftThread, ], diff --git a/apps/web/src/components/chat/DraftEmptyState.tsx b/apps/web/src/components/chat/DraftEmptyState.tsx index 5b3331c2..f6892b51 100644 --- a/apps/web/src/components/chat/DraftEmptyState.tsx +++ b/apps/web/src/components/chat/DraftEmptyState.tsx @@ -1,12 +1,6 @@ import { scopedProjectKey, scopeProjectRef } from "@threadlines/client-runtime"; import type { ScopedProjectRef } from "@threadlines/contracts"; -import { - BugIcon, - CheckIcon, - CompassIcon, - GitCompareArrowsIcon, - MessagesSquareIcon, -} from "lucide-react"; +import { CheckIcon, MessagesSquareIcon } from "lucide-react"; import { useMemo } from "react"; import { usePrimaryEnvironmentId } from "../../environments/primary"; @@ -16,7 +10,6 @@ import { resolveGeneralChatsProjectRef } from "../../lib/generalChats"; import { selectGeneralChatsProjectAcrossEnvironments, useStore } from "../../store"; import { ProjectFavicon } from "../ProjectFavicon"; import { RecentThreadsList } from "../RecentThreadsList"; -import { Button } from "../ui/button"; import { riseDelay, ThreadlinesFigure } from "../ThreadlinesFigure"; import { Menu, @@ -32,21 +25,12 @@ interface DraftEmptyStateProps { currentProjectRef: ScopedProjectRef | null; currentProjectName: string | null; isGeneralChat: boolean; - onInsertPrompt?: ((text: string) => void) | undefined; } -/** Starter prompts inserted into the composer for editing, not sent. */ -const STARTER_PROMPTS = [ - { icon: CompassIcon, prompt: "Explain this codebase" }, - { icon: GitCompareArrowsIcon, prompt: "Review my uncommitted changes" }, - { icon: BugIcon, prompt: "Fix a bug" }, -] as const; - export function DraftEmptyState({ currentProjectRef, currentProjectName, isGeneralChat, - onInsertPrompt, }: DraftEmptyStateProps) { const { handleNewThread, orderedProjects } = useHandleNewThread(); const activeEnvironmentId = useStore((state) => state.activeEnvironmentId); @@ -131,28 +115,8 @@ export function DraftEmptyState({ ? - {!isGeneralChat && onInsertPrompt ? ( -