mirror of
https://github.com/supabase/supabase.git
synced 2026-05-24 20:58:45 +08:00
* feat: add basic api keys ui * init JWT secrets. rough * Update JWTSecretKeysTable.tsx * added some info hover cards. • found this this is probably the wrong direction • will create a new page for next iteration. * init new version * add illustrations * Update JWTSecretKeysTablev2.tsx * chore: delete API key now works * some style changes * added better tables * Update JWTSecretKeysTablev2.tsx * add public JWT dialog * moar * adding sub layout in * starts adding in a ButtonGroup * about to make into separate components * added quick copy to project loading screen * build state * basic loading * confirm dialog and loading states * switched for better loading experience * moved styles of Input to InputVariants * issue with ref type * loading,error and rest states * new loading states * alt l;ayout * add group * updated error states for permissions * copy button behaviour for secret keys * delete dialog * Update QuickKeyCopy.tsx * fix type errors * Update JWTSecretKeysTablev2.tsx * update menu to hide pages * Update SettingsMenu.utils.tsx * Update resource-query.ts * remove old file * moved JWT secrets to use valtio * Update api-keys-query.ts * fix typecheck * rename files * remove JWT stuff * revert file * remove more JWT stuff * Update package.json * Update pnpm-lock.yaml * Update ProjectLayout.tsx * Update PublishableAPIKeys.tsx * Update api-keys-query.ts * refactor api-keys-query * Update SettingsMenu.utils.tsx * Some clean up * more clean up and refactor * Update APIKeyRow.tsx * Update LayoutHeader.tsx * resolve comments * Update CreateSecretAPIKeyModal.tsx * Update APIKeyRow.tsx * Add perms check for delete API keys * Remove console log * Delete ConnectDialog.tsx * use project ref --------- Co-authored-by: Stojan Dimitrovski <sdimitrovski@gmail.com> Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
147 lines
4.6 KiB
TypeScript
147 lines
4.6 KiB
TypeScript
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
|
import { useMemo } from 'react'
|
|
|
|
import { useParams } from 'common'
|
|
import { FormHeader } from 'components/ui/Forms/FormHeader'
|
|
import { APIKeysData, useAPIKeysQuery } from 'data/api-keys/api-keys-query'
|
|
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
|
import { Card, CardContent, EyeOffIcon, Skeleton, WarningIcon, cn } from 'ui'
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from 'ui/src/components/shadcn/ui/table'
|
|
import { APIKeyRow } from './APIKeyRow'
|
|
import CreateSecretAPIKeyModal from './CreateSecretAPIKeyModal'
|
|
|
|
export const SecretAPIKeys = () => {
|
|
const { ref: projectRef } = useParams()
|
|
const {
|
|
data: apiKeysData,
|
|
isLoading: isLoadingApiKeys,
|
|
error,
|
|
} = useAPIKeysQuery({ projectRef, reveal: false })
|
|
|
|
const isLoadingPermissions = !usePermissionsLoaded()
|
|
const canReadAPIKeys = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, '*')
|
|
|
|
const secretApiKeys = useMemo(
|
|
() =>
|
|
apiKeysData?.filter(
|
|
(key): key is Extract<APIKeysData[number], { type: 'secret' }> => key.type === 'secret'
|
|
) ?? [],
|
|
[apiKeysData]
|
|
)
|
|
|
|
const empty = secretApiKeys?.length === 0 && !isLoadingApiKeys && !isLoadingPermissions
|
|
|
|
const RowLoading = () => (
|
|
<TableRow>
|
|
<TableCell>
|
|
<Skeleton className="max-w-12 h-4 rounded-full" />
|
|
</TableCell>
|
|
<TableCell>
|
|
<Skeleton className="max-w-60 h-4 rounded-full" />
|
|
</TableCell>
|
|
<TableCell>
|
|
<Skeleton className="w-2 h-4 rounded-full" />
|
|
</TableCell>
|
|
</TableRow>
|
|
)
|
|
|
|
const TableContainer = ({ children }: { children: React.ReactNode }) => (
|
|
<div>
|
|
<FormHeader
|
|
title="Secret keys"
|
|
description="These API keys allow privileged access to your project's APIs. Use in servers, functions, workers or other backend components of your application. Keep secret and never publish."
|
|
actions={<CreateSecretAPIKeyModal />}
|
|
/>
|
|
<Card className={cn('w-full overflow-hidden', !empty && 'bg-surface-100')}>
|
|
<CardContent className="p-0">
|
|
<Table className="p-5">
|
|
<TableHeader>
|
|
<TableRow className={cn('bg-200', empty && 'hidden')}>
|
|
<TableHead
|
|
key=""
|
|
className="text-left font-mono uppercase text-xs text-foreground-lighter h-auto py-2 overflow-hidden"
|
|
>
|
|
Name
|
|
</TableHead>
|
|
<TableHead className="text-left font-mono uppercase text-xs text-foreground-lighter h-auto py-2 pr-0">
|
|
API Key
|
|
</TableHead>
|
|
<TableHead
|
|
className="text-right font-mono uppercase text-xs text-foreground-lighter h-auto py-2"
|
|
key="actions"
|
|
/>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody className="">{children}</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)
|
|
|
|
if (isLoadingApiKeys || isLoadingPermissions) {
|
|
return (
|
|
<TableContainer>
|
|
<RowLoading />
|
|
<RowLoading />
|
|
</TableContainer>
|
|
)
|
|
}
|
|
|
|
if (!canReadAPIKeys) {
|
|
return (
|
|
<TableContainer>
|
|
<div className="!rounded-b-md overflow-hidden py-12 flex flex-col gap-1 items-center justify-center">
|
|
<EyeOffIcon />
|
|
<p className="text-sm text-foreground">
|
|
You do not have permission to read API Secret Keys
|
|
</p>
|
|
<p className="text-foreground-light">
|
|
Contact your organization owner/admin to request access.
|
|
</p>
|
|
</div>
|
|
</TableContainer>
|
|
)
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<TableContainer>
|
|
<div className="!rounded-b-md overflow-hidden py-12 flex flex-col gap-1 items-center justify-center">
|
|
<WarningIcon />
|
|
<p className="text-sm text-warning-600">Error loading Secret API Keys</p>
|
|
<p className="text-warning/75">{error.message}</p>
|
|
</div>
|
|
</TableContainer>
|
|
)
|
|
}
|
|
|
|
if (empty) {
|
|
return (
|
|
<TableContainer>
|
|
<div className="!rounded-b-md overflow-hidden py-12 flex flex-col gap-1 items-center justify-center">
|
|
<p className="text-sm text-foreground">No secret API keys exist</p>
|
|
<p className="text-sm text-foreground-light">
|
|
Your project can't be accessed using secret API keys.
|
|
</p>
|
|
</div>
|
|
</TableContainer>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<TableContainer>
|
|
{secretApiKeys.map((apiKey) => (
|
|
<APIKeyRow key={apiKey.id} apiKey={apiKey} />
|
|
))}
|
|
</TableContainer>
|
|
)
|
|
}
|