From ec02a89b69cc964772cc76c4e8362548545fca72 Mon Sep 17 00:00:00 2001
From: Danny White <3104761+dnywh@users.noreply.github.com>
Date: Mon, 5 Oct 2026 12:29:48 +1100
Subject: [PATCH] polish aws marketplace purchase surfaces
Move the Studio callout into the plan cards grid, quiet Billing to a More information link, and tighten the www ambient mask.
---
.../AwsMarketplacePurchaseCallout.tsx | 48 +++++++++----------
.../Subscription/CancellationFlow.tsx | 2 +-
.../Subscription/PlanCards.tsx | 10 +++-
.../Subscription/PlanUpdatePanelShell.tsx | 6 +--
.../Subscription/PlanUpdateSidePanel.test.tsx | 14 +++---
.../Subscription/PlanUpdateSidePanel.tsx | 8 +---
.../Subscription/Subscription.test.tsx | 18 +++++--
.../Subscription/Subscription.tsx | 28 +++++++++--
.../components/Partners/BackgroundPattern.tsx | 2 +-
packages/common/telemetry-constants.ts | 2 +-
packages/shared-data/plans.ts | 2 +-
11 files changed, 85 insertions(+), 55 deletions(-)
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/AwsMarketplacePurchaseCallout.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/AwsMarketplacePurchaseCallout.tsx
index a01278ebbf9..9967ada127f 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/AwsMarketplacePurchaseCallout.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/AwsMarketplacePurchaseCallout.tsx
@@ -1,34 +1,34 @@
import { ExternalLink } from 'lucide-react'
import { Button } from 'ui'
+import { Admonition } from 'ui-patterns/Admonition'
-import { BASE_PATH } from '@/lib/constants'
+import PartnerIcon from '@/components/ui/PartnerIcon'
+import { MANAGED_BY } from '@/lib/constants/infrastructure'
const AWS_MARKETPLACE_URL = 'https://supabase.com/aws-marketplace'
export function AwsMarketplacePurchaseCallout() {
return (
-
-
-
-

-
-
-
Purchase through AWS Marketplace
-
- Apply Supabase spend toward an AWS commitment and manage billing through AWS.
-
-
-
- }>
-
- View purchase options
-
-
-
+
+ }
+ title="Prefer purchasing through AWS Marketplace?"
+ description="Apply Supabase spend toward an AWS commitment and manage billing through AWS."
+ actions={
+ }>
+
+ View options
+
+
+ }
+ />
)
}
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/CancellationFlow.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/CancellationFlow.tsx
index c1b4288de28..10cc79b0e77 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/CancellationFlow.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/CancellationFlow.tsx
@@ -160,7 +160,7 @@ export const InitiateCancellationFlowButton = (props: InitiateCancellationFlowBu
setVisible(true)
}}
>
- {props.children ?? 'Cancel Subscription'}
+ {props.children ?? 'Cancel subscription'}
void
}
@@ -37,6 +39,7 @@ export function PlanCards({
selectedOrganization,
variant,
entryDelay,
+ showAwsMarketplacePurchase = false,
onSelectTier,
}: PlanCardsProps) {
const router = useRouter()
@@ -45,7 +48,7 @@ export function PlanCards({
const entryAnimation = getPlanCardsEntryAnimation(entryDelay)
return (
-
+
{subscriptionsPlans.map((plan) => {
const planMeta = availablePlans.find((p) => p.id === plan.id.split('tier_')[1])
const price = planMeta?.price ?? 0
@@ -95,6 +98,11 @@ export function PlanCards({
/>
)
})}
+ {showAwsMarketplacePurchase && (
+
+
+
+ )}
)
}
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdatePanelShell.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdatePanelShell.tsx
index eef5b0ee34c..32fc245b90d 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdatePanelShell.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdatePanelShell.tsx
@@ -62,7 +62,7 @@ export function PlanUpdateFullScreenShell({
onClick={onClose}
className="fixed top-4 left-4 z-10"
>
- Go back to Studio
+ Back
- Change subscription plan for {organizationName}
+ Change subscription plan for {organizationName}
{notice}
{children}
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.test.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.test.tsx
index 06eb154eb34..61c40181376 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.test.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.test.tsx
@@ -279,7 +279,7 @@ describe('PlanUpdateSidePanel', () => {
it('renders the full-screen shell instead of the sheet', () => {
render()
- expect(screen.getByRole('button', { name: /Go back to Studio/ })).toBeInTheDocument()
+ expect(screen.getByRole('button', { name: /Back/ })).toBeInTheDocument()
expect(screen.getByRole('link', { name: /Compare plans/ })).toBeInTheDocument()
expect(screen.queryByRole('link', { name: 'Pricing' })).not.toBeInTheDocument()
})
@@ -296,8 +296,8 @@ describe('PlanUpdateSidePanel', () => {
it('offers AWS Marketplace as a separate purchasing route', () => {
render()
- expect(screen.getByText('Purchase through AWS Marketplace')).toBeInTheDocument()
- expect(screen.getByRole('link', { name: 'View purchase options' })).toHaveAttribute(
+ expect(screen.getByText('Prefer purchasing through AWS Marketplace?')).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: 'View options' })).toHaveAttribute(
'href',
'https://supabase.com/aws-marketplace'
)
@@ -331,7 +331,7 @@ describe('PlanUpdateSidePanel', () => {
it('renders gap rows inside the full-screen shell', () => {
render()
- expect(screen.getByRole('button', { name: /Go back to Studio/ })).toBeInTheDocument()
+ expect(screen.getByRole('button', { name: /Back/ })).toBeInTheDocument()
expect(screen.getByText('Daily backups')).toBeInTheDocument()
expect(screen.getByText('1-day log retention')).toBeInTheDocument()
// Free has a `lesser` item → "Plan limits"; Pro has only `missing` items → "Not included"
@@ -352,7 +352,7 @@ describe('PlanUpdateSidePanel', () => {
it('opens neither shell, so the fullscreen variant cannot flash the sheet', () => {
render()
- expect(screen.queryByRole('button', { name: /Go back to Studio/ })).not.toBeInTheDocument()
+ expect(screen.queryByRole('button', { name: /Back/ })).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Upgrade to Pro' })).not.toBeInTheDocument()
})
@@ -377,8 +377,8 @@ describe('PlanUpdateSidePanel', () => {
render()
expect(screen.getByRole('link', { name: 'Pricing' })).toBeInTheDocument()
- expect(screen.queryByRole('button', { name: /Go back to Studio/ })).not.toBeInTheDocument()
- expect(screen.getByText('Purchase through AWS Marketplace')).toBeInTheDocument()
+ expect(screen.queryByRole('button', { name: /Back/ })).not.toBeInTheDocument()
+ expect(screen.getByText('Prefer purchasing through AWS Marketplace?')).toBeInTheDocument()
})
})
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx
index dda572973e2..11fa707629c 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx
@@ -6,7 +6,6 @@ import { useRouter } from 'next/router'
import { useCallback, useEffect, useEffectEvent, useMemo, useRef, useState } from 'react'
import { plans as subscriptionsPlans } from 'shared-data/plans'
-import { AwsMarketplacePurchaseCallout } from './AwsMarketplacePurchaseCallout'
import { CancellationFlow } from './CancellationFlow'
import {
isFullScreenPresentation,
@@ -268,14 +267,11 @@ export const PlanUpdateSidePanel = () => {
selectedOrganization={selectedOrganization}
variant={presentation}
entryDelay={isFullScreen ? contentDelay : undefined}
+ showAwsMarketplacePurchase={isPlanPresentationEligible}
onSelectTier={setSelectedTier}
/>
)
- const awsMarketplaceCallout = isPlanPresentationEligible ? (
-
- ) : null
-
return (
<>
{isFullScreen && isPanelOpen && (
@@ -286,7 +282,6 @@ export const PlanUpdateSidePanel = () => {
contentDelay={contentDelay}
onClose={onClose}
>
- {awsMarketplaceCallout}
{planCards}
)}
@@ -298,7 +293,6 @@ export const PlanUpdateSidePanel = () => {
notice={notice}
onClose={onClose}
>
- {awsMarketplaceCallout}
{planCards}
)}
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.test.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.test.tsx
index 7a29ec41f0c..94a5fdc92b6 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.test.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.test.tsx
@@ -5,9 +5,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import Subscription from './Subscription'
import { render } from '@/tests/helpers'
-const { mockSubscription, mockSetPanelKey } = vi.hoisted(() => ({
+const { mockSubscription, mockSetPanelKey, mockSelectedOrganization } = vi.hoisted(() => ({
mockSubscription: vi.fn(),
mockSetPanelKey: vi.fn(),
+ mockSelectedOrganization: vi.fn(),
}))
vi.mock('common', async (importOriginal) => {
@@ -29,7 +30,7 @@ vi.mock('@/hooks/misc/useCheckPermissions', () => ({
vi.mock('@/hooks/misc/useSelectedOrganization', () => ({
useSelectedOrganizationQuery: () => ({
- data: { managed_by: 'supabase' },
+ data: mockSelectedOrganization(),
}),
}))
@@ -53,6 +54,7 @@ vi.mock('./PlanUpdateSidePanel', () => ({
describe('Subscription', () => {
beforeEach(() => {
+ mockSelectedOrganization.mockReturnValue({ managed_by: 'supabase' })
mockSubscription.mockReturnValue({
data: {
plan: { id: 'free', name: 'Free' },
@@ -76,11 +78,15 @@ describe('Subscription', () => {
expect(mockSetPanelKey).toHaveBeenCalledWith('subscriptionPlan')
})
- it('shows AWS Marketplace as an alternative purchasing route', () => {
+ it('links to Compare plans and AWS Marketplace under More information', () => {
render()
- expect(screen.getByText('Purchase through AWS Marketplace')).toBeInTheDocument()
- expect(screen.getByRole('link', { name: 'View purchase options' })).toHaveAttribute(
+ expect(screen.getByText('More information')).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: /Compare plans/ })).toHaveAttribute(
+ 'href',
+ 'https://supabase.com/pricing#compare-plans'
+ )
+ expect(screen.getByRole('link', { name: /AWS Marketplace/ })).toHaveAttribute(
'href',
'https://supabase.com/aws-marketplace'
)
@@ -104,5 +110,7 @@ describe('Subscription', () => {
screen.queryByRole('button', { name: 'Change subscription plan' })
).not.toBeInTheDocument()
expect(screen.getByText('Unable to update plan from Enterprise')).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: /Compare plans/ })).toBeInTheDocument()
+ expect(screen.queryByRole('link', { name: /AWS Marketplace/ })).not.toBeInTheDocument()
})
})
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx
index 5c2a008396e..8cd831184d2 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx
@@ -1,12 +1,12 @@
import { PermissionAction, SupportCategories } from '@supabase/shared-types/out/constants'
import { useFlag, useParams } from 'common'
+import { ExternalLink } from 'lucide-react'
import Link from 'next/link'
import { Button } from 'ui'
import { Admonition } from 'ui-patterns/Admonition'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import { Restriction } from '../Restriction'
-import { AwsMarketplacePurchaseCallout } from './AwsMarketplacePurchaseCallout'
import { InitiateCancellationFlowButton } from './CancellationFlow'
import { PlanUpdateSidePanel } from './PlanUpdateSidePanel'
import { SupportLink } from '@/components/interfaces/Support/SupportLink'
@@ -23,6 +23,9 @@ import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganizati
import { MANAGED_BY } from '@/lib/constants/infrastructure'
import { useOrgSettingsPageStateSnapshot } from '@/state/organization-settings'
+const COMPARE_PLANS_URL = 'https://supabase.com/pricing#compare-plans'
+const AWS_MARKETPLACE_URL = 'https://supabase.com/aws-marketplace'
+
const Subscription = () => {
const { slug } = useParams()
const snap = useOrgSettingsPageStateSnapshot()
@@ -66,6 +69,25 @@ const Subscription = () => {
usage quotas.
+
+
More information
+
+
+
+
+ {canPurchaseThroughAws && (
+
+
+
+ )}
+
+
@@ -100,15 +122,13 @@ const Subscription = () => {
{currentPlan && currentPlan.id !== 'free' && (
- Cancel Subscription
+ Cancel subscription
)}
)}
- {canPurchaseThroughAws && }
-
{!canChangeTier && (
{projectUpdateDisabled ? (
diff --git a/apps/www/components/Partners/BackgroundPattern.tsx b/apps/www/components/Partners/BackgroundPattern.tsx
index e5182a25bb5..16138750ed9 100644
--- a/apps/www/components/Partners/BackgroundPattern.tsx
+++ b/apps/www/components/Partners/BackgroundPattern.tsx
@@ -35,7 +35,7 @@ const BackgroundPattern = ({ className, variant = 'center' }: BackgroundPatternP
{variant === 'edges' && (
)}
{/* Soft brand-green radial glow from the top */}
diff --git a/packages/common/telemetry-constants.ts b/packages/common/telemetry-constants.ts
index bf8bed7b580..c03ecdb533b 100644
--- a/packages/common/telemetry-constants.ts
+++ b/packages/common/telemetry-constants.ts
@@ -1436,7 +1436,7 @@ export interface SqlEditorQueryRunButtonClickedEvent {
}
/**
- * User clicked on the "Cancel Subscription" Button on the billing settings page.
+ * User clicked on the "Cancel subscription" Button on the billing settings page.
*
* @group Events
* @source studio
diff --git a/packages/shared-data/plans.ts b/packages/shared-data/plans.ts
index bc2f7cfd893..742d52526db 100644
--- a/packages/shared-data/plans.ts
+++ b/packages/shared-data/plans.ts
@@ -107,6 +107,6 @@ export const plans: PricingInformation[] = [
priceLabel: '',
priceMonthly: 'Custom',
preface: '',
- cta: 'Contact Us',
+ cta: 'Contact us',
},
] as const