Skip to content

Commit 3d5870f

Browse files
hfjoshenlim
andauthored
fix: api docs with new api keys (supabase#36531)
* fix: api docs with new api keys * Smol UI refactor --------- Co-authored-by: Joshen Lim <[email protected]>
1 parent 9f8cc1b commit 3d5870f

File tree

3 files changed

+114
-54
lines changed

3 files changed

+114
-54
lines changed

apps/studio/components/interfaces/Docs/LangSelector.tsx

Lines changed: 100 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,49 @@
1-
import { PermissionAction } from '@supabase/shared-types/out/constants'
21
import { Key } from 'lucide-react'
2+
import { useMemo } from 'react'
33

44
import { useParams } from 'common'
55
import type { showApiKey } from 'components/interfaces/Docs/Docs.types'
6-
import { getAPIKeys, useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
7-
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
6+
import { useAPIKeysQuery } from 'data/api-keys/api-keys-query'
87
import {
98
Button,
109
DropdownMenu,
1110
DropdownMenuContent,
12-
DropdownMenuItem,
11+
DropdownMenuGroup,
12+
DropdownMenuLabel,
13+
DropdownMenuRadioGroup,
14+
DropdownMenuRadioItem,
15+
DropdownMenuSeparator,
1316
DropdownMenuTrigger,
1417
} from 'ui'
1518

1619
const DEFAULT_KEY = { name: 'hide', key: 'SUPABASE_KEY' }
1720

1821
interface LangSelectorProps {
1922
selectedLang: string
20-
showApiKey: showApiKey
23+
selectedApiKey: showApiKey
2124
setSelectedLang: (selectedLang: string) => void
22-
setShowApiKey: (showApiKey: showApiKey) => void
25+
setSelectedApiKey: (showApiKey: showApiKey) => void
2326
}
2427

2528
const LangSelector = ({
2629
selectedLang,
27-
showApiKey,
30+
selectedApiKey,
2831
setSelectedLang,
29-
setShowApiKey,
32+
setSelectedApiKey,
3033
}: LangSelectorProps) => {
3134
const { ref: projectRef } = useParams()
32-
const canReadServiceKey = useCheckPermissions(
33-
PermissionAction.READ,
34-
'service_api_keys.service_role_key'
35-
)
3635

37-
const { data: settings } = useProjectSettingsV2Query({ projectRef })
38-
const { anonKey: anonApiKey, serviceKey: serviceApiKey } = getAPIKeys(settings)
36+
const { data: apiKeys = [], isLoading: isLoadingAPIKeys } = useAPIKeysQuery({
37+
projectRef,
38+
reveal: false,
39+
})
40+
41+
const legacyKeys = useMemo(() => apiKeys.filter(({ type }) => type === 'legacy'), [apiKeys])
42+
const publishableKeys = useMemo(
43+
() => apiKeys.filter(({ type }) => type === 'publishable'),
44+
[apiKeys]
45+
)
46+
const secretKeys = useMemo(() => apiKeys.filter(({ type }) => type === 'secret'), [apiKeys])
3947

4048
return (
4149
<div className="p-1 w-1/2 ml-auto">
@@ -62,48 +70,93 @@ const LangSelector = ({
6270
>
6371
Bash
6472
</button>
65-
{selectedLang == 'bash' && (
66-
<div className="flex">
73+
{selectedLang == 'bash' && !isLoadingAPIKeys && apiKeys && apiKeys.length > 0 && (
74+
<div className="flex gap-x-1">
6775
<div className="flex items-center gap-2 p-1 pl-2 text-xs text-foreground-lighter">
6876
<Key size={12} strokeWidth={1.5} />
69-
<span>Project API key :</span>
77+
<span>Project API key:</span>
7078
</div>
7179
<DropdownMenu>
7280
<DropdownMenuTrigger asChild>
73-
<Button type="default">{showApiKey.name}</Button>
81+
<Button type="outline">
82+
{selectedApiKey.name === 'hide' ? 'Hide keys' : selectedApiKey.name}
83+
</Button>
7484
</DropdownMenuTrigger>
7585
<DropdownMenuContent align="end" side="bottom">
76-
<>
77-
<DropdownMenuItem key="hide" onClick={() => setShowApiKey(DEFAULT_KEY)}>
78-
hide
79-
</DropdownMenuItem>
80-
{anonApiKey && (
81-
<DropdownMenuItem
82-
key="anon"
83-
onClick={() =>
84-
setShowApiKey({
85-
key: anonApiKey.api_key ?? '-',
86-
name: 'anon (public)',
87-
})
88-
}
89-
>
90-
<p>anon (public)</p>
91-
</DropdownMenuItem>
86+
<DropdownMenuRadioGroup value={selectedApiKey.key}>
87+
<DropdownMenuRadioItem
88+
key="hide"
89+
value={DEFAULT_KEY.key}
90+
onClick={() => setSelectedApiKey(DEFAULT_KEY)}
91+
>
92+
Hide keys
93+
</DropdownMenuRadioItem>
94+
95+
{publishableKeys.length > 0 && (
96+
<>
97+
<DropdownMenuSeparator />
98+
<DropdownMenuLabel>Publishable keys</DropdownMenuLabel>
99+
{publishableKeys.map((key) => {
100+
const value = key.api_key
101+
return (
102+
<DropdownMenuRadioItem
103+
key={key.id}
104+
value={value}
105+
onClick={() =>
106+
setSelectedApiKey({
107+
name: `Publishable key: ${key.name}`,
108+
key: value,
109+
})
110+
}
111+
>
112+
{key.name}
113+
</DropdownMenuRadioItem>
114+
)
115+
})}
116+
</>
92117
)}
93-
{canReadServiceKey && (
94-
<DropdownMenuItem
95-
key="service"
96-
onClick={() =>
97-
setShowApiKey({
98-
key: serviceApiKey?.api_key ?? '-',
99-
name: 'service_role (secret)',
100-
})
101-
}
102-
>
103-
<p>service_role (secret)</p>
104-
</DropdownMenuItem>
118+
119+
{secretKeys.length > 0 && (
120+
<>
121+
<DropdownMenuSeparator />
122+
<DropdownMenuLabel>Secret keys</DropdownMenuLabel>
123+
{secretKeys.map((key) => {
124+
const value = key.prefix + '...'
125+
return (
126+
<DropdownMenuRadioItem
127+
key={key.id}
128+
value={value}
129+
onClick={() =>
130+
setSelectedApiKey({ name: `Secret key: ${key.name}`, key: value })
131+
}
132+
>
133+
{key.name}
134+
</DropdownMenuRadioItem>
135+
)
136+
})}
137+
</>
105138
)}
106-
</>
139+
140+
<DropdownMenuSeparator />
141+
142+
<DropdownMenuGroup>
143+
<DropdownMenuLabel>JWT-based legacy keys</DropdownMenuLabel>
144+
{legacyKeys.map((key) => {
145+
const value = key.api_key
146+
return (
147+
<DropdownMenuRadioItem
148+
key={key.id}
149+
value={value}
150+
onClick={() =>
151+
setSelectedApiKey({ name: `Legacy key: ${key.name}`, key: value })
152+
}
153+
>
154+
{key.name}
155+
</DropdownMenuRadioItem>
156+
)
157+
})}
158+
</DropdownMenuGroup>
159+
</DropdownMenuRadioGroup>
107160
</DropdownMenuContent>
108161
</DropdownMenu>
109162
</div>

apps/studio/data/config/project-settings-v2-query.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export const useProjectSettingsV2Query = <TData = ProjectSettingsData>(
6363
)
6464
}
6565

66+
/**
67+
* @deprecated Use api-keys-query instead!
68+
*/
6669
export const getAPIKeys = (settings?: ProjectSettings) => {
6770
const anonKey = (settings?.service_api_keys ?? []).find((x) => x.tags === 'anon')
6871
const serviceKey = (settings?.service_api_keys ?? []).find((x) => x.tags === 'service_role')

apps/studio/pages/project/[ref]/api/index.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import { useState } from 'react'
33

44
import { GeneralContent, ResourceContent, RpcContent } from 'components/interfaces/Docs'
55
import LangSelector from 'components/interfaces/Docs/LangSelector'
6+
import DefaultLayout from 'components/layouts/DefaultLayout'
67
import DocsLayout from 'components/layouts/DocsLayout/DocsLayout'
78
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
89
import { useCustomDomainsQuery } from 'data/custom-domains/custom-domains-query'
910
import { useProjectJsonSchemaQuery } from 'data/docs/project-json-schema-query'
1011
import { snakeToCamel } from 'lib/helpers'
1112
import type { NextPageWithLayout } from 'types'
12-
import DefaultLayout from 'components/layouts/DefaultLayout'
1313

1414
const PageConfig: NextPageWithLayout = () => {
1515
return <DocView />
@@ -29,7 +29,7 @@ const DocView = () => {
2929

3030
const { ref: projectRef, page, resource, rpc } = useParams()
3131
const [selectedLang, setSelectedLang] = useState<any>('js')
32-
const [showApiKey, setShowApiKey] = useState<any>(DEFAULT_KEY)
32+
const [selectedApikey, setSelectedApiKey] = useState<any>(DEFAULT_KEY)
3333

3434
const { data: settings, error: settingsError } = useProjectSettingsV2Query({ projectRef })
3535
const {
@@ -112,9 +112,9 @@ const DocView = () => {
112112
<div className="sticky top-0 z-40 flex flex-row-reverse w-full ">
113113
<LangSelector
114114
selectedLang={selectedLang}
115-
showApiKey={showApiKey}
115+
selectedApiKey={selectedApikey}
116116
setSelectedLang={setSelectedLang}
117-
setShowApiKey={setShowApiKey}
117+
setSelectedApiKey={setSelectedApiKey}
118118
/>
119119
</div>
120120
<div>
@@ -124,7 +124,7 @@ const DocView = () => {
124124
selectedLang={selectedLang}
125125
resourceId={resource}
126126
resources={resources}
127-
showApiKey={showApiKey.key}
127+
showApiKey={selectedApikey.key}
128128
refreshDocs={refreshDocs}
129129
/>
130130
) : rpc ? (
@@ -133,11 +133,15 @@ const DocView = () => {
133133
rpcId={rpc}
134134
paths={paths}
135135
rpcs={rpcs}
136-
showApiKey={showApiKey.key}
136+
showApiKey={selectedApikey.key}
137137
refreshDocs={refreshDocs}
138138
/>
139139
) : (
140-
<GeneralContent selectedLang={selectedLang} showApiKey={showApiKey.key} page={page} />
140+
<GeneralContent
141+
selectedLang={selectedLang}
142+
showApiKey={selectedApikey.key}
143+
page={page}
144+
/>
141145
)}
142146
</div>
143147
</div>

0 commit comments

Comments
 (0)