fix(webui): improve UX recovery and empty states (#5315)

This commit is contained in:
chengyongru
2026-08-10 15:22:25 +08:00
committed by GitHub
parent 43511decc9
commit 71a99b0780
18 changed files with 755 additions and 231 deletions
+54
View File
@@ -350,6 +350,30 @@ function longPress(badge: HTMLElement, pointerId = 7) {
}
describe("ThreadComposer", () => {
it("locks an async send and keeps the draft when it is rejected", async () => {
let resolveSend!: (accepted: boolean) => void;
const onSend = vi.fn(() => new Promise<boolean>((resolve) => {
resolveSend = resolve;
}));
render(
<ThreadComposer
onSend={onSend}
placeholder="Type your message..."
/>,
);
const input = screen.getByLabelText("Message input");
fireEvent.change(input, { target: { value: "keep this pending draft" } });
fireEvent.click(screen.getByRole("button", { name: "Send message" }));
expect(input).toBeDisabled();
expect(screen.getByRole("button", { name: "Send message" })).toBeDisabled();
await act(async () => resolveSend(false));
await waitFor(() => expect(input).toBeEnabled());
expect(input).toHaveValue("keep this pending draft");
});
it("dismisses the touch keyboard after a successful send", async () => {
vi.stubGlobal("matchMedia", vi.fn((query: string) => ({
matches: query === "(hover: none) and (pointer: coarse)",
@@ -1113,6 +1137,36 @@ describe("ThreadComposer", () => {
}));
});
it.each([
["Windows", "D:\\Users\\test\\.nanobot\\workspace", "D:\\path\\to\\project"],
["macOS", "/Users/test/.nanobot/workspace", "/Users/name/project"],
["Linux", "/home/test/.nanobot/workspace", "/home/name/project"],
])("uses a %s path example for the project picker", async (_, projectPath, placeholder) => {
const user = userEvent.setup();
const defaultScope = {
project_path: projectPath,
project_name: "workspace",
access_mode: "restricted" as const,
restrict_to_workspace: true,
};
render(
<ThreadComposer
onSend={vi.fn()}
placeholder="Ask anything..."
variant="hero"
workspaceScope={defaultScope}
workspaceDefaultScope={defaultScope}
workspaceControls={{ can_change_project: true, can_use_full_access: true }}
onWorkspaceScopeChange={vi.fn()}
/>,
);
await user.click(screen.getByRole("button", { name: "Choose project" }));
expect(await screen.findByLabelText("Paste path")).toHaveAttribute("placeholder", placeholder);
});
it("slides project controls closed without offering a compact replacement", () => {
const defaultScope = {
project_path: "/Users/test/.nanobot/workspace",