MarketplaceDetail.tsx130 lines · main
| 1 | import { ArrowUpRight, BookOpen, Settings } from 'lucide-react' |
| 2 | import { Button, cn } from 'ui' |
| 3 | import { GenericSkeletonLoader, ShimmeringLoader } from 'ui-patterns' |
| 4 | import { Admonition } from 'ui-patterns/admonition' |
| 5 | |
| 6 | import { MarketplaceDetailHero } from './MarketplaceDetailHero' |
| 7 | import { MarketplaceDetailTopBar } from './MarketplaceDetailTopBar' |
| 8 | import { OverviewTab } from './OverviewTab' |
| 9 | import { InstallIntegrationSheet } from '@/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet/InstallIntegrationSheet' |
| 10 | import { InstallOAuthIntegrationButton } from '@/components/interfaces/Integrations/Integration/IntegrationOverviewTabV2/InstallIntegrationSheet/InstallOAuthIntegrationButton' |
| 11 | import { useIntegrationDetail } from '@/components/interfaces/Integrations/Landing/useIntegrationDetail' |
| 12 | import { UnknownInterface } from '@/components/ui/UnknownInterface' |
| 13 | |
| 14 | export const centeredContentClass = 'mx-auto w-full max-w-6xl px-6 xl:px-10' |
| 15 | |
| 16 | export const MarketplaceDetail = () => { |
| 17 | const { |
| 18 | ref, |
| 19 | activeRoute, |
| 20 | isKnownRoute, |
| 21 | layout, |
| 22 | tabs, |
| 23 | isReady, |
| 24 | isWrapperBlocked, |
| 25 | pageTitle, |
| 26 | pageSubTitle, |
| 27 | integration, |
| 28 | isInstalled, |
| 29 | isAvailableLoading, |
| 30 | isInstalledLoading, |
| 31 | Component, |
| 32 | } = useIntegrationDetail() |
| 33 | |
| 34 | if (!isReady) return null |
| 35 | if (isWrapperBlocked) return <UnknownInterface urlBack={`/project/${ref}/integrations`} /> |
| 36 | |
| 37 | if (isAvailableLoading || isInstalledLoading) { |
| 38 | return ( |
| 39 | <> |
| 40 | <MarketplaceDetailTopBar title="" /> |
| 41 | <div className={cn(centeredContentClass, 'border-b bg-surface-75 pt-10')}> |
| 42 | <div className="mx-auto flex w-full max-w-6xl flex-col gap-3 pb-6"> |
| 43 | <ShimmeringLoader className="h-9 w-64" /> |
| 44 | <ShimmeringLoader className="h-4 w-96" /> |
| 45 | </div> |
| 46 | </div> |
| 47 | <div className={cn(centeredContentClass, 'py-8')}> |
| 48 | <GenericSkeletonLoader /> |
| 49 | </div> |
| 50 | </> |
| 51 | ) |
| 52 | } |
| 53 | |
| 54 | if (!integration) { |
| 55 | return ( |
| 56 | <> |
| 57 | <MarketplaceDetailTopBar title="Integration not found" /> |
| 58 | <div className={cn(centeredContentClass, 'py-8')}> |
| 59 | <Admonition type="warning" title="This integration is not currently available"> |
| 60 | Please try again later or contact support if the problem persists. |
| 61 | </Admonition> |
| 62 | </div> |
| 63 | </> |
| 64 | ) |
| 65 | } |
| 66 | |
| 67 | const renderInstallAction = () => { |
| 68 | if (integration.type === 'oauth') { |
| 69 | return <InstallOAuthIntegrationButton integration={integration} /> |
| 70 | } |
| 71 | if (isInstalled) { |
| 72 | return ( |
| 73 | <Button type="outline" disabled icon={<Settings size={13} />}> |
| 74 | Installed |
| 75 | </Button> |
| 76 | ) |
| 77 | } |
| 78 | return <InstallIntegrationSheet integration={integration} /> |
| 79 | } |
| 80 | |
| 81 | const CustomPageComponent = activeRoute !== 'overview' && isKnownRoute ? Component : null |
| 82 | |
| 83 | return ( |
| 84 | <> |
| 85 | <MarketplaceDetailTopBar |
| 86 | title={integration.name} |
| 87 | isInstalled={isInstalled} |
| 88 | actions={ |
| 89 | <> |
| 90 | {integration.docsUrl && ( |
| 91 | <Button |
| 92 | type="text" |
| 93 | size="tiny" |
| 94 | icon={<BookOpen size={13} />} |
| 95 | iconRight={<ArrowUpRight size={13} />} |
| 96 | asChild |
| 97 | > |
| 98 | <a href={integration.docsUrl} target="_blank" rel="noreferrer"> |
| 99 | Docs |
| 100 | </a> |
| 101 | </Button> |
| 102 | )} |
| 103 | {renderInstallAction()} |
| 104 | </> |
| 105 | } |
| 106 | /> |
| 107 | |
| 108 | <MarketplaceDetailHero |
| 109 | integration={integration} |
| 110 | title={pageTitle} |
| 111 | subtitle={pageSubTitle} |
| 112 | tabs={tabs} |
| 113 | /> |
| 114 | |
| 115 | {activeRoute === 'overview' ? ( |
| 116 | <div className={centeredContentClass}> |
| 117 | <OverviewTab integration={integration} isInstalled={isInstalled} /> |
| 118 | </div> |
| 119 | ) : CustomPageComponent ? ( |
| 120 | layout === 'constrained' ? ( |
| 121 | <div className={centeredContentClass}> |
| 122 | <CustomPageComponent /> |
| 123 | </div> |
| 124 | ) : ( |
| 125 | <CustomPageComponent /> |
| 126 | ) |
| 127 | ) : null} |
| 128 | </> |
| 129 | ) |
| 130 | } |