1- import { PermissionAction } from '@supabase/shared-types/out/constants'
21import { Key } from 'lucide-react'
2+ import { useMemo } from 'react'
33
44import { useParams } from 'common'
55import 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'
87import {
98 Button ,
109 DropdownMenu ,
1110 DropdownMenuContent ,
12- DropdownMenuItem ,
11+ DropdownMenuGroup ,
12+ DropdownMenuLabel ,
13+ DropdownMenuRadioGroup ,
14+ DropdownMenuRadioItem ,
15+ DropdownMenuSeparator ,
1316 DropdownMenuTrigger ,
1417} from 'ui'
1518
1619const DEFAULT_KEY = { name : 'hide' , key : 'SUPABASE_KEY' }
1720
1821interface 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
2528const 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 >
0 commit comments