mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 18:05:11 +03:00
## What kind of change does this PR introduce? Mechanical cleanup on top of the Button default-variant change (#50160). ## What is the current behavior? Many callsites still pass `variant="default"` even though that is now the component default. ## What is the new behavior? Removes redundant static `variant="default"` from legacy `Button` and `ButtonTooltip` callsites. Keeps explicit defaults where they document the API: - `button-default.tsx` and `button-sizes.tsx` demos - `DocsButton`, which pins neutral styling at the wrapper boundary ## To test Studio: - [Auth → Rate Limits](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/auth/rate-limits): dirty the form so Cancel appears; Cancel stays neutral, Save stays green - [Project Settings → API Keys](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/settings/api-keys): `DocsButton` in the header actions stays neutral Design system: - [Design system → Button](https://design-system-git-dnywh-dc924ac1-supabase.vercel.app/design-system/docs/components/button): `button-default` / `button-sizes` still show explicit default styling; Primary (green) is restricted to the Primary section (and `asChild`) WWW: - [www → Brand assets](https://zone-www-dot-com-git-dnywh-dc924ac1-supabase.vercel.app/brand-assets): Download logo kit / Download button kit stay neutral
177 lines
5.9 KiB
TypeScript
177 lines
5.9 KiB
TypeScript
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
|
import { useParams } from 'common'
|
|
import { EyeOff, Key } from 'lucide-react'
|
|
import { useMemo } from 'react'
|
|
import {
|
|
Button,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuLabel,
|
|
DropdownMenuRadioGroup,
|
|
DropdownMenuRadioItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
ToggleGroup,
|
|
ToggleGroupItem,
|
|
} from 'ui'
|
|
|
|
import type { ShowApiKey } from '@/components/interfaces/Docs/Docs.types'
|
|
import { useAPIKeysQuery } from '@/data/api-keys/api-keys-query'
|
|
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
|
|
|
|
const DEFAULT_KEY = { name: 'hide', key: 'SUPABASE_KEY' }
|
|
|
|
interface LangSelectorProps {
|
|
selectedLang: 'js' | 'bash'
|
|
selectedApiKey: ShowApiKey
|
|
setSelectedLang: (selectedLang: 'js' | 'bash') => void
|
|
setSelectedApiKey: (key: ShowApiKey) => void
|
|
}
|
|
|
|
export const LangSelector = ({
|
|
selectedLang,
|
|
selectedApiKey,
|
|
setSelectedLang,
|
|
setSelectedApiKey,
|
|
}: LangSelectorProps) => {
|
|
const { ref: projectRef } = useParams()
|
|
|
|
const { can: canReadAPIKeys } = useAsyncCheckPermissions(PermissionAction.SECRETS_READ, '*')
|
|
const { data: apiKeys = [], isPending: isLoadingAPIKeys } = useAPIKeysQuery(
|
|
{
|
|
projectRef,
|
|
reveal: false,
|
|
},
|
|
{ enabled: canReadAPIKeys }
|
|
)
|
|
|
|
const legacyKeys = useMemo(() => apiKeys.filter(({ type }) => type === 'legacy'), [apiKeys])
|
|
const publishableKeys = useMemo(
|
|
() => apiKeys.filter(({ type }) => type === 'publishable'),
|
|
[apiKeys]
|
|
)
|
|
const secretKeys = useMemo(() => apiKeys.filter(({ type }) => type === 'secret'), [apiKeys])
|
|
|
|
return (
|
|
<div className="flex items-center gap-x-1">
|
|
<ToggleGroup
|
|
type="single"
|
|
value={selectedLang}
|
|
variant="outline"
|
|
onValueChange={(value) => {
|
|
if (value) setSelectedLang(value as 'js' | 'bash')
|
|
}}
|
|
size="sm"
|
|
className="flex-1 flex"
|
|
>
|
|
<ToggleGroupItem value="js" className="flex-1 px-2 py-1 h-7 text-xs">
|
|
JavaScript
|
|
</ToggleGroupItem>
|
|
<ToggleGroupItem value="bash" className="flex-1 px-2 py-1 h-7 text-xs">
|
|
Bash
|
|
</ToggleGroupItem>
|
|
</ToggleGroup>
|
|
{selectedLang == 'bash' ? (
|
|
canReadAPIKeys &&
|
|
!isLoadingAPIKeys &&
|
|
apiKeys &&
|
|
apiKeys.length > 0 && (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button size="tiny" className="p-0 h-7 w-7">
|
|
{selectedApiKey.key === DEFAULT_KEY.key ? (
|
|
<EyeOff size={12} strokeWidth={1.5} />
|
|
) : (
|
|
<Key size={12} strokeWidth={1.5} />
|
|
)}
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" side="bottom" className="w-48">
|
|
<DropdownMenuRadioGroup value={selectedApiKey.key}>
|
|
<DropdownMenuRadioItem
|
|
key="hide"
|
|
value={DEFAULT_KEY.key}
|
|
onClick={() => setSelectedApiKey(DEFAULT_KEY)}
|
|
>
|
|
Hide keys
|
|
</DropdownMenuRadioItem>
|
|
|
|
{publishableKeys.length > 0 && (
|
|
<>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuLabel>Publishable keys</DropdownMenuLabel>
|
|
{publishableKeys.map((key) => {
|
|
const value = key.api_key
|
|
return (
|
|
<DropdownMenuRadioItem
|
|
key={key.id}
|
|
value={value}
|
|
onClick={() =>
|
|
setSelectedApiKey({
|
|
name: `Publishable key: ${key.name}`,
|
|
key: value,
|
|
})
|
|
}
|
|
>
|
|
{key.name}
|
|
</DropdownMenuRadioItem>
|
|
)
|
|
})}
|
|
</>
|
|
)}
|
|
|
|
{secretKeys.length > 0 && (
|
|
<>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuLabel>Secret keys</DropdownMenuLabel>
|
|
{secretKeys.map((key) => {
|
|
const value = key.prefix + '...'
|
|
return (
|
|
<DropdownMenuRadioItem
|
|
key={key.id}
|
|
value={value}
|
|
onClick={() =>
|
|
setSelectedApiKey({ name: `Secret key: ${key.name}`, key: value })
|
|
}
|
|
>
|
|
{key.name}
|
|
</DropdownMenuRadioItem>
|
|
)
|
|
})}
|
|
</>
|
|
)}
|
|
|
|
{legacyKeys.length > 0 && (
|
|
<>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuGroup>
|
|
<DropdownMenuLabel>JWT-based legacy keys</DropdownMenuLabel>
|
|
{legacyKeys.map((key) => {
|
|
const value = key.api_key
|
|
return (
|
|
<DropdownMenuRadioItem
|
|
key={key.id}
|
|
value={value}
|
|
onClick={() =>
|
|
setSelectedApiKey({ name: `Legacy key: ${key.name}`, key: value })
|
|
}
|
|
>
|
|
{key.name}
|
|
</DropdownMenuRadioItem>
|
|
)
|
|
})}
|
|
</DropdownMenuGroup>
|
|
</>
|
|
)}
|
|
</DropdownMenuRadioGroup>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
)
|
|
) : (
|
|
<div className="w-7 h-7" />
|
|
)}
|
|
</div>
|
|
)
|
|
}
|