File size: 2,337 Bytes
9b906ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { useQueries } from "@tanstack/react-query";
import { useActiveBackendContext } from "#/contexts/active-backend-context";
import {
  getCloudOrganizations,
  getCurrentCloudApiKey,
} from "#/api/cloud/organization-service.api";
import type { Backend } from "#/api/backend-registry/types";

/**
 * Fetch organizations for every registered cloud backend in parallel.
 *
 * Used by the BackendSelector to flatten each cloud backend into per-org
 * rows. Each query is keyed by the backend ID so React Query caches
 * responses independently and a switch (which clears the cache) refetches.
 */
export function useAllCloudOrganizations() {
  const { backends } = useActiveBackendContext();
  const cloudBackends = backends.filter((b) => b.kind === "cloud");

  const queries = useQueries({
    queries: cloudBackends.map((backend) => ({
      queryKey: [
        "cloud-organizations",
        backend.id,
        backend.connectionRevision ?? 0,
      ],
      // Filter the user's full org membership down to the single org the
      // backend's API key is bound to. The cloud enforces one-key-one-org
      // server-side (HTTP 403 otherwise); without this filter the
      // selector would advertise orgs the key cannot use. Legacy keys
      // with no binding fall through unfiltered.
      queryFn: async () => {
        const orgs = await getCloudOrganizations(backend);
        if (backend.authMode === "cookie") return orgs;

        const key = await getCurrentCloudApiKey(backend);
        if (key.isLegacyKey || key.orgId === null) return orgs;
        return {
          ...orgs,
          items: orgs.items.filter((o) => o.id === key.orgId),
        };
      },
      staleTime: 1000 * 60 * 5,
      retry: false,
      meta: { disableToast: true },
    })),
  });

  // Map backend id -> result to make consumers easy to read.
  const byBackendId: Record<
    string,
    {
      backend: Backend;
      isLoading: boolean;
      orgs: { id: string; name: string; is_personal?: boolean }[];
      currentOrgId: string | null;
    }
  > = {};
  cloudBackends.forEach((backend, index) => {
    const q = queries[index];
    byBackendId[backend.id] = {
      backend,
      isLoading: q.isLoading,
      orgs: q.data?.items ?? [],
      currentOrgId: q.data?.currentOrgId ?? null,
    };
  });

  return byBackendId;
}