Files
2a018833fd Joshen/fe 2900 migrate stripe sync engine to new UI (#44427)
## Context

Part of marketplace integrations, this moves the last integration over
to the new integrations UI

Just a heads up though that the code changes imo are quite messy - am
trying to figure out how to shift a lot of the integration logic (e.g
installing, installation progress tracking, etc) into a code
configuration within `Integrations.constants.ts` so pardon the
mid-transition state. I reckon we'll be able to clean up things once
requirements are bit more clearer. (Refer to "Moving forward" section
below for details)

## Changes involved
- Much of the details on the Stripe Sync Engine page will now live in
the Installation panel
<img width="1143" height="512" alt="image"
src="https://github.com/user-attachments/assets/cb23e49d-cc4e-4ad6-8a47-0bc3fe81ede7"
/>
<img width="656" height="955" alt="image"
src="https://github.com/user-attachments/assets/ff0e33c5-52ab-480f-b941-ebf3fd0708c5"
/>

- Code wise, `useStripeSyncStatus` will retrieve `ref` and
`connectionString` itself, don't need to pass in as parameters

## To test
- [ ] Verify that you can install + uninstall Stripe Sync Engine with
the flag off
- [ ] Verify that you can install + uninstall Stripe Sync Engine with
the flag on

## Moving forward
Couple of notes + open questions at the top of my head
- We'll need to do away with integration-specific overview UI (e.g
Queues, Data API, Webhooks, Wrappers, Stripe Sync Engine)
- Everything needs to be defined in code, so `IntegrationDefinition`
within `Integrations.constants.ts` is also a bit fluid at the moment as
we figure out what properties we need / don't need
- We'll need to figure out a way to do the following from a code config
POV, keeping in mind that integrations will be fetched remotely from a
DB
- How to trigger the installation of the integration (e.g from a set of
commands? SQL?)
- How to track the progress of the installation (e.g We can do long
polling but on what data?)
- How to uninstall the integration (if applicable, e.g Stripe Sync
Engine supports this)
  - How all this this can work for self-hosted/CLI


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

* **New Features**
* New modular integration install experience: interactive install sheet
with form inputs, installation overview (Extensions & SQL), advanced
per-extension schema settings, and dedicated installation settings.
* New Stripe Sync Engine overview and action controls for
install/upgrade/uninstall flows.

* **Bug Fixes & Improvements**
* Improved installation status handling, long-polling/status checks,
progress/error reporting and telemetry; more robust install/uninstall
flows and error recovery.

* **Tests**
  * Updated install-sheet tests to better simulate form submission.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
2026-04-07 15:08:10 +09:00

133 lines
3.8 KiB
TypeScript

import { PermissionAction } from '@supabase/shared-types/out/constants'
import { Button, cn } from 'ui'
import { hasInstallError, hasUninstallError } from './stripe-sync-status'
import { useStripeSyncStatus } from '@/components/interfaces/Integrations/templates/StripeSyncEngine/useStripeSyncStatus'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
export const IntegrationInstalledActions = ({
className,
disabled,
upgradeAvailable,
installing,
uninstalling,
setShowUninstallModal,
setShouldShowInstallSheet,
}: {
className?: string
disabled?: boolean
upgradeAvailable: boolean
installing: boolean
uninstalling: boolean
isUninstallRequested: boolean
setShowUninstallModal: (value: boolean) => void
setShouldShowInstallSheet: (value: boolean) => void
}) => {
const { can: canManageSecrets } = useAsyncCheckPermissions(
PermissionAction.FUNCTIONS_SECRET_WRITE,
'*'
)
const {
schemaComment: { status: installationStatus },
} = useStripeSyncStatus()
const uninstallError = hasUninstallError(installationStatus)
return (
<>
<div className={cn('flex gap-x-2 justify-end', className)}>
{upgradeAvailable && !uninstallError && !uninstalling && (
<ButtonTooltip
type="primary"
onClick={() => setShouldShowInstallSheet(true)}
disabled={disabled}
loading={installing}
tooltip={{
content: {
text: !canManageSecrets
? 'You need additional permissions to upgrade the Stripe Sync Engine.'
: undefined,
},
}}
>
Upgrade integration
</ButtonTooltip>
)}
<ButtonTooltip
type="default"
onClick={() => setShowUninstallModal(true)}
disabled={disabled}
loading={uninstalling}
tooltip={{
content: {
text: !canManageSecrets
? 'You need additional permissions to uninstall the Stripe Sync Engine.'
: undefined,
},
}}
>
{uninstallError ? 'Retry uninstallation' : 'Uninstall integration'}
</ButtonTooltip>
</div>
</>
)
}
export const IntegrationNotInstalledActions = ({
className,
installing,
canInstall,
isUninstallRequested,
hideInstallCTA = false,
handleUninstall,
setShouldShowInstallSheet,
}: {
className?: string
installing: boolean
canInstall: boolean
isUninstallRequested: boolean
hideInstallCTA?: boolean
handleUninstall: () => void
setShouldShowInstallSheet: (value: boolean) => void
}) => {
const { can: canManageSecrets } = useAsyncCheckPermissions(
PermissionAction.FUNCTIONS_SECRET_WRITE,
'*'
)
const {
schemaComment: { status: installationStatus },
} = useStripeSyncStatus()
const installError = hasInstallError(installationStatus)
return (
<div className={cn('flex gap-x-2 justify-end', className)}>
{!hideInstallCTA && (
<ButtonTooltip
type="primary"
onClick={() => 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'}
</ButtonTooltip>
)}
{installError && (
<Button type="default" loading={isUninstallRequested} onClick={handleUninstall}>
Uninstall
</Button>
)}
</div>
)
}