fix(webui): polish responsive layout

This commit is contained in:
chengyongru
2026-07-23 18:22:02 +08:00
committed by chengyongru
parent 4b1547db7d
commit 6c0f151f6e
20 changed files with 372 additions and 80 deletions
+7 -4
View File
@@ -1608,8 +1608,8 @@ describe("App layout", () => {
expect(screen.queryByTestId("overview-logo-nanobot-workspace")).not.toBeInTheDocument();
expect(screen.queryByRole("navigation", { name: "Sidebar navigation" })).not.toBeInTheDocument();
const settingsNav = screen.getByRole("navigation", { name: "Settings sections" });
expect(settingsNav.className).toContain("overflow-x-auto");
expect(settingsNav.className).not.toContain("grid-cols-2");
expect(settingsNav.className).not.toContain("overflow-x-auto");
expect(within(settingsNav).getByRole("button", { name: "Settings: Overview" })).toBeInTheDocument();
expect(within(settingsNav).getByRole("button", { name: "Overview" })).toHaveAttribute(
"aria-current",
"page",
@@ -1622,10 +1622,13 @@ describe("App layout", () => {
expect(within(settingsNav).queryByRole("button", { name: "Apps" })).not.toBeInTheDocument();
expect(within(settingsNav).getByRole("button", { name: "Security" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Sign out" })).toBeInTheDocument();
fireEvent.click(within(settingsNav).getByRole("button", { name: "Appearance" }));
fireEvent.pointerDown(within(settingsNav).getByRole("button", { name: "Settings: Overview" }));
fireEvent.click(await screen.findByRole("menuitem", { name: "Appearance" }));
expect(screen.getByText("Brand logos")).toBeInTheDocument();
expect(screen.getByRole("switch", { name: "Brand logos" })).toBeInTheDocument();
fireEvent.click(within(settingsNav).getByRole("button", { name: "Models" }));
expect(within(settingsNav).getByRole("button", { name: "Settings: Appearance" })).toBeInTheDocument();
fireEvent.pointerDown(within(settingsNav).getByRole("button", { name: "Settings: Appearance" }));
fireEvent.click(await screen.findByRole("menuitem", { name: "Models" }));
expect(screen.queryByText("AI")).not.toBeInTheDocument();
expect(screen.getByText("Current configuration")).toBeInTheDocument();
expect(screen.queryByText("Presets")).not.toBeInTheDocument();
+4 -1
View File
@@ -1365,7 +1365,10 @@ describe("SettingsView Apps catalog", () => {
renderSettingsView({ initialSection: "channels" });
const emailRow = await screen.findByRole("button", { name: "View Email settings" });
expect(screen.getByPlaceholderText("Search channels")).toBeInTheDocument();
expect(screen.getByPlaceholderText("Search channels")).toHaveClass(
"focus-visible:ring-0",
"focus-visible:ring-offset-0",
);
expect(screen.queryByRole("switch", { name: "Email channel" })).not.toBeInTheDocument();
fireEvent.click(emailRow);
+29 -1
View File
@@ -726,7 +726,7 @@ describe("ThreadComposer", () => {
/>,
);
fireEvent.pointerDown(screen.getByRole("button", { name: "Workspace access mode" }));
fireEvent.pointerDown(screen.getByRole("button", { name: /Workspace access mode/ }));
fireEvent.click(await screen.findByRole("menuitem", { name: /Full Access/ }));
expect(onWorkspaceScopeChange).toHaveBeenCalledWith(
@@ -738,6 +738,34 @@ describe("ThreadComposer", () => {
);
});
it("exposes full and compact workspace labels for container-driven compression", () => {
render(
<ThreadComposer
onSend={vi.fn()}
placeholder="Type your message..."
variant="hero"
workspaceScope={{
project_path: "/tmp/project",
project_name: "project",
access_mode: "full",
restrict_to_workspace: false,
}}
workspaceControls={{ can_change_project: true, can_use_full_access: true }}
onWorkspaceScopeChange={vi.fn()}
/>,
);
const accessButton = screen.getByRole("button", {
name: "Workspace access mode: Full Access",
});
const fullLabel = within(accessButton).getByText("Full Access");
const shortLabel = within(accessButton).getByText("Full");
expect(accessButton).toHaveAttribute("title", "Full Access");
expect(fullLabel).toHaveClass("thread-composer-access-label-full");
expect(shortLabel).toHaveClass("thread-composer-access-label-short");
expect(shortLabel).toHaveClass("hidden");
});
it("keeps project selection as a compact composer dropdown", async () => {
const onWorkspaceScopeChange = vi.fn();
const defaultScope = {
+3 -1
View File
@@ -941,7 +941,9 @@ describe("ThreadShell", () => {
);
await act(async () => {});
expect(screen.getByText(HERO_GREETING_PATTERN)).toBeInTheDocument();
const greeting = screen.getByRole("heading", { level: 1, name: HERO_GREETING_PATTERN });
expect(greeting).toHaveAttribute("data-testid", "hero-greeting");
expect(greeting).toHaveClass("whitespace-nowrap");
expect(screen.getByPlaceholderText("Ask anything...")).toBeInTheDocument();
expect(screen.queryByRole("button", { name: "Write code" })).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: "Create a project plan" })).not.toBeInTheDocument();