- {alert &&
{alert}
}
+
+ {!!alert &&
{alert}
}
+
+
+
{dependsOnExtension && (
Required extensions
@@ -66,16 +70,12 @@ export const IntegrationOverviewTab = ({
return (
-
-
- {requiredExtension}
-
-
+ {requiredExtension}
{extension ? (
@@ -100,6 +100,7 @@ export const IntegrationOverviewTab = ({
)}
+
{!!actions && (
{
@@ -86,8 +86,8 @@ export const useInstalledIntegrations = () => {
}
if (integration.id === 'stripe_sync_engine') {
const stripeSchema = findStripeSchema(schemas)
- const status = parseStripeSchemaStatus(stripeSchema)
- return checkIsInstalled(status)
+ const parsedSchema = parseStripeSchema(stripeSchema)
+ return checkIsInstalled(parsedSchema.status)
}
if (integration.type === 'wrapper') {
return wrappers.find((w) => wrapperMetaComparator(integration.meta, w))
diff --git a/apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationError.tsx b/apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationError.tsx
new file mode 100644
index 0000000000000..2c8e63d7b5c66
--- /dev/null
+++ b/apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationError.tsx
@@ -0,0 +1,60 @@
+import { useParams } from 'common'
+import { Button } from 'ui'
+import { Admonition } from 'ui-patterns'
+
+import { ContactSupportButton } from '@/components/ui/AlertError'
+
+export const InstallationError = ({
+ error,
+ handleUninstall,
+ handleOpenInstallSheet,
+}: {
+ error: 'install' | 'uninstall'
+ handleUninstall: () => void
+ handleOpenInstallSheet: () => void
+}) => {
+ const { ref } = useParams()
+
+ if (error === 'uninstall') {
+ return (
+
+
+ Retry uninstall
+
+
+
+ }
+ />
+ )
+ }
+
+ if (error === 'install') {
+ return (
+
+
+ Retry install
+
+
+
+ }
+ />
+ )
+ }
+
+ return null
+}
diff --git a/apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationOverview.tsx b/apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationOverview.tsx
index fa12685ee6640..d1a3343376fd7 100644
--- a/apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationOverview.tsx
+++ b/apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationOverview.tsx
@@ -4,13 +4,12 @@ import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { useStripeSyncInstallMutation } from 'data/database-integrations/stripe/stripe-sync-install-mutation'
import { useStripeSyncUninstallMutation } from 'data/database-integrations/stripe/stripe-sync-uninstall-mutation'
import { useSchemasQuery } from 'data/database/schemas-query'
-import { formatRelative } from 'date-fns'
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useTrack } from 'lib/telemetry/track'
-import { AlertCircle, BadgeCheck, Check, ExternalLink, RefreshCwIcon } from 'lucide-react'
+import { ExternalLink } from 'lucide-react'
import Link from 'next/link'
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { useCallback, useEffect, useRef, useState } from 'react'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
@@ -32,6 +31,8 @@ import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import * as z from 'zod'
import { IntegrationOverviewTab } from '../../Integration/IntegrationOverviewTab'
+import { InstallationError } from './InstallationError'
+import { StatusDisplay } from './StatusDisplay'
import {
canInstall as checkCanInstall,
hasInstallError,
@@ -39,13 +40,13 @@ import {
isInstallDone,
isInstalled,
isInstalling,
- isSyncRunning,
isUninstallDone,
isUninstalling,
} from './stripe-sync-status'
import { StripeSyncChangesCard } from './StripeSyncChangesCard'
import { useStripeSyncStatus } from '@/components/interfaces/Integrations/templates/StripeSyncEngine/useStripeSyncStatus'
import { InlineLink } from '@/components/ui/InlineLink'
+import { useSSLEnforcementQuery } from '@/data/ssl-enforcement/ssl-enforcement-query'
const installFormSchema = z.object({
stripeSecretKey: z.string().min(1, 'Stripe API key is required'),
@@ -69,8 +70,9 @@ export const StripeSyncInstallationPage = () => {
mode: 'onSubmit',
})
- // Use the unified status hook
- const { installationStatus, syncState } = useStripeSyncStatus({
+ const {
+ parsedSchema: { status: installationStatus },
+ } = useStripeSyncStatus({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
@@ -81,13 +83,11 @@ export const StripeSyncInstallationPage = () => {
'*'
)
- const isSyncing = isSyncRunning(syncState)
-
const installed = isInstalled(installationStatus)
const installError = hasInstallError(installationStatus)
const uninstallError = hasUninstallError(installationStatus)
const installInProgress = isInstalling(installationStatus)
- const uninsallInProgress = isUninstalling(installationStatus)
+ const uninstallInProgress = isUninstalling(installationStatus)
const installDone = isInstallDone(installationStatus)
const uninstallDone = isUninstallDone(installationStatus)
@@ -116,15 +116,25 @@ export const StripeSyncInstallationPage = () => {
// Combine schema status with mutation/initiated states for UI
const installing = installInProgress || isInstallRequested || isInstallInitiated
- const uninstalling = uninsallInProgress || isUninstallRequested || isUninstallInitiated
+ const uninstalling = uninstallInProgress || isUninstallRequested || isUninstallInitiated
const canInstall = checkCanInstall(installationStatus) && !installed && !installing
+ const hasError = (uninstallError || installError) && !uninstalling && !installing
+
// Poll for schema changes during transitions
useSchemasQuery(
{ projectRef: project?.ref, connectionString: project?.connectionString },
{ refetchInterval: installing || uninstalling ? 5000 : false }
)
+ const { data: sslEnforcementConfiguration, isSuccess: isSuccessSslEnforcement } =
+ useSSLEnforcementQuery({
+ projectRef: project?.ref,
+ })
+ const isSSLEnforced =
+ sslEnforcementConfiguration?.appliedSuccessfully &&
+ sslEnforcementConfiguration?.currentConfig.database
+
const handleUninstall = useCallback(() => {
if (!project?.ref) return
@@ -148,152 +158,6 @@ export const StripeSyncInstallationPage = () => {
}
}
- const tableEditorUrl = `/project/${project?.ref}/editor?schema=stripe`
-
- const alert = useMemo(() => {
- if (uninstallError) {
- return (
-
-
- There was an error during the uninstallation of the Stripe Sync Engine. Please try
- again. If the problem persists, contact support.
-
-
-
- Try Again
-
-
-
- )
- }
-
- if (installError) {
- return (
-
-
- There was an error during the installation of the Stripe Sync Engine. Please try
- reinstalling the integration. If the problem persists, contact support.
-
-
- Try Again
-
- Uninstall
-
-
-
- )
- }
-
- if (syncState && installed && !uninstalling) {
- return (
-
-
- {isSyncing ? (
- <>
-
-
-
Sync in progress...
-
-
- Started {formatRelative(new Date(syncState.started_at!), new Date())}
-
- >
- ) : (
- <>
-
-
-
All up to date
-
- View data
-
-
-
- Last synced {formatRelative(new Date(syncState.closed_at!), new Date())}
-
- >
- )}
-
-
- )
- }
-
- return null
- }, [
- uninstallError,
- installError,
- syncState,
- isSyncing,
- installed,
- isUninstallRequested,
- tableEditorUrl,
- uninstalling,
- handleOpenInstallSheet,
- handleUninstall,
- ])
-
- const statusDisplay = useMemo(() => {
- if (uninstallError) {
- return (
-
-
- Uninstallation error
-
- )
- }
- if (uninstalling) {
- return (
-
-
- Uninstalling...
-
- )
- }
- if (installError) {
- return (
-
-
- Installation error
-
- )
- }
- if (installing) {
- return (
-
-
- Installing...
-
- )
- }
- if (isSyncing && installed) {
- return (
-
-
- Sync in progress...
-
- )
- }
- if (installed) {
- return (
-
- Installed
-
- )
- }
- return (
-
Not installed
- )
- }, [uninstallError, uninstalling, installError, installing, isSyncing, installed])
-
// Track install failures
useEffect(() => {
if (!installError) {
@@ -324,39 +188,61 @@ export const StripeSyncInstallationPage = () => {
}, [isUninstallInitiated, uninstallDone])
return (
- <>
-
-
-
- setShouldShowInstallSheet(true)}
- disabled={!canInstall || !canManageSecrets}
- tooltip={{
- content: {
- text: !canInstall
- ? 'Your database already uses a schema named "stripe"'
- : !canManageSecrets
- ? 'You need additional permissions to install the Stripe Sync Engine.'
- : undefined,
- },
- }}
- >
- Install integration
-
-
- >
- ) : installed && !uninstalling ? (
+
+ ) : null
+ }
+ status={
+
+ }
+ actions={
+ !installed && !uninstalling && !uninstallError ? (
+ <>
+
+
+ setShouldShowInstallSheet(true)}
+ disabled={!canInstall || !canManageSecrets}
+ loading={installing}
+ tooltip={{
+ content: {
+ text: !canInstall
+ ? 'Your database already uses a schema named "stripe"'
+ : !canManageSecrets
+ ? 'You need additional permissions to install the Stripe Sync Engine.'
+ : undefined,
+ },
+ }}
+ >
+ {installError ? 'Retry installation' : 'Install integration'}
+
+ {installError && (
+
+ Uninstall
+
+ )}
+
+ >
+ ) : installed || uninstalling || uninstallError ? (
+ <>
+
setShowUninstallModal(true)}
disabled={!canManageSecrets}
+ loading={uninstalling}
tooltip={{
content: {
text: !canManageSecrets
@@ -368,30 +254,34 @@ export const StripeSyncInstallationPage = () => {
Uninstall integration
- ) : null
- }
- >
-
-
-
-
- {installRequestError && (
-