import { PermissionAction } from '@supabase/shared-types/out/constants' import { Search } from 'lucide-react' import { useEffect, useState } from 'react' import { toast } from 'sonner' import { useParams } from 'common' import AlertError from 'components/ui/AlertError' import NoPermission from 'components/ui/NoPermission' import { useSecretsDeleteMutation } from 'data/secrets/secrets-delete-mutation' import { useSecretsQuery } from 'data/secrets/secrets-query' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { parseAsString, useQueryState } from 'nuqs' import { Badge, Card, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from 'ui' import { Input } from 'ui-patterns/DataInputs/Input' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import AddNewSecretForm from './AddNewSecretForm' import EdgeFunctionSecret from './EdgeFunctionSecret' import { EditSecretSheet } from './EditSecretSheet' export const EdgeFunctionSecrets = () => { const { ref: projectRef } = useParams() const [searchString, setSearchString] = useState('') const { can: canReadSecrets, isLoading: isLoadingSecretsPermissions } = useAsyncCheckPermissions( PermissionAction.FUNCTIONS_SECRET_READ, '*' ) const { can: canUpdateSecrets } = useAsyncCheckPermissions(PermissionAction.SECRETS_WRITE, '*') const { data = [], error, isPending: isLoading, isSuccess, isError, } = useSecretsQuery( { projectRef: projectRef, }, { enabled: canReadSecrets } ) const [selectedIdToEdit, setSelectedIdToEdit] = useQueryState( 'edit', parseAsString.withOptions({ history: 'push', clearOnDefault: true }) ) const selectedSecretToEdit = data.find((secret) => secret.name === selectedIdToEdit) const [selectedIdToDelete, setSelectedIdToDelete] = useQueryState( 'delete', parseAsString.withOptions({ history: 'push', clearOnDefault: true }) ) const selectedSecretToDelete = data.find((secret) => secret.name === selectedIdToDelete) const { mutate: deleteSecret, isPending: isDeleting, isSuccess: isSuccessDelete, } = useSecretsDeleteMutation({ onSuccess: (_, variables) => { toast.success(`Successfully deleted secret “${variables.secrets[0]}”`) setSelectedIdToDelete(null) }, }) const secrets = searchString.length > 0 ? data?.filter((secret) => secret.name.toLowerCase().includes(searchString.toLowerCase())) ?? [] : data ?? [] const headers = [ Name, Digest SHA256 , Updated, , ] const showLoadingState = isLoadingSecretsPermissions || (canReadSecrets && isLoading) useEffect(() => { if (!!selectedIdToEdit && isSuccess && !selectedSecretToEdit) { toast(`Secret ${selectedIdToEdit} cannot be found`) setSelectedIdToEdit(null) } }, [isSuccess, selectedIdToEdit, selectedSecretToEdit, setSelectedIdToEdit]) useEffect(() => { if (!!selectedIdToDelete && isSuccess && !selectedSecretToDelete && !isSuccessDelete) { toast(`Secret ${selectedIdToDelete} cannot be found`) setSelectedIdToDelete(null) } }, [ isSuccess, isSuccessDelete, selectedIdToDelete, selectedSecretToDelete, setSelectedIdToDelete, ]) return ( <> {showLoadingState ? ( ) : !canReadSecrets ? ( ) : ( <> {isError && } {isSuccess && ( <>
{!canUpdateSecrets ? ( ) : ( )}
{canUpdateSecrets && !canReadSecrets ? ( ) : canReadSecrets ? (
setSearchString(e.target.value)} icon={} />
{headers} {secrets.length > 0 ? ( secrets.map((secret) => ( setSelectedIdToEdit(secret.name)} onSelectDelete={() => setSelectedIdToDelete(secret.name)} /> )) ) : secrets.length === 0 && searchString.length > 0 ? (

No results found

Your search for "{searchString}" did not return any results

) : (

No secrets created

There are no secrets associated with your project yet

)}
) : null} )} )} setSelectedIdToEdit(null)} /> setSelectedIdToDelete(null)} onConfirm={() => { if (selectedSecretToDelete) { deleteSecret({ projectRef, secrets: [selectedSecretToDelete.name] }) } }} >

Ensure none of your edge functions are actively using this secret before deleting it. This action cannot be undone.

) }