fix(dashboard): mobile chat New Chat button placement + merged fn-2469

- ChatView mobile: hide the top sidebar header's "New Chat" button on
  <=768px and show the existing footer button as a pinned full-width
  action with safe-area padding. Both buttons existed in JSX; only
  CSS was needed.
- styles.css: comments compose/edit textareas use var(--surface) so
  they remain visible against the task detail modal's --card panel
  (in light theme --bg and --card both resolve to #ffffff).
- Includes resolved-conflict changes from fusion/fn-2469 in
  ModelOnboardingModal and SettingsModal (and the related test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-24 20:43:17 -07:00
parent 2498b7d235
commit 1fba5ea60a
5 changed files with 208 additions and 2 deletions

View File

@@ -2928,6 +2928,64 @@ describe("ModelOnboardingModal", () => {
});
});
it("shows OAuth login instructions during pending auth and clears them on cancel", async () => {
mockLoginProvider.mockResolvedValueOnce({
url: "https://auth.example.com/login",
instructions: "Use code WXYZ-9876 to finish authentication.",
});
render(<ModelOnboardingModal onComplete={vi.fn()} addToast={vi.fn()} projectId="proj_123" />);
await waitFor(() => {
expect(screen.getByText("Login")).toBeTruthy();
});
fireEvent.click(screen.getByText("Login"));
await waitFor(() => {
expect(screen.getByTestId("onboarding-login-instructions-anthropic").textContent).toContain("WXYZ-9876");
});
fireEvent.click(screen.getByText("Cancel"));
await waitFor(() => {
expect(screen.queryByTestId("onboarding-login-instructions-anthropic")).toBeNull();
});
});
it("shows GitHub login instructions during connect attempts", async () => {
mockFetchAuthStatus.mockImplementation(() => Promise.resolve({
providers: [
{ id: "anthropic", name: "Anthropic", authenticated: false, type: "oauth" },
{ id: "github", name: "GitHub", authenticated: false, type: "oauth" },
],
}));
mockLoginProvider.mockImplementation((providerId: string) => {
if (providerId === "github") {
return Promise.resolve({
url: "https://github.com/login/device",
instructions: "Enter device code GH-2469 on github.com/login/device.",
});
}
return Promise.resolve({ url: "https://auth.example.com/login" });
});
render(<ModelOnboardingModal onComplete={vi.fn()} addToast={vi.fn()} projectId="proj_123" />);
await navigateToGitHubStep();
fireEvent.click(screen.getByRole("button", { name: /Connect/ }));
await waitFor(() => {
expect(screen.getByTestId("onboarding-login-instructions-github").textContent).toContain("GH-2469");
});
fireEvent.click(screen.getByText("Cancel"));
await waitFor(() => {
expect(screen.queryByTestId("onboarding-login-instructions-github")).toBeNull();
});
});
it("login failure shows error toast and sets outcome to failed", async () => {
mockLoginProvider.mockRejectedValueOnce(new Error("Login failed: Invalid credentials"));