mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 23:59:08 +03:00
feat: sql-to-rest docs tool
This commit is contained in:
1 parent
2b17f5a51d
commit
4e59f69511
7 files changed
+151
-4
No files matched your search
@@ -1024,6 +1024,11 @@ export const api: NavMenuConstant = {
|
||||
url: '/guides/api/rest/generating-types',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'SQL to REST API Tool',
|
||||
url: '/guides/api/sql-to-rest',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'Guides',
|
||||
url: '/guides/api',
|
||||
|
||||
@@ -32,9 +32,9 @@ import { NavData } from './NavData'
|
||||
import { SharedData } from './SharedData'
|
||||
|
||||
// Partials
|
||||
import HuggingFaceDeployment from './MDX/ai/quickstart_hf_deployment.mdx'
|
||||
import DatabaseSetup from './MDX/database_setup.mdx'
|
||||
import GetSessionWarning from './MDX/get_session_warning.mdx'
|
||||
import HuggingFaceDeployment from './MDX/ai/quickstart_hf_deployment.mdx'
|
||||
import KotlinProjectSetup from './MDX/kotlin_project_setup.mdx'
|
||||
import MigrationWarnings from './MDX/migration_warnings.mdx'
|
||||
import ProjectSetup from './MDX/project_setup.mdx'
|
||||
@@ -43,6 +43,7 @@ import SocialProviderSettingsSupabase from './MDX/social_provider_settings_supab
|
||||
import SocialProviderSetup from './MDX/social_provider_setup.mdx'
|
||||
|
||||
// Icons
|
||||
import { IconArrowDown, IconCheck } from 'ui'
|
||||
import {
|
||||
IconMenuApi,
|
||||
IconMenuAuth,
|
||||
@@ -65,9 +66,9 @@ import {
|
||||
IconMenuStorage,
|
||||
IconMenuSwift,
|
||||
} from './Navigation/NavigationMenu/HomeMenuIcons'
|
||||
import { IconArrowDown, IconCheck } from 'ui'
|
||||
|
||||
// Heavy/rare (lazy-loaded)
|
||||
import SqlToRest from '@ui-patterns/SqlToRest'
|
||||
import { AppleSecretGenerator } from './AppleSecretGenerator'
|
||||
import { Extensions } from './Extensions'
|
||||
import { JwtGenerator } from './JwtGenerator'
|
||||
@@ -151,6 +152,7 @@ const components = {
|
||||
SharedData,
|
||||
SocialProviderSettingsSupabase,
|
||||
SocialProviderSetup,
|
||||
SqlToRest,
|
||||
StepHikeCompact,
|
||||
TabPanel: (props: any) => <Tabs.Panel {...props}>{props.children}</Tabs.Panel>,
|
||||
Tabs: (props: any) => <Tabs wrappable {...props} />,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
id: 'sql-to-rest'
|
||||
title: 'SQL to REST API Tool'
|
||||
description: 'Convert SQL queries to HTTP requests and Supabase client code'
|
||||
---
|
||||
|
||||
<SqlToRest />
|
||||
Generated
+4
-1
@@ -48193,15 +48193,18 @@
|
||||
"packages/ui-patterns": {
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"cmdk": "^0.2.1",
|
||||
"common": "*",
|
||||
"lodash": "*",
|
||||
"lucide-react": "*",
|
||||
"monaco-editor": "*",
|
||||
"next-themes": "*",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-hot-toast": "*",
|
||||
"react-tooltip": "*",
|
||||
"reactflow": "*",
|
||||
"sql-to-rest": "*",
|
||||
"tsconfig": "*",
|
||||
"ui": "*"
|
||||
},
|
||||
@@ -49005,4 +49008,4 @@
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import Editor, { useMonaco } from '@monaco-editor/react'
|
||||
import type { editor } from 'monaco-editor'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useCallback, useEffect, useLayoutEffect, useState } from 'react'
|
||||
import { processSql, renderHttp, renderSupabaseJs } from 'sql-to-rest'
|
||||
import { CodeBlock, Tabs } from 'ui'
|
||||
|
||||
const defaultValue = `select
|
||||
*
|
||||
from
|
||||
books
|
||||
where
|
||||
title = 'Cheese'
|
||||
`
|
||||
|
||||
export default function SqlToRest() {
|
||||
const [sql, setSql] = useState(defaultValue)
|
||||
const [httpRequest, setHttpRequest] = useState('')
|
||||
const [curlRequest, setCurlRequest] = useState('')
|
||||
const [jsCode, setJsCode] = useState('')
|
||||
const [errorMessage, setErrorMessage] = useState<string>()
|
||||
|
||||
const monaco = useMonaco()
|
||||
const { resolvedTheme } = useTheme()
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (monaco && resolvedTheme) {
|
||||
const mode = getTheme(resolvedTheme)
|
||||
monaco.editor.defineTheme('supabase', mode)
|
||||
}
|
||||
}, [resolvedTheme, monaco])
|
||||
|
||||
const process = useCallback(async (sql: string) => {
|
||||
console.log({ sql })
|
||||
setSql(sql)
|
||||
|
||||
try {
|
||||
const statement = await processSql(sql)
|
||||
const { method, path } = renderHttp(statement)
|
||||
const { code } = renderSupabaseJs(statement)
|
||||
|
||||
setErrorMessage(undefined)
|
||||
setHttpRequest(`${method} ${path}`)
|
||||
setCurlRequest(`curl -X ${method} ${path}`)
|
||||
setJsCode(code)
|
||||
} catch (error) {
|
||||
if (!(error instanceof Error)) {
|
||||
console.error(error)
|
||||
return
|
||||
}
|
||||
|
||||
setErrorMessage(error.message)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Process initial value only
|
||||
useEffect(() => {
|
||||
process(sql)
|
||||
}, [process])
|
||||
|
||||
return (
|
||||
<div className="flex justify-between gap-4">
|
||||
<div className="flex-1 h-96 py-4 border rounded-md bg-[#1e1e1e]">
|
||||
<Editor
|
||||
language="pgsql"
|
||||
theme="supabase"
|
||||
value={sql}
|
||||
options={{
|
||||
tabSize: 2,
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
}}
|
||||
onChange={async (sql) => {
|
||||
if (!sql) {
|
||||
return
|
||||
}
|
||||
await process(sql)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 flex-col gap-2">
|
||||
<Tabs defaultActiveId="http">
|
||||
<Tabs.Panel id="http" label="HTTP" className="flex flex-col gap-4">
|
||||
<CodeBlock language="bash" hideLineNumbers className="self-stretch" hideCopy>
|
||||
{httpRequest}
|
||||
</CodeBlock>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel id="curl" label="cURL" className="flex flex-col gap-4">
|
||||
<CodeBlock language="bash" hideLineNumbers className="self-stretch">
|
||||
{curlRequest}
|
||||
</CodeBlock>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel id="js" label="JavaScript">
|
||||
<CodeBlock language="js" hideLineNumbers className="self-stretch">
|
||||
{jsCode}
|
||||
</CodeBlock>
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
{errorMessage && <div className="text-red-900">{errorMessage}</div>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: this was copied from studio - find a way to share it between sites
|
||||
export const getTheme = (theme: string): editor.IStandaloneThemeData => {
|
||||
const isDarkMode = theme.includes('dark')
|
||||
// [TODO] Probably need better theming for light mode
|
||||
return {
|
||||
base: isDarkMode ? 'vs-dark' : 'vs', // can also be vs-dark or hc-black
|
||||
inherit: true, // can also be false to completely replace the builtin rules
|
||||
rules: [
|
||||
{
|
||||
token: '',
|
||||
background: isDarkMode ? '1f1f1f' : 'f0f0f0',
|
||||
foreground: isDarkMode ? 'd4d4d4' : '444444',
|
||||
},
|
||||
{ token: 'string.sql', foreground: '24b47e' },
|
||||
{ token: 'comment', foreground: '666666' },
|
||||
{ token: 'predefined.sql', foreground: isDarkMode ? 'D4D4D4' : '444444' },
|
||||
],
|
||||
colors: { 'editor.background': isDarkMode ? '#1f1f1f' : '#f0f0f0' },
|
||||
}
|
||||
}
|
||||
@@ -18,3 +18,4 @@ export * from './Dialogs/ConfirmDialog'
|
||||
export * from './Dialogs/ConfirmationModal'
|
||||
export * from './AssistantChat/AssistantChatForm'
|
||||
export * from './AssistantChat/AssistantCommandsPopover'
|
||||
export * from './SqlToRest'
|
||||
@@ -8,15 +8,18 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"cmdk": "^0.2.1",
|
||||
"common": "*",
|
||||
"lodash": "*",
|
||||
"lucide-react": "*",
|
||||
"monaco-editor": "*",
|
||||
"next-themes": "*",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-hot-toast": "*",
|
||||
"react-tooltip": "*",
|
||||
"reactflow": "*",
|
||||
"sql-to-rest": "*",
|
||||
"tsconfig": "*",
|
||||
"ui": "*"
|
||||
},
|
||||
@@ -28,4 +31,4 @@
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user