mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 20:35:07 +03:00
## Context Related to marketplace integrations Shifts Database Webhooks integration to the new Integrations UI. This one's a bit different from the previous PRs as this involves a full SQL installation query instead of only just a database extension. So am tweaking `Integrations.constants` a little. For context eventually all the integrations will be pulled remotely from a database, so am still trying to figure out an optimal data structure, but requirements will be clearer as we build out the UI RE installing integrations: - For now, if the integration has a provided SQL installation command, that'll take precedence - Else, if the integration has a provided SQL installation query, we'll use that on the /query endpoint - Otherwise, if the integration only requires database extensions, dashboard will generate the queries to install the extensions - In the case of the former tho, we won't allow users to choose which schema to install the extension in too Just ping me if any clarification's required! ## To test - [ ] Verify that you can install the database webhooks with the new integration UI - [ ] Verify that behaviour is status quo without the new integration UI
121 lines
4.1 KiB
TypeScript
121 lines
4.1 KiB
TypeScript
import { useParams } from 'common'
|
|
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
|
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
|
import { PropsWithChildren, ReactNode } from 'react'
|
|
import { Badge, Card, CardContent, cn, Separator } from 'ui'
|
|
|
|
import { INTEGRATIONS } from '../Landing/Integrations.constants'
|
|
import { BuiltBySection } from './BuildBySection'
|
|
import { MarkdownContent } from './MarkdownContent'
|
|
import { MissingExtensionAlert } from './MissingExtensionAlert'
|
|
|
|
export interface IntegrationOverviewTabProps {
|
|
actions?: ReactNode
|
|
status?: string | ReactNode
|
|
alert?: ReactNode
|
|
hideRequiredExtensionsSection?: boolean
|
|
}
|
|
|
|
export const IntegrationOverviewTab = ({
|
|
actions,
|
|
alert,
|
|
status,
|
|
children,
|
|
hideRequiredExtensionsSection = false,
|
|
}: PropsWithChildren<IntegrationOverviewTabProps>) => {
|
|
const { id } = useParams()
|
|
const { data: project } = useSelectedProjectQuery()
|
|
|
|
const integration = INTEGRATIONS.find((i) => i.id === id)
|
|
|
|
const { data: extensions } = useDatabaseExtensionsQuery({
|
|
projectRef: project?.ref,
|
|
connectionString: project?.connectionString,
|
|
})
|
|
|
|
if (!integration) {
|
|
return <div>Unsupported integration type</div>
|
|
}
|
|
|
|
const dependsOnExtension = (integration.requiredExtensions ?? []).length > 0
|
|
|
|
const installableExtensions = (extensions ?? []).filter((ext) =>
|
|
(integration.requiredExtensions ?? []).includes(ext.name)
|
|
)
|
|
const hasToInstallExtensions = installableExtensions.some((x) => !x.installed_version)
|
|
|
|
// The integration requires extensions that are not available to install on the current database image
|
|
const hasMissingExtensions =
|
|
installableExtensions.length !== integration.requiredExtensions.length
|
|
|
|
return (
|
|
<div className="flex flex-col gap-8 py-10">
|
|
<BuiltBySection integration={integration} status={status} />
|
|
|
|
{!!alert && <div className="px-10 max-w-4xl">{alert}</div>}
|
|
|
|
<MarkdownContent key={integration.id} integrationId={integration.id} />
|
|
|
|
<Separator />
|
|
|
|
{dependsOnExtension && !hideRequiredExtensionsSection && (
|
|
<div className="px-4 md:px-10 max-w-4xl flex flex-col gap-y-4">
|
|
<h4>Required extensions</h4>
|
|
<Card>
|
|
<CardContent className="p-0">
|
|
<ul className="text-foreground-light text-sm">
|
|
{(integration.requiredExtensions ?? []).map((requiredExtension, idx) => {
|
|
const extension = (extensions ?? []).find((ext) => ext.name === requiredExtension)
|
|
const isInstalled = !!extension?.installed_version
|
|
const isLastRow = idx === (integration.requiredExtensions?.length ?? 0) - 1
|
|
|
|
return (
|
|
<li
|
|
key={requiredExtension}
|
|
className={cn(
|
|
'flex items-center justify-between gap-3 py-2 px-3',
|
|
!isLastRow ? 'border-b' : ''
|
|
)}
|
|
>
|
|
<code className="text-xs">{requiredExtension}</code>
|
|
|
|
<div className="shrink-0">
|
|
{extension ? (
|
|
isInstalled ? (
|
|
<Badge>Installed</Badge>
|
|
) : (
|
|
<MissingExtensionAlert extension={extension} />
|
|
)
|
|
) : (
|
|
<span className="text-foreground-muted">Unavailable</span>
|
|
)}
|
|
</div>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
|
|
{hasMissingExtensions && (
|
|
<div className="py-3 px-4 border-t">{integration.missingExtensionsAlert}</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)}
|
|
|
|
{!!actions && (
|
|
<div
|
|
aria-disabled={hasToInstallExtensions}
|
|
className={cn(
|
|
'px-10 max-w-4xl',
|
|
hasToInstallExtensions && 'opacity-25 [&_button]:pointer-events-none'
|
|
)}
|
|
>
|
|
{actions}
|
|
</div>
|
|
)}
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|