Home / Function/ Connect() — supabase Function Reference

Connect() — supabase Function Reference

Architecture documentation for the Connect() function in Connect.tsx from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  7a580dbf_0dd5_87fe_b7f0_afad9b0cdd6f["Connect()"]
  5d5315d4_34ce_e96b_4aa1_ea6d63eea71d["getContentFilePath()"]
  7a580dbf_0dd5_87fe_b7f0_afad9b0cdd6f -->|calls| 5d5315d4_34ce_e96b_4aa1_ea6d63eea71d
  8f857c80_b8a5_cc93_9656_f0b4af5b7195["inferConnectTabFromParentKey()"]
  7a580dbf_0dd5_87fe_b7f0_afad9b0cdd6f -->|calls| 8f857c80_b8a5_cc93_9656_f0b4af5b7195
  style 7a580dbf_0dd5_87fe_b7f0_afad9b0cdd6f fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/interfaces/Connect/Connect.tsx lines 39–501

export const Connect = () => {
  const router = useRouter()
  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 connectionTypes = CONNECTION_TYPES.filter(({ key }) => {
    if (key === 'frameworks') {
      return showAppFrameworks
    }
    if (key === 'mobiles') {
      return showMobileFrameworks
    }
    if (key === 'orms') {
      return showOrms
    }
    return true
  })

  // helper to get the connection type object
  function getConnectionObjectForTab(tab: string | null) {
    switch (tab) {
      case 'frameworks':
        return FRAMEWORKS
      case 'mobiles':
        return MOBILES
      case 'orms':
        return ORMS
      default:
        return FRAMEWORKS
    }
  }

  const [open, setOpen] = useQueryState('showConnect', parseAsBoolean.withDefault(false))
  const [tab, setTab] = useQueryState('connectTab', parseAsString.withDefault('direct'))
  const [queryFramework, setQueryFramework] = useQueryState('framework', parseAsString)
  const [queryUsing, setQueryUsing] = useQueryState('using', parseAsString)
  const [queryWith, setQueryWith] = useQueryState('with', parseAsString)
  const [_, setQueryType] = useQueryState('type', parseAsString)
  const [__, setQuerySource] = useQueryState('source', parseAsString)
  const [___, setQueryMethod] = useQueryState('method', parseAsString)

  const [connectionObject, setConnectionObject] = useState<ConnectionType[]>(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: open })
  const { can: canReadAPIKeys } = useAsyncCheckPermissions(
    PermissionAction.READ,
    'service_api_keys'
  )

  const handleParentChange = (value: string) => {
    setSelectedParent(value)
    setQueryFramework(value)

    const parent = connectionObject.find((item) => item.key === value)
    const firstChild = parent?.children?.[0]

    if (firstChild) {
      setSelectedChild(firstChild.key)
      setQueryUsing(firstChild.key)

      const firstGrandchild = firstChild.children?.[0]
      if (firstGrandchild) {
        setSelectedGrandchild(firstGrandchild.key)
        setQueryWith(firstGrandchild.key)
      } else {
        setSelectedGrandchild('')
        setQueryWith(null)
      }
    } else {
      setSelectedChild('')
      setQueryUsing(null)
      setSelectedGrandchild('')
      setQueryWith(null)
    }
  }

  const handleChildChange = (value: string) => {
    setSelectedChild(value)
    setQueryUsing(value)

    const parent = connectionObject.find((item) => item.key === selectedParent)
    const child = parent?.children.find((child) => child.key === value)
    const firstGrandchild = child?.children?.[0]

    if (firstGrandchild) {
      setSelectedGrandchild(firstGrandchild.key)
      setQueryWith(firstGrandchild.key)
    } else {
      setSelectedGrandchild('')
      setQueryWith(null)
    }
  }

  const handleGrandchildChange = (value: string) => {
    setSelectedGrandchild(value)
    if (value) {
      setQueryWith(value)
    } else {
      setQueryWith(null)
    }
  }

  // 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) {
    setTab(type)

    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 { data: apiKeys } = useAPIKeysQuery({ projectRef }, { enabled: canReadAPIKeys })
  const { anonKey, publishableKey } = canReadAPIKeys
    ? getKeys(apiKeys)
    : { anonKey: null, publishableKey: null }

  const projectKeys = useMemo(() => {
    const protocol = settings?.app_config?.protocol ?? 'https'
    const endpoint = settings?.app_config?.endpoint ?? ''
    const apiHost = canReadAPIKeys ? `${protocol}://${endpoint ?? '-'}` : ''

    return {
      apiUrl: apiHost ?? null,
      anonKey: anonKey?.api_key ?? null,
      publishableKey: publishableKey?.api_key ?? null,
    }
  }, [
    settings?.app_config?.protocol,
    settings?.app_config?.endpoint,
    canReadAPIKeys,
    anonKey?.api_key,
    publishableKey?.api_key,
  ])

  const filePath = getContentFilePath({
    connectionObject,
    selectedParent,
    selectedChild,
    selectedGrandchild,
  })

  const resetQueryStates = () => {
    setQueryFramework(null)
    setQueryUsing(null)
    setQueryWith(null)
    setQueryType(null)
    setQuerySource(null)
    setQueryMethod(null)
  }

  const handleDialogChange = (dialogOpen: boolean) => {
    if (!dialogOpen) {
      setTab(null)
      resetQueryStates()
    }
    setOpen(dialogOpen)
  }

  useEffect(() => {
    if (!open) return
    const noConnectTabInUrl = typeof router.query.connectTab === 'undefined'
    const hasQuery = queryFramework || queryUsing || queryWith
    const inferred = inferConnectTabFromParentKey(queryFramework)

    if (noConnectTabInUrl && hasQuery && inferred) {
      setTab(inferred)
      if (inferred === 'frameworks') setConnectionObject(FRAMEWORKS)
      if (inferred === 'mobiles') setConnectionObject(MOBILES)
      if (inferred === 'orms') setConnectionObject(ORMS)
    }
  }, [open, router.query.connectTab, queryFramework, queryUsing, queryWith, setTab])

  useEffect(() => {
    if (!open) return

    const newConnectionObject = getConnectionObjectForTab(tab)
    setConnectionObject(newConnectionObject)

    const parent =
      newConnectionObject.find((item) => item.key === queryFramework) ?? newConnectionObject[0]
    setSelectedParent(parent?.key ?? '')

    if (queryFramework) {
      if (parent?.key !== queryFramework) setQueryFramework(parent?.key ?? null)
    }

    const child =
      parent?.children.find((child) => child.key === queryUsing) ?? parent?.children?.[0]
    setSelectedChild(child?.key ?? '')

    if (queryUsing) {
      if (child?.key !== queryUsing) setQueryUsing(child?.key ?? null)
    }

    const grandchild =
      child?.children.find((child) => child.key === queryWith) ?? child?.children?.[0]
    setSelectedGrandchild(grandchild?.key ?? '')

    if (queryWith) {
      if (grandchild?.key !== queryWith) setQueryWith(grandchild?.key ?? null)
    }
  }, [
    open,
    tab,
    queryFramework,
    setQueryFramework,
    queryUsing,
    setQueryUsing,
    queryWith,
    setQueryWith,
  ])

  return (
    <Dialog open={open} onOpenChange={handleDialogChange}>
      <DialogContent className={cn('sm:max-w-5xl p-0 rounded-lg')} centered={false}>
        <DialogHeader className={cn('text-left', DIALOG_PADDING_X)}>
          <DialogTitle>
            Connect to your project
            {connectionTypes.length === 1 ? ` via ${connectionTypes[0].label.toLowerCase()}` : null}
          </DialogTitle>
          <DialogDescription>
            Get the connection strings and environment variables for your app.
          </DialogDescription>
        </DialogHeader>

        <Tabs_Shadcn_
          value={tab}
          onValueChange={(value) => {
            resetQueryStates()
            handleConnectionType(value)
          }}
        >
          {connectionTypes.length > 1 ? (
            <TabsList_Shadcn_ className={cn('flex overflow-x-scroll gap-x-4', DIALOG_PADDING_X)}>
              {connectionTypes.map((type) => (
                <TabsTrigger_Shadcn_ key={type.key} value={type.key} className="px-0">
                  {type.label}
                </TabsTrigger_Shadcn_>
              ))}
            </TabsList_Shadcn_>
          ) : (
            <DialogSectionSeparator />
          )}

          {connectionTypes.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 (
                <TabsContent_Shadcn_
                  key="direct"
                  value="direct"
                  className={cn('!mt-0', 'p-0', 'flex flex-col gap-6')}
                >
                  <div className={DIALOG_PADDING_Y}>
                    <DatabaseConnectionString />
                  </div>
                </TabsContent_Shadcn_>
              )
            }

            if (type.key === 'mcp') {
              return (
                <TabsContent_Shadcn_
                  key="mcp"
                  value="mcp"
                  className={cn(DIALOG_PADDING_X, DIALOG_PADDING_Y, '!mt-0')}
                >
                  <McpTabContent projectKeys={projectKeys} />
                </TabsContent_Shadcn_>
              )
            }

            if (type.key === 'api-keys') {
              return (
                <TabsContent_Shadcn_
                  key="api-keys"
                  value="api-keys"
                  className={cn(DIALOG_PADDING_X, DIALOG_PADDING_Y, '!mt-0')}
                >
                  <ApiKeysTabContent projectKeys={projectKeys} />
                </TabsContent_Shadcn_>
              )
            }

            const connectionTabMap: Record<
              string,
              'App Frameworks' | 'Mobile Frameworks' | 'ORMs'
            > = {
              frameworks: 'App Frameworks',
              mobiles: 'Mobile Frameworks',
              orms: 'ORMs',
            }
            const connectionTab = connectionTabMap[type.key] || 'App Frameworks'
            const selectedFrameworkOrTool =
              connectionObject.find((item) => item.key === selectedParent)?.label || ''

            return (
              <TabsContent_Shadcn_
                key={`content-${type.key}`}
                value={type.key}
                className={cn(DIALOG_PADDING_X, DIALOG_PADDING_Y, '!mt-0')}
              >
                <div className="flex flex-col md:flex-row gap-2 justify-between">
                  <div className="flex flex-col md:flex-row items-stretch md:items-center gap-2 md:gap-3">
                    <ConnectDropdown
                      state={selectedParent}
                      updateState={handleParentChange}
                      label={
                        connectionObject === FRAMEWORKS || connectionObject === MOBILES
                          ? 'Framework'
                          : 'Tool'
                      }
                      items={connectionObject}
                    />
                    {selectedParent && hasChildOptions && (
                      <ConnectDropdown
                        state={selectedChild}
                        updateState={handleChildChange}
                        label="Using"
                        items={getChildOptions()}
                      />
                    )}
                    {selectedChild && hasGrandChildOptions && (
                      <ConnectDropdown
                        state={selectedGrandchild}
                        updateState={handleGrandchildChange}
                        label="With"
                        items={getGrandchildrenOptions()}
                      />
                    )}
                  </div>
                  {connectionObject.find((item) => item.key === selectedParent)?.guideLink && (
                    <Button asChild type="default" icon={<ExternalLink strokeWidth={1.5} />}>
                      <a
                        target="_blank"
                        rel="noreferrer"
                        href={
                          connectionObject.find((item) => item.key === selectedParent)?.guideLink ||
                          ''
                        }
                      >
                        {connectionObject.find((item) => item.key === selectedParent)?.label} guide
                      </a>
                    </Button>
                  )}
                </div>
                <p className="text-xs text-foreground-lighter my-3">
                  Add the following files below to your application
                </p>
                <ConnectTabContent
                  projectKeys={projectKeys}
                  filePath={filePath}
                  connectionTab={connectionTab}
                  selectedFrameworkOrTool={selectedFrameworkOrTool}
                  className="rounded-b-none"
                />
                {IS_PLATFORM && (
                  <Panel.Notice
                    className="border border-t-0 rounded-lg rounded-t-none"
                    badgeLabel="Changelog"
                    title="New publishable and secret API keys"
                    description={
                      <>
                        <p>
                          View your publishable and secret API keys from the project{' '}
                          <Link href={`/project/${projectRef}/settings/api-keys`}>
                            API settings page
                          </Link>
                        </p>
                        <p>
                          To learn more about the new API keys, read the{' '}
                          <a
                            href="https://supabase.com/docs/guides/api/api-keys"
                            target="_blank"
                            rel="noreferrer"
                          >
                            documentation
                          </a>
                        </p>
                      </>
                    }
                    href={`${BASE_PATH}/project/${projectRef}/settings/api-keys`}
                    buttonText="View API keys"
                  />
                )}
              </TabsContent_Shadcn_>
            )
          })}
        </Tabs_Shadcn_>
      </DialogContent>
    </Dialog>
  )
}

Subdomains

Frequently Asked Questions

What does Connect() do?
Connect() is a function in the supabase codebase.
What does Connect() call?
Connect() calls 2 function(s): getContentFilePath, inferConnectTabFromParentKey.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free