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 -->
76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
import type { IncidentCache } from '@/lib/api/incident-status'
|
|
import { normalizeRegion } from '@/lib/status-page/status-page.utils'
|
|
|
|
type BannerIncident = { id: string; cache?: IncidentCache | null }
|
|
|
|
/**
|
|
* Determines whether the incident status banner should be shown to a given user,
|
|
* given all active incidents and the user's project state.
|
|
*
|
|
* Returns true if any incident matches the user's context.
|
|
*
|
|
* @param incidents - Active incidents from the incident-status endpoint
|
|
* @param hasProjects - Whether the user has any projects at all
|
|
* @param userRegions - Deduplicated set of regions of all databases (primary and read replicas)
|
|
* owned by the user, normalized via normalizeRegion
|
|
* @param hasUnknownRegions - True when region data is incomplete (an org has more than 100
|
|
* projects, or an org's projects failed to load). When true, the region check is skipped and
|
|
* a match is assumed.
|
|
*/
|
|
export function shouldShowBanner({
|
|
incidents,
|
|
hasProjects,
|
|
userRegions,
|
|
hasUnknownRegions = false,
|
|
}: {
|
|
incidents: Array<BannerIncident>
|
|
hasProjects: boolean
|
|
userRegions: ReadonlySet<string>
|
|
hasUnknownRegions?: boolean
|
|
}): boolean {
|
|
return incidents.some((incident) => {
|
|
// Forced incidents are shown unconditionally, regardless of regions or project state
|
|
if (incident.cache?.force) return true
|
|
|
|
const affectedRegions = incident.cache?.affected_regions ?? []
|
|
const affectsProjectCreation = incident.cache?.affects_project_creation ?? false
|
|
|
|
// Users with no projects only see the banner if the incident affects project creation
|
|
// and has no specific region targeting (inline notice in RegionSelector handles region-specific incidents)
|
|
if (!hasProjects) return affectsProjectCreation && affectedRegions.length === 0
|
|
|
|
// User has projects: if no region restriction, always show
|
|
if (affectedRegions.length === 0) return true
|
|
|
|
// Region data is incomplete — assume the user has a database in an affected region
|
|
if (hasUnknownRegions) return true
|
|
|
|
// Region restriction: only show if the user has a database in an affected region
|
|
return affectedRegions.some((region) => userRegions.has(normalizeRegion(region)))
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Returns the IDs of incidents that are relevant to the given user.
|
|
*
|
|
* An incident is considered relevant if it would trigger banner visibility for
|
|
* the user, per the same logic as shouldShowBanner.
|
|
*/
|
|
export function getRelevantIncidentIds({
|
|
incidents,
|
|
hasProjects,
|
|
userRegions,
|
|
hasUnknownRegions = false,
|
|
}: {
|
|
incidents: Array<BannerIncident>
|
|
hasProjects: boolean
|
|
userRegions: ReadonlySet<string>
|
|
hasUnknownRegions?: boolean
|
|
}): Array<string> {
|
|
return incidents
|
|
.filter((incident) =>
|
|
shouldShowBanner({ incidents: [incident], hasProjects, userRegions, hasUnknownRegions })
|
|
)
|
|
.map((incident) => incident.id)
|
|
}
|