Files
supabase/apps/studio/components/interfaces/Organization/OAuthApps/OAuthSecrets/OAuthSecrets.tsx
T
Jonathan Summers-MuirandJoshen Lim aefb34fd9c Feat: Adds Oauth client management (#34591)
* adds Oauth client update

* moar

* Update OAuthSecrets.tsx

* Fix TS issues

* moar

* Minor refactors

* Minor refactors

* Tidy up

* Clean up

* Clean up

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2025-04-07 17:43:46 +08:00

93 lines
3.3 KiB
TypeScript

import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useState } from 'react'
import { useParams } from 'common'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { InlineLink } from 'components/ui/InlineLink'
import { useClientSecretCreateMutation } from 'data/oauth-secrets/client-secret-create-mutation'
import { CreatedSecret, useClientSecretsQuery } from 'data/oauth-secrets/client-secrets-query'
import { OAuthApp } from 'data/oauth/oauth-apps-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { Alert_Shadcn_, AlertTitle_Shadcn_, InfoIcon } from 'ui'
import { SecretRow } from './SecretRow'
interface Props {
selectedApp?: OAuthApp
}
export const OAuthSecrets = ({ selectedApp }: Props) => {
const { slug } = useParams()
const [createdSecret, setCreatedSecret] = useState<CreatedSecret>()
const canManageSecrets = useCheckPermissions(PermissionAction.UPDATE, 'oauth_apps')
const { id: appId } = selectedApp ?? {}
const { data } = useClientSecretsQuery({ slug, appId })
const secrets = data?.client_secrets ?? []
const { mutate: createSecret, isLoading: isCreatingSecret } = useClientSecretCreateMutation({
onSuccess: (data) => setCreatedSecret(data),
})
const handleCreateSecret = () => {
if (!slug) return console.error('Slug is required')
if (!appId) return console.error('App ID is required')
createSecret({ slug, appId })
}
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between">
<div className="flex flex-col">
<span className="text-sm text-foreground">Client secrets</span>
<span className="text-sm text-foreground-light">
For handling callbacks in the OAuth 2.0 flow. Learn more{' '}
<InlineLink href="https://supabase.com/docs/guides/integrations/build-a-supabase-integration#handling-the-callback">
here
</InlineLink>
.
</span>
</div>
{canManageSecrets && (
<ButtonTooltip
type="default"
disabled={!appId || secrets.length >= 5}
onClick={handleCreateSecret}
loading={isCreatingSecret}
tooltip={{
content: {
side: 'bottom',
text: secrets.length >= 5 ? 'You can only have up to 5 client secrets' : undefined,
},
}}
>
Generate new secret
</ButtonTooltip>
)}
</div>
{createdSecret && (
<Alert_Shadcn_ variant="default">
<InfoIcon />
<AlertTitle_Shadcn_>
Make sure to copy your new client secret now. You won't be able to see it again.
</AlertTitle_Shadcn_>
</Alert_Shadcn_>
)}
<div className="-space-y-px">
{secrets
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
.map((secret) => {
const isNew = createdSecret?.id === secret.id
const _secret = isNew
? { ...secret, client_secret: createdSecret.client_secret }
: secret
return <SecretRow key={secret.id} secret={_secret} appId={appId} />
})}
</div>
</div>
)
}