Files
supabase/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx
Joshen Lim 90d3b56db0 Joshen/fe 2621 show custom domain on dashboard and connect modal (#43233)
## Context

Main fix is to adjust the new home page + connect dialog (and connect
sheet) to render the project's custom domain if available

<img width="471" height="255" alt="image"
src="https://github.com/user-attachments/assets/3a208b2e-bdeb-43f5-a2e7-3495881dbaaa"
/>
<img width="1065" height="233" alt="image"
src="https://github.com/user-attachments/assets/2a7b8f81-8c0b-4803-bf0a-fc16a2f1e0e1"
/>

## Changes involved

- Created a `useProjectApiUrl` hook that will return the API URL
depending if custom domains is available, otherwise default to default
project API URL
- Refactored all the other places that were manually deriving the
project's endpoint
  - Storage Explorer -> copy URL
  - Edge Functions
  - Integrations -> Data API + API Docs
  - Auth Providers -> Callback URL
- Also updated the copy CTA for the addons page
  - Instead of just "Change xxx", make it a bit more actionable
  - For add ons with binary states (Custom domains, IPv4)
    - If not enabled yet, "Enable xxx", otherwise "Toggle xxx"
  - For PITR
- If not enabled yet, "Enable PITR", otherwise "Change recovery
duration"
  - Also added "Edit custom domain" CTA if enabled
<img width="1144" height="518" alt="image"
src="https://github.com/user-attachments/assets/4f152ea5-0cc7-412c-95e8-ad5bb37c19c3"
/>


## To test
- [ ] Verify that for a project with custom domain set up, all the
affected UI mentioned in the above section look correct
2026-03-03 11:37:08 +08:00

109 lines
3.8 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 { useMemo } from 'react'
import { cn, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from 'ui'
import type { ProjectKeys } from './Connect.types'
import { ConnectConfigSection, ModeSelector } from './ConnectConfigSection'
import { ConnectStepsSection } from './ConnectStepsSection'
import { useConnectState } from './useConnectState'
import { useProjectApiUrl } from '@/data/config/project-endpoint-query'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
export const ConnectSheet = () => {
const { ref: projectRef } = useParams()
const {
projectConnectionShowAppFrameworks: showAppFrameworks,
projectConnectionShowMobileFrameworks: showMobileFrameworks,
projectConnectionShowOrms: showOrms,
} = useIsFeatureEnabled([
'project_connection:show_app_frameworks',
'project_connection:show_mobile_frameworks',
'project_connection:show_orms',
])
const [showConnect, setShowConnect] = useQueryState(
'showConnect',
parseAsBoolean.withDefault(false)
)
const [, setConnectTab] = useQueryState('connectTab', parseAsString)
const handleOpenChange = (sheetOpen: boolean) => {
if (!sheetOpen) {
setConnectTab(null)
}
setShowConnect(sheetOpen)
}
const { state, activeFields, resolvedSteps, schema, getFieldOptions, setMode, updateField } =
useConnectState()
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 availableModeIds = useMemo(() => {
const modes: string[] = []
const showFrameworks = showAppFrameworks || showMobileFrameworks
if (showFrameworks) modes.push('framework')
modes.push('direct')
if (showOrms) modes.push('orm')
modes.push('mcp')
return modes
}, [showAppFrameworks, showMobileFrameworks, showOrms])
const availableModes = useMemo(
() => schema.modes.filter((m) => availableModeIds.includes(m.id)),
[schema.modes, availableModeIds]
)
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={setMode} />
</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>
)
}