mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## Summary - Extracts `useUserProjectRegions` (org + project region aggregation, fail-open on fetch errors) and `useEmergencyIncidentOverride` (the `ongoingIncident` flag / env var check) out of `useStatusPageBannerVisibility`, so the upcoming incident.io status-page banner can reuse both without duplicating the org/project fan-out logic. - No behavior change for the legacy banner except one intentional fix: `StatusPageBanner.utils.ts` compared the incident's affected regions (lowercased) against the user's regions (not normalized), so a mixed-case region on either side could silently fail to match. Both sides now go through the same `normalizeRegion` helper. - Part of the Linear FE-4057 stack (PR 5a of 6). Base branch is PR 4 (`charis/fe-4057-pr4-project-creation-status-admonition`), not master. Linear: FE-4057 ## Test plan - [x] `pnpm --filter studio run typecheck` - [x] `pnpm --filter studio run lint:ratchet` - [x] `pnpm knip --workspace apps/studio` - [x] `pnpm test:prettier` - [x] `pnpm --filter studio exec vitest run` on the touched test files and the `hooks/misc/` and `components/layouts/AppLayout/` directories (all passing, no regressions) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved status banner targeting by matching incidents against normalized regions across the user’s projects. * Updated banner visibility checks to handle incomplete project or region data, including when project information fails to load. * Improved loading behavior so the banner can be evaluated based on user-region data rather than waiting for separate organization and project requests. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
68 lines
2.2 KiB
TypeScript
68 lines
2.2 KiB
TypeScript
import { useQueries, type UseQueryResult } from '@tanstack/react-query'
|
|
|
|
import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
|
|
import { projectKeys } from '@/data/projects/keys'
|
|
import {
|
|
getOrganizationProjects,
|
|
type OrgProjectsInfiniteData,
|
|
} from '@/data/projects/org-projects-infinite-query'
|
|
import { normalizeRegion, type UserRegionContext } from '@/lib/status-page/status-page.utils'
|
|
|
|
const PROJECTS_PAGE_LIMIT = 100
|
|
const PROJECTS_STALE_TIME_MS = 5 * 60 * 1000
|
|
|
|
const LOADING: UserProjectRegionsState = { status: 'loading' }
|
|
|
|
const FAIL_OPEN: UserProjectRegionsState = {
|
|
status: 'resolved',
|
|
context: { hasProjects: true, regions: new Set<string>(), isComplete: false },
|
|
}
|
|
|
|
export type UserProjectRegionsState =
|
|
| { status: 'loading' }
|
|
| { status: 'resolved'; context: UserRegionContext }
|
|
|
|
function combineOrgProjects(
|
|
results: Array<UseQueryResult<OrgProjectsInfiniteData>>
|
|
): UserProjectRegionsState {
|
|
if (results.some((r) => r.isPending)) return LOADING
|
|
|
|
const anyErrored = results.some((r) => r.isError)
|
|
const anyTruncated = results.some(
|
|
(r) => r.data !== undefined && r.data.pagination.count > r.data.projects.length
|
|
)
|
|
|
|
const projects = results.flatMap((r) => r.data?.projects ?? [])
|
|
const regions = new Set(
|
|
projects.flatMap((p) => p.databases.map((db) => normalizeRegion(db.region)))
|
|
)
|
|
|
|
return {
|
|
status: 'resolved',
|
|
context: {
|
|
hasProjects: projects.length > 0 || anyErrored,
|
|
regions,
|
|
isComplete: !anyErrored && !anyTruncated,
|
|
},
|
|
}
|
|
}
|
|
|
|
export function useUserProjectRegions({ enabled }: { enabled: boolean }): UserProjectRegionsState {
|
|
const { data: organizations, isError: isOrganizationsError } = useOrganizationsQuery({ enabled })
|
|
|
|
const projectsState = useQueries({
|
|
queries: (organizations ?? []).map((org) => ({
|
|
queryKey: projectKeys.bannerProjectsByOrg(org.slug),
|
|
queryFn: ({ signal }: { signal: AbortSignal }) =>
|
|
getOrganizationProjects({ slug: org.slug, limit: PROJECTS_PAGE_LIMIT }, signal),
|
|
staleTime: PROJECTS_STALE_TIME_MS,
|
|
enabled,
|
|
})),
|
|
combine: combineOrgProjects,
|
|
})
|
|
|
|
if (!enabled) return LOADING
|
|
if (organizations === undefined) return isOrganizationsError ? FAIL_OPEN : LOADING
|
|
return projectsState
|
|
}
|