import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' import dayjs from 'dayjs' import { Check, Key, Trash } from 'lucide-react' import { useState } from 'react' import { toast } from 'sonner' import { cn } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import CopyButton from '@/components/ui/CopyButton' import { useClientSecretDeleteMutation } from '@/data/oauth-secrets/client-secret-delete-mutation' import { Secret, useClientSecretsQuery } from '@/data/oauth-secrets/client-secrets-query' import { useOrganizationMembersQuery } from '@/data/organizations/organization-members-query' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' export interface SecretRowProps { secret: Secret appId?: string } export const SecretRow = ({ secret, appId }: SecretRowProps) => { const { slug } = useParams() const [showDeleteModal, setShowDeleteModal] = useState(false) const { can: canManageSecrets } = useAsyncCheckPermissions(PermissionAction.UPDATE, 'oauth_apps') const { data } = useClientSecretsQuery({ slug, appId }) const secrets = data?.client_secrets ?? [] const isLast = secrets.length === 1 const { data: members = [] } = useOrganizationMembersQuery({ slug }) const generatedBy = members.find((x) => x.gotrue_id === secret.created_by) const generatedByName = generatedBy?.username ?? generatedBy?.primary_email ?? secret.created_by const { mutate: deleteSecret, isPending: isDeleting } = useClientSecretDeleteMutation({ onSuccess: () => { // Show success toast and close modal after successful deletion toast.success('Successfully deleted client secret') setShowDeleteModal(false) }, }) const handleDelete = () => { if (!slug) return console.error('Slug is required') if (!appId) return console.error('App ID is required') deleteSecret({ slug, appId, secretId: secret.id }) } const isNew = secret.client_secret !== undefined return ( <>
{isNew && }

{isNew ? secret.client_secret : `${secret.client_secret_alias}${'*'.repeat(36)}`}

{isNew && secret.client_secret && ( )}

Added {isNew ? 'now' : dayjs(secret.created_at).fromNow()} by {generatedByName}

{secret.last_used_at && (

Last used {dayjs(secret.last_used_at).fromNow()}

)} {!secret.last_used_at && !isNew && (

Never used

)}
} disabled={!appId || !canManageSecrets || isLast} onClick={() => setShowDeleteModal(true)} tooltip={{ content: { className: 'w-64 text-center', side: 'bottom', text: !canManageSecrets ? 'You need additional permissions to delete client secrets' : isLast ? 'You must have at least one client secret for the OAuth application to function.' : undefined, }, }} />
setShowDeleteModal(false)} onConfirm={handleDelete} disabled={isLast} alert={{ title: 'This action cannot be undone', description: 'The client secret will be permanently removed and cannot be recovered.', }} >

{isLast ? 'The last client secret cannot be deleted. Please generate a new secret before deleting this one.' : 'Are you sure you want to delete this client secret?'}

) }