Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/data/organizations/orgs-query.ts
2501 views
1
/**
2
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { useQuery, useQueryClient } from "@tanstack/react-query";
8
import { useCallback } from "react";
9
import { useLocation } from "react-router";
10
import { organizationClient } from "../../service/public-api";
11
import { useCurrentUser } from "../../user-context";
12
import { noPersistence } from "../setup";
13
import { Organization } from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
14
15
export function useOrganizationsInvalidator() {
16
const user = useCurrentUser();
17
18
const queryClient = useQueryClient();
19
return useCallback(() => {
20
console.log("Invalidating orgs... " + JSON.stringify(getQueryKey(user?.id)));
21
queryClient.invalidateQueries(getQueryKey(user?.id));
22
}, [user?.id, queryClient]);
23
}
24
25
export function useOrganizations() {
26
const user = useCurrentUser();
27
const query = useQuery<Organization[], Error>(
28
getQueryKey(user?.id),
29
async () => {
30
console.log("Fetching orgs... " + JSON.stringify(getQueryKey(user?.id)));
31
if (!user) {
32
console.log("useOrganizations with empty user");
33
return [];
34
}
35
36
const response = await organizationClient.listOrganizations({});
37
return response.organizations;
38
},
39
{
40
enabled: !!user,
41
cacheTime: 1000 * 60 * 60 * 1, // 1 hour
42
staleTime: 1000 * 60 * 60 * 1, // 1 hour
43
// We'll let an ErrorBoundary catch the error
44
useErrorBoundary: true,
45
},
46
);
47
return query;
48
}
49
50
function getQueryKey(userId?: string) {
51
return noPersistence(["organizations", userId]);
52
}
53
54
// Custom hook to return the current org if one is selected
55
export function useCurrentOrg(): { data?: Organization; isLoading: boolean } {
56
const location = useLocation();
57
const orgs = useOrganizations();
58
const user = useCurrentUser();
59
60
if (orgs.isLoading || !orgs.data || !user) {
61
return { data: undefined, isLoading: true };
62
}
63
let orgId = localStorage.getItem("active-org");
64
let org: Organization | undefined = undefined;
65
if (orgId) {
66
org = orgs.data.find((org) => org.id === orgId);
67
}
68
69
// 1. Check for org slug
70
const orgSlugParam = getOrgSlugFromQuery(location.search);
71
if (orgSlugParam) {
72
org = orgs.data.find((org) => org.slug === orgSlugParam);
73
}
74
75
// 2. Check for org id
76
// id is more speficic than slug, so it takes precedence
77
const orgIdParam = new URLSearchParams(location.search).get("org");
78
if (orgIdParam) {
79
orgId = orgIdParam;
80
org = orgs.data.find((org) => org.id === orgId);
81
}
82
83
// 3. Fallback: pick the first org
84
if (!org) {
85
org = orgs.data[0];
86
}
87
88
// Persist the selected org
89
if (org) {
90
localStorage.setItem("active-org", org.id);
91
} else if (orgId && (orgs.isLoading || orgs.isStale)) {
92
// orgs are still fetching, but we have an orgId
93
localStorage.setItem("active-org", orgId);
94
} else {
95
localStorage.removeItem("active-org");
96
}
97
return { data: org, isLoading: false };
98
}
99
100
export function getOrgSlugFromQuery(search: string): string | undefined {
101
return new URLSearchParams(search).get("orgSlug") || undefined;
102
}
103
104