mirror of
https://github.com/supabase/supabase.git
synced 2026-09-08 19:08:44 +08:00
## Context PR here mainly breaks up the files under `ConnectSheet` to separate the functional logic so that we can write unit tests. No behavior changes intended beyond the bug fixes ## Changes involved - **Test organization:** moved all root-level `ConnectSheet` test files into `ConnectSheet/__tests__/` for consistency with other parts of the codebase that use this convention. - **Bug fix:** read replica label had a stray `}` / missing `)`, rendering as e.g. `Read Replica (us-east-1 - abc123})` instead of `Read Replica (us-east-1 - abc123)`. - **`ConnectSheet.tsx`:** extracted the "hydrate sheet state on open" `useEffect` logic (mode/field/URL param resolution from URL vs. localStorage) into a new `ConnectSheet.utils.ts`, with unit tests - **`useConnectServerEnv.ts`:** fixed two race conditions in the secret reveal/hide flow: - `toggle()` and `getValue()` could each fire a separate reveal request if triggered close together — now deduped to share one in-flight request. - `getValue()` could hide a secret that had just been explicitly revealed by a concurrent `toggle()`, due to reading a stale closure value — now reads the live state via `useLatest`. - Also stopped swallowing the original error on reveal failure (now attached via `cause`). - Added tests for the above, plus the 10s auto-hide timer (previously untested). - **`ConnectStepsSection.tsx`:** extracted `resolveContentPath` and the three inline "show notice" booleans (IPv4 addon, session pooler, self-hosted MCP) into `ConnectStepsSection.utils.ts`, matching the existing pattern for the Data API notice. Added unit tests for all of them. ## To test - [ ] Just a basic smoke test of the Connect sheet should do <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved connect setup hydration so saved preferences and URL values are applied more consistently when opening the sheet, including automatic URL backfilling where needed. * Refreshed connection guidance notices (IPv4 add-on, session pooler, and self-hosted MCP) with more consistent logic. * **Bug Fixes** * Fixed secret reveal behavior to keep concurrent reveal actions in sync, handle failures more safely, and ensure auto-hide works reliably. * Corrected the read-replica option label formatting. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
102 lines
3.7 KiB
TypeScript
102 lines
3.7 KiB
TypeScript
import type { ConnectMode } from './Connect.types'
|
|
import { CONNECT_MODES } from './Connect.types'
|
|
import type { ConnectSheetPrefs } from './useConnectSheetParams'
|
|
|
|
export type ConnectSheetQueryParams = {
|
|
connectTab: string | null
|
|
framework: string | null
|
|
using: string | null
|
|
method: string | null
|
|
type: string | null
|
|
mcpClient: string | null
|
|
}
|
|
|
|
export type ConnectSheetUrlUpdates = Partial<Record<keyof ConnectSheetQueryParams, string | null>>
|
|
|
|
export type ConnectSheetFieldUpdate = { fieldId: string; value: string }
|
|
|
|
export type ConnectSheetHydration = {
|
|
mode: ConnectMode | null
|
|
fieldUpdates: ConnectSheetFieldUpdate[]
|
|
urlUpdates: ConnectSheetUrlUpdates
|
|
}
|
|
|
|
function isConnectMode(value: string): value is ConnectMode {
|
|
return CONNECT_MODES.some((mode) => mode === value)
|
|
}
|
|
|
|
export function mapConnectTabToMode(tab: string | null): ConnectMode | null {
|
|
if (!tab) return null
|
|
switch (tab) {
|
|
case 'frameworks':
|
|
case 'mobiles':
|
|
return 'framework'
|
|
case 'orms':
|
|
return 'orm'
|
|
default:
|
|
return isConnectMode(tab) ? tab : null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Computes what should happen when the Connect sheet is opened: which mode/fields
|
|
* to hydrate from storedPrefs (falling back for whatever isn't already in the URL),
|
|
* and which URL params to backfill so the URL reflects the restored state.
|
|
*
|
|
* Field/URL updates are driven by `mappedMode` regardless of whether that mode is
|
|
* currently available — only the `mode` result (used to call `setMode`) is gated on
|
|
* `availableModeIds`, matching the sheet's pre-extraction behavior.
|
|
*/
|
|
export function resolveConnectSheetHydration(
|
|
query: ConnectSheetQueryParams,
|
|
storedPrefs: ConnectSheetPrefs,
|
|
availableModeIds: ConnectMode[]
|
|
): ConnectSheetHydration {
|
|
const effectiveTab = query.connectTab ?? storedPrefs.connectTab ?? null
|
|
const effectiveFramework = query.framework ?? storedPrefs.framework ?? null
|
|
const effectiveUsing = query.using ?? storedPrefs.using ?? null
|
|
const effectiveMethod = query.method ?? storedPrefs.method ?? null
|
|
const effectiveType = query.type ?? storedPrefs.type ?? null
|
|
const effectiveMcpClient = query.mcpClient ?? storedPrefs.mcpClient ?? null
|
|
|
|
const mappedMode = mapConnectTabToMode(effectiveTab)
|
|
const mode = mappedMode && availableModeIds.includes(mappedMode) ? mappedMode : null
|
|
|
|
const fieldUpdates: ConnectSheetFieldUpdate[] = []
|
|
const urlUpdates: ConnectSheetUrlUpdates = {}
|
|
|
|
if (query.connectTab === null && effectiveTab) urlUpdates.connectTab = effectiveTab
|
|
|
|
if (mappedMode === 'framework') {
|
|
if (effectiveFramework) {
|
|
fieldUpdates.push({ fieldId: 'framework', value: effectiveFramework })
|
|
if (query.framework === null) urlUpdates.framework = effectiveFramework
|
|
if (effectiveUsing) {
|
|
fieldUpdates.push({ fieldId: 'frameworkVariant', value: effectiveUsing })
|
|
if (query.using === null) urlUpdates.using = effectiveUsing
|
|
}
|
|
}
|
|
} else if (mappedMode === 'orm') {
|
|
if (effectiveFramework) {
|
|
fieldUpdates.push({ fieldId: 'orm', value: effectiveFramework })
|
|
if (query.framework === null) urlUpdates.framework = effectiveFramework
|
|
}
|
|
} else if (mappedMode === 'direct') {
|
|
if (effectiveMethod) {
|
|
fieldUpdates.push({ fieldId: 'connectionMethod', value: effectiveMethod })
|
|
if (query.method === null) urlUpdates.method = effectiveMethod
|
|
}
|
|
if (effectiveType) {
|
|
fieldUpdates.push({ fieldId: 'connectionType', value: effectiveType })
|
|
if (query.type === null) urlUpdates.type = effectiveType
|
|
}
|
|
} else if (mappedMode === 'mcp') {
|
|
if (effectiveMcpClient) {
|
|
fieldUpdates.push({ fieldId: 'mcpClient', value: effectiveMcpClient })
|
|
if (query.mcpClient === null) urlUpdates.mcpClient = effectiveMcpClient
|
|
}
|
|
}
|
|
|
|
return { mode, fieldUpdates, urlUpdates }
|
|
}
|