Improve loading and success handlers for JWT keys (#37109)

This commit is contained in:
Joshen Lim authored and GitHub committed 2025-07-14 21:51:31 +08:00
1 parent 57edade445
commit f93058ca73
2 files changed
+66 -22

No files matched your search

@@ -55,6 +55,7 @@ export default function JWTSecretKeysTable() {
const newJwtSecrets = useFlag('newJwtSecrets')
const [selectedKey, setSelectedKey] = useState<JWTSigningKey>()
const [selectedKeyToUpdate, setSelectedKeyToUpdate] = useState<string>()
const [shownDialog, setShownDialog] = useState<DialogType>()
const { data: signingKeys, isLoading: isLoadingSigningKeys } = useJWTSigningKeysQuery({
@@ -76,7 +77,12 @@ export default function JWTSecretKeysTable() {
)
const { mutate: updateJWTSigningKey, isLoading: isUpdatingJWTSigningKey } =
useJWTSigningKeyUpdateMutation({ onSuccess: () => resetDialog() })
useJWTSigningKeyUpdateMutation({
onSuccess: () => {
resetDialog()
setSelectedKeyToUpdate(undefined)
},
})
const { mutate: deleteJWTSigningKey, isLoading: isDeletingJWTSigningKey } =
useJWTSigningKeyDeleteMutation({ onSuccess: () => resetDialog(), onError: () => resetDialog() })
@@ -118,19 +124,33 @@ export default function JWTSecretKeysTable() {
}
const handlePreviouslyUsedKey = async (keyId: string) => {
updateJWTSigningKey({ projectRef, keyId, status: 'previously_used' })
setSelectedKeyToUpdate(keyId)
updateJWTSigningKey(
{ projectRef, keyId, status: 'previously_used' },
{ onSuccess: () => toast.success('Successfully moved key to previously used') }
)
}
const handleStandbyKey = (keyId: string) => {
updateJWTSigningKey({ projectRef: projectRef!, keyId, status: 'standby' })
setSelectedKeyToUpdate(keyId)
updateJWTSigningKey(
{ projectRef: projectRef!, keyId, status: 'standby' },
{ onSuccess: () => toast.success('Successfully moved key to standby') }
)
}
const handleRevokeKey = (keyId: string) => {
updateJWTSigningKey({ projectRef: projectRef!, keyId, status: 'revoked' })
updateJWTSigningKey(
{ projectRef: projectRef!, keyId, status: 'revoked' },
{ onSuccess: () => toast.success('Successfully revoked key') }
)
}
const handleDeleteKey = (keyId: string) => {
deleteJWTSigningKey({ projectRef: projectRef!, keyId })
deleteJWTSigningKey(
{ projectRef: projectRef!, keyId },
{ onSuccess: () => toast.success('Successfully deleted key') }
)
}
if (isLoading) {
@@ -152,7 +172,7 @@ export default function JWTSecretKeysTable() {
description="Switch the standby key to in use. All new JSON Web Tokens issued by Supabase Auth will be signed with this key."
buttonLabel="Rotate keys"
onClick={() => setShownDialog('rotate')}
loading={isLoadingMutation}
loading={isUpdatingJWTSigningKey}
icon={<RotateCw className="size-4" />}
type="primary"
/>
@@ -206,12 +226,15 @@ export default function JWTSecretKeysTable() {
<SigningKeyRow
key={standbyKey.id}
signingKey={standbyKey}
legacyKey={legacyKey}
standbyKey={standbyKey}
isLoading={
selectedKeyToUpdate === standbyKey.id && isUpdatingJWTSigningKey
}
setSelectedKey={setSelectedKey}
setShownDialog={setShownDialog}
handleStandbyKey={handleStandbyKey}
handlePreviouslyUsedKey={handlePreviouslyUsedKey}
legacyKey={legacyKey}
standbyKey={standbyKey}
/>
)}
{inUseKey && (
@@ -271,12 +294,13 @@ export default function JWTSecretKeysTable() {
<SigningKeyRow
key={key.id}
signingKey={key}
legacyKey={legacyKey}
standbyKey={standbyKey}
isLoading={selectedKeyToUpdate === key.id && isUpdatingJWTSigningKey}
setSelectedKey={setSelectedKey}
setShownDialog={setShownDialog}
handleStandbyKey={handleStandbyKey}
handlePreviouslyUsedKey={handlePreviouslyUsedKey}
legacyKey={legacyKey}
standbyKey={standbyKey}
/>
))}
</AnimatePresence>
@@ -12,6 +12,7 @@ import {
} from 'lucide-react'
import { components } from 'api-types'
import { DropdownMenuItemTooltip } from 'components/ui/DropdownMenuItemTooltip'
import { JWTSigningKey } from 'data/jwt-signing-keys/jwt-signing-keys-query'
import {
Badge,
@@ -35,6 +36,7 @@ interface SigningKeyRowProps {
handleStandbyKey: (keyId: string) => void
legacyKey?: JWTSigningKey | null
standbyKey?: JWTSigningKey | null
isLoading?: boolean
}
const MotionTableRow = motion(TableRow)
@@ -47,6 +49,7 @@ export const SigningKeyRow = ({
handleStandbyKey,
legacyKey,
standbyKey,
isLoading = false,
}: SigningKeyRowProps) => (
<MotionTableRow
key={signingKey.id}
@@ -112,9 +115,14 @@ export const SigningKeyRow = ({
{(signingKey.status !== 'in_use' || signingKey.algorithm !== 'HS256') && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type="text" className="px-2" icon={<MoreVertical className="size-4" />} />
<Button
type="text"
className="px-1.5"
loading={isLoading}
icon={<MoreVertical className="size-4" />}
/>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuContent align="end" className="w-52">
{signingKey.algorithm !== 'HS256' && (
<DropdownMenuItem
onSelect={() => {
@@ -139,15 +147,21 @@ export const SigningKeyRow = ({
)}
{signingKey.status === 'previously_used' && (
<>
<DropdownMenuItem
onSelect={() => {
handleStandbyKey(signingKey.id)
}}
<DropdownMenuItemTooltip
disabled={!!standbyKey}
onSelect={() => handleStandbyKey(signingKey.id)}
tooltip={{
content: {
side: 'left',
text: !!standbyKey
? 'You may only have one standby key at a time'
: undefined,
},
}}
>
<CircleArrowUp className="mr-2 size-4" />
Move to standby key
</DropdownMenuItem>
</DropdownMenuItemTooltip>
<DropdownMenuItem
onSelect={() => {
setSelectedKey(signingKey)
@@ -162,15 +176,21 @@ export const SigningKeyRow = ({
)}
{signingKey.status === 'revoked' && (
<>
<DropdownMenuItem
onSelect={() => {
handleStandbyKey(signingKey.id)
}}
<DropdownMenuItemTooltip
disabled={!!standbyKey}
onSelect={() => handleStandbyKey(signingKey.id)}
tooltip={{
content: {
side: 'left',
text: !!standbyKey
? 'You may only have one standby key at a time'
: undefined,
},
}}
>
<CircleArrowUp className="mr-2 size-4" />
Move to standby key
</DropdownMenuItem>
</DropdownMenuItemTooltip>
<DropdownMenuItem
onSelect={() => {
setSelectedKey(signingKey)