diff --git a/frontend/__tests__/components/features/user/user-context-menu.test.tsx b/frontend/__tests__/components/features/user/user-context-menu.test.tsx index d02207b518..4ba98cdd86 100644 --- a/frontend/__tests__/components/features/user/user-context-menu.test.tsx +++ b/frontend/__tests__/components/features/user/user-context-menu.test.tsx @@ -54,7 +54,7 @@ describe("UserContextMenu", () => { }); it("should render the default context items for a user", () => { - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); screen.getByTestId("org-selector"); screen.getByText("ACCOUNT_SETTINGS$LOGOUT"); @@ -83,7 +83,7 @@ describe("UserContextMenu", () => { }, }); - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); // Wait for config to load and verify that navigation items are rendered (except organization-members/org which are filtered out) const expectedItems = SAAS_NAV_ITEMS.filter( @@ -99,14 +99,14 @@ describe("UserContextMenu", () => { }); it("should not display Organization Members menu item for regular users (filtered out)", () => { - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); // Organization Members is filtered out from nav items for all users expect(screen.queryByText("Organization Members")).not.toBeInTheDocument(); }); it("should render a documentation link", () => { - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); const docsLink = screen.getByText("SIDEBAR$DOCS").closest("a"); expect(docsLink).toHaveAttribute("href", "https://docs.openhands.dev"); @@ -131,7 +131,7 @@ describe("UserContextMenu", () => { }); it("should render OSS_NAV_ITEMS when in OSS mode", async () => { - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); // Wait for the config to load and OSS nav items to appear await waitFor(() => { @@ -147,7 +147,7 @@ describe("UserContextMenu", () => { }); it("should not display Organization Members menu item in OSS mode", async () => { - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); // Wait for the config to load await waitFor(() => { @@ -177,7 +177,7 @@ describe("UserContextMenu", () => { }, }); - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); await waitFor(() => { // Other nav items should still be visible @@ -204,7 +204,7 @@ describe("UserContextMenu", () => { }, }); - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); await waitFor(() => { expect( @@ -234,7 +234,7 @@ describe("UserContextMenu", () => { it("should call the logout handler when Logout is clicked", async () => { const logoutSpy = vi.spyOn(AuthService, "logout"); - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); const logoutButton = screen.getByText("ACCOUNT_SETTINGS$LOGOUT"); await userEvent.click(logoutButton); @@ -257,7 +257,7 @@ describe("UserContextMenu", () => { }, }); - renderUserContextMenu({ type: "user", onClose: vi.fn }); + renderUserContextMenu({ type: "member", onClose: vi.fn }); // Wait for config to load and test a few representative nav items have the correct href await waitFor(() => { @@ -298,7 +298,7 @@ describe("UserContextMenu", () => { it("should call the onClose handler when clicking outside the context menu", async () => { const onCloseMock = vi.fn(); - renderUserContextMenu({ type: "user", onClose: onCloseMock }); + renderUserContextMenu({ type: "member", onClose: onCloseMock }); const contextMenu = screen.getByTestId("user-context-menu"); await userEvent.click(contextMenu); @@ -350,7 +350,7 @@ describe("UserContextMenu", () => { test("the user can change orgs", async () => { const onCloseMock = vi.fn(); - renderUserContextMenu({ type: "user", onClose: onCloseMock }); + renderUserContextMenu({ type: "member", onClose: onCloseMock }); const orgSelector = screen.getByTestId("org-selector"); expect(orgSelector).toBeInTheDocument(); @@ -369,7 +369,7 @@ describe("UserContextMenu", () => { it("should have Personal Account as the default selected option with null value", async () => { const onCloseMock = vi.fn(); - renderUserContextMenu({ type: "user", onClose: onCloseMock }); + renderUserContextMenu({ type: "member", onClose: onCloseMock }); const orgSelector = screen.getByTestId("org-selector"); diff --git a/frontend/__tests__/routes/manage-org.test.tsx b/frontend/__tests__/routes/manage-org.test.tsx index cfbf1d91ac..9501f5965d 100644 --- a/frontend/__tests__/routes/manage-org.test.tsx +++ b/frontend/__tests__/routes/manage-org.test.tsx @@ -95,7 +95,7 @@ describe("Manage Org Route", () => { org_id: string; user_id: string; email: string; - role: "owner" | "admin" | "user"; + role: "owner" | "admin" | "member"; llm_api_key: string; max_iterations: number; llm_model: string; @@ -680,9 +680,9 @@ describe("Manage Org Route", () => { expect(deleteButton).not.toBeDisabled(); }); - it.each<{ role: "admin" | "user"; roleName: string }>([ + it.each<{ role: "admin" | "member"; roleName: string }>([ { role: "admin", roleName: "Admin" }, - { role: "user", roleName: "User" }, + { role: "member", roleName: "Member" }, ])( "should not show delete organization button when user lacks canDeleteOrganization permission ($roleName role)", async ({ role }) => { diff --git a/frontend/__tests__/routes/manage-organization-members.test.tsx b/frontend/__tests__/routes/manage-organization-members.test.tsx index 4e39a15722..55f82a4d0a 100644 --- a/frontend/__tests__/routes/manage-organization-members.test.tsx +++ b/frontend/__tests__/routes/manage-organization-members.test.tsx @@ -39,7 +39,7 @@ const RouteStub = createRoutesStub([ }, { Component: () =>
, - path: "/settings/user", + path: "/settings/member", }, ], }, @@ -147,7 +147,7 @@ describe("Manage Organization Members Route", () => { org_id: string; user_id: string; email: string; - role: "owner" | "admin" | "user"; + role: "owner" | "admin" | "member"; llm_api_key: string; max_iterations: number; llm_model: string; @@ -173,7 +173,7 @@ describe("Manage Organization Members Route", () => { org_id: string; user_id: string; email: string; - role: "owner" | "admin" | "user"; + role: "owner" | "admin" | "member"; llm_api_key: string; max_iterations: number; llm_model: string; @@ -222,7 +222,7 @@ describe("Manage Organization Members Route", () => { const expectAllRoleOptionsPresent = (dropdown: HTMLElement) => { expect(within(dropdown).getByText(/owner/i)).toBeInTheDocument(); expect(within(dropdown).getByText(/admin/i)).toBeInTheDocument(); - expect(within(dropdown).getByText(/user/i)).toBeInTheDocument(); + expect(within(dropdown).getByText(/member/i)).toBeInTheDocument(); }; // Helper function to close dropdown by clicking outside @@ -305,11 +305,11 @@ describe("Manage Organization Members Route", () => { const memberListItems = await screen.findAllByTestId("member-item"); const userRoleMember = memberListItems[2]; // third member is "user" - let userCombobox = within(userRoleMember).getByText(/^User$/i); + let userCombobox = within(userRoleMember).getByText(/^Member$/i); expect(userCombobox).toBeInTheDocument(); // Change role from user to admin - await changeMemberRole(userRoleMember, "user", "admin"); + await changeMemberRole(userRoleMember, "member", "admin"); expect(updateMemberRoleSpy).toHaveBeenCalledExactlyOnceWith({ userId: "3", // assuming the third member is the one being updated @@ -323,16 +323,16 @@ describe("Manage Organization Members Route", () => { expect(userCombobox).toBeInTheDocument(); // Revert the role back to user - await changeMemberRole(userRoleMember, "admin", "user"); + await changeMemberRole(userRoleMember, "admin", "member"); expect(updateMemberRoleSpy).toHaveBeenNthCalledWith(2, { userId: "3", orgId: "1", - role: "user", + role: "member", }); // Verify the role has been reverted in the UI - userCombobox = within(userRoleMember).getByText(/^User$/i); + userCombobox = within(userRoleMember).getByText(/^Member$/i); expect(userCombobox).toBeInTheDocument(); }); @@ -410,7 +410,7 @@ describe("Manage Organization Members Route", () => { const userEmail = within(userRoleMember).getByText("charlie@acme.org"); expect(userEmail).toBeInTheDocument(); - const userCombobox = within(userRoleMember).getByText(/^User$/i); + const userCombobox = within(userRoleMember).getByText(/^Member$/i); await userEvent.click(userCombobox); const dropdown = within(userRoleMember).getByTestId( @@ -487,7 +487,7 @@ describe("Manage Organization Members Route", () => { org_id: "1", user_id: "4", email: "tom@acme.org", - role: "user", + role: "member", llm_api_key: "**********", max_iterations: 20, llm_model: "gpt-4", @@ -510,7 +510,7 @@ describe("Manage Organization Members Route", () => { expect(invitedBadge).toBeInTheDocument(); // should not have a role combobox - await userEvent.click(within(invitedMember).getByText(/^User$/i)); + await userEvent.click(within(invitedMember).getByText(/^Member$/i)); expect( within(invitedMember).queryByTestId( "organization-member-role-context-menu", @@ -553,7 +553,7 @@ describe("Manage Organization Members Route", () => { org_id: "1", user_id: "1", email: "test@example.com", - role: "user" as const, + role: "member" as const, llm_api_key: "**********", max_iterations: 20, llm_model: "gpt-4", @@ -638,7 +638,7 @@ describe("Manage Organization Members Route", () => { // Test with user member const userMember = await findMemberByEmail("charlie@acme.org"); - const userDropdown = await openRoleDropdown(userMember, "user"); + const userDropdown = await openRoleDropdown(userMember, "member"); // Verify all three role options are present for user member expectAllRoleOptionsPresent(userDropdown); @@ -665,7 +665,7 @@ describe("Manage Organization Members Route", () => { // Check user member dropdown const userMember = memberListItems[2]; // user member - const userDropdown = await openRoleDropdown(userMember, "user"); + const userDropdown = await openRoleDropdown(userMember, "member"); expectOwnerOptionNotPresent(userDropdown); await closeDropdown(); @@ -674,7 +674,7 @@ describe("Manage Organization Members Route", () => { const anotherUserMember = memberListItems[3]; // another user member const anotherUserDropdown = await openRoleDropdown( anotherUserMember, - "user", + "member", ); expectOwnerOptionNotPresent(anotherUserDropdown); } @@ -713,7 +713,7 @@ describe("Manage Organization Members Route", () => { // Test changing user to owner const userMember = await findMemberByEmail("charlie@acme.org"); - await changeMemberRole(userMember, "user", "owner"); + await changeMemberRole(userMember, "member", "owner"); expect(updateMemberRoleSpy).toHaveBeenNthCalledWith(2, { userId: "3", @@ -765,16 +765,16 @@ describe("Manage Organization Members Route", () => { }, orgIndex: 2, // org 3 memberEmail: "stephan@all-hands.dev", - currentRole: "user", - newRole: "user", + currentRole: "member", + newRole: "member", expectedApiCall: { userId: "9", orgId: "3", - role: "user" as const, + role: "member" as const, }, }, { - description: "Admin should be able to change user's role to admin", + description: "Admin should be able to change member's role to admin", userData: { org_id: "3", user_id: "7", // Ray is admin in org 3 @@ -789,7 +789,7 @@ describe("Manage Organization Members Route", () => { }, orgIndex: 2, // org 3 memberEmail: "stephan@all-hands.dev", - currentRole: "user", + currentRole: "member", newRole: "admin", expectedApiCall: { userId: "9", diff --git a/frontend/src/components/features/org/organization-member-list-item.tsx b/frontend/src/components/features/org/organization-member-list-item.tsx index fd5155a62d..4882bf5187 100644 --- a/frontend/src/components/features/org/organization-member-list-item.tsx +++ b/frontend/src/components/features/org/organization-member-list-item.tsx @@ -51,12 +51,14 @@ export function OrganizationMemberListItem({ > {email} + {status === "invited" && ( {t(I18nKey.ORG$STATUS_INVITED)} )} +