StripeSyncInstallationPage() — supabase Function Reference
Architecture documentation for the StripeSyncInstallationPage() function in InstallationOverview.tsx from the supabase codebase.
Entity Profile
Relationship Graph
Source Code
apps/studio/components/interfaces/Integrations/templates/StripeSyncEngine/InstallationOverview.tsx lines 43–419
export const StripeSyncInstallationPage = () => {
const { data: project } = useSelectedProjectQuery()
const track = useTrack()
const hasTrackedInstallFailed = useRef(false)
const [shouldShowInstallSheet, setShouldShowInstallSheet] = useState(false)
const [isInstallInitiated, setIsInstallInitiated] = useState(false)
const formId = 'stripe-sync-install-form'
const form = useForm<z.infer<typeof installFormSchema>>({
resolver: zodResolver(installFormSchema),
defaultValues: {
stripeSecretKey: '',
},
mode: 'onSubmit',
})
const { data: schemas } = useSchemasQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const {
mutate: installStripeSync,
isPending: isInstalling,
error: installError,
reset: resetInstallError,
} = useStripeSyncInstallMutation({
onSuccess: () => {
toast.success('Stripe Sync installation started')
setShouldShowInstallSheet(false)
form.reset()
setIsInstallInitiated(true)
},
})
const { mutate: uninstallStripeSync, isPending: isUninstalling } = useStripeSyncUninstallMutation(
{
onSuccess: () => {
toast.success('Stripe Sync uninstallation started')
},
}
)
const stripeSchema = schemas?.find((s) => s.name === 'stripe')
// Determine installation status from schema description
const isInstalled =
stripeSchema &&
stripeSchema.comment?.startsWith(STRIPE_SCHEMA_COMMENT_PREFIX) &&
stripeSchema.comment.includes(INSTALLATION_INSTALLED_SUFFIX)
const schemaShowsInProgress =
stripeSchema &&
stripeSchema.comment?.startsWith(STRIPE_SCHEMA_COMMENT_PREFIX) &&
stripeSchema.comment?.includes(INSTALLATION_STARTED_SUFFIX)
const setupInProgress = schemaShowsInProgress || isInstalling || isInstallInitiated
const setupError =
stripeSchema &&
stripeSchema.comment?.startsWith(STRIPE_SCHEMA_COMMENT_PREFIX) &&
stripeSchema.comment?.includes(INSTALLATION_ERROR_SUFFIX)
useEffect(() => {
if (!setupError) {
hasTrackedInstallFailed.current = false
return
}
if (!hasTrackedInstallFailed.current) {
hasTrackedInstallFailed.current = true
// This isn't ideal because it will fire on every page load while in error state
// in the future we should connect this in the backend to track accurately
track('integration_install_failed', {
integrationName: 'stripe_sync_engine',
})
}
}, [setupError, track])
useEffect(() => {
// Clear the install initiated flag once we detect completion or error from the schema
if (isInstallInitiated && (isInstalled || setupError)) {
setIsInstallInitiated(false)
}
}, [isInstallInitiated, isInstalled, setupError])
// Check if there's an existing stripe schema that wasn't created by this integration
const hasConflictingSchema =
stripeSchema && !stripeSchema.comment?.startsWith(STRIPE_SCHEMA_COMMENT_PREFIX)
const canInstall = !hasConflictingSchema && !isInstalled && !setupInProgress
// Sync state query - only enabled when installed
const { data: syncState } = useStripeSyncingState(
{
projectRef: project?.ref!,
connectionString: project?.connectionString,
},
{
refetchInterval: 4000,
enabled: !!isInstalled,
}
)
// Poll for schema changes during installation
useSchemasQuery(
{
projectRef: project?.ref,
connectionString: project?.connectionString,
},
{
refetchInterval: setupInProgress ? 5000 : false,
}
)
const isSyncing = !!syncState && !syncState.closed_at && syncState.status === 'running'
const handleUninstall = () => {
if (!project?.ref) return
uninstallStripeSync({
projectRef: project.ref,
})
}
const handleOpenInstallSheet = () => {
resetInstallError()
setShouldShowInstallSheet(true)
}
const handleCloseInstallSheet = (isOpen: boolean) => {
if (isInstalling) return
setShouldShowInstallSheet(isOpen)
if (!isOpen) {
form.reset()
resetInstallError()
}
}
const tableEditorUrl = `/project/${project?.ref}/editor?schema=stripe`
const alert = useMemo(() => {
if (setupError) {
return (
<Admonition type="destructive" showIcon={true} title="Installation Error">
<div>
There was an error during the installation of the Stripe Sync Engine. Please try
reinstalling the integration. If the problem persists, contact support.
</div>
<div className="flex gap-2 mt-4">
<Button onClick={handleOpenInstallSheet}>Try Again</Button>
<Button
type="warning"
onClick={handleUninstall}
loading={isUninstalling}
disabled={isUninstalling}
>
Uninstall
</Button>
</div>
</Admonition>
)
}
if (syncState) {
return (
<Admonition type="default" showIcon={false}>
<div className="flex items-center justify-between gap-2">
{isSyncing ? (
<>
<div className="flex items-center gap-2 animate-pulse">
<RefreshCwIcon size={14} />
<div>Sync in progress...</div>
</div>
<div className="text-foreground-light text-sm">
Started {formatRelative(new Date(syncState.started_at!), new Date())}
</div>
</>
) : (
<>
<div className="flex items-center gap-2">
<BadgeCheck size={14} className="text-brand" />
<div>All up to date</div>
<Button asChild type="link">
<Link href={tableEditorUrl}>View data</Link>
</Button>
</div>
<div className="text-foreground-light text-sm">
Last synced {formatRelative(new Date(syncState.closed_at!), new Date())}
</div>
</>
)}
</div>
</Admonition>
)
}
return null
}, [
setupError,
setupInProgress,
syncState,
isSyncing,
isUninstalling,
handleOpenInstallSheet,
handleUninstall,
])
const status = useMemo(() => {
if (isInstalled) {
return (
<span className="flex items-center gap-2 text-foreground-light text-sm">
<Check size={14} strokeWidth={1.5} className="text-brand" /> Installed
</span>
)
}
if (setupInProgress) {
return (
<span className="flex items-center gap-2 text-foreground-light text-sm">
<RefreshCwIcon size={14} className="animate-spin text-foreground-lighter" />
Installing...
</span>
)
}
if (syncState) {
return (
<span className="flex items-center gap-2 text-foreground-light text-sm">
<RefreshCwIcon size={14} className="animate-spin text-foreground-lighter" />
Sync in progress...
</span>
)
}
if (setupError) {
return (
<span className="flex items-center gap-2 text-foreground-light text-sm">
<AlertCircle size={14} className="text-destructive" />
Installation error
</span>
)
}
return (
<span className="flex items-center gap-2 text-foreground-light text-sm">Not installed</span>
)
}, [isInstalled, setupInProgress, syncState, setupError])
return (
<IntegrationOverviewTab
alert={alert}
status={status}
actions={
!isInstalled && !setupInProgress && !setupError ? (
<StripeSyncChangesCard
canInstall={canInstall}
onInstall={() => setShouldShowInstallSheet(true)}
/>
) : null
}
>
<Sheet open={!!shouldShowInstallSheet} onOpenChange={handleCloseInstallSheet}>
<SheetContent size="lg" tabIndex={undefined} className="flex flex-col gap-0">
<Form_Shadcn_ {...form}>
<form
id={formId}
onSubmit={form.handleSubmit(({ stripeSecretKey }) => {
if (!project?.ref) return
installStripeSync({ projectRef: project.ref, stripeSecretKey })
})}
className="overflow-auto flex-grow px-0 flex flex-col"
>
<SheetHeader>
<SheetTitle>Install Stripe Sync Engine</SheetTitle>
</SheetHeader>
<SheetSection className="flex-1">
<StripeSyncChangesCard />
<Admonition type="warning" className="mt-6">
<p>
This integration currently requires{' '}
<Link
href="https://supabase.com/docs/guides/platform/ssl-enforcement"
target="_blank"
rel="noopener noreferrer"
className="underline"
>
SSL Enforcement
</Link>{' '}
to be disabled during initial setup. Support for SSL Enforcement will be added
in a future update. Once installed, all webhook and sync operations use
HTTPS/SSL.
</p>
</Admonition>
<h3 className="heading-default mb-4 mt-6">Configuration</h3>
{installError && (
<Admonition type="destructive" className="mb-4">
<div className="flex items-start gap-2">
<AlertCircle size={16} className="mt-0.5 flex-shrink-0" />
<div>
<p className="font-medium">Installation failed</p>
<p className="text-sm">{installError.message}</p>
</div>
</div>
</Admonition>
)}
<FormField_Shadcn_
control={form.control}
name="stripeSecretKey"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Stripe API key"
description="Your Stripe secret key. Requires write access to Webhook Endpoints and read-only access to all other categories."
>
<FormControl_Shadcn_ className="col-span-8">
<Input
id="stripe_api_key"
name="stripe_api_key"
placeholder="Enter your Stripe API key"
autoComplete="stripe-api-key"
reveal={false}
disabled={isInstalling}
type="password"
value={field.value}
onChange={(e) => field.onChange(e.target.value)}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<div className="flex items-center mt-4 gap-2">
<Button asChild type="default" icon={<ExternalLink />}>
<Link
href="https://dashboard.stripe.com/apikeys"
target="_blank"
rel="noopener noreferrer"
>
Get Stripe API key
</Link>
</Button>
<Button asChild type="default" icon={<ExternalLink />}>
<Link
href="https://support.stripe.com/questions/what-are-stripe-api-keys-and-how-to-find-them"
target="_blank"
rel="noopener noreferrer"
>
What are Stripe API keys?
</Link>
</Button>
</div>
</SheetSection>
<SheetFooter>
<Button
type="default"
disabled={isInstalling}
onClick={() => handleCloseInstallSheet(false)}
>
Cancel
</Button>
<Button
form={formId}
htmlType="submit"
type="primary"
loading={isInstalling}
disabled={!form.formState.isValid || isInstalling}
>
{isInstalling ? 'Starting Installation...' : 'Start Installation'}
</Button>
</SheetFooter>
</form>
</Form_Shadcn_>
</SheetContent>
</Sheet>
</IntegrationOverviewTab>
)
}
Domain
Subdomains
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free