Files
supabase/apps/studio/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet/InstallOAuthIntegrationButton.tsx
T
Raminder Singh a1cdfaeca1 feat: open oauth apps in new tab to avoid losing studio context (#45304)
Currently when a user clicks the **Install integration** button on an
OAuth integration like Grafana, they are redirected to the partner
website in the same tab in which they clicked the button. This makes
them lose context in the Supabase Studio. This PR changes the behaviour
such that the partner website will be opened in a new tab.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* OAuth integration installation now opens the redirect URL in a new
browser tab instead of redirecting the current window, allowing users to
remain in the application while completing the integration process.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-28 15:05:38 +08:00

82 lines
2.5 KiB
TypeScript

import { useParams } from 'common'
import { useMemo } from 'react'
import { toast } from 'sonner'
import { Button } from 'ui'
import type { IntegrationDefinition } from '@/components/interfaces/Integrations/Landing/Integrations.constants'
import { useAPIKeysQuery } from '@/data/api-keys/api-keys-query'
import { useInstallOAuthIntegrationMutation } from '@/data/marketplace/install-oauth-integration-mutation'
interface InstallOAuthIntegrationButtonProps {
integration: IntegrationDefinition
}
export function InstallOAuthIntegrationButton({ integration }: InstallOAuthIntegrationButtonProps) {
const { ref: projectRef } = useParams()
const { data: apiKeys, isLoading: isApiKeysLoading } = useAPIKeysQuery(
{ projectRef, reveal: false },
{ enabled: !!projectRef }
)
const { mutate: installOAuthIntegration, isPending: isInstalling } =
useInstallOAuthIntegrationMutation({
onSuccess: (data) => {
if ('redirectUrl' in data) {
if (!data.redirectUrl) {
toast.error('Failed to redirect because redirect URL is invalid')
return
}
window.open(data.redirectUrl, '_blank', 'noreferrer')
} else {
toast.error('Failed to start integration installation')
}
},
})
const isLoading =
integration.installIdentificationMethod === 'secret_key_prefix' && isApiKeysLoading
const isIntegrationInstalled = useMemo(() => {
if (!integration) return false
const prefix = integration.secretKeyPrefix
if (integration.installIdentificationMethod !== 'secret_key_prefix' || !prefix) return false
if (isApiKeysLoading || !apiKeys) return false
return apiKeys.some((k) => k.type === 'secret' && k.name.startsWith(prefix))
}, [apiKeys, integration, isApiKeysLoading])
const handleInstallClick = async () => {
if (!integration || !projectRef) return
if (integration.installUrlType === 'post') {
if (!integration.listingId) return toast.error('Listing ID is required')
installOAuthIntegration({ projectRef, id: integration.listingId })
} else {
window.location.href = integration.installUrl ?? '/'
}
}
return (
<>
{isIntegrationInstalled ? (
<Button disabled type="outline" className="shrink-0">
Installed
</Button>
) : (
<Button
type="primary"
className="shrink-0"
loading={isInstalling || isLoading}
disabled={isLoading}
onClick={handleInstallClick}
>
Install integration
</Button>
)}
</>
)
}