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 });
|
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 });
|
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
|
||||||
|
|
||||||
screen.getByTestId("org-selector");
|
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(
|
expect(
|
||||||
screen.queryByText("ORG$INVITE_ORG_MEMBERS"),
|
screen.queryByText("ORG$INVITE_ORG_MEMBERS"),
|
||||||
@@ -304,6 +312,20 @@ describe("UserContextMenu", () => {
|
|||||||
screen.queryByText("Organization Members"),
|
screen.queryByText("Organization Members"),
|
||||||
).not.toBeInTheDocument();
|
).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", () => {
|
describe("HIDE_LLM_SETTINGS feature flag", () => {
|
||||||
@@ -382,10 +404,15 @@ describe("UserContextMenu", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should call the logout handler when Logout is clicked", async () => {
|
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");
|
const logoutSpy = vi.spyOn(AuthService, "logout");
|
||||||
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
|
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);
|
await userEvent.click(logoutButton);
|
||||||
|
|
||||||
expect(logoutSpy).toHaveBeenCalledOnce();
|
expect(logoutSpy).toHaveBeenCalledOnce();
|
||||||
@@ -488,6 +515,10 @@ describe("UserContextMenu", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should call the onClose handler after each action", async () => {
|
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
|
// Mock a team org so org management buttons are visible
|
||||||
vi.spyOn(organizationService, "getOrganizations").mockResolvedValue({
|
vi.spyOn(organizationService, "getOrganizations").mockResolvedValue({
|
||||||
items: [MOCK_TEAM_ORG_ACME],
|
items: [MOCK_TEAM_ORG_ACME],
|
||||||
@@ -497,7 +528,8 @@ describe("UserContextMenu", () => {
|
|||||||
const onCloseMock = vi.fn();
|
const onCloseMock = vi.fn();
|
||||||
renderUserContextMenu({ type: "owner", onClose: onCloseMock, onOpenInviteModal: 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);
|
await userEvent.click(logoutButton);
|
||||||
expect(onCloseMock).toHaveBeenCalledTimes(1);
|
expect(onCloseMock).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
|||||||
@@ -156,13 +156,16 @@ export function UserContextMenu({
|
|||||||
{t(I18nKey.SIDEBAR$DOCS)}
|
{t(I18nKey.SIDEBAR$DOCS)}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ContextMenuListItem
|
{/* Only show logout in saas mode - oss mode has no session to invalidate */}
|
||||||
onClick={handleLogout}
|
{isSaasMode && (
|
||||||
className={contextMenuListItemClassName}
|
<ContextMenuListItem
|
||||||
>
|
onClick={handleLogout}
|
||||||
<IoLogOutOutline className="text-white" size={16} />
|
className={contextMenuListItemClassName}
|
||||||
{t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
|
>
|
||||||
</ContextMenuListItem>
|
<IoLogOutOutline className="text-white" size={16} />
|
||||||
|
{t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
|
||||||
|
</ContextMenuListItem>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,13 +35,14 @@ export const useGitUser = () => {
|
|||||||
}
|
}
|
||||||
}, [user.data]);
|
}, [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.
|
// refreshed. Since this happens at login, we log out.
|
||||||
|
// In oss mode, skip auto-logout since there's no token refresh mechanism
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (user?.error?.response?.status === 401) {
|
if (user?.error?.response?.status === 401 && config?.app_mode === "saas") {
|
||||||
logout.mutate();
|
logout.mutate();
|
||||||
}
|
}
|
||||||
}, [user.status]);
|
}, [user.status, config?.app_mode]);
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user