track source when viewing plans (#33405)

* track source when viewing plans

* remove log

* rename event

* Update apps/studio/components/interfaces/Organization/BillingSettings/Restriction.tsx

Co-authored-by: Long Hoang <1732217+loong@users.noreply.github.com>

* Update apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/BillingMetric.tsx

Co-authored-by: Long Hoang <1732217+loong@users.noreply.github.com>

* Update apps/studio/components/interfaces/Organization/BillingSettings/Restriction.tsx

Co-authored-by: Long Hoang <1732217+loong@users.noreply.github.com>

* Update apps/studio/components/interfaces/Organization/BillingSettings/Restriction.tsx

Co-authored-by: Long Hoang <1732217+loong@users.noreply.github.com>

* added docs for tracking

* prettier

* chore: rename origins to give more hints on where these are coming from

---------

Co-authored-by: Long Hoang <1732217+loong@users.noreply.github.com>
This commit is contained in:
Saxon Fletcher
2025-02-10 16:45:36 +10:00
committed by GitHub
parent 7743314541
commit 15841c6bf3
32 changed files with 111 additions and 36 deletions

View File

@@ -127,7 +127,9 @@ export const CollectionForm = ({
className="mt-2"
type="primary"
onClick={() =>
router.push(`/org/${currentOrg?.slug}/billing?panel=subscriptionPlan`)
router.push(
`/org/${currentOrg?.slug}/billing?panel=subscriptionPlan&source=dataWarehouseIncreaseRetention`
)
}
>
Upgrade plan

View File

@@ -62,6 +62,7 @@ const BackupsList = () => {
icon={<Clock size={20} />}
primaryText="Free Plan does not include project backups."
secondaryText="Upgrade to the Pro Plan for up to 7 days of scheduled backups."
source="backups"
/>
)
}

View File

@@ -314,7 +314,11 @@ export function DiskManagementForm() {
title="Compute and Disk configuration is not available on the Free Plan"
actions={
<Button type="default" asChild>
<Link href={`/org/${org?.slug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
<Link
href={`/org/${org?.slug}/billing?panel=subscriptionPlan&source=diskManagementConfigure`}
>
Upgrade plan
</Link>
</Button>
}
description="You will need to upgrade to at least the Pro Plan to configure compute and disk"

View File

@@ -316,7 +316,7 @@ export function DiskManagementPanelForm() {
<Link
target="_blank"
rel="noreferrer"
href={`/org/${org?.slug}/billing?panel=subscriptionPlan`}
href={`/org/${org?.slug}/billing?panel=subscriptionPlan&source=diskManagementPanelDiskSize`}
>
Upgrade plan
</Link>

View File

@@ -166,7 +166,7 @@ const AuditLogs = () => {
<div className="flex items-center">
<Button type="primary" asChild>
<Link href={`/org/${slug}/billing?panel=subscriptionPlan`}>
<Link href={`/org/${slug}/billing?panel=subscriptionPlan&source=auditLogs`}>
Upgrade subscription
</Link>
</Button>

View File

@@ -143,7 +143,11 @@ const BillingMetric = ({
) : (
<div>
<Button type="default" asChild>
<Link href={`/org/${slug}/billing?panel=subscriptionPlan`}>Upgrade</Link>
<Link
href={`/org/${slug}/billing?panel=subscriptionPlan&source=billingBreakdownUsage${metric.anchor}`}
>
Upgrade
</Link>
</Button>
</div>
)}

View File

@@ -97,7 +97,11 @@ export const Restriction = () => {
</p>
<div className="flex items-center gap-x-2 mt-3">
<Button asChild key="upgrade-button" type="default">
<Link href={`/org/${org?.slug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
<Link
href={`/org/${org?.slug}/billing?panel=subscriptionPlan&source=fairUseGracePeriodStarted`}
>
Upgrade plan
</Link>
</Button>
<Button asChild type="default" icon={<ExternalLink />}>
<a href="https://supabase.com/docs/guides/platform/billing-faq#fair-use-policy">
@@ -124,7 +128,11 @@ export const Restriction = () => {
</p>
<div className="flex items-center gap-x-2 mt-3">
<Button key="upgrade-button" asChild type="default">
<Link href={`/org/${org?.slug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
<Link
href={`/org/${org?.slug}/billing?panel=subscriptionPlan&source=fairUseGracePeriodOver`}
>
Upgrade plan
</Link>
</Button>
<Button asChild type="default" icon={<ExternalLink />}>
<a href="https://supabase.com/docs/guides/platform/billing-faq#fair-use-policy">
@@ -151,7 +159,11 @@ export const Restriction = () => {
</p>
<div className="flex items-center gap-x-2 mt-3">
<Button key="upgrade-button" asChild type="default">
<Link href={`/org/${org?.slug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
<Link
href={`/org/${org?.slug}/billing?panel=subscriptionPlan&source=fairUseRestricted`}
>
Upgrade plan
</Link>
</Button>
<Button asChild type="default" icon={<ExternalLink />}>
<a href="https://supabase.com/docs/guides/platform/billing-faq#fair-use-policy">

View File

@@ -139,7 +139,7 @@ const PaymentMethodSelection = ({
<AddNewPaymentMethodModal
visible={showAddNewPaymentMethodModal}
returnUrl={`${getURL()}/org/${selectedOrganization?.slug}/billing?panel=subscriptionPlan`}
returnUrl={`${getURL()}/org/${selectedOrganization?.slug}/billing?panel=subscriptionPlan&source=paymentMethod`}
onCancel={() => setShowAddNewPaymentMethodModal(false)}
autoMarkAsDefaultPaymentMethod={true}
onConfirm={async () => {

View File

@@ -7,7 +7,7 @@ import { useRouter } from 'next/router'
import { useEffect, useRef, useState } from 'react'
import { toast } from 'sonner'
import { TelemetryActions } from 'common/telemetry-constants'
import { StudioPricingSidePanelOpenedEvent, TelemetryActions } from 'common/telemetry-constants'
import { billingPartnerLabel } from 'components/interfaces/Billing/Subscription/Subscription.utils'
import Table from 'components/to-be-cleaned/Table'
import AlertError from 'components/ui/AlertError'
@@ -126,11 +126,18 @@ const PlanUpdateSidePanel = () => {
useEffect(() => {
if (visible) {
setSelectedTier(undefined)
const source = Array.isArray(router.query.source)
? router.query.source[0]
: router.query.source
const properties: StudioPricingSidePanelOpenedEvent['properties'] = {
currentPlan: subscription?.plan?.name,
}
if (source) {
properties.origin = source
}
sendEvent({
action: TelemetryActions.STUDIO_PRICING_SIDE_PANEL_OPENED,
properties: {
currentPlan: subscription?.plan?.name,
},
properties,
groups: { organization: slug ?? 'Unknown' },
})
}

View File

@@ -75,7 +75,7 @@ const SOC2 = () => {
{isSuccess && (
<div className="flex items-center justify-center h-full">
{currentPlan?.id === 'free' || currentPlan?.id === 'pro' ? (
<Link href={`/org/${slug}/billing?panel=subscriptionPlan`}>
<Link href={`/org/${slug}/billing?panel=subscriptionPlan&source=soc2`}>
<Button type="default">Upgrade to Team</Button>
</Link>
) : (

View File

@@ -74,7 +74,9 @@ const SecurityQuestionnaire = () => {
{isSuccess && (
<div className="flex items-center justify-center h-full">
{currentPlan?.id === 'free' || currentPlan?.id === 'pro' ? (
<Link href={`/org/${slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${slug}/billing?panel=subscriptionPlan&source=securityQuestionnaire`}
>
<Button type="default">Upgrade to Team</Button>
</Link>
) : (

View File

@@ -305,7 +305,10 @@ const NewOrgForm = ({ onPaymentMethodReset }: NewOrgFormProps) => {
<p>
The plan applies only to this new organization. To upgrade an existing
organization,{' '}
<Link className="underline" href="/org/_/billing?panel=subscriptionPlan">
<Link
className="underline"
href="/org/_/billing?panel=subscriptionPlan&source=newOrgUpgradeExisting"
>
click here
</Link>
.

View File

@@ -38,7 +38,11 @@ const FreeProjectLimitWarning = ({
<div>
<Button asChild type="default">
<Link href={`/org/${orgSlug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
<Link
href={`/org/${orgSlug}/billing?panel=subscriptionPlan&source=freeProjectLimitWarning`}
>
Upgrade plan
</Link>
</Button>
</div>
</div>

View File

@@ -408,7 +408,9 @@ export const InviteMemberButton = () => {
{isSuccessSubscription &&
(currentPlan?.id === 'free' || currentPlan?.id === 'pro') && (
<Button asChild type="default">
<Link href={`/org/${slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${slug}/billing?panel=subscriptionPlan&source=inviteMemberSSO`}
>
Upgrade to Team
</Link>
</Button>

View File

@@ -13,14 +13,14 @@ export const generateUsageData = (attribute: string, days: number): DataPoint[]
})
}
export const getUpgradeUrl = (slug: string, subscription?: OrgSubscription) => {
export const getUpgradeUrl = (slug: string, subscription?: OrgSubscription, source?: string) => {
if (!subscription) {
return `/org/${slug}/billing`
}
return subscription?.plan?.id === 'pro' && subscription?.usage_billing_enabled === false
? `/org/${slug}/billing#cost-control`
: `/org/${slug}/billing?panel=subscriptionPlan`
: `/org/${slug}/billing?panel=subscriptionPlan&source=usage${source}`
}
const compactNumberFormatter = new Intl.NumberFormat('en-US', {

View File

@@ -53,7 +53,7 @@ const AttributeUsage = ({
isSuccess,
currentBillingCycleSelected,
}: AttributeUsageProps) => {
const upgradeUrl = getUpgradeUrl(slug ?? '', subscription)
const upgradeUrl = getUpgradeUrl(slug ?? '', subscription, attribute.key)
const usageRatio = (usageMeta?.usage ?? 0) / (usageMeta?.pricing_free_units ?? 0)
const usageExcess = (usageMeta?.usage ?? 0) - (usageMeta?.pricing_free_units ?? 0)
const usageBasedBilling = subscription?.usage_billing_enabled

View File

@@ -282,7 +282,9 @@ const ComputeInstanceSidePanel = () => {
title="Changing your compute size is only available on the Pro Plan"
actions={
<Button asChild type="default">
<Link href={`/org/${organization?.slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=computeInstanceSidePanel`}
>
View available plans
</Link>
</Button>

View File

@@ -229,7 +229,9 @@ const CustomDomainSidePanel = () => {
title="Custom domains are unavailable on the Free Plan"
actions={
<Button asChild type="default">
<Link href={`/org/${organization?.slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=customDomainSidePanel`}
>
View available plans
</Link>
</Button>

View File

@@ -222,7 +222,9 @@ const IPv4SidePanel = () => {
<Admonition type="note" title="IPv4 add-on is unavailable on the Free Plan">
<p>Upgrade your plan to enable a IPv4 address for your project</p>
<Button asChild type="default">
<Link href={`/org/${organization?.slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=ipv4SidePanel`}
>
View available plans
</Link>
</Button>

View File

@@ -279,7 +279,9 @@ const PITRSidePanel = () => {
title="Changing your Point-In-Time-Recovery is only available on the Pro Plan"
actions={
<Button asChild type="default">
<Link href={`/org/${organization?.slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=pitrSidePanel`}
>
View available plans
</Link>
</Button>

View File

@@ -39,14 +39,18 @@ export const DatabaseReadOnlyAlert = () => {
</li>
{subscription?.plan.id === 'free' ? (
<li>
<Link href={`/org/${organization?.slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=databaseReadOnlyAlertUpgradePlan`}
>
<a className="text underline">Upgrade to the Pro Plan</a>
</Link>{' '}
to increase your database size limit to 8GB.
</li>
) : subscription?.plan.id === 'pro' && subscription?.usage_billing_enabled ? (
<li>
<Link href={`/org/${organization?.slug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=databaseReadOnlyAlertSpendCap`}
>
<a className="text-foreground underline">Disable your Spend Cap</a>
</Link>{' '}
to allow your project to auto-scale and expand beyond the 8GB database size limit

View File

@@ -90,6 +90,7 @@ const CustomDomainConfig = () => {
: 'To configure a custom domain for your project, please enable the add-on'
}
addon="customDomain"
source="customDomain"
disabled={customDomainsDisabledDueToQuota}
/>
) : (

View File

@@ -301,7 +301,7 @@ const DeployNewReplicaPanel = ({
<Link
href={
isFreePlan
? `/org/${org?.slug}/billing?panel=subscriptionPlan`
? `/org/${org?.slug}/billing?panel=subscriptionPlan&source=deployNewReplicaPanelSmallCompute`
: diskAndComputeFormEnabled
? `/project/${projectRef}/settings/compute-and-disk`
: `/project/${projectRef}/settings/addons?panel=computeInstance`
@@ -400,7 +400,7 @@ const DeployNewReplicaPanel = ({
<Link
href={
isFreePlan
? `/org/${org?.slug}/billing?panel=subscriptionPlan`
? `/org/${org?.slug}/billing?panel=subscriptionPlan&source=deployNewReplicaPanelMaxReplicas`
: diskAndComputeFormEnabled
? `/project/${projectRef}/settings/compute-and-disk`
: `/project/${projectRef}/settings/addons?panel=computeInstance`

View File

@@ -59,7 +59,11 @@ const UpgradePrompt: React.FC<Props> = ({ show, setShowUpgradePrompt }) => {
Close
</Button>
<Button asChild size="tiny">
<Link href={`/org/${organization?.slug}/billing?panel=subscriptionPlan`}>Upgrade</Link>
<Link
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=logsRetentionUpgradePrompt`}
>
Upgrade
</Link>
</Button>
</Modal.Content>
</Modal>

View File

@@ -56,7 +56,11 @@ export const PlanExpectationInfoBox = ({
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-y-2 sm:gap-x-2">
<Button asChild>
<Link href={`/org/${orgSlug}/billing?panel=subscriptionPlan`}>Upgrade project</Link>
<Link
href={`/org/${orgSlug}/billing?panel=subscriptionPlan&source=planSupportExpectationInfoBox`}
>
Upgrade project
</Link>
</Button>
<Button asChild type="default" icon={<ExternalLink />}>
<Link

View File

@@ -22,7 +22,7 @@ const BranchingPlanNotice = () => {
<AlertDescription_Shadcn_>
<Button size="tiny" type="default" className="mt-4">
<Link
href={`/org/${selectedOrg?.slug}/billing?panel=subscriptionPlan`}
href={`/org/${selectedOrg?.slug}/billing?panel=subscriptionPlan&source=enableBranchingButton`}
onClick={() => snap.setShowEnableBranchingModal(false)}
>
Upgrade to Pro

View File

@@ -290,7 +290,9 @@ export const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
</ButtonTooltip>
{isFreePlan ? (
<Button asChild type="primary">
<Link href={`/org/${orgSlug}/billing?panel=subscriptionPlan`}>
<Link
href={`/org/${orgSlug}/billing?panel=subscriptionPlan&source=projectPausedStateRestore`}
>
Upgrade to Pro
</Link>
</Button>

View File

@@ -268,6 +268,7 @@ const StorageSettings = () => {
icon={<Clock size={14} className="text-foreground-muted" />}
primaryText="Free Plan has a fixed upload file size limit of 50 MB."
secondaryText="Upgrade to the Pro Plan for a configurable upload file size limit of up to 50 GB."
source="storageSizeLimit"
/>
</div>
)}

View File

@@ -16,6 +16,7 @@ interface UpgradeToProProps {
secondaryText: string
addon?: 'pitr' | 'customDomain' | 'computeInstance'
buttonText?: string
source?: string
disabled?: boolean
}
@@ -25,6 +26,7 @@ const UpgradeToPro = ({
secondaryText,
addon,
buttonText,
source = 'upgrade',
disabled = false,
}: UpgradeToProProps) => {
const project = useSelectedProject()
@@ -80,8 +82,8 @@ const UpgradeToPro = ({
<Link
href={
plan === 'free'
? `/org/${organization?.slug ?? '_'}/billing?panel=subscriptionPlan`
: `/project/${project?.ref ?? '_'}/settings/addons?panel=${addon}`
? `/org/${organization?.slug ?? '_'}/billing?panel=subscriptionPlan&source=${source}`
: `/project/${project?.ref ?? '_'}/settings/addons?panel=${addon}&source=${source}`
}
>
{buttonText || (plan === 'free' ? 'Upgrade to Pro' : 'Enable add on')}

View File

@@ -89,6 +89,7 @@ const PITR = () => {
{!isEnabled ? (
<UpgradeToPro
addon="pitr"
source="pitr"
primaryText="Point in Time Recovery is a Pro Plan add-on."
secondaryText={
plan === 'free'

View File

@@ -195,6 +195,7 @@ const RestoreToNewProject = () => {
return (
<UpgradeToPro
buttonText="Upgrade"
source="backupsRestoreToNewProject"
primaryText="Restore to a new project requires a pro plan or above."
secondaryText="To restore to a new project, you need to upgrade to a Pro plan and have physical backups enabled."
/>

View File

@@ -1069,7 +1069,13 @@ export interface StudioPricingPlanCtaClickedEvent {
*/
export interface StudioPricingSidePanelOpenedEvent {
action: TelemetryActions.STUDIO_PRICING_SIDE_PANEL_OPENED
properties: { currentPlan?: string }
properties: {
currentPlan?: string
/**
* Tracks how user landed on the Pricing side panel, e.g. diskManagementPanelDiskSize, backupsRestoreToNewProject
*/
origin?: string
}
groups: { organization: string }
}