import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' import { ExternalLink, Plug } from 'lucide-react' import { parseAsBoolean, useQueryState } from 'nuqs' import { useMemo, useState } from 'react' import { DatabaseConnectionString } from 'components/interfaces/Connect/DatabaseConnectionString' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import Panel from 'components/ui/Panel' import { useAPIKeysQuery } from 'data/api-keys/api-keys-query' import { getAPIKeys, useProjectSettingsV2Query } from 'data/config/project-settings-v2-query' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedProject } from 'hooks/misc/useSelectedProject' import { PROJECT_STATUS } from 'lib/constants' import { Button, DIALOG_PADDING_X, DIALOG_PADDING_Y, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_, Tabs_Shadcn_, cn, } from 'ui' import { CONNECTION_TYPES, ConnectionType, FRAMEWORKS, MOBILES, ORMS } from './Connect.constants' import { getContentFilePath } from './Connect.utils' import ConnectDropdown from './ConnectDropdown' import ConnectTabContent from './ConnectTabContent' export const Connect = () => { const { ref: projectRef } = useParams() const selectedProject = useSelectedProject() const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY const [showConnect, setShowConnect] = useQueryState( 'showConnect', parseAsBoolean.withDefault(false) ) const [connectionObject, setConnectionObject] = useState(FRAMEWORKS) const [selectedParent, setSelectedParent] = useState(connectionObject[0].key) // aka nextjs const [selectedChild, setSelectedChild] = useState( connectionObject.find((item) => item.key === selectedParent)?.children[0]?.key ?? '' ) const [selectedGrandchild, setSelectedGrandchild] = useState( connectionObject .find((item) => item.key === selectedParent) ?.children.find((child) => child.key === selectedChild)?.children[0]?.key || '' ) const { data: settings } = useProjectSettingsV2Query({ projectRef }, { enabled: showConnect }) const canReadAPIKeys = useCheckPermissions(PermissionAction.READ, 'service_api_keys') const handleParentChange = (value: string) => { setSelectedParent(value) // check if parent has children setSelectedChild(connectionObject.find((item) => item.key === value)?.children[0]?.key ?? '') // check if child has grandchildren setSelectedGrandchild( connectionObject.find((item) => item.key === value)?.children[0]?.children[0]?.key ?? '' ) } const handleChildChange = (value: string) => { setSelectedChild(value) const parent = connectionObject.find((item) => item.key === selectedParent) const child = parent?.children.find((child) => child.key === value) if (child && child.children.length > 0) { setSelectedGrandchild(child.children[0].key) } else { setSelectedGrandchild('') } } const handleGrandchildChange = (value: string) => { setSelectedGrandchild(value) } // reset the parent/child/grandchild when the connection type (tab) changes function handleConnectionTypeChange(connections: ConnectionType[]) { setSelectedParent(connections[0].key) if (connections[0]?.children.length > 0) { setSelectedChild(connections[0].children[0].key) if (connections[0].children[0]?.children.length > 0) { setSelectedGrandchild(connections[0].children[0].children[0].key) } else { setSelectedGrandchild('') } } else { setSelectedChild('') setSelectedGrandchild('') } } function handleConnectionType(type: string) { if (type === 'frameworks') { setConnectionObject(FRAMEWORKS) handleConnectionTypeChange(FRAMEWORKS) } if (type === 'mobiles') { setConnectionObject(MOBILES) handleConnectionTypeChange(MOBILES) } if (type === 'orms') { setConnectionObject(ORMS) handleConnectionTypeChange(ORMS) } } const getChildOptions = () => { const parent = connectionObject.find((item) => item.key === selectedParent) if (parent && parent.children.length > 0) { return parent.children } return [] } const getGrandchildrenOptions = () => { const parent = connectionObject.find((item) => item.key === selectedParent) const subCategory = parent?.children.find((child) => child.key === selectedChild) if (subCategory && subCategory.children.length > 0) { return subCategory.children } return [] } const { anonKey } = canReadAPIKeys ? getAPIKeys(settings) : { anonKey: null } const { data: apiKeys } = useAPIKeysQuery({ projectRef, reveal: false }) const projectKeys = useMemo(() => { const protocol = settings?.app_config?.protocol ?? 'https' const endpoint = settings?.app_config?.endpoint ?? '' const apiHost = canReadAPIKeys ? `${protocol}://${endpoint ?? '-'}` : '' const apiUrl = canReadAPIKeys ? apiHost : null return { apiUrl: apiHost ?? null, anonKey: anonKey?.api_key ?? null, publishableKey: apiKeys?.find(({ type }) => type === 'publishable')?.api_key ?? null, } }, [apiKeys, anonKey, canReadAPIKeys, settings]) const filePath = getContentFilePath({ connectionObject, selectedParent, selectedChild, selectedGrandchild, }) if (!isActiveHealthy) { return ( } tooltip={{ content: { side: 'bottom', text: 'Project is currently not active and cannot be connected', }, }} > Connect ) } return ( setShowConnect(!open ? null : open)}> Connect to your project Get the connection strings and environment variables for your app handleConnectionType(value)}> {CONNECTION_TYPES.map((type) => ( {type.label} ))} {CONNECTION_TYPES.map((type) => { const hasChildOptions = (connectionObject.find((parent) => parent.key === selectedParent)?.children.length || 0) > 0 const hasGrandChildOptions = (connectionObject .find((parent) => parent.key === selectedParent) ?.children.find((child) => child.key === selectedChild)?.children.length || 0) > 0 if (type.key === 'direct') { return (
) } return (
{selectedParent && hasChildOptions && ( )} {selectedChild && hasGrandChildOptions && ( )}
{connectionObject.find((item) => item.key === selectedParent)?.guideLink && ( )}

Add the following files below to your application

) })}
) }