Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f1028f0
fix: simplify sidebar nav and add settings-focused rails
FraterCCCLXIII May 11, 2026
5cfed2a
fix: improve collapsed sidebar expand affordance
FraterCCCLXIII May 11, 2026
3c3107c
fix: refresh conversation panel filtering and sidebar visual separation
FraterCCCLXIII May 11, 2026
00622b2
fix: prevent conversation list horizontal overflow
FraterCCCLXIII May 11, 2026
f2abb9b
fix: refine sidebar conversation list layout and interactions
FraterCCCLXIII May 11, 2026
c8659dd
fix: simplify sidebar new conversation entry
FraterCCCLXIII May 11, 2026
273b31b
fix: align sidebar conversation header and new-link state
FraterCCCLXIII May 11, 2026
bf03df7
fix: tighten sidebar conversation list spacing
FraterCCCLXIII May 11, 2026
5d4b373
fix: align collapsed backend switcher with shared dropdown
FraterCCCLXIII May 11, 2026
b18c8b2
fix: show backend connection dot on collapsed server control
FraterCCCLXIII May 11, 2026
26dad10
fix: hide conversation rail items in collapsed sidebar
FraterCCCLXIII May 11, 2026
1142e8d
fix: align older-conversations menu with dropdown styles
FraterCCCLXIII May 11, 2026
96388be
fix: standardize conversation and backend dropdown color tokens
FraterCCCLXIII May 11, 2026
d7f0cc1
fix: make backend footer controls transparent at rest
FraterCCCLXIII May 11, 2026
08d4c53
fix: refine sidebar settings state and load-more styling
FraterCCCLXIII May 11, 2026
d546738
fix: remove extra indentation from settings sidebar tabs
FraterCCCLXIII May 11, 2026
45b8a60
fix: add matching left padding to chat layout container
FraterCCCLXIII May 11, 2026
3d725ab
fix: streamline and center home onboarding layout
FraterCCCLXIII May 11, 2026
809b91e
fix: restore collapsed settings navigation action
FraterCCCLXIII May 12, 2026
11b4712
feat(sidebar): open backend dropdown on hover in both collapsed and e…
FraterCCCLXIII May 12, 2026
827e5ec
fix(sidebar): add close delay so cursor can reach dropdown before it …
FraterCCCLXIII May 12, 2026
d936c7a
fix(sidebar): keep backend popover open on mouse-leave so modal click…
FraterCCCLXIII May 12, 2026
c590c19
fix(sidebar): lift modal state to Sidebar so Add/Manage Backend work …
FraterCCCLXIII May 13, 2026
2040209
fix(sidebar): restore missing AutomationsIcon import
FraterCCCLXIII May 13, 2026
fd86949
fix(sidebar): make collapsed backend popover dropdown actions work
FraterCCCLXIII May 13, 2026
b4634a0
fix(dropdown): wire hidden combobox trigger for collapsed nav
FraterCCCLXIII May 13, 2026
87a0b4c
refactor: resolve merge conflicts
hieptl May 14, 2026
3f34d4d
fix: lint
hieptl May 14, 2026
2c79644
fix: failing tests
hieptl May 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 10 additions & 76 deletions __tests__/components/backends/backend-selector.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
within,
} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { createRoutesStub, MemoryRouter, useParams } from "react-router";
import { createRoutesStub, MemoryRouter } from "react-router";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { __resetActiveStoreForTests } from "#/api/backend-registry/active-store";
import {
Expand Down Expand Up @@ -70,7 +70,11 @@ function TestSeed({
async function openDropdown() {
const user = userEvent.setup();
const wrapper = screen.getByTestId("backend-selector");
await user.click(within(wrapper).getByTestId("dropdown-trigger"));
// BackendSelector renders Dropdown with `openOnHover` while the trigger is
// visible — clicking the toggle button would open via hover and then
// immediately close via the click handler. Hovering the wrapper alone is
// enough to surface the menu.
await user.hover(wrapper);
return user;
}

Expand Down Expand Up @@ -421,80 +425,6 @@ describe("BackendSelector", () => {
expect(await screen.findByTestId("home")).toBeInTheDocument();
});

it("jumps to the target backend's most recently selected conversation when switching from a conversation route", async () => {
// Pre-seed two local backends and the per-backend "last selected"
// slot for the target. The BackendSelector reads the remembered
// slot synchronously during `onChange`, so the localStorage write
// has to happen before the snapshot is rebuilt.
const sourceBackendId = "source-local";
const targetBackendId = "target-local";
window.localStorage.setItem(
"openhands-backends",
JSON.stringify([
{
id: sourceBackendId,
name: "Source Local",
host: "http://localhost:9000",
apiKey: "k",
kind: "local",
},
{
id: targetBackendId,
name: "Local 1",
host: "http://localhost:9001",
apiKey: "k",
kind: "local",
},
]),
);
window.localStorage.setItem(
"openhands-active-backend",
JSON.stringify({ backendId: sourceBackendId, orgId: null }),
);
window.localStorage.setItem(
"openhands-last-conversation-by-backend",
JSON.stringify({ [targetBackendId]: "remembered-convo" }),
);
// Reset the in-memory snapshot so the seeded localStorage is read.
__resetActiveStoreForTests();

// One conversation route that renders the BackendSelector for the
// initial id and a probe div for the remembered id so we can
// observe the navigation target.
function ConversationRoute() {
const { conversationId } = useParams<{ conversationId: string }>();
if (conversationId === "remembered-convo") {
return <div data-testid="convo-route">{conversationId}</div>;
}
return <BackendSelector />;
}
function HomeRoute() {
return <div data-testid="home" />;
}
const RouterStub = createRoutesStub([
{ path: "/conversations/:conversationId", Component: ConversationRoute },
{ path: "/conversations", Component: HomeRoute },
]);
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
render(
<QueryClientProvider client={queryClient}>
<ActiveBackendProvider>
<RouterStub initialEntries={["/conversations/old-convo-on-A"]} />
</ActiveBackendProvider>
</QueryClientProvider>,
);

const user = await openDropdown();
await user.click(screen.getByText("Local 1"));

const convo = await screen.findByTestId("convo-route");
expect(convo).toHaveTextContent("remembered-convo");
// The home route should never have been visited.
expect(screen.queryByTestId("home")).not.toBeInTheDocument();
});

it("stays on the current page when switching backends from a non-conversation route", async () => {
function SettingsRoute() {
return (
Expand Down Expand Up @@ -802,6 +732,10 @@ describe("BackendSelector", () => {
</QueryClientProvider>,
);

const settingsButton = screen.getByTestId("backend-selector-settings-link");
expect(settingsButton.className).toContain("bg-[#1f1f1f99]");
expect(settingsButton.className).toContain("text-white");

const user = await openDropdown();
await user.click(screen.getByText("Local 1"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ describe("ConversationCard", () => {

within(card).getByText("Conversation 1");

// Just check that the card contains the expected text content
expect(card).toHaveTextContent("ago");

// Use a regex to match the time part since it might have whitespace
const timeRegex = new RegExp(
formatTimeDelta(new Date("2021-10-01T12:00:00Z")),
Expand Down
Loading
Loading