From debba30a77bfa7b7c23ad8a0df4c5ee6f7b0f4e0 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Fri, 23 Sep 2022 16:59:01 +0800 Subject: [PATCH] Add simplified API copy paste snippet on project home page --- .../Home/NewProjectPanel/APIKeys.tsx | 162 +++++++++++++++++- .../Home/NewProjectPanel/NewProjectPanel.tsx | 9 +- .../components/to-be-cleaned/Docs/Snippets.js | 22 +++ 3 files changed, 187 insertions(+), 6 deletions(-) diff --git a/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx b/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx index be15452cdae..c870e476db0 100644 --- a/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx +++ b/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx @@ -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 ( {

Your API is secured behind an API gateway which requires an API Key for every request.
- You can use the keys below to use Supabase client libraries. + You can use the parameters below to use Supabase client libraries.

} - >
+ > + {isProjectSettingsError || isJwtSecretUpdateStatusError ? ( +
+ +

+ {isProjectSettingsError ? 'Failed to retrieve API keys' : 'Failed to update JWT secret'} +

+
+ ) : isApiKeysEmpty || isProjectSettingsLoading || isJwtSecretUpdateStatusLoading ? ( +
+ +

+ {isProjectSettingsLoading || isApiKeysEmpty + ? 'Retrieving API keys' + : 'JWT secret is being updated'} +

+
+ ) : ( + <> + + + + + +

API Key

+
+ {anonKey.tags?.split(',').map((x: any, i: number) => ( + + {x} + + ))} + {'public'} +
+ + } + 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={ +

+ 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{' '} + + here + {' '} + to bypass RLS. +

+ } + /> +
+
+
+ {availableLanguages.map((language) => { + const isSelected = selectedLanguage.key === language.key + return ( +
setSelectedLanguage(language)} + > + {language.name} +
+ ) + })} +
+
+ + {selectedLanguageSnippet} + +
+
+ + )} + ) } diff --git a/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx b/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx index 9564a3d16d3..f11d3ed79dc 100644 --- a/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx +++ b/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx @@ -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 = ({}) => {

Connecting to your new project

- Interact with your database through the Supabase client libraries with your API keys. + Interact with your database through the{' '} + + Supabase client libraries + {' '} + with your API keys.

More information about your project's keys can be found in your project's API @@ -235,8 +238,6 @@ const NewProjectPanel: FC = ({}) => {

- -
) diff --git a/studio/components/to-be-cleaned/Docs/Snippets.js b/studio/components/to-be-cleaned/Docs/Snippets.js index 47487a35999..f28c1a1db9e 100644 --- a/studio/components/to-be-cleaned/Docs/Snippets.js +++ b/studio/components/to-be-cleaned/Docs/Snippets.js @@ -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 main() async { + await Supabase.initialize(url: supabaseUrl, anonKey: supabaseKey); + runApp(MyApp()); +}`, + }, }), authKey: (title, varName, apikey) => ({ title: `${title}`,