mirror of
https://github.com/supabase/supabase.git
synced 2026-10-12 04:45:08 +03:00
## Summary Re-ports PR #43119 against the current `ProjectHome` codebase (the original PR targeted `HomeNew/` which was removed during the `homeNew` graduation in #43437). Also unifies the `connectSheet` and `connectSection` feature flags into a single `connectSection` flag — the `connectSheet` flag is removed entirely, so both the ConnectSheet (header) and ConnectSection (homepage row) are controlled by one experiment. - Adds `connectSection` PostHog experiment flag that controls two things: 1. Swaps the Getting Started section for a Connect section on the project homepage for new projects (< 10 days old) 2. Swaps the legacy Connect dialog for the new ConnectSheet panel in the header - **Control** (`getting-started`): existing Getting Started section + legacy Connect dialog in header - **Treatment** (`connect`): new 4-tile Connect section + ConnectSheet in header - `undefined` (loading): neither section renders, avoiding flash - Tiles filtered by the same `useIsFeatureEnabled` flags as ConnectSheet (`show_app_frameworks`, `show_mobile_frameworks`, `show_orms`) - Connect tile clicks tracked via `home_connect_action_clicked`; section render tracked via `home_connect_section_exposed`; sheet opens tracked via `connect_sheet_opened` with source attribution (`header_button` or `connect_section`) ## Changes - `packages/common/telemetry-constants.ts` — new `home_connect_section_exposed`, `home_connect_action_clicked`, and `connect_sheet_opened` event types - `ConnectSheet/ConnectSheet.tsx` — read `connectTab` query param and sync to active mode on open; `handleModeChange` keeps param in sync on tab switch; fire `connect_sheet_opened` event with source attribution on open - `ConnectButton/ConnectButton.tsx` — set `connectSource=header_button` query param on click - `ProjectHome/ConnectSection.tsx` — new component (4-tile connect card); set `connectSource=connect_section` on tile click - `ProjectHome/Home.tsx` — experiment flag wiring - `LayoutHeader/LayoutHeader.tsx` — read `connectSection` flag instead of `connectSheet` to toggle ConnectSheet vs legacy Connect dialog ## Test plan To test on the Vercel preview, set `connectSection=connect` to 100% in PostHog (or override via cookie `ph_override_connectSection=connect`). No separate `connectSheet` flag is needed — `connectSection` controls both features. - [x] Treatment (`connect` variant) — "Get connected" section renders on new project, Getting Started hidden - [x] Control (`getting-started`) — Getting Started renders, Connect section hidden - [x] Mature project (> 10 days) — neither section regardless of flag - [x] Clicking each tile opens ConnectSheet on the correct tab (Framework / Direct / ORM / MCP) - [x] Switching tabs inside sheet updates `connectTab` URL param - [x] Closing sheet clears `connectTab` param - [x] Direct URL deep-link (`?showConnect=true&connectTab=orm`) opens sheet on correct tab - [x] Dark mode — background gradient renders correctly - [x] Light mode — background switches to light gradient - [x] Responsive layout — 4 cols (xl), 2×2 (md), stacked (mobile) - [x] Telemetry — `home_connect_section_exposed` fires once on load; `home_connect_action_clicked` fires with correct `mode` - [x] Treatment — header Connect button opens ConnectSheet (not legacy Connect dialog) - [x] Control — header Connect button opens legacy Connect dialog (not ConnectSheet) - [x] Telemetry — clicking a ConnectSection tile fires `connect_sheet_opened` with `source: 'connect_section'` - [x] Telemetry — clicking header Connect button fires `connect_sheet_opened` with `source: 'header_button'` --------- Co-authored-by: Ali Waseem <waseema393@gmail.com>
130 lines
4.3 KiB
TypeScript
130 lines
4.3 KiB
TypeScript
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
|
import { useParams } from 'common'
|
|
import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query'
|
|
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
|
import { parseAsBoolean, parseAsString, useQueryState } from 'nuqs'
|
|
import { useEffect, useMemo, useRef } from 'react'
|
|
import { cn, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from 'ui'
|
|
|
|
import type { ConnectMode, ProjectKeys } from './Connect.types'
|
|
import { CONNECT_MODES } from './Connect.types'
|
|
import { ConnectConfigSection, ModeSelector } from './ConnectConfigSection'
|
|
import { ConnectStepsSection } from './ConnectStepsSection'
|
|
import { useConnectState } from './useConnectState'
|
|
import { useAvailableConnectModes } from './useAvailableConnectModes'
|
|
import { useProjectApiUrl } from '@/data/config/project-endpoint-query'
|
|
import { useAppStateSnapshot } from '@/state/app-state'
|
|
import { useTrack } from 'lib/telemetry/track'
|
|
|
|
function isConnectMode(value: string): value is ConnectMode {
|
|
return CONNECT_MODES.some((mode) => mode === value)
|
|
}
|
|
|
|
export const ConnectSheet = () => {
|
|
const { ref: projectRef } = useParams()
|
|
|
|
const availableModeIds = useAvailableConnectModes()
|
|
|
|
const [showConnect, setShowConnect] = useQueryState(
|
|
'showConnect',
|
|
parseAsBoolean.withDefault(false)
|
|
)
|
|
const [connectTab, setConnectTab] = useQueryState('connectTab', parseAsString)
|
|
const { connectSheetSource, setConnectSheetSource } = useAppStateSnapshot()
|
|
const track = useTrack()
|
|
const prevShowConnect = useRef(false)
|
|
|
|
const { state, activeFields, resolvedSteps, schema, getFieldOptions, setMode, updateField } =
|
|
useConnectState()
|
|
|
|
useEffect(() => {
|
|
const justOpened = showConnect && !prevShowConnect.current
|
|
prevShowConnect.current = showConnect
|
|
|
|
if (!justOpened) return
|
|
|
|
track('connect_sheet_opened', { source: connectSheetSource })
|
|
setConnectSheetSource('header_button')
|
|
|
|
if (connectTab && isConnectMode(connectTab) && availableModeIds.includes(connectTab)) {
|
|
setMode(connectTab)
|
|
}
|
|
}, [
|
|
showConnect,
|
|
connectSheetSource,
|
|
connectTab,
|
|
availableModeIds,
|
|
track,
|
|
setConnectSheetSource,
|
|
setMode,
|
|
])
|
|
|
|
const handleOpenChange = (sheetOpen: boolean) => {
|
|
if (!sheetOpen) {
|
|
setConnectTab(null)
|
|
}
|
|
setShowConnect(sheetOpen)
|
|
}
|
|
|
|
const { data: endpoint = '' } = useProjectApiUrl({ projectRef }, { enabled: showConnect })
|
|
|
|
const { can: canReadAPIKeys } = useAsyncCheckPermissions(
|
|
PermissionAction.READ,
|
|
'service_api_keys'
|
|
)
|
|
const { data: apiKeys } = useAPIKeysQuery({ projectRef }, { enabled: canReadAPIKeys })
|
|
const { anonKey, publishableKey } = canReadAPIKeys
|
|
? getKeys(apiKeys)
|
|
: { anonKey: null, publishableKey: null }
|
|
|
|
const projectKeys: ProjectKeys = useMemo(() => {
|
|
return {
|
|
apiUrl: endpoint,
|
|
anonKey: anonKey?.api_key ?? null,
|
|
publishableKey: publishableKey?.api_key ?? null,
|
|
}
|
|
}, [endpoint, anonKey?.api_key, publishableKey?.api_key])
|
|
|
|
const availableModes = useMemo(
|
|
() => schema.modes.filter((m) => availableModeIds.includes(m.id)),
|
|
[schema.modes, availableModeIds]
|
|
)
|
|
|
|
const handleModeChange = (mode: ConnectMode) => {
|
|
setMode(mode)
|
|
setConnectTab(mode)
|
|
}
|
|
|
|
return (
|
|
<Sheet open={showConnect} onOpenChange={handleOpenChange}>
|
|
<SheetContent size="lg" className="flex flex-col gap-0 p-0 space-y-0" tabIndex={undefined}>
|
|
<SheetHeader className={cn('text-left border-b shrink-0 py-6 px-8')}>
|
|
<SheetTitle>Connect to your project</SheetTitle>
|
|
<SheetDescription>Choose how you want to use Supabase</SheetDescription>
|
|
</SheetHeader>
|
|
|
|
<div className="flex flex-1 flex-col overflow-y-auto divide-y">
|
|
<div className="p-8">
|
|
<ModeSelector
|
|
modes={availableModes}
|
|
selected={state.mode}
|
|
onChange={handleModeChange}
|
|
/>
|
|
</div>
|
|
|
|
<div className="border-b p-8">
|
|
<ConnectConfigSection
|
|
state={state}
|
|
activeFields={activeFields}
|
|
onFieldChange={updateField}
|
|
getFieldOptions={getFieldOptions}
|
|
/>
|
|
</div>
|
|
|
|
<ConnectStepsSection steps={resolvedSteps} state={state} projectKeys={projectKeys} />
|
|
</div>
|
|
</SheetContent>
|
|
</Sheet>
|
|
)
|
|
}
|