bring back old connect

This commit is contained in:
Saxon Fletcher committed 2026-01-29 14:50:46 +10:00
1 parent d5672abc2d
commit 69b42adfac
9 files changed
+135 -181

No files matched your search

@@ -1,4 +1,4 @@
import { useConnectCommands } from '@/components/interfaces/ConnectSheet/Connect.Commands'
import { useConnectCommands } from '@/components/interfaces/ConnectButton/Connect.Commands'
import { IS_PLATFORM } from 'common'
import { useBranchCommands } from 'components/interfaces/BranchManagement/Branch.Commands'
import {
@@ -1,20 +1,18 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { IS_PLATFORM, useParams } from 'common'
import { ExternalLink, Plug } from 'lucide-react'
import { parseAsBoolean, parseAsString, useQueryState } from 'nuqs'
import { ExternalLink } from 'lucide-react'
import { parseAsString, useQueryState } from 'nuqs'
import { useEffect, useMemo, useState } from 'react'
import { ApiKeysTabContent } from 'components/interfaces/Connect/ApiKeysTabContent'
import { DatabaseConnectionString } from 'components/interfaces/Connect/DatabaseConnectionString'
import { McpTabContent } from 'components/interfaces/Connect/McpTabContent'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import Panel from 'components/ui/Panel'
import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query'
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { BASE_PATH, PROJECT_STATUS } from 'lib/constants'
import { BASE_PATH } from 'lib/constants'
import { useRouter } from 'next/router'
import {
Button,
@@ -26,7 +24,6 @@ import {
DialogHeader,
DialogSectionSeparator,
DialogTitle,
DialogTrigger,
TabsContent_Shadcn_,
TabsList_Shadcn_,
TabsTrigger_Shadcn_,
@@ -39,11 +36,14 @@ import { ConnectDropdown } from './ConnectDropdown'
import { ConnectTabContent } from './ConnectTabContent'
import Link from 'next/link'
export const Connect = () => {
interface ConnectProps {
open: boolean
onOpenChange: (open: boolean) => void
}
export const Connect = ({ open, onOpenChange }: ConnectProps) => {
const router = useRouter()
const { ref: projectRef } = useParams()
const { data: selectedProject } = useSelectedProjectQuery()
const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY
const {
projectConnectionShowAppFrameworks: showAppFrameworks,
@@ -68,11 +68,6 @@ export const Connect = () => {
return true
})
const [showConnect, setShowConnect] = useQueryState(
'showConnect',
parseAsBoolean.withDefault(false)
)
// helper to get the connection type object
function getConnectionObjectForTab(tab: string | null) {
switch (tab) {
@@ -106,7 +101,7 @@ export const Connect = () => {
?.children.find((child) => child.key === selectedChild)?.children[0]?.key || ''
)
const { data: settings } = useProjectSettingsV2Query({ projectRef }, { enabled: showConnect })
const { data: settings } = useProjectSettingsV2Query({ projectRef }, { enabled: open })
const { can: canReadAPIKeys } = useAsyncCheckPermissions(
PermissionAction.READ,
'service_api_keys'
@@ -258,18 +253,16 @@ export const Connect = () => {
setQueryMethod(null)
}
const handleDialogChange = (open: boolean) => {
if (!open) {
setShowConnect(null)
const handleDialogChange = (nextOpen: boolean) => {
if (!nextOpen) {
setTab(null)
resetQueryStates()
} else {
setShowConnect(open)
}
onOpenChange(nextOpen)
}
useEffect(() => {
if (!showConnect) return
if (!open) return
const noConnectTabInUrl = typeof router.query.connectTab === 'undefined'
const hasQuery = queryFramework || queryUsing || queryWith
const inferred = inferConnectTabFromParentKey(queryFramework)
@@ -280,10 +273,10 @@ export const Connect = () => {
if (inferred === 'mobiles') setConnectionObject(MOBILES)
if (inferred === 'orms') setConnectionObject(ORMS)
}
}, [showConnect, router.query.connectTab, queryFramework, queryUsing, queryWith, setTab])
}, [open, router.query.connectTab, queryFramework, queryUsing, queryWith, setTab])
useEffect(() => {
if (!showConnect) return
if (!open) return
const newConnectionObject = getConnectionObjectForTab(tab)
setConnectionObject(newConnectionObject)
@@ -312,7 +305,7 @@ export const Connect = () => {
if (grandchild?.key !== queryWith) setQueryWith(grandchild?.key ?? null)
}
}, [
showConnect,
open,
tab,
queryFramework,
setQueryFramework,
@@ -322,32 +315,8 @@ export const Connect = () => {
setQueryWith,
])
if (!isActiveHealthy) {
return (
<ButtonTooltip
disabled
type="default"
className="rounded-full"
icon={<Plug className="rotate-90" />}
tooltip={{
content: {
side: 'bottom',
text: 'Project is currently not active and cannot be connected',
},
}}
>
Connect
</ButtonTooltip>
)
}
return (
<Dialog open={showConnect} onOpenChange={handleDialogChange}>
<DialogTrigger asChild>
<Button type="default" className="rounded-full" icon={<Plug className="rotate-90" />}>
<span>Connect</span>
</Button>
</DialogTrigger>
<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>
@@ -1,5 +1,6 @@
import { Plug } from 'lucide-react'
import { useRouter } from 'next/router'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { PROJECT_STATUS } from 'lib/constants'
import type { ICommand } from 'ui-patterns/CommandMenu'
@@ -20,7 +21,6 @@ export function useConnectCommands() {
id: 'connect-to-project',
name: 'Connect to your project',
action: () => {
// Open the Connect dialog by setting the showConnect query param
router.push(
{
pathname: router.pathname,
@@ -37,7 +37,6 @@ export function useConnectCommands() {
id: 'connect-mcp',
name: 'Connect via MCP',
action: () => {
// Open the Connect dialog with MCP tab
router.push(
{
pathname: router.pathname,
@@ -0,0 +1,95 @@
import { Plug } from 'lucide-react'
import { ComponentProps, useEffect, useState } from 'react'
import { parseAsBoolean, parseAsString, useQueryState } from 'nuqs'
import { Connect } from 'components/interfaces/Connect/Connect'
import { ConnectSheet } from 'components/interfaces/ConnectSheet/ConnectSheet'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { usePHFlag } from 'hooks/ui/useFlag'
import { PROJECT_STATUS } from 'lib/constants'
import { Button } from 'ui'
interface ConnectButtonProps {
buttonType?: ComponentProps<typeof Button>['type']
renderDialog?: boolean
}
export const ConnectButton = ({
buttonType = 'default',
renderDialog = true,
}: ConnectButtonProps) => {
const connectSheetFlag = usePHFlag<string | boolean>('connectSheet')
const isConnectSheetEnabled = connectSheetFlag === true || connectSheetFlag === 'variation'
const { data: selectedProject } = useSelectedProjectQuery()
const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY
const [showConnect, setShowConnect] = useQueryState(
'showConnect',
parseAsBoolean.withDefault(false)
)
const [connectTab, setConnectTab] = useQueryState('connectTab', parseAsString)
const [connectMode, setConnectMode] = useState<'dialog' | 'sheet'>(
isConnectSheetEnabled ? 'sheet' : 'dialog'
)
useEffect(() => {
if (showConnect) return
setConnectMode(isConnectSheetEnabled ? 'sheet' : 'dialog')
}, [isConnectSheetEnabled, showConnect])
const handleOpenChange = (open: boolean) => {
if (!open) {
setShowConnect(null)
setConnectTab(null)
return
}
setShowConnect(true)
}
if (!isActiveHealthy) {
return (
<ButtonTooltip
disabled
type="default"
className="rounded-full"
icon={<Plug className="rotate-90" />}
tooltip={{
content: {
side: 'bottom',
text: 'Project is currently not active and cannot be connected',
},
}}
>
Connect
</ButtonTooltip>
)
}
return (
<>
<Button
type={buttonType}
className="rounded-full"
icon={<Plug className="rotate-90" />}
onClick={() => handleOpenChange(true)}
>
<span>Connect</span>
</Button>
{renderDialog ? (
connectMode === 'sheet' ? (
<ConnectSheet
open={showConnect}
onOpenChange={handleOpenChange}
connectTab={connectTab}
/>
) : (
<Connect open={showConnect} onOpenChange={handleOpenChange} />
)
) : null}
</>
)
}
@@ -1,60 +0,0 @@
import { Plug } from 'lucide-react'
import { useRouter } from 'next/router'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { PROJECT_STATUS } from 'lib/constants'
import type { ICommand } from 'ui-patterns/CommandMenu'
import { useRegisterCommands, useSetCommandMenuOpen } from 'ui-patterns/CommandMenu'
import { COMMAND_MENU_SECTIONS } from 'components/interfaces/App/CommandMenu/CommandMenu.utils'
import { orderCommandSectionsByPriority } from 'components/interfaces/App/CommandMenu/ordering'
export function useConnectCommands() {
const router = useRouter()
const setIsOpen = useSetCommandMenuOpen()
const { data: selectedProject } = useSelectedProjectQuery()
const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY
useRegisterCommands(
COMMAND_MENU_SECTIONS.ACTIONS,
[
{
id: 'connect-to-project',
name: 'Connect to your project',
action: () => {
// Open the Connect dialog by setting the showConnect query param
router.push(
{
pathname: router.pathname,
query: { ...router.query, showConnect: 'true' },
},
undefined,
{ shallow: true }
)
setIsOpen(false)
},
icon: () => <Plug className="rotate-90" />,
},
{
id: 'connect-mcp',
name: 'Connect via MCP',
action: () => {
// Open the Connect dialog with MCP tab
router.push(
{
pathname: router.pathname,
query: { ...router.query, showConnect: 'true', connectTab: 'mcp' },
},
undefined,
{ shallow: true }
)
setIsOpen(false)
},
icon: () => <Plug className="rotate-90" />,
},
] as ICommand[],
{
enabled: !!selectedProject && isActiveHealthy,
orderSection: orderCommandSectionsByPriority,
sectionMeta: { priority: 2 },
}
)
}
@@ -1,25 +1,18 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { Plug } from 'lucide-react'
import { useRouter } from 'next/router'
import { ComponentProps, useEffect, useMemo, useState } from 'react'
import { useEffect, useMemo } from 'react'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { DatabaseSelector } from 'components/ui/DatabaseSelector'
import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query'
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { PROJECT_STATUS } from 'lib/constants'
import {
Button,
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
cn
} from 'ui'
@@ -29,14 +22,12 @@ import { ConnectStepsSection } from './ConnectStepsSection'
import { useConnectState } from './useConnectState'
interface ConnectSheetProps {
buttonType?: ComponentProps<typeof Button>['type']
open: boolean
onOpenChange: (open: boolean) => void
connectTab?: string | null
}
export const ConnectSheet = ({ buttonType = 'default' }: ConnectSheetProps) => {
const router = useRouter()
const { data: selectedProject } = useSelectedProjectQuery()
const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY
export const ConnectSheet = ({ open, onOpenChange, connectTab }: ConnectSheetProps) => {
const {
projectConnectionShowAppFrameworks: showAppFrameworks,
projectConnectionShowMobileFrameworks: showMobileFrameworks,
@@ -60,8 +51,6 @@ export const ConnectSheet = ({ buttonType = 'default' }: ConnectSheetProps) => {
return modes
}, [showAppFrameworks, showMobileFrameworks, showOrms])
const [showConnect, setShowConnect] = useState(false)
const {
state,
updateField,
@@ -82,7 +71,7 @@ export const ConnectSheet = ({ buttonType = 'default' }: ConnectSheetProps) => {
const { ref: projectRef } = useParams()
const { data: settings } = useProjectSettingsV2Query(
{ projectRef },
{ enabled: showConnect }
{ enabled: open }
)
const { can: canReadAPIKeys } = useAsyncCheckPermissions(
PermissionAction.READ,
@@ -114,61 +103,23 @@ export const ConnectSheet = ({ buttonType = 'default' }: ConnectSheetProps) => {
publishableKey?.api_key,
])
const handleSheetChange = (open: boolean) => {
if (!open && router.query.showConnect === 'true') {
const nextQuery = { ...router.query }
delete nextQuery.showConnect
delete nextQuery.connectTab
router.replace({ pathname: router.pathname, query: nextQuery }, undefined, { shallow: true })
}
setShowConnect(open)
}
const handleSourceChange = (databaseId: string) => {
// Database selection is handled by the DatabaseSelector's internal state
// We just need to trigger a re-render of connection strings
}
useEffect(() => {
if (!router.isReady) return
if (router.query.showConnect === 'true') {
setShowConnect(true)
const connectTab = router.query.connectTab
if (typeof connectTab === 'string') {
if (connectTab === 'mcp') setMode('mcp')
else if (connectTab === 'orms') setMode('orm')
else if (connectTab === 'direct') setMode('direct')
else if (connectTab === 'frameworks' || connectTab === 'mobiles') setMode('framework')
}
if (!open) return
if (typeof connectTab === 'string') {
if (connectTab === 'mcp') setMode('mcp')
else if (connectTab === 'orms') setMode('orm')
else if (connectTab === 'direct') setMode('direct')
else if (connectTab === 'frameworks' || connectTab === 'mobiles') setMode('framework')
}
}, [router.isReady, router.query.connectTab, router.query.showConnect, setMode])
if (!isActiveHealthy) {
return (
<ButtonTooltip
disabled
type="default"
className="rounded-full"
icon={<Plug className="rotate-90" />}
tooltip={{
content: {
side: 'bottom',
text: 'Project is currently not active and cannot be connected',
},
}}
>
Connect
</ButtonTooltip>
)
}
}, [connectTab, open, setMode])
return (
<Sheet open={showConnect} onOpenChange={handleSheetChange}>
<SheetTrigger asChild>
<Button type={buttonType} className="rounded-full" icon={<Plug className="rotate-90" />}>
<span>Connect</span>
</Button>
</SheetTrigger>
<Sheet open={open} onOpenChange={onOpenChange}>
<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')}>
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
@@ -2,7 +2,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
import { JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
import { Loader } from 'lucide-react'
import { ConnectSheet } from '@/components/interfaces/ConnectSheet/ConnectSheet'
import { ConnectButton } from '@/components/interfaces/ConnectButton/ConnectButton'
import { ConnectionIcon } from '@/components/interfaces/ConnectSheet/ConnectionIcon'
import { useParams } from 'common'
import { AlertError } from 'components/ui/AlertError'
@@ -208,7 +208,7 @@ export const APIKeys = () => {
Connect to your project from a variety of frameworks, ORMs, an MCP server, or even
directly via connection string.
</p>
<ConnectSheet />
<ConnectButton renderDialog={false} />
</div>
</CardContent>
</>
@@ -1,7 +1,7 @@
import { Code, Table2 } from 'lucide-react'
import { useCallback, useMemo, useState } from 'react'
import { ConnectSheet } from '@/components/interfaces/ConnectSheet/ConnectSheet'
import { ConnectButton } from '@/components/interfaces/ConnectButton/ConnectButton'
import { useParams } from 'common'
import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
@@ -50,7 +50,7 @@ export function GettingStartedSection({ value, onChange }: GettingStartedSection
return [
{
label: 'Connect',
component: <ConnectSheet buttonType="primary" />,
component: <ConnectButton buttonType="primary" renderDialog={false} />,
},
]
}, [])
@@ -3,7 +3,7 @@ import { ChevronLeft } from 'lucide-react'
import Link from 'next/link'
import { ReactNode, useMemo } from 'react'
import { ConnectSheet } from '@/components/interfaces/ConnectSheet/ConnectSheet'
import { ConnectButton } from '@/components/interfaces/ConnectButton/ConnectButton'
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
import { useIsBranching2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import { LocalDropdown } from 'components/interfaces/LocalDropdown'
@@ -198,7 +198,7 @@ export const LayoutHeader = ({
}}
>
{IS_PLATFORM && gitlessBranching && <MergeRequestButton />}
<ConnectSheet />
<ConnectButton />
</motion.div>
)}
</AnimatePresence>