Path: blob/main/components/dashboard/src/data/organizations/orgs-query.ts
2501 views
/**1* Copyright (c) 2023 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { useQuery, useQueryClient } from "@tanstack/react-query";7import { useCallback } from "react";8import { useLocation } from "react-router";9import { organizationClient } from "../../service/public-api";10import { useCurrentUser } from "../../user-context";11import { noPersistence } from "../setup";12import { Organization } from "@gitpod/public-api/lib/gitpod/v1/organization_pb";1314export function useOrganizationsInvalidator() {15const user = useCurrentUser();1617const queryClient = useQueryClient();18return useCallback(() => {19console.log("Invalidating orgs... " + JSON.stringify(getQueryKey(user?.id)));20queryClient.invalidateQueries(getQueryKey(user?.id));21}, [user?.id, queryClient]);22}2324export function useOrganizations() {25const user = useCurrentUser();26const query = useQuery<Organization[], Error>(27getQueryKey(user?.id),28async () => {29console.log("Fetching orgs... " + JSON.stringify(getQueryKey(user?.id)));30if (!user) {31console.log("useOrganizations with empty user");32return [];33}3435const response = await organizationClient.listOrganizations({});36return response.organizations;37},38{39enabled: !!user,40cacheTime: 1000 * 60 * 60 * 1, // 1 hour41staleTime: 1000 * 60 * 60 * 1, // 1 hour42// We'll let an ErrorBoundary catch the error43useErrorBoundary: true,44},45);46return query;47}4849function getQueryKey(userId?: string) {50return noPersistence(["organizations", userId]);51}5253// Custom hook to return the current org if one is selected54export function useCurrentOrg(): { data?: Organization; isLoading: boolean } {55const location = useLocation();56const orgs = useOrganizations();57const user = useCurrentUser();5859if (orgs.isLoading || !orgs.data || !user) {60return { data: undefined, isLoading: true };61}62let orgId = localStorage.getItem("active-org");63let org: Organization | undefined = undefined;64if (orgId) {65org = orgs.data.find((org) => org.id === orgId);66}6768// 1. Check for org slug69const orgSlugParam = getOrgSlugFromQuery(location.search);70if (orgSlugParam) {71org = orgs.data.find((org) => org.slug === orgSlugParam);72}7374// 2. Check for org id75// id is more speficic than slug, so it takes precedence76const orgIdParam = new URLSearchParams(location.search).get("org");77if (orgIdParam) {78orgId = orgIdParam;79org = orgs.data.find((org) => org.id === orgId);80}8182// 3. Fallback: pick the first org83if (!org) {84org = orgs.data[0];85}8687// Persist the selected org88if (org) {89localStorage.setItem("active-org", org.id);90} else if (orgId && (orgs.isLoading || orgs.isStale)) {91// orgs are still fetching, but we have an orgId92localStorage.setItem("active-org", orgId);93} else {94localStorage.removeItem("active-org");95}96return { data: org, isLoading: false };97}9899export function getOrgSlugFromQuery(search: string): string | undefined {100return new URLSearchParams(search).get("orgSlug") || undefined;101}102103104