From bc9afa9d470dca31dbd815d6cc726465757c82f1 Mon Sep 17 00:00:00 2001 From: Saxon Fletcher Date: Mon, 2 Feb 2026 13:40:29 +1000 Subject: [PATCH] remove other modes for review --- .../interfaces/ConnectSheet/ConnectSheet.tsx | 21 +- .../ConnectSheet/connect.schema.test.ts | 169 +++-------- .../interfaces/ConnectSheet/connect.schema.ts | 187 ------------- .../ConnectSheet/content/drizzle/content.tsx | 64 ----- .../ConnectSheet/content/prisma/content.tsx | 62 ---- .../steps/direct-connection/content.tsx | 93 ------ .../content/steps/direct-files/content.tsx | 264 ------------------ .../content/steps/direct-install/content.tsx | 36 --- .../mcp/claude-code/add-server/content.tsx | 47 ---- .../mcp/claude-code/authenticate/content.tsx | 22 -- .../steps/mcp/codex/add-server/content.tsx | 47 ---- .../steps/mcp/codex/authenticate/content.tsx | 18 -- .../steps/mcp/codex/enable-remote/content.tsx | 19 -- .../steps/mcp/codex/verify/content.tsx | 14 - .../content/steps/mcp/cursor/content.tsx | 90 ------ .../content/steps/orm-install/content.tsx | 36 --- .../ConnectSheet/useConnectState.test.ts | 225 +-------------- 17 files changed, 47 insertions(+), 1367 deletions(-) delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/drizzle/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/prisma/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/direct-files/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/direct-install/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/add-server/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/authenticate/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/add-server/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/authenticate/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/enable-remote/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/verify/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/cursor/content.tsx delete mode 100644 apps/studio/components/interfaces/ConnectSheet/content/steps/orm-install/content.tsx diff --git a/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx b/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx index 94e88691cbf..cc0b4ff7fff 100644 --- a/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx +++ b/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx @@ -23,25 +23,17 @@ export const ConnectSheet = ({ open, onOpenChange, connectTab }: ConnectSheetPro const { projectConnectionShowAppFrameworks: showAppFrameworks, projectConnectionShowMobileFrameworks: showMobileFrameworks, - projectConnectionShowOrms: showOrms, } = useIsFeatureEnabled([ 'project_connection:show_app_frameworks', 'project_connection:show_mobile_frameworks', - 'project_connection:show_orms', ]) // Filter available modes based on feature flags 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]) + return showFrameworks ? ['framework'] : [] + }, [showAppFrameworks, showMobileFrameworks]) const { state, updateField, setMode, activeFields, resolvedSteps, getFieldOptions, schema } = useConnectState() @@ -90,10 +82,7 @@ export const ConnectSheet = ({ open, onOpenChange, connectTab }: ConnectSheetPro useEffect(() => { 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') + if (connectTab === 'frameworks' || connectTab === 'mobiles') setMode('framework') } }, [connectTab, open, setMode]) @@ -123,7 +112,9 @@ export const ConnectSheet = ({ open, onOpenChange, connectTab }: ConnectSheetPro
{/* Configuration Section */}
- + {availableModes.length > 1 && ( + + )}
{ test('should have all required modes', () => { const modeIds = connectSchema.modes.map((m) => m.id) - expect(modeIds).toContain('framework') - expect(modeIds).toContain('direct') - expect(modeIds).toContain('orm') - expect(modeIds).toContain('mcp') + expect(modeIds).toEqual(['framework']) }) test('each mode should have required properties', () => { @@ -34,23 +31,19 @@ describe('connect.schema:structure', () => { expect(frameworkMode?.fields).toContain('frameworkUi') }) - test('direct mode should have correct fields', () => { + test('direct mode should be removed', () => { const directMode = connectSchema.modes.find((m) => m.id === 'direct') - expect(directMode?.fields).toContain('connectionMethod') - expect(directMode?.fields).toContain('useSharedPooler') - expect(directMode?.fields).toContain('connectionType') + expect(directMode).toBeUndefined() }) - test('orm mode should have correct fields', () => { + test('orm mode should be removed', () => { const ormMode = connectSchema.modes.find((m) => m.id === 'orm') - expect(ormMode?.fields).toContain('orm') + expect(ormMode).toBeUndefined() }) - test('mcp mode should have correct fields', () => { + test('mcp mode should be removed', () => { const mcpMode = connectSchema.modes.find((m) => m.id === 'mcp') - expect(mcpMode?.fields).toContain('mcpClient') - expect(mcpMode?.fields).toContain('mcpReadonly') - expect(mcpMode?.fields).toContain('mcpFeatures') + expect(mcpMode).toBeUndefined() }) test('all mode fields should exist in fields definition', () => { @@ -89,37 +82,29 @@ describe('connect.schema:fields', () => { expect(field.dependsOn).toEqual({ framework: ['nextjs', 'react'] }) }) - test('connectionMethod field should have radio-list type', () => { + test('connectionMethod field should be removed', () => { const field = connectSchema.fields.connectionMethod - expect(field.type).toBe('radio-list') - expect(field.options).toEqual({ source: 'connectionMethods' }) - expect(field.defaultValue).toBe('direct') + expect(field).toBeUndefined() }) - test('useSharedPooler field should depend on transaction connection method', () => { + test('useSharedPooler field should be removed', () => { const field = connectSchema.fields.useSharedPooler - expect(field.type).toBe('switch') - expect(field.dependsOn).toEqual({ connectionMethod: ['transaction'] }) + expect(field).toBeUndefined() }) - test('orm field should have radio-list type', () => { + test('orm field should be removed', () => { const field = connectSchema.fields.orm - expect(field.type).toBe('radio-list') - expect(field.options).toEqual({ source: 'orms' }) - expect(field.defaultValue).toBe('prisma') + expect(field).toBeUndefined() }) - test('mcpClient field should have select type', () => { + test('mcpClient field should be removed', () => { const field = connectSchema.fields.mcpClient - expect(field.type).toBe('select') - expect(field.options).toEqual({ source: 'mcpClients' }) - expect(field.defaultValue).toBe('cursor') + expect(field).toBeUndefined() }) - test('mcpFeatures field should have multi-select type', () => { + test('mcpFeatures field should be removed', () => { const field = connectSchema.fields.mcpFeatures - expect(field.type).toBe('multi-select') - expect(field.options).toEqual({ source: 'mcpFeatures' }) + expect(field).toBeUndefined() }) }) @@ -198,101 +183,35 @@ describe('connect.schema:steps resolution', () => { }) describe('direct mode steps', () => { - test('should resolve connection step for default direct mode', () => { + test('should not resolve steps for direct mode', () => { const state: ConnectState = { mode: 'direct' } const steps = resolveSteps(connectSchema, state) - expect(steps.find((s) => s.id === 'connection')).toBeDefined() - }) - - test('should resolve install and files steps for nodejs connection type', () => { - const state: ConnectState = { mode: 'direct', connectionType: 'nodejs' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'direct-install')).toBeDefined() - expect(steps.find((s) => s.id === 'direct-files')).toBeDefined() - }) - - test('should resolve install and files steps for golang connection type', () => { - const state: ConnectState = { mode: 'direct', connectionType: 'golang' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'direct-install')).toBeDefined() - expect(steps.find((s) => s.id === 'direct-files')).toBeDefined() - }) - - test('should resolve install and files steps for python connection type', () => { - const state: ConnectState = { mode: 'direct', connectionType: 'python' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'direct-install')).toBeDefined() - }) - - test('should resolve install and files steps for dotnet connection type', () => { - const state: ConnectState = { mode: 'direct', connectionType: 'dotnet' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'direct-install')).toBeDefined() + expect(steps.length).toBe(0) }) }) describe('orm mode steps', () => { - test('should resolve install and configure steps for prisma', () => { + test('should not resolve steps for orm mode', () => { const state: ConnectState = { mode: 'orm', orm: 'prisma' } const steps = resolveSteps(connectSchema, state) - expect(steps.find((s) => s.id === 'install')).toBeDefined() - expect(steps.find((s) => s.id === 'configure')).toBeDefined() - expect(steps.find((s) => s.id === 'install-skills')).toBeDefined() - }) - - test('should resolve install and configure steps for drizzle', () => { - const state: ConnectState = { mode: 'orm', orm: 'drizzle' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'install')).toBeDefined() - expect(steps.find((s) => s.id === 'configure')).toBeDefined() + expect(steps.length).toBe(0) }) }) describe('mcp mode steps', () => { - test('should resolve configure step for cursor client', () => { + test('should not resolve steps for mcp mode', () => { const state: ConnectState = { mode: 'mcp', mcpClient: 'cursor' } const steps = resolveSteps(connectSchema, state) - expect(steps.find((s) => s.id === 'configure-mcp')).toBeDefined() - expect(steps.find((s) => s.id === 'install-skills')).toBeDefined() - }) - - test('should resolve codex-specific steps for codex client', () => { - const state: ConnectState = { mode: 'mcp', mcpClient: 'codex' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'codex-add-server')).toBeDefined() - expect(steps.find((s) => s.id === 'codex-enable-remote')).toBeDefined() - expect(steps.find((s) => s.id === 'codex-authenticate')).toBeDefined() - expect(steps.find((s) => s.id === 'codex-verify')).toBeDefined() - }) - - test('should resolve claude-code-specific steps for claude-code client', () => { - const state: ConnectState = { mode: 'mcp', mcpClient: 'claude-code' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'claude-add-server')).toBeDefined() - expect(steps.find((s) => s.id === 'claude-authenticate')).toBeDefined() - }) - - test('should resolve default mcp steps for other clients', () => { - const state: ConnectState = { mode: 'mcp', mcpClient: 'unknown-client' } - const steps = resolveSteps(connectSchema, state) - - expect(steps.find((s) => s.id === 'configure-mcp')).toBeDefined() + expect(steps.length).toBe(0) }) }) describe('skills install step', () => { test('should include skills install step in all modes', () => { - const modes: ConnectState['mode'][] = ['framework', 'direct', 'orm', 'mcp'] + const modes: ConnectState['mode'][] = ['framework'] modes.forEach((mode) => { const state: ConnectState = { mode } @@ -336,12 +255,11 @@ describe('connect.schema:step content paths', () => { expect(exploreStep?.content).toBe('steps/shadcn/explore') }) - test('direct connection step should have valid content path', () => { + test('direct connection step should not be resolved', () => { const state: ConnectState = { mode: 'direct' } const steps = resolveSteps(connectSchema, state) - const connectionStep = steps.find((s) => s.id === 'connection') - expect(connectionStep?.content).toBe('steps/direct-connection') + expect(steps.length).toBe(0) }) test('skills install step should have valid content path', () => { @@ -352,50 +270,31 @@ describe('connect.schema:step content paths', () => { expect(skillsStep?.content).toBe('steps/skills-install') }) - test('orm configure step should use template content path', () => { - // The ORM configure step uses a template {{orm}} that gets resolved - // by the dynamic import system, not the resolver + test('orm configure step should not be resolved', () => { const state: ConnectState = { mode: 'orm', orm: 'prisma' } const steps = resolveSteps(connectSchema, state) - const configureStep = steps.find((s) => s.id === 'configure') - // The content path uses template syntax for the component loader - expect(configureStep?.content).toBe('{{orm}}') + expect(steps.length).toBe(0) }) - test('mcp cursor configure step should have valid content path', () => { + test('mcp cursor configure step should not be resolved', () => { const state: ConnectState = { mode: 'mcp', mcpClient: 'cursor' } const steps = resolveSteps(connectSchema, state) - const configureStep = steps.find((s) => s.id === 'configure-mcp') - expect(configureStep?.content).toBe('steps/mcp/cursor') + expect(steps.length).toBe(0) }) - test('codex steps should have valid content paths', () => { + test('codex steps should not be resolved', () => { const state: ConnectState = { mode: 'mcp', mcpClient: 'codex' } const steps = resolveSteps(connectSchema, state) - expect(steps.find((s) => s.id === 'codex-add-server')?.content).toBe( - 'steps/mcp/codex/add-server' - ) - expect(steps.find((s) => s.id === 'codex-enable-remote')?.content).toBe( - 'steps/mcp/codex/enable-remote' - ) - expect(steps.find((s) => s.id === 'codex-authenticate')?.content).toBe( - 'steps/mcp/codex/authenticate' - ) - expect(steps.find((s) => s.id === 'codex-verify')?.content).toBe('steps/mcp/codex/verify') + expect(steps.length).toBe(0) }) - test('claude-code steps should have valid content paths', () => { + test('claude-code steps should not be resolved', () => { const state: ConnectState = { mode: 'mcp', mcpClient: 'claude-code' } const steps = resolveSteps(connectSchema, state) - expect(steps.find((s) => s.id === 'claude-add-server')?.content).toBe( - 'steps/mcp/claude-code/add-server' - ) - expect(steps.find((s) => s.id === 'claude-authenticate')?.content).toBe( - 'steps/mcp/claude-code/authenticate' - ) + expect(steps.length).toBe(0) }) }) diff --git a/apps/studio/components/interfaces/ConnectSheet/connect.schema.ts b/apps/studio/components/interfaces/ConnectSheet/connect.schema.ts index f4171d1877b..a33703373df 100644 --- a/apps/studio/components/interfaces/ConnectSheet/connect.schema.ts +++ b/apps/studio/components/interfaces/ConnectSheet/connect.schema.ts @@ -60,92 +60,6 @@ const frameworkShadcnExploreStep: StepDefinition = { content: 'steps/shadcn/explore', } -const directConnectionStep: StepDefinition = { - id: 'connection', - title: 'Connection string', - description: 'Copy the connection details for your database.', - content: 'steps/direct-connection', -} - -const directInstallStep: StepDefinition = { - id: 'direct-install', - title: 'Install dependencies', - description: 'Run this command to install the required dependencies.', - content: 'steps/direct-install', -} - -const directFilesStep: StepDefinition = { - id: 'direct-files', - title: 'Add files', - description: 'Add the following files to your project.', - content: 'steps/direct-files', -} - -const mcpConfigureStep: StepDefinition = { - id: 'configure-mcp', - title: 'Configure MCP', - description: 'Set up your MCP client.', - content: 'steps/mcp/cursor', -} - -// Codex-specific MCP steps -const codexAddServerStep: StepDefinition = { - id: 'codex-add-server', - title: 'Add the Supabase MCP server to Codex', - description: 'Run this command to add the server.', - content: 'steps/mcp/codex/add-server', -} - -const codexEnableRemoteStep: StepDefinition = { - id: 'codex-enable-remote', - title: 'Enable remote MCP client support', - description: 'Add this to your ~/.codex/config.toml file.', - content: 'steps/mcp/codex/enable-remote', -} - -const codexAuthenticateStep: StepDefinition = { - id: 'codex-authenticate', - title: 'Authenticate', - description: 'Run the authentication command.', - content: 'steps/mcp/codex/authenticate', -} - -const codexVerifyStep: StepDefinition = { - id: 'codex-verify', - title: 'Verify authentication', - description: 'Run /mcp inside Codex to verify.', - content: 'steps/mcp/codex/verify', -} - -const claudeAddServerStep: StepDefinition = { - id: 'claude-add-server', - title: 'Add MCP server', - description: 'Add the MCP server to your project config using the command line.', - content: 'steps/mcp/claude-code/add-server', -} - -const claudeAuthenticateStep: StepDefinition = { - id: 'claude-authenticate', - title: 'Authenticate', - description: - 'After configuring the MCP server, you need to authenticate. In a regular terminal (not the IDE extension) run:', - content: 'steps/mcp/claude-code/authenticate', -} - -const ormInstallStep: StepDefinition = { - id: 'install', - title: 'Install ORM', - description: 'Add the ORM to your project.', - content: 'steps/orm-install', -} - -const ormConfigureStep: StepDefinition = { - id: 'configure', - title: 'Configure ORM', - description: 'Set up your ORM configuration.', - content: '{{orm}}', -} - const skillsInstallStep: StepDefinition = { id: 'install-skills', title: 'Install Agent Skills (Optional)', @@ -169,24 +83,6 @@ export const connectSchema: ConnectSchema = { description: 'Use a client library', fields: ['framework', 'frameworkVariant', 'library', 'frameworkUi'], }, - { - id: 'direct', - label: 'Direct', - description: 'Connection string', - fields: ['connectionMethod', 'useSharedPooler', 'connectionType'], - }, - { - id: 'orm', - label: 'ORM', - description: 'Third-party library', - fields: ['orm'], - }, - { - id: 'mcp', - label: 'MCP', - description: 'Connect your agent', - fields: ['mcpClient', 'mcpReadonly', 'mcpFeatures'], - }, ], // ------------------------------------------------------------------------- @@ -224,64 +120,6 @@ export const connectSchema: ConnectSchema = { defaultValue: false, dependsOn: { framework: ['nextjs', 'react'] }, }, - - // Direct connection fields - connectionMethod: { - id: 'connectionMethod', - type: 'radio-list', - label: 'Connection Method', - options: { source: 'connectionMethods' }, - defaultValue: 'direct', - }, - useSharedPooler: { - id: 'useSharedPooler', - type: 'switch', - label: 'Use IPv4 connection (Shared Pooler)', - description: 'Only recommended when your network does not support IPv6', - defaultValue: false, - dependsOn: { connectionMethod: ['transaction'] }, - }, - connectionType: { - id: 'connectionType', - type: 'select', - label: 'Type', - options: { source: 'connectionTypes' }, - defaultValue: 'uri', - }, - - // ORM fields - orm: { - id: 'orm', - type: 'radio-list', - label: 'ORM', - options: { source: 'orms' }, - defaultValue: 'prisma', - }, - - // MCP fields - mcpClient: { - id: 'mcpClient', - type: 'select', - label: 'Client', - description: 'Choose the MCP client you are using.', - options: { source: 'mcpClients' }, - defaultValue: 'cursor', - }, - mcpReadonly: { - id: 'mcpReadonly', - type: 'switch', - label: 'Read-only', - description: 'Only allow read operations on your database', - defaultValue: false, - }, - mcpFeatures: { - id: 'mcpFeatures', - type: 'multi-select', - label: 'Feature groups', - description: - 'Only enable a subset of features. Helps keep the number of tools within MCP client limits.', - options: { source: 'mcpFeatures' }, - }, }, // ------------------------------------------------------------------------- @@ -317,31 +155,6 @@ export const connectSchema: ConnectSchema = { DEFAULT: [frameworkInstallStep, frameworkConfigureStep, skillsInstallStep], }, }, - direct: { - connectionType: { - nodejs: [directInstallStep, directFilesStep, skillsInstallStep], - golang: [directInstallStep, directFilesStep, skillsInstallStep], - dotnet: [directInstallStep, directFilesStep, skillsInstallStep], - python: [directInstallStep, directFilesStep, skillsInstallStep], - sqlalchemy: [directInstallStep, directFilesStep, skillsInstallStep], - DEFAULT: [directConnectionStep, skillsInstallStep], - }, - }, - orm: [ormInstallStep, ormConfigureStep, skillsInstallStep], - mcp: { - mcpClient: { - codex: [ - codexAddServerStep, - codexEnableRemoteStep, - codexAuthenticateStep, - codexVerifyStep, - skillsInstallStep, - ], - 'claude-code': [claudeAddServerStep, claudeAuthenticateStep, skillsInstallStep], - DEFAULT: [mcpConfigureStep, skillsInstallStep], - }, - }, - DEFAULT: [skillsInstallStep], }, }, } diff --git a/apps/studio/components/interfaces/ConnectSheet/content/drizzle/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/drizzle/content.tsx deleted file mode 100644 index 1a693850624..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/drizzle/content.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { MultipleCodeBlock } from 'ui-patterns/MultipleCodeBlock' - -import type { ContentFileProps } from '@/components/interfaces/ConnectSheet/Connect.types' - -const ContentFile = ({ connectionStringPooler }: ContentFileProps) => { - const files = [ - { - name: '.env', - language: 'bash', - code: - connectionStringPooler.ipv4SupportedForDedicatedPooler && - connectionStringPooler.transactionDedicated - ? ` -DATABASE_URL="${connectionStringPooler.transactionDedicated}" - ` - : connectionStringPooler.transactionDedicated && - !connectionStringPooler.ipv4SupportedForDedicatedPooler - ? ` -# Use Shared connection pooler (supports both IPv4/IPv6) -DATABASE_URL="${connectionStringPooler.transactionShared}" - -# If your network supports IPv6 or you purchased IPv4 addon, use dedicated pooler -# DATABASE_URL="${connectionStringPooler.transactionDedicated}" - ` - : ` -DATABASE_URL="${connectionStringPooler.transactionShared}" -`, - }, - { - name: 'drizzle/schema.tsx', - language: 'tsx', - code: ` -import { pgTable, serial, text, varchar } from "drizzle-orm/pg-core"; - -export const users = pgTable('users', { - id: serial('id').primaryKey(), - fullName: text('full_name'), - phone: varchar('phone', { length: 256 }), -}); - `, - }, - { - name: 'index.tsx', - language: 'tsx', - code: ` -import { drizzle } from 'drizzle-orm/postgres-js' -import postgres from 'postgres' -import { users } from './schema' - -const connectionString = process.env.DATABASE_URL - -// Disable prefetch as it is not supported for "Transaction" pool mode -const client = postgres(connectionString, { prepare: false }) -const db = drizzle(client); - -const allUsers = await db.select().from(users); - `, - }, - ] - - return -} - -export default ContentFile diff --git a/apps/studio/components/interfaces/ConnectSheet/content/prisma/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/prisma/content.tsx deleted file mode 100644 index 27ec291ce63..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/prisma/content.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { IS_PLATFORM } from 'lib/constants' -import { MultipleCodeBlock } from 'ui-patterns/MultipleCodeBlock' - -import type { ContentFileProps } from '@/components/interfaces/ConnectSheet/Connect.types' - -const ContentFile = ({ connectionStringPooler }: ContentFileProps) => { - const files = [ - { - name: '.env.local', - language: 'bash', - code: - connectionStringPooler.ipv4SupportedForDedicatedPooler && - connectionStringPooler.transactionDedicated - ? ` -# Connect to Supabase via connection pooling. -DATABASE_URL="${connectionStringPooler.transactionDedicated}?pgbouncer=true" - -# Direct connection to the database. Used for migrations. -DIRECT_URL="${connectionStringPooler.sessionDedicated}" - ` - : connectionStringPooler.transactionDedicated && - !connectionStringPooler.ipv4SupportedForDedicatedPooler - ? ` -# Connect to Supabase via Shared Connection Pooler -DATABASE_URL="${connectionStringPooler.transactionShared}?pgbouncer=true" - -# Direct connection to the database through Shared Pooler (supports IPv4/IPv6). Used for migrations. -DIRECT_URL="${connectionStringPooler.sessionShared}" - -# If your network supports IPv6 or you purchased IPv4 addon, use dedicated pooler -# DATABASE_URL="${connectionStringPooler.transactionDedicated}?pgbouncer=true" -# DIRECT_URL="${connectionStringPooler.sessionDedicated}" - ` - : ` -# Connect to Supabase ${IS_PLATFORM ? 'via connection pooling' : ''} -DATABASE_URL="${IS_PLATFORM ? `${connectionStringPooler.transactionShared}?pgbouncer=true` : connectionStringPooler.direct}" - -# Direct connection to the database. Used for migrations -DIRECT_URL="${IS_PLATFORM ? connectionStringPooler.sessionShared : connectionStringPooler.direct}" -`, - }, - { - name: 'prisma/schema.prisma', - language: 'bash', - code: ` -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") - directUrl = env("DIRECT_URL") -} - `, - }, - ] - - return -} - -export default ContentFile diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx deleted file mode 100644 index ec404cfc90d..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { useMemo } from 'react' -import { CodeBlock } from 'ui' -import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' - -import { - type ConnectionStringMethod, - type DatabaseConnectionType, -} from '../../../Connect.constants' -import type { StepContentProps } from '../../../Connect.types' -import { ConnectionParameters } from '../../../ConnectionParameters' -import { - PASSWORD_PLACEHOLDER, - buildConnectionParameters, - buildSafeConnectionString, - parseConnectionParams, - resolveConnectionString, -} from '../../../ConnectionString.utils' - -const buildPsqlCommand = (params: { host: string; port: string; database: string; user: string }) => - `psql -h ${params.host} -p ${params.port} -d ${params.database} -U ${params.user}` - -const buildJdbcString = (params: { host: string; port: string; database: string; user: string }) => - `jdbc:postgresql://${params.host}:${params.port}/${params.database}?user=${params.user}&password=${PASSWORD_PLACEHOLDER}` - -/** - * Step component for direct database connections. - * Uses state to determine which connection string to show. - */ -function DirectConnectionContent({ state, connectionStringPooler }: StepContentProps) { - const connectionType = (state.connectionType as DatabaseConnectionType) ?? 'uri' - const connectionMethod = (state.connectionMethod as ConnectionStringMethod) ?? 'direct' - const useSharedPooler = Boolean(state.useSharedPooler) - - // Determine which connection string to use - const resolvedConnectionString = useMemo( - () => - resolveConnectionString({ - connectionMethod, - useSharedPooler, - connectionStringPooler, - }), - [connectionMethod, useSharedPooler, connectionStringPooler] - ) - - const connectionParams = useMemo( - () => parseConnectionParams(resolvedConnectionString), - [resolvedConnectionString] - ) - - const safeConnectionString = useMemo( - () => buildSafeConnectionString(resolvedConnectionString, connectionParams), - [resolvedConnectionString, connectionParams] - ) - - const connectionString = useMemo(() => { - switch (connectionType) { - case 'psql': - return buildPsqlCommand(connectionParams) - case 'jdbc': - return buildJdbcString(connectionParams) - case 'php': - return `DATABASE_URL=${safeConnectionString}` - case 'uri': - default: - return safeConnectionString - } - }, [connectionType, connectionParams, safeConnectionString]) - - if (!resolvedConnectionString) { - return ( -
- -
- ) - } - - return ( -
- - {connectionString} - - -
- ) -} - -export default DirectConnectionContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-files/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-files/content.tsx deleted file mode 100644 index 7d8602fafa3..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-files/content.tsx +++ /dev/null @@ -1,264 +0,0 @@ -import { useEffect, useMemo, useState } from 'react' -import { CodeBlock } from 'ui' -import { MultipleCodeBlock } from 'ui-patterns/MultipleCodeBlock' -import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' - -import { - type ConnectionStringMethod, - type DatabaseConnectionType, -} from '../../../Connect.constants' -import type { StepContentProps } from '../../../Connect.types' -import { ConnectionParameters } from '../../../ConnectionParameters' -import { - PASSWORD_PLACEHOLDER, - buildConnectionParameters, - buildSafeConnectionString, - parseConnectionParams, - resolveConnectionString, -} from '../../../ConnectionString.utils' - -const DOTNET_CONFIG_COMMAND = - 'dotnet add package Microsoft.Extensions.Configuration.Json --version YOUR_DOTNET_VERSION' - -type DirectFilesConfig = { - files: { - name: string - language?: string - code: string - }[] - connectionStringFile?: string - postCommands?: { label: string; command: string }[] -} - -function DirectFilesContent({ state, connectionStringPooler }: StepContentProps) { - const connectionType = (state.connectionType as DatabaseConnectionType) ?? 'uri' - const connectionMethod = (state.connectionMethod as ConnectionStringMethod) ?? 'direct' - const useSharedPooler = Boolean(state.useSharedPooler) - - const resolvedConnectionString = useMemo( - () => - resolveConnectionString({ - connectionMethod, - useSharedPooler, - connectionStringPooler, - }), - [connectionMethod, useSharedPooler, connectionStringPooler] - ) - - const connectionParams = useMemo( - () => parseConnectionParams(resolvedConnectionString), - [resolvedConnectionString] - ) - - const safeConnectionString = useMemo( - () => buildSafeConnectionString(resolvedConnectionString, connectionParams), - [resolvedConnectionString, connectionParams] - ) - - const config: DirectFilesConfig | null = useMemo(() => { - const envFile = { - name: '.env', - language: 'bash', - code: `DATABASE_URL=${safeConnectionString}`, - } - - switch (connectionType) { - case 'nodejs': - return { - files: [ - { - name: 'db.js', - language: 'js', - code: `import postgres from 'postgres' - -const connectionString = process.env.DATABASE_URL -const sql = postgres(connectionString) - -export default sql`, - }, - envFile, - ], - connectionStringFile: envFile.name, - } - - case 'golang': - return { - files: [ - { - name: 'main.go', - language: 'go', - code: `package main - -import ( -\t"context" -\t"log" -\t"os" -\t"github.com/jackc/pgx/v5" -) - -func main() { -\tconn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL")) -\tif err != nil { -\t\tlog.Fatalf("Failed to connect to the database: %v", err) -\t} -\tdefer conn.Close(context.Background()) - -\t// Example query to test connection -\tvar version string -\tif err := conn.QueryRow(context.Background(), "SELECT version()").Scan(&version); err != nil { -\t\tlog.Fatalf("Query failed: %v", err) -\t} - -\tlog.Println("Connected to:", version) -}`, - }, - envFile, - ], - connectionStringFile: envFile.name, - } - - case 'dotnet': - return { - files: [ - { - name: 'appsettings.json', - language: 'json', - code: `{ - "ConnectionStrings": { - "DefaultConnection": "Host=${connectionParams.host};Database=${connectionParams.database};Username=${connectionParams.user};Password=${PASSWORD_PLACEHOLDER};SSL Mode=Require;Trust Server Certificate=true" - } -}`, - }, - ], - connectionStringFile: 'appsettings.json', - postCommands: [ - { - label: 'Add the configuration package to read the settings.', - command: DOTNET_CONFIG_COMMAND, - }, - ], - } - - case 'python': - return { - files: [ - { - name: 'main.py', - language: 'python', - code: `import psycopg2 -from dotenv import load_dotenv -import os - -# Load environment variables from .env -load_dotenv() - -# Fetch variables -DATABASE_URL = os.getenv("DATABASE_URL") - -# Connect to the database -connection = psycopg2.connect(DATABASE_URL)`, - }, - envFile, - ], - connectionStringFile: envFile.name, - } - - case 'sqlalchemy': - return { - files: [ - { - name: 'main.py', - language: 'python', - code: `from sqlalchemy import create_engine -# from sqlalchemy.pool import NullPool -from dotenv import load_dotenv -import os - -# Load environment variables from .env -load_dotenv() - -# Fetch variables -USER = os.getenv("user") -PASSWORD = os.getenv("password") -HOST = os.getenv("host") -PORT = os.getenv("port") -DBNAME = os.getenv("dbname") - -# Construct the SQLAlchemy connection string -DATABASE_URL = f"postgresql+psycopg2://{USER}:{PASSWORD}@{HOST}:{PORT}/{DBNAME}?sslmode=require" - -# Create the SQLAlchemy engine -engine = create_engine(DATABASE_URL) -# If using Transaction Pooler or Session Pooler, we want to ensure we disable SQLAlchemy client side pooling - -# https://docs.sqlalchemy.org/en/20/core/pooling.html#switching-pool-implementations -# engine = create_engine(DATABASE_URL, poolclass=NullPool) - -# Test the connection -try: - with engine.connect() as connection: - print("Connection successful!") -except Exception as e: - print(f"Failed to connect: {e}")`, - }, - { - name: '.env', - language: 'bash', - code: [ - `user=${connectionParams.user}`, - `password=${PASSWORD_PLACEHOLDER}`, - `host=${connectionParams.host}`, - `port=${connectionParams.port}`, - `dbname=${connectionParams.database}`, - ].join('\n'), - }, - ], - connectionStringFile: '.env', - } - - default: - return null - } - }, [connectionType, safeConnectionString, connectionParams]) - - const defaultFile = config?.files[0]?.name ?? '' - const [activeFile, setActiveFile] = useState(defaultFile) - - useEffect(() => { - setActiveFile(defaultFile) - }, [connectionType, defaultFile]) - - if (!resolvedConnectionString) { - return ( -
- -
- ) - } - - if (!config?.files.length) { - return null - } - - return ( -
- - - {(config.postCommands ?? []).map((command) => ( -
-

{command.label}

- - {command.command} - -
- ))} -
- ) -} - -export default DirectFilesContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-install/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-install/content.tsx deleted file mode 100644 index e66e2a7359e..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-install/content.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { CodeBlock } from 'ui' - -import type { StepContentProps } from '../../../Connect.types' -import examples from '../../../DirectConnectionExamples' - -/** - * Step component for direct connection install commands. - */ -function DirectInstallContent({ state }: StepContentProps) { - const connectionType = (state.connectionType as string) ?? 'uri' - const example = examples[connectionType as keyof typeof examples] - const exampleInstallCommands = example?.installCommands ?? [] - - if (exampleInstallCommands.length === 0) { - return null - } - - return ( -
- {exampleInstallCommands.map((cmd) => ( - - {cmd} - - ))} -
- ) -} - -export default DirectInstallContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/add-server/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/add-server/content.tsx deleted file mode 100644 index 00d1d68013e..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/add-server/content.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useMemo } from 'react' -import { CodeBlock } from 'ui' - -import { IS_PLATFORM } from 'lib/constants' -import { FEATURE_GROUPS_NON_PLATFORM, FEATURE_GROUPS_PLATFORM } from 'ui-patterns/McpUrlBuilder' -import type { StepContentProps } from '../../../../../Connect.types' - -function useMcpUrl( - state: StepContentProps['state'], - projectKeys: StepContentProps['projectKeys'] -): string { - const readonly = Boolean(state.mcpReadonly) - const selectedFeatures = Array.isArray(state.mcpFeatures) ? state.mcpFeatures : [] - const baseUrl = IS_PLATFORM ? 'https://mcp.supabase.com' : projectKeys.apiUrl ?? '' - - return useMemo(() => { - const params = new URLSearchParams() - if (readonly) params.set('readonly', 'true') - - const supportedFeatures = IS_PLATFORM ? FEATURE_GROUPS_PLATFORM : FEATURE_GROUPS_NON_PLATFORM - const validFeatures = selectedFeatures.filter((f) => - supportedFeatures.some((group) => group.id === f) - ) - if (validFeatures.length > 0) { - params.set('features', validFeatures.join(',')) - } - - const queryString = params.toString() - return queryString ? `${baseUrl}?${queryString}` : baseUrl - }, [baseUrl, readonly, selectedFeatures]) -} - -function ClaudeAddServerContent({ state, projectKeys }: StepContentProps) { - const mcpUrl = useMcpUrl(state, projectKeys) - const command = `claude mcp add --scope project --transport http supabase "${mcpUrl}"` - - return ( - - ) -} - -export default ClaudeAddServerContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/authenticate/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/authenticate/content.tsx deleted file mode 100644 index 298140ef247..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/claude-code/authenticate/content.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { CodeBlock } from 'ui' - -import type { StepContentProps } from '../../../../../Connect.types' - -function ClaudeAuthenticateContent(_props: StepContentProps) { - return ( -
- -

- Select the supabase{' '} - server, then Authenticate to begin the flow. -

-
- ) -} - -export default ClaudeAuthenticateContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/add-server/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/add-server/content.tsx deleted file mode 100644 index 4a6ade248eb..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/add-server/content.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useMemo } from 'react' -import { CodeBlock } from 'ui' - -import { IS_PLATFORM } from 'lib/constants' -import { FEATURE_GROUPS_NON_PLATFORM, FEATURE_GROUPS_PLATFORM } from 'ui-patterns/McpUrlBuilder' -import type { StepContentProps } from '../../../../../Connect.types' - -function useMcpUrl( - state: StepContentProps['state'], - projectKeys: StepContentProps['projectKeys'] -): string { - const readonly = Boolean(state.mcpReadonly) - const selectedFeatures = Array.isArray(state.mcpFeatures) ? state.mcpFeatures : [] - const baseUrl = IS_PLATFORM ? 'https://mcp.supabase.com' : projectKeys.apiUrl ?? '' - - return useMemo(() => { - const params = new URLSearchParams() - if (readonly) params.set('readonly', 'true') - - const supportedFeatures = IS_PLATFORM ? FEATURE_GROUPS_PLATFORM : FEATURE_GROUPS_NON_PLATFORM - const validFeatures = selectedFeatures.filter((f) => - supportedFeatures.some((group) => group.id === f) - ) - if (validFeatures.length > 0) { - params.set('features', validFeatures.join(',')) - } - - const queryString = params.toString() - return queryString ? `${baseUrl}?${queryString}` : baseUrl - }, [baseUrl, readonly, selectedFeatures]) -} - -function CodexAddServerContent({ state, projectKeys }: StepContentProps) { - const mcpUrl = useMcpUrl(state, projectKeys) - const command = `codex mcp add supabase --url ${mcpUrl}` - - return ( - - ) -} - -export default CodexAddServerContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/authenticate/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/authenticate/content.tsx deleted file mode 100644 index 979eb58049f..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/authenticate/content.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { CodeBlock } from 'ui' - -import type { StepContentProps } from '../../../../../Connect.types' - -function CodexAuthenticateContent(_props: StepContentProps) { - const command = 'codex mcp login supabase' - - return ( - - ) -} - -export default CodexAuthenticateContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/enable-remote/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/enable-remote/content.tsx deleted file mode 100644 index ee6e8bd59ef..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/enable-remote/content.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { CodeBlock } from 'ui' - -import type { StepContentProps } from '../../../../../Connect.types' - -function CodexEnableRemoteContent(_props: StepContentProps) { - const configContent = `[mcp] -remote_mcp_client_enabled = true` - - return ( - - ) -} - -export default CodexEnableRemoteContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/verify/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/verify/content.tsx deleted file mode 100644 index 2f2d55e6ab7..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/codex/verify/content.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type { StepContentProps } from '../../../../../Connect.types' - -function CodexVerifyContent(_props: StepContentProps) { - return ( -
-

- Run /mcp inside Codex to - verify authentication. -

-
- ) -} - -export default CodexVerifyContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/cursor/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/cursor/content.tsx deleted file mode 100644 index c6acbea846e..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/mcp/cursor/content.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useParams } from 'common' -import { BASE_PATH, IS_PLATFORM } from 'lib/constants' -import { useTrack } from 'lib/telemetry/track' -import { useMemo } from 'react' -import { - createMcpCopyHandler, - FEATURE_GROUPS_NON_PLATFORM, - FEATURE_GROUPS_PLATFORM, - getMcpUrl, - MCP_CLIENTS, - McpConfigurationDisplay, -} from 'ui-patterns/McpUrlBuilder' -import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' - -import type { StepContentProps } from '../../../../Connect.types' - -function McpCursorContent({ state, projectKeys }: StepContentProps) { - const { ref: projectRef } = useParams() - - if (!projectRef) { - return ( -
- - -
- ) - } - - return -} - -function McpCursorContentInner({ - projectRef, - projectKeys, - state, -}: { - projectRef: string - projectKeys: StepContentProps['projectKeys'] - state: StepContentProps['state'] -}) { - const track = useTrack() - - const selectedClient = useMemo(() => { - const clientKey = String(state.mcpClient ?? '') - return MCP_CLIENTS.find((c) => c.key === clientKey) ?? MCP_CLIENTS[0] - }, [state.mcpClient]) - - const readonly = Boolean(state.mcpReadonly) - const selectedFeatures = Array.isArray(state.mcpFeatures) ? state.mcpFeatures : [] - - const selectedFeaturesSupported = useMemo(() => { - const supportedFeatures = IS_PLATFORM ? FEATURE_GROUPS_PLATFORM : FEATURE_GROUPS_NON_PLATFORM - return selectedFeatures.filter((feature) => - supportedFeatures.some((group) => group.id === feature) - ) - }, [selectedFeatures]) - - const handleCopy = useMemo( - () => - createMcpCopyHandler({ - selectedClient, - source: 'studio', - onTrack: (event) => track(event.action, event.properties, event.groups), - projectRef, - }), - [selectedClient, track, projectRef] - ) - - const { clientConfig } = getMcpUrl({ - projectRef, - isPlatform: IS_PLATFORM, - apiUrl: projectKeys.apiUrl ?? undefined, - readonly, - features: selectedFeaturesSupported, - selectedClient, - }) - - return ( - - ) -} - -export default McpCursorContent diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/orm-install/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/orm-install/content.tsx deleted file mode 100644 index a07c6b404a5..00000000000 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/orm-install/content.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { CodeBlock } from 'ui' - -import type { StepContentProps } from '../../../Connect.types' - -const ORM_INSTALL_COMMANDS: Record = { - prisma: ['npm install prisma --save-dev', 'npx prisma init'], - drizzle: ['npm install drizzle-orm', 'npm install drizzle-kit --save-dev'], -} - -function OrmInstallContent({ state }: StepContentProps) { - const ormKey = String(state.orm ?? '') - const commands = ORM_INSTALL_COMMANDS[ormKey] - - if (!commands?.length) { - return null - } - - return ( -
- {commands.map((cmd, index) => ( - - {cmd} - - ))} -
- ) -} - -export default OrmInstallContent diff --git a/apps/studio/components/interfaces/ConnectSheet/useConnectState.test.ts b/apps/studio/components/interfaces/ConnectSheet/useConnectState.test.ts index 6741601c7f6..80f3c128a8b 100644 --- a/apps/studio/components/interfaces/ConnectSheet/useConnectState.test.ts +++ b/apps/studio/components/interfaces/ConnectSheet/useConnectState.test.ts @@ -30,10 +30,11 @@ describe('useConnectState', () => { test('should accept initial state override', () => { const { result } = renderHook(() => - useConnectState({ mode: 'direct', connectionMethod: 'transaction' }) + useConnectState({ framework: 'react', frameworkVariant: 'vite' }) ) - expect(result.current.state.mode).toBe('direct') - expect(result.current.state.connectionMethod).toBe('transaction') + expect(result.current.state.mode).toBe('framework') + expect(result.current.state.framework).toBe('react') + expect(result.current.state.frameworkVariant).toBe('vite') }) test('should merge initial state with defaults', () => { @@ -48,50 +49,7 @@ describe('useConnectState', () => { // ============================================================================ describe('setMode', () => { - test('should switch to direct mode', () => { - const { result } = renderHook(() => useConnectState()) - - act(() => { - result.current.setMode('direct') - }) - - expect(result.current.state.mode).toBe('direct') - }) - - test('should initialize direct mode defaults when switching', () => { - const { result } = renderHook(() => useConnectState()) - - act(() => { - result.current.setMode('direct') - }) - - expect(result.current.state.connectionMethod).toBeDefined() - expect(result.current.state.connectionType).toBeDefined() - }) - - test('should switch to orm mode and initialize defaults', () => { - const { result } = renderHook(() => useConnectState()) - - act(() => { - result.current.setMode('orm') - }) - - expect(result.current.state.mode).toBe('orm') - expect(result.current.state.orm).toBe('prisma') - }) - - test('should switch to mcp mode and initialize defaults', () => { - const { result } = renderHook(() => useConnectState()) - - act(() => { - result.current.setMode('mcp') - }) - - expect(result.current.state.mode).toBe('mcp') - expect(result.current.state.mcpClient).toBeDefined() - }) - - test('should preserve framework state when switching back to framework mode', () => { + test('should preserve framework state when setting framework mode', () => { const { result } = renderHook(() => useConnectState()) // Change framework @@ -99,12 +57,7 @@ describe('useConnectState', () => { result.current.updateField('framework', 'react') }) - // Switch to direct - act(() => { - result.current.setMode('direct') - }) - - // Switch back to framework + // Set framework mode again act(() => { result.current.setMode('framework') }) @@ -167,44 +120,6 @@ describe('useConnectState', () => { expect(result.current.state.library).toBe('supabasejs') }) - test('should update connection method', () => { - const { result } = renderHook(() => useConnectState({ mode: 'direct' })) - - act(() => { - result.current.updateField('connectionMethod', 'transaction') - }) - - expect(result.current.state.connectionMethod).toBe('transaction') - }) - - test('should clear useSharedPooler when connectionMethod changes to direct', () => { - const { result } = renderHook(() => - useConnectState({ - mode: 'direct', - connectionMethod: 'transaction', - useSharedPooler: true, - }) - ) - - act(() => { - result.current.updateField('connectionMethod', 'direct') - }) - - // useSharedPooler is cleared because it depends on connectionMethod: ['transaction'] - // When the dependency is not satisfied, the field is removed from state - expect(result.current.state.useSharedPooler).toBeUndefined() - }) - - test('should update MCP client', () => { - const { result } = renderHook(() => useConnectState({ mode: 'mcp' })) - - act(() => { - result.current.updateField('mcpClient', 'codex') - }) - - expect(result.current.state.mcpClient).toBe('codex') - }) - test('should update boolean fields', () => { const { result } = renderHook(() => useConnectState()) @@ -214,16 +129,6 @@ describe('useConnectState', () => { expect(result.current.state.frameworkUi).toBe(true) }) - - test('should update ORM selection', () => { - const { result } = renderHook(() => useConnectState({ mode: 'orm' })) - - act(() => { - result.current.updateField('orm', 'drizzle') - }) - - expect(result.current.state.orm).toBe('drizzle') - }) }) // ============================================================================ @@ -258,47 +163,6 @@ describe('useConnectState', () => { const fieldIds = result.current.activeFields.map((f) => f.id) expect(fieldIds).not.toContain('frameworkUi') }) - - test('should return direct mode fields', () => { - const { result } = renderHook(() => useConnectState({ mode: 'direct' })) - - const fieldIds = result.current.activeFields.map((f) => f.id) - expect(fieldIds).toContain('connectionMethod') - expect(fieldIds).toContain('connectionType') - }) - - test('should show useSharedPooler only for transaction connection method', () => { - const { result } = renderHook(() => - useConnectState({ mode: 'direct', connectionMethod: 'transaction' }) - ) - - const fieldIds = result.current.activeFields.map((f) => f.id) - expect(fieldIds).toContain('useSharedPooler') - }) - - test('should hide useSharedPooler for direct connection method', () => { - const { result } = renderHook(() => - useConnectState({ mode: 'direct', connectionMethod: 'direct' }) - ) - - const fieldIds = result.current.activeFields.map((f) => f.id) - expect(fieldIds).not.toContain('useSharedPooler') - }) - - test('should return orm mode fields', () => { - const { result } = renderHook(() => useConnectState({ mode: 'orm' })) - - const fieldIds = result.current.activeFields.map((f) => f.id) - expect(fieldIds).toContain('orm') - }) - - test('should return mcp mode fields', () => { - const { result } = renderHook(() => useConnectState({ mode: 'mcp' })) - - const fieldIds = result.current.activeFields.map((f) => f.id) - expect(fieldIds).toContain('mcpClient') - expect(fieldIds).toContain('mcpReadonly') - }) }) // ============================================================================ @@ -319,28 +183,6 @@ describe('useConnectState', () => { expect(stepIds).toContain('install') }) - test('should resolve different steps for mcp mode', () => { - const { result } = renderHook(() => useConnectState({ mode: 'mcp' })) - - const stepIds = result.current.resolvedSteps.map((s) => s.id) - // MCP mode should have configure step - expect(stepIds.some((id) => id.includes('configure') || id.includes('mcp'))).toBe(true) - }) - - test('should resolve different steps for different mcp clients', () => { - const { result: cursorResult } = renderHook(() => - useConnectState({ mode: 'mcp', mcpClient: 'cursor' }) - ) - const { result: codexResult } = renderHook(() => - useConnectState({ mode: 'mcp', mcpClient: 'codex' }) - ) - - // Codex has more steps than cursor - expect(codexResult.current.resolvedSteps.length).toBeGreaterThanOrEqual( - cursorResult.current.resolvedSteps.length - ) - }) - test('should include skills install step', () => { const { result } = renderHook(() => useConnectState()) @@ -348,21 +190,6 @@ describe('useConnectState', () => { expect(stepIds).toContain('install-skills') }) - test('should resolve steps for direct mode', () => { - const { result } = renderHook(() => useConnectState({ mode: 'direct' })) - - expect(result.current.resolvedSteps.length).toBeGreaterThan(0) - }) - - test('should resolve steps for orm mode', () => { - const { result } = renderHook(() => useConnectState({ mode: 'orm' })) - - expect(result.current.resolvedSteps.length).toBeGreaterThan(0) - const stepIds = result.current.resolvedSteps.map((s) => s.id) - expect(stepIds).toContain('install') - expect(stepIds).toContain('configure') - }) - test('should resolve shadcn steps when frameworkUi is true', () => { const { result } = renderHook(() => useConnectState({ framework: 'nextjs', frameworkUi: true }) @@ -403,41 +230,6 @@ describe('useConnectState', () => { expect(options).toEqual([]) }) - test('should return connection method options', () => { - const { result } = renderHook(() => useConnectState({ mode: 'direct' })) - - const options = result.current.getFieldOptions('connectionMethod') - expect(options.length).toBeGreaterThan(0) - expect(options.some((o) => o.value === 'direct')).toBe(true) - expect(options.some((o) => o.value === 'transaction')).toBe(true) - }) - - test('should return connection type options', () => { - const { result } = renderHook(() => useConnectState({ mode: 'direct' })) - - const options = result.current.getFieldOptions('connectionType') - expect(options.length).toBeGreaterThan(0) - expect(options.some((o) => o.value === 'uri')).toBe(true) - expect(options.some((o) => o.value === 'psql')).toBe(true) - }) - - test('should return ORM options', () => { - const { result } = renderHook(() => useConnectState({ mode: 'orm' })) - - const options = result.current.getFieldOptions('orm') - expect(options.length).toBeGreaterThan(0) - expect(options.some((o) => o.value === 'prisma')).toBe(true) - expect(options.some((o) => o.value === 'drizzle')).toBe(true) - }) - - test('should return MCP client options', () => { - const { result } = renderHook(() => useConnectState({ mode: 'mcp' })) - - const options = result.current.getFieldOptions('mcpClient') - expect(options.length).toBeGreaterThan(0) - expect(options.some((o) => o.value === 'cursor')).toBe(true) - }) - test('should return empty array for unknown field', () => { const { result } = renderHook(() => useConnectState()) @@ -473,10 +265,7 @@ describe('useConnectState', () => { const { result } = renderHook(() => useConnectState()) const modeIds = result.current.schema.modes.map((m) => m.id) - expect(modeIds).toContain('framework') - expect(modeIds).toContain('direct') - expect(modeIds).toContain('orm') - expect(modeIds).toContain('mcp') + expect(modeIds).toEqual(['framework']) }) }) })