fix(webui): improve UX recovery and empty states (#5315)
This commit is contained in:
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user