fix(ui): scope useAllTeams to caller for non-admins so key list shows team budgets

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Devin AI 2026-07-31 20:05:50 +00:00
parent fa56283806
commit fe3d2fe00e
2 changed files with 44 additions and 6 deletions

View file

@ -855,6 +855,36 @@ describe("useAllTeams", () => {
expect(fetchMock).toHaveBeenCalledTimes(1);
});
it("omits user_id for admins so every team is returned", async () => {
fetchMock.mockResolvedValue(pageResponse(mockTeams, 1, 1));
const { result } = renderHook(() => useAllTeams(), { wrapper });
await waitFor(() => expect(result.current.isSuccess).toBe(true));
const url = fetchMock.mock.calls[0][0] as string;
expect(new URLSearchParams(url.split("?")[1]).get("user_id")).toBeNull();
});
it("scopes to the caller's user_id for non-admins so /v2/team/list does not 401", async () => {
mockUseAuthorized.mockReturnValue({
accessToken: "test-access-token",
userId: "test-user-id",
userRole: "Internal User",
token: "test-token",
userEmail: "test@example.com",
premiumUser: false,
disabledPersonalKeyCreation: null,
showSSOBanner: false,
});
fetchMock.mockResolvedValue(pageResponse(mockTeams, 1, 1));
const { result } = renderHook(() => useAllTeams(), { wrapper });
await waitFor(() => expect(result.current.isSuccess).toBe(true));
const url = fetchMock.mock.calls[0][0] as string;
expect(new URLSearchParams(url.split("?")[1]).get("user_id")).toBe("test-user-id");
});
it("does not execute when accessToken is missing", () => {
mockUseAuthorized.mockReturnValue({
accessToken: null,

View file

@ -114,24 +114,32 @@ export const useTeams = (): UseQueryResult<Team[]> => {
const ALL_TEAMS_PAGE_SIZE = 100;
const fetchAllTeamsPaged = async (accessToken: string): Promise<Team[]> => {
const firstPage: TeamsResponse = await teamListCall(accessToken, 1, ALL_TEAMS_PAGE_SIZE);
const fetchAllTeamsPaged = async (accessToken: string, userID?: string | null): Promise<Team[]> => {
const options: TeamListCallOptions = { userID: userID ?? undefined };
const firstPage: TeamsResponse = await teamListCall(accessToken, 1, ALL_TEAMS_PAGE_SIZE, options);
const totalPages = firstPage.total_pages ?? 1;
if (totalPages <= 1) return firstPage.teams;
const remainingPages: TeamsResponse[] = await Promise.all(
Array.from({ length: totalPages - 1 }, (_, i) => teamListCall(accessToken, i + 2, ALL_TEAMS_PAGE_SIZE)),
Array.from({ length: totalPages - 1 }, (_, i) => teamListCall(accessToken, i + 2, ALL_TEAMS_PAGE_SIZE, options)),
);
return [firstPage, ...remainingPages].flatMap((page) => page.teams);
};
export const useAllTeams = (): UseQueryResult<Team[]> => {
const { accessToken } = useAuthorized();
const { accessToken, userId, userRole } = useAuthorized();
const isAdmin = userRole === "Admin" || userRole === "Admin Viewer";
const scopedUserId = isAdmin ? null : userId;
return useQuery<Team[]>({
queryKey: teamKeys.list({
filters: { scope: "all", pageSize: ALL_TEAMS_PAGE_SIZE, accessToken: accessToken ?? "" },
filters: {
scope: "all",
pageSize: ALL_TEAMS_PAGE_SIZE,
accessToken: accessToken ?? "",
userId: scopedUserId ?? "",
},
}),
queryFn: async () => await fetchAllTeamsPaged(accessToken!),
queryFn: async () => await fetchAllTeamsPaged(accessToken!, scopedUserId),
enabled: Boolean(accessToken),
staleTime: 30000,
});