mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 05:37:20 +08:00
Fix: Prevent auto-logout on 401 errors in oss mode (#13466)
This commit is contained in:
@@ -156,11 +156,19 @@ describe("UserContextMenu", () => {
|
||||
useSelectedOrganizationStore.setState({ organizationId: null });
|
||||
});
|
||||
|
||||
it("should render the default context items for a user", () => {
|
||||
it("should render the default context items for a user", async () => {
|
||||
vi.spyOn(OptionService, "getConfig").mockResolvedValue(
|
||||
createMockWebClientConfig({ app_mode: "saas" }),
|
||||
);
|
||||
|
||||
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
|
||||
|
||||
screen.getByTestId("org-selector");
|
||||
screen.getByText("ACCOUNT_SETTINGS$LOGOUT");
|
||||
|
||||
// Wait for config to load so logout button appears
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("ACCOUNT_SETTINGS$LOGOUT")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.queryByText("ORG$INVITE_ORG_MEMBERS"),
|
||||
@@ -304,6 +312,20 @@ describe("UserContextMenu", () => {
|
||||
screen.queryByText("Organization Members"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should not display logout button in OSS mode", async () => {
|
||||
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
|
||||
|
||||
// Wait for the config to load
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("SETTINGS$NAV_LLM")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Verify logout button is NOT rendered in OSS mode
|
||||
expect(
|
||||
screen.queryByText("ACCOUNT_SETTINGS$LOGOUT"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("HIDE_LLM_SETTINGS feature flag", () => {
|
||||
@@ -382,10 +404,15 @@ describe("UserContextMenu", () => {
|
||||
});
|
||||
|
||||
it("should call the logout handler when Logout is clicked", async () => {
|
||||
vi.spyOn(OptionService, "getConfig").mockResolvedValue(
|
||||
createMockWebClientConfig({ app_mode: "saas" }),
|
||||
);
|
||||
|
||||
const logoutSpy = vi.spyOn(AuthService, "logout");
|
||||
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
|
||||
|
||||
const logoutButton = screen.getByText("ACCOUNT_SETTINGS$LOGOUT");
|
||||
// Wait for config to load so logout button appears
|
||||
const logoutButton = await screen.findByText("ACCOUNT_SETTINGS$LOGOUT");
|
||||
await userEvent.click(logoutButton);
|
||||
|
||||
expect(logoutSpy).toHaveBeenCalledOnce();
|
||||
@@ -488,6 +515,10 @@ describe("UserContextMenu", () => {
|
||||
});
|
||||
|
||||
it("should call the onClose handler after each action", async () => {
|
||||
vi.spyOn(OptionService, "getConfig").mockResolvedValue(
|
||||
createMockWebClientConfig({ app_mode: "saas" }),
|
||||
);
|
||||
|
||||
// Mock a team org so org management buttons are visible
|
||||
vi.spyOn(organizationService, "getOrganizations").mockResolvedValue({
|
||||
items: [MOCK_TEAM_ORG_ACME],
|
||||
@@ -497,7 +528,8 @@ describe("UserContextMenu", () => {
|
||||
const onCloseMock = vi.fn();
|
||||
renderUserContextMenu({ type: "owner", onClose: onCloseMock, onOpenInviteModal: vi.fn });
|
||||
|
||||
const logoutButton = screen.getByText("ACCOUNT_SETTINGS$LOGOUT");
|
||||
// Wait for config to load so logout button appears
|
||||
const logoutButton = await screen.findByText("ACCOUNT_SETTINGS$LOGOUT");
|
||||
await userEvent.click(logoutButton);
|
||||
expect(onCloseMock).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
||||
@@ -156,13 +156,16 @@ export function UserContextMenu({
|
||||
{t(I18nKey.SIDEBAR$DOCS)}
|
||||
</a>
|
||||
|
||||
<ContextMenuListItem
|
||||
onClick={handleLogout}
|
||||
className={contextMenuListItemClassName}
|
||||
>
|
||||
<IoLogOutOutline className="text-white" size={16} />
|
||||
{t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
|
||||
</ContextMenuListItem>
|
||||
{/* Only show logout in saas mode - oss mode has no session to invalidate */}
|
||||
{isSaasMode && (
|
||||
<ContextMenuListItem
|
||||
onClick={handleLogout}
|
||||
className={contextMenuListItemClassName}
|
||||
>
|
||||
<IoLogOutOutline className="text-white" size={16} />
|
||||
{t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
|
||||
</ContextMenuListItem>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,13 +35,14 @@ export const useGitUser = () => {
|
||||
}
|
||||
}, [user.data]);
|
||||
|
||||
// If we get a 401 here, it means that the integration tokens need to be
|
||||
// In saas mode, a 401 means that the integration tokens need to be
|
||||
// refreshed. Since this happens at login, we log out.
|
||||
// In oss mode, skip auto-logout since there's no token refresh mechanism
|
||||
React.useEffect(() => {
|
||||
if (user?.error?.response?.status === 401) {
|
||||
if (user?.error?.response?.status === 401 && config?.app_mode === "saas") {
|
||||
logout.mutate();
|
||||
}
|
||||
}, [user.status]);
|
||||
}, [user.status, config?.app_mode]);
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user