mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
Add simplified API copy paste snippet on project home page
This commit is contained in:
1 parent
91d69fb801
commit
debba30a77
3 files changed
+187
-6
No files matched your search
@@ -1,6 +1,58 @@
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Input, IconLoader, IconAlertCircle } from '@supabase/ui'
|
||||
import { JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useJwtSecretUpdateStatus, useProjectSettings } from 'hooks'
|
||||
import { DEFAULT_PROJECT_API_SERVICE_ID } from 'lib/constants'
|
||||
import Snippets from 'components/to-be-cleaned/Docs/Snippets'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import SimpleCodeBlock from 'components/to-be-cleaned/SimpleCodeBlock'
|
||||
|
||||
const APIKeys = () => {
|
||||
const router = useRouter()
|
||||
const { ref } = router.query
|
||||
|
||||
const availableLanguages = [
|
||||
{ name: 'Javascript', key: 'js' },
|
||||
{ name: 'Python', key: 'python' },
|
||||
{ name: 'Dart', key: 'dart' },
|
||||
]
|
||||
const [selectedLanguage, setSelectedLanguage] = useState(availableLanguages[0])
|
||||
|
||||
const {
|
||||
services,
|
||||
isError: isProjectSettingsError,
|
||||
isLoading: isProjectSettingsLoading,
|
||||
} = useProjectSettings(ref as string | undefined)
|
||||
|
||||
const {
|
||||
jwtSecretUpdateStatus,
|
||||
isError: isJwtSecretUpdateStatusError,
|
||||
isLoading: isJwtSecretUpdateStatusLoading,
|
||||
}: any = useJwtSecretUpdateStatus(ref)
|
||||
|
||||
const canReadAPIKeys = checkPermissions(PermissionAction.READ, 'service_api_keys')
|
||||
|
||||
// Get the API service
|
||||
const apiService = (services ?? []).find((x: any) => x.app.id == DEFAULT_PROJECT_API_SERVICE_ID)
|
||||
const apiConfig = apiService?.app_config ?? {}
|
||||
const apiKeys = apiService?.service_api_keys ?? []
|
||||
|
||||
// API keys should not be empty. However it can be populated with a delay on project creation
|
||||
const isApiKeysEmpty = apiKeys.length === 0
|
||||
const isNotUpdatingJwtSecret =
|
||||
jwtSecretUpdateStatus === undefined || jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updated
|
||||
|
||||
const apiUrl = `https://${apiConfig.endpoint}`
|
||||
const anonKey = apiKeys.find((key: any) => key.tags === 'anon')
|
||||
|
||||
const clientInitSnippet: any = Snippets.init(apiUrl)
|
||||
const selectedLanguageSnippet =
|
||||
clientInitSnippet[selectedLanguage.key]?.code ?? 'No snippet available'
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title={
|
||||
@@ -9,11 +61,117 @@ const APIKeys = () => {
|
||||
<p className="text-sm text-scale-1000">
|
||||
Your API is secured behind an API gateway which requires an API Key for every request.
|
||||
<br />
|
||||
You can use the keys below to use Supabase client libraries.
|
||||
You can use the parameters below to use Supabase client libraries.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
></Panel>
|
||||
>
|
||||
{isProjectSettingsError || isJwtSecretUpdateStatusError ? (
|
||||
<div className="py-8 flex items-center justify-center space-x-2">
|
||||
<IconAlertCircle size={16} strokeWidth={1.5} />
|
||||
<p className="text-sm text-scale-1100">
|
||||
{isProjectSettingsError ? 'Failed to retrieve API keys' : 'Failed to update JWT secret'}
|
||||
</p>
|
||||
</div>
|
||||
) : isApiKeysEmpty || isProjectSettingsLoading || isJwtSecretUpdateStatusLoading ? (
|
||||
<div className="py-8 flex items-center justify-center space-x-2">
|
||||
<IconLoader className="animate-spin" size={16} strokeWidth={1.5} />
|
||||
<p className="text-sm text-scale-1100">
|
||||
{isProjectSettingsLoading || isApiKeysEmpty
|
||||
? 'Retrieving API keys'
|
||||
: 'JWT secret is being updated'}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Panel.Content>
|
||||
<Input
|
||||
label="Project URL"
|
||||
readOnly
|
||||
copy
|
||||
disabled
|
||||
className="input-mono"
|
||||
value={apiUrl}
|
||||
descriptionText="A RESTful endpoint for querying and managing your database."
|
||||
layout="horizontal"
|
||||
/>
|
||||
</Panel.Content>
|
||||
<Panel.Content
|
||||
className={
|
||||
'border-t border-panel-border-interior-light dark:border-panel-border-interior-dark'
|
||||
}
|
||||
>
|
||||
<Input
|
||||
readOnly
|
||||
disabled
|
||||
layout="horizontal"
|
||||
className="input-mono"
|
||||
// @ts-ignore
|
||||
label={
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm">API Key</p>
|
||||
<div className="flex items-center space-x-1 -ml-1">
|
||||
{anonKey.tags?.split(',').map((x: any, i: number) => (
|
||||
<code key={`${x}${i}`} className="text-xs">
|
||||
{x}
|
||||
</code>
|
||||
))}
|
||||
<code className="text-xs">{'public'}</code>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
copy={canReadAPIKeys && isNotUpdatingJwtSecret}
|
||||
reveal={anonKey.tags !== 'anon' && canReadAPIKeys && isNotUpdatingJwtSecret}
|
||||
value={
|
||||
!canReadAPIKeys
|
||||
? 'You need additional permissions to view API keys'
|
||||
: jwtSecretUpdateStatus === JwtSecretUpdateStatus.Failed
|
||||
? 'JWT secret update failed, new API key may have issues'
|
||||
: jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updating
|
||||
? 'Updating JWT secret...'
|
||||
: anonKey.api_key
|
||||
}
|
||||
onChange={() => {}}
|
||||
descriptionText={
|
||||
<p>
|
||||
This key is safe to use in a browser if you have enabled Row Level Security (RLS)
|
||||
for your tables and configured policies. You may also use the service key which
|
||||
can be found{' '}
|
||||
<Link href={`/project/${ref}/settings/api`}>
|
||||
<a className="text-brand-800 hover:text-brand-900 transition">here</a>
|
||||
</Link>{' '}
|
||||
to bypass RLS.
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
</Panel.Content>
|
||||
<div className="border-t border-panel-border-interior-light dark:border-panel-border-interior-dark">
|
||||
<div className="flex items-center bg-scale-200">
|
||||
{availableLanguages.map((language) => {
|
||||
const isSelected = selectedLanguage.key === language.key
|
||||
return (
|
||||
<div
|
||||
key={language.key}
|
||||
className={[
|
||||
'px-3 py-1 text-sm cursor-pointer transition',
|
||||
`${!isSelected ? 'bg-scale-100 text-scale-1000' : 'bg-scale-300'}`,
|
||||
].join(' ')}
|
||||
onClick={() => setSelectedLanguage(language)}
|
||||
>
|
||||
{language.name}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div className="bg-scale-300 px-4 py-6 min-h-[200px]">
|
||||
<SimpleCodeBlock className={selectedLanguage.key}>
|
||||
{selectedLanguageSnippet}
|
||||
</SimpleCodeBlock>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Panel>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Button, IconKey, IconArchive, IconExternalLink, IconCode } from '@supab
|
||||
import Panel from 'components/ui/Panel'
|
||||
import APIKeys from './APIKeys'
|
||||
import GetStartedHero from './GetStartedHero'
|
||||
import { DisplayApiSettings, DisplayConfigSettings } from 'components/ui/ProjectSettings'
|
||||
|
||||
interface Props {}
|
||||
|
||||
@@ -210,7 +209,11 @@ const NewProjectPanel: FC<Props> = ({}) => {
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-xl text-scale-1200">Connecting to your new project</h3>
|
||||
<p className="lg:max-w-sm text-scale-1100">
|
||||
Interact with your database through the Supabase client libraries with your API keys.
|
||||
Interact with your database through the{' '}
|
||||
<Link href="https://supabase.com/docs/reference">
|
||||
<a className="text-brand-900">Supabase client libraries</a>
|
||||
</Link>{' '}
|
||||
with your API keys.
|
||||
</p>
|
||||
<p className="lg:max-w-sm text-scale-1100">
|
||||
More information about your project's keys can be found in your project's API
|
||||
@@ -235,8 +238,6 @@ const NewProjectPanel: FC<Props> = ({}) => {
|
||||
</div>
|
||||
<div className="col-span-8">
|
||||
<APIKeys />
|
||||
<DisplayApiSettings />
|
||||
<DisplayConfigSettings />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -33,6 +33,28 @@ const supabaseUrl = '${endpoint}'
|
||||
const supabaseKey = process.env.SUPABASE_KEY
|
||||
const supabase = createClient(supabaseUrl, supabaseKey)`,
|
||||
},
|
||||
python: {
|
||||
language: 'python',
|
||||
code: `
|
||||
import os
|
||||
from supabase import create_client, Client
|
||||
|
||||
url: str = '${endpoint}'
|
||||
key: str = os.environ.get("SUPABASE_KEY")
|
||||
supabase: Client = create_client(url, key)
|
||||
`,
|
||||
},
|
||||
dart: {
|
||||
language: 'dart',
|
||||
code: `
|
||||
final supabaseUrl = '${endpoint}'
|
||||
final supabaseKey = String.fromEnvironment('SUPABASE_KEY')
|
||||
|
||||
Future<void> main() async {
|
||||
await Supabase.initialize(url: supabaseUrl, anonKey: supabaseKey);
|
||||
runApp(MyApp());
|
||||
}`,
|
||||
},
|
||||
}),
|
||||
authKey: (title, varName, apikey) => ({
|
||||
title: `${title}`,
|
||||
|
||||
Reference in new issue
Block a user