mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-01-07 22:14:03 -05:00
hotfix(frontend): org naming consistency (#12164)
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import { within, screen, render } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
|
||||
import { organizationService } from "#/api/organization-service/organization-service.api";
|
||||
import { InviteOrganizationMemberModal } from "#/components/features/org/invite-organization-member-modal";
|
||||
import { useSelectedOrganizationStore } from "#/stores/selected-organization-store";
|
||||
|
||||
vi.mock("react-router", () => ({
|
||||
useRevalidator: vi.fn(() => ({ revalidate: vi.fn() })),
|
||||
}));
|
||||
|
||||
const renderInviteOrganizationMemberModal = (config?: {
|
||||
onClose: () => void;
|
||||
@@ -19,16 +24,14 @@ const renderInviteOrganizationMemberModal = (config?: {
|
||||
},
|
||||
);
|
||||
|
||||
vi.mock("#/context/use-selected-organization", () => ({
|
||||
useSelectedOrganizationId: vi.fn(() => ({
|
||||
orgId: "1",
|
||||
setOrgId: vi.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
describe("InviteOrganizationMemberModal", () => {
|
||||
beforeEach(() => {
|
||||
useSelectedOrganizationStore.setState({ organizationId: "1" });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
useSelectedOrganizationStore.setState({ organizationId: null });
|
||||
});
|
||||
|
||||
it("should call onClose the modal when the close button is clicked", async () => {
|
||||
|
||||
@@ -3,35 +3,35 @@ import { describe, expect, it } from "vitest";
|
||||
import { useSelectedOrganizationStore } from "#/stores/selected-organization-store";
|
||||
|
||||
describe("useSelectedOrganizationStore", () => {
|
||||
it("should have null as initial orgId", () => {
|
||||
it("should have null as initial organizationId", () => {
|
||||
const { result } = renderHook(() => useSelectedOrganizationStore());
|
||||
expect(result.current.orgId).toBeNull();
|
||||
expect(result.current.organizationId).toBeNull();
|
||||
});
|
||||
|
||||
it("should update orgId when setOrgId is called", () => {
|
||||
it("should update organizationId when setOrganizationId is called", () => {
|
||||
const { result } = renderHook(() => useSelectedOrganizationStore());
|
||||
|
||||
act(() => {
|
||||
result.current.setOrgId("org-123");
|
||||
result.current.setOrganizationId("org-123");
|
||||
});
|
||||
|
||||
expect(result.current.orgId).toBe("org-123");
|
||||
expect(result.current.organizationId).toBe("org-123");
|
||||
});
|
||||
|
||||
it("should allow setting orgId to null", () => {
|
||||
it("should allow setting organizationId to null", () => {
|
||||
const { result } = renderHook(() => useSelectedOrganizationStore());
|
||||
|
||||
act(() => {
|
||||
result.current.setOrgId("org-123");
|
||||
result.current.setOrganizationId("org-123");
|
||||
});
|
||||
|
||||
expect(result.current.orgId).toBe("org-123");
|
||||
expect(result.current.organizationId).toBe("org-123");
|
||||
|
||||
act(() => {
|
||||
result.current.setOrgId(null);
|
||||
result.current.setOrganizationId(null);
|
||||
});
|
||||
|
||||
expect(result.current.orgId).toBeNull();
|
||||
expect(result.current.organizationId).toBeNull();
|
||||
});
|
||||
|
||||
it("should share state across multiple hook instances", () => {
|
||||
@@ -43,9 +43,9 @@ describe("useSelectedOrganizationStore", () => {
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result1.current.setOrgId("shared-org");
|
||||
result1.current.setOrganizationId("shared-organization");
|
||||
});
|
||||
|
||||
expect(result2.current.orgId).toBe("shared-org");
|
||||
expect(result2.current.organizationId).toBe("shared-organization");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ export function SettingsNavigation({
|
||||
onCloseMobileMenu,
|
||||
navigationItems,
|
||||
}: SettingsNavigationProps) {
|
||||
const { orgId, setOrgId } = useSelectedOrganizationId();
|
||||
const { organizationId, setOrganizationId } = useSelectedOrganizationId();
|
||||
const { data: organizations } = useOrganizations();
|
||||
const { data: me } = useMe();
|
||||
|
||||
@@ -56,7 +56,7 @@ export function SettingsNavigation({
|
||||
testId="org-select"
|
||||
name="organization"
|
||||
placeholder="Please select an organization"
|
||||
selectedKey={orgId || ""}
|
||||
selectedKey={organizationId || ""}
|
||||
items={
|
||||
organizations?.map((org) => ({
|
||||
key: org.id,
|
||||
@@ -65,9 +65,9 @@ export function SettingsNavigation({
|
||||
}
|
||||
onSelectionChange={(org) => {
|
||||
if (org) {
|
||||
setOrgId(org.toString());
|
||||
setOrganizationId(org.toString());
|
||||
} else {
|
||||
setOrgId(null);
|
||||
setOrganizationId(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -96,7 +96,7 @@ export function SettingsNavigation({
|
||||
if (
|
||||
(navItem.to === "/settings/org-members" ||
|
||||
navItem.to === "/settings/org") &&
|
||||
(isUser || !orgId)
|
||||
(isUser || !organizationId)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ interface UserContextMenuProps {
|
||||
export function UserContextMenu({ type, onClose }: UserContextMenuProps) {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { orgId, setOrgId } = useSelectedOrganizationId();
|
||||
const { organizationId, setOrganizationId } = useSelectedOrganizationId();
|
||||
const { data: organizations } = useOrganizations();
|
||||
const { mutate: logout } = useLogout();
|
||||
const ref = useClickOutsideElement<HTMLDivElement>(onClose);
|
||||
@@ -100,7 +100,7 @@ export function UserContextMenu({ type, onClose }: UserContextMenuProps) {
|
||||
testId="org-selector"
|
||||
name="organization"
|
||||
placeholder="Please select an organization"
|
||||
selectedKey={orgId || "personal"}
|
||||
selectedKey={organizationId || "personal"}
|
||||
items={[
|
||||
{ key: "personal", label: "Personal Account" },
|
||||
...(organizations?.map((org) => ({
|
||||
@@ -110,11 +110,11 @@ export function UserContextMenu({ type, onClose }: UserContextMenuProps) {
|
||||
]}
|
||||
onSelectionChange={(org) => {
|
||||
if (org === "personal") {
|
||||
setOrgId(null);
|
||||
setOrganizationId(null);
|
||||
} else if (org) {
|
||||
setOrgId(org.toString());
|
||||
setOrganizationId(org.toString());
|
||||
} else {
|
||||
setOrgId(null);
|
||||
setOrganizationId(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -3,14 +3,15 @@ import { useSelectedOrganizationStore } from "#/stores/selected-organization-sto
|
||||
|
||||
export const useSelectedOrganizationId = () => {
|
||||
const revalidator = useRevalidator();
|
||||
const { orgId, setOrgId: setOrgIdStore } = useSelectedOrganizationStore();
|
||||
const { organizationId, setOrganizationId: setOrganizationIdStore } =
|
||||
useSelectedOrganizationStore();
|
||||
|
||||
const setOrgId = (newOrgId: string | null) => {
|
||||
setOrgIdStore(newOrgId);
|
||||
const setOrganizationId = (newOrganizationId: string | null) => {
|
||||
setOrganizationIdStore(newOrganizationId);
|
||||
// Revalidate route to ensure the latest orgId is used.
|
||||
// This is useful for redirecting the user away from admin-only org pages.
|
||||
revalidator.revalidate();
|
||||
};
|
||||
|
||||
return { orgId, setOrgId };
|
||||
return { organizationId, setOrganizationId };
|
||||
};
|
||||
|
||||
@@ -6,16 +6,16 @@ import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
export const useDeleteOrganization = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
const { orgId, setOrgId } = useSelectedOrganizationId();
|
||||
const { organizationId, setOrganizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: () => {
|
||||
if (!orgId) throw new Error("Organization ID is required");
|
||||
return organizationService.deleteOrganization({ orgId });
|
||||
if (!organizationId) throw new Error("Organization ID is required");
|
||||
return organizationService.deleteOrganization({ orgId: organizationId });
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["organizations"] });
|
||||
setOrgId(null);
|
||||
setOrganizationId(null);
|
||||
navigate("/");
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,14 +4,14 @@ import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useInviteMembersBatch = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: ({ emails }: { emails: string[] }) =>
|
||||
organizationService.inviteMembers({ orgId: orgId!, emails }),
|
||||
organizationService.inviteMembers({ orgId: organizationId!, emails }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["organizations", "members", orgId],
|
||||
queryKey: ["organizations", "members", organizationId],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,14 +4,14 @@ import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useRemoveMember = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: ({ userId }: { userId: string }) =>
|
||||
organizationService.removeMember({ orgId: orgId!, userId }),
|
||||
organizationService.removeMember({ orgId: organizationId!, userId }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["organizations", "members", orgId],
|
||||
queryKey: ["organizations", "members", organizationId],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useUpdateMemberRole = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
@@ -15,11 +15,11 @@ export const useUpdateMemberRole = () => {
|
||||
userId: string;
|
||||
role: OrganizationUserRole;
|
||||
}) => {
|
||||
if (!orgId) {
|
||||
if (!organizationId) {
|
||||
throw new Error("Organization ID is required to update member role");
|
||||
}
|
||||
return organizationService.updateMember({
|
||||
orgId,
|
||||
orgId: organizationId,
|
||||
userId,
|
||||
role,
|
||||
});
|
||||
|
||||
@@ -4,15 +4,20 @@ import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useUpdateOrganization = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (name: string) => {
|
||||
if (!orgId) throw new Error("Organization ID is required");
|
||||
return organizationService.updateOrganization({ orgId, name });
|
||||
if (!organizationId) throw new Error("Organization ID is required");
|
||||
return organizationService.updateOrganization({
|
||||
orgId: organizationId,
|
||||
name,
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["organizations", orgId] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["organizations", organizationId],
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,13 +5,13 @@ import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useMe = () => {
|
||||
const { data: config } = useConfig();
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
const isSaas = config?.APP_MODE === "saas";
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["organizations", orgId, "me"],
|
||||
queryFn: () => organizationService.getMe({ orgId: orgId! }),
|
||||
enabled: isSaas && !!orgId,
|
||||
queryKey: ["organizations", organizationId, "me"],
|
||||
queryFn: () => organizationService.getMe({ orgId: organizationId! }),
|
||||
enabled: isSaas && !!organizationId,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,12 +3,12 @@ import { organizationService } from "#/api/organization-service/organization-ser
|
||||
import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useOrganizationMembers = () => {
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["organizations", "members", orgId],
|
||||
queryKey: ["organizations", "members", organizationId],
|
||||
queryFn: () =>
|
||||
organizationService.getOrganizationMembers({ orgId: orgId! }),
|
||||
enabled: !!orgId,
|
||||
organizationService.getOrganizationMembers({ orgId: organizationId! }),
|
||||
enabled: !!organizationId,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,12 +3,14 @@ import { organizationService } from "#/api/organization-service/organization-ser
|
||||
import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useOrganizationPaymentInfo = () => {
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["organizations", orgId, "payment"],
|
||||
queryKey: ["organizations", organizationId, "payment"],
|
||||
queryFn: () =>
|
||||
organizationService.getOrganizationPaymentInfo({ orgId: orgId! }),
|
||||
enabled: !!orgId,
|
||||
organizationService.getOrganizationPaymentInfo({
|
||||
orgId: organizationId!,
|
||||
}),
|
||||
enabled: !!organizationId,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,11 +3,12 @@ import { organizationService } from "#/api/organization-service/organization-ser
|
||||
import { useSelectedOrganizationId } from "#/context/use-selected-organization";
|
||||
|
||||
export const useOrganization = () => {
|
||||
const { orgId } = useSelectedOrganizationId();
|
||||
const { organizationId } = useSelectedOrganizationId();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["organizations", orgId],
|
||||
queryFn: () => organizationService.getOrganization({ orgId: orgId! }),
|
||||
enabled: !!orgId,
|
||||
queryKey: ["organizations", organizationId],
|
||||
queryFn: () =>
|
||||
organizationService.getOrganization({ orgId: organizationId! }),
|
||||
enabled: !!organizationId,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,29 +2,29 @@ import { create } from "zustand";
|
||||
import { devtools } from "zustand/middleware";
|
||||
|
||||
interface SelectedOrganizationState {
|
||||
orgId: string | null;
|
||||
organizationId: string | null;
|
||||
}
|
||||
|
||||
interface SelectedOrganizationActions {
|
||||
setOrgId: (orgId: string | null) => void;
|
||||
setOrganizationId: (orgId: string | null) => void;
|
||||
}
|
||||
|
||||
type SelectedOrganizationStore = SelectedOrganizationState &
|
||||
SelectedOrganizationActions;
|
||||
|
||||
const initialState: SelectedOrganizationState = {
|
||||
orgId: null,
|
||||
organizationId: null,
|
||||
};
|
||||
|
||||
export const useSelectedOrganizationStore = create<SelectedOrganizationStore>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
...initialState,
|
||||
setOrgId: (orgId) => set({ orgId }),
|
||||
setOrganizationId: (organizationId) => set({ organizationId }),
|
||||
}),
|
||||
{ name: "SelectedOrganizationStore" },
|
||||
),
|
||||
);
|
||||
|
||||
export const getSelectedOrganizationIdFromStore = (): string | null =>
|
||||
useSelectedOrganizationStore.getState().orgId;
|
||||
useSelectedOrganizationStore.getState().organizationId;
|
||||
|
||||
Reference in New Issue
Block a user