Files
Charisandsupabase-autofix-bot cdc2dc4e26 refactor(studio): import SQL editor store from source, delete facade + barrel (#47533)
## What

Final PR of the SQL editor state re-layering stack. Removes the
compatibility shims left in place during the migration:

- Migrates all **23** consumers of the `@/state/sql-editor-v2` facade to
import directly from `@/state/sql-editor/sql-editor-state`, where
`useSqlEditorV2StateSnapshot`, `getSqlEditorV2StateSnapshot`,
`useSnippets`, and `useSnippetFolders` actually live.
- Deletes `state/sql-editor-v2.ts` (the facade) and
`state/sql-editor/index.ts` (the barrel). Both re-exported the same
symbols; nothing imports them after the migration.

This collapses the two-layer re-export (`sql-editor-v2` → `index` →
source) into direct source imports, matching the repo convention to
avoid barrel re-export files.

## Notes

- Pure import-path migration — no behavior change. All 23 consumers
imported only value symbols that resolve to `sql-editor-state.ts`; none
imported the `StateSnippet`/`StateSnippetFolder` types via the facade.
- Symbol names keep their `V2` suffix for now — renaming
`useSqlEditorV2StateSnapshot` etc. is a separate, larger churn best done
on its own.
- 25 files: 23 one-line import changes + 2 deletions (23 insertions / 39
deletions).

## Validation

- `pnpm --filter studio typecheck` ✅ (confirms no dangling facade/barrel
imports anywhere)
- `pnpm exec vitest --run state/sql-editor/` ✅ (113 passed)
- lint ✅ (0 errors; no ratcheted-rule regressions — a path swap can't
add `any`/deps/nested-component violations, and no import-order rule is
enforced)
- grep confirms zero remaining `sql-editor-v2` references

---------

Co-authored-by: supabase-autofix-bot <noreply@supabase.com>
2026-07-02 13:15:47 -04:00

174 lines
5.6 KiB
TypeScript

import { snakeCase } from 'lodash'
import { ExternalLink } from 'lucide-react'
import Link from 'next/link'
import { useState } from 'react'
import {
Button,
cn,
Dialog,
DialogContent,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
type DialogProps,
} from 'ui'
import { CodeBlock } from 'ui-patterns/CodeBlock'
import {
generateFileCliCommand,
generateMigrationCliCommand,
generateSeedCliCommand,
} from './SQLEditor.utils'
import { TwoOptionToggle } from '@/components/ui/TwoOptionToggle'
import { DOCS_URL } from '@/lib/constants'
import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor/sql-editor-state'
const CLI_DOCS_URL = `${DOCS_URL}/guides/cli/local-development`
export interface DownloadSnippetModalProps extends DialogProps {
id: string
}
type DownloadFormat = 'migration' | 'seed' | 'sql'
export const DownloadSnippetModal = ({ id, ...props }: DownloadSnippetModalProps) => {
const snapV2 = useSqlEditorV2StateSnapshot()
const snippet = snapV2.snippets[id]?.snippet
const migrationName = snakeCase(snippet?.name)
const [downloadFormat, setDownloadFormat] = useState<DownloadFormat>('migration')
const [selectedView, setSelectedView] = useState<'CLI' | 'NPX'>('CLI')
const SNIPPETS = [
{
id: 'migration' as const,
label: 'Migration',
caption: (
<>
Run this command from your project directory to download the snippet in a new migration
named <code className="text-code-inline break-normal">{migrationName}</code>.
</>
),
docLink: {
label: 'About migrations',
href: `${DOCS_URL}/guides/deployment/database-migrations`,
},
cli: generateMigrationCliCommand(id, migrationName),
npx: generateMigrationCliCommand(id, migrationName, true),
},
{
id: 'seed' as const,
label: 'Seed file',
caption: (
<>
Run this command from your project directory to download the snippet. If your query
consists of sample data, append it to the end of{' '}
<code className="text-code-inline break-normal">supabase/seed.sql</code>.
</>
),
docLink: {
label: 'About seeding',
href: `${DOCS_URL}/guides/local-development/seeding-your-database`,
},
cli: generateSeedCliCommand(id),
npx: generateSeedCliCommand(id, true),
},
{
id: 'sql' as const,
label: 'SQL file',
caption: (
<>
Run this command from your project directory to download the snippet into a new SQL file
named <code className="text-code-inline break-normal">{migrationName}.sql</code>.
</>
),
cli: generateFileCliCommand(id, migrationName),
npx: generateFileCliCommand(id, migrationName, true),
},
]
const selectedSnippet = SNIPPETS.find((s) => s.id === downloadFormat) ?? SNIPPETS[0]
const commandValue = selectedView === 'CLI' ? selectedSnippet.cli : selectedSnippet.npx
return (
<Dialog {...props}>
<DialogContent>
<DialogHeader>
<DialogTitle>Export query</DialogTitle>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection className="flex flex-col gap-y-4">
<div className="flex items-center justify-between gap-x-2">
<p className="text-sm">Export as</p>
<Select
value={downloadFormat}
onValueChange={(value) => setDownloadFormat(value as DownloadFormat)}
>
<SelectTrigger className="w-auto">
<SelectValue />
</SelectTrigger>
<SelectContent>
{SNIPPETS.map((snippet) => (
<SelectItem key={snippet.id} value={snippet.id}>
{snippet.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex flex-col gap-y-2">
<div className="flex items-center justify-between gap-x-2">
<p className="text-sm">Run with</p>
<TwoOptionToggle
width={50}
options={['CLI', 'NPX']}
activeOption={selectedView}
borderOverride="border-muted"
onClickOption={() =>
selectedView === 'CLI' ? setSelectedView('NPX') : setSelectedView('CLI')
}
/>
</div>
<CodeBlock
language="bash"
value={commandValue}
hideLineNumbers
wrapperClassName="[&_pre]:px-4 [&_pre]:py-3"
className={cn(
'!bg-surface-75 border-border [&_code]:text-[12px] [&_code]:text-foreground'
)}
/>
<p className="text-xs text-foreground-lighter leading-relaxed">
{selectedSnippet.caption}
</p>
</div>
</DialogSection>
<DialogSection>
<div className="flex items-center justify-start gap-x-2">
{selectedSnippet.docLink && (
<Button asChild variant="default" icon={<ExternalLink />}>
<Link href={selectedSnippet.docLink.href} target="_blank" rel="noreferrer">
{selectedSnippet.docLink.label}
</Link>
</Button>
)}
<Button asChild variant="default" icon={<ExternalLink />}>
<Link href={CLI_DOCS_URL} target="_blank" rel="noreferrer">
About CLI
</Link>
</Button>
</div>
</DialogSection>
</DialogContent>
</Dialog>
)
}