chore: use data/fetchers and API spec (#20196)

* chore: use data/fetchers and API spec

* Remove unused imports

---------

Co-authored-by: Thomas Eckl <31189692+ecktoteckto@users.noreply.github.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
authored and GitHub committed 2024-01-08 14:39:32 +08:00
1 parent bcc99b0cb5
commit 1fb755bfc7
32 files changed
+295 -236

No files matched your search

@@ -1,6 +1,5 @@
import { IS_PLATFORM } from 'lib/constants'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { ProjectSelectedAddon } from 'data/subscriptions/project-addons-query'
import { OrgSubscription, ProjectSelectedAddon } from 'data/subscriptions/types'
export const getAddons = (selectedAddons: ProjectSelectedAddon[]) => {
const computeInstance = selectedAddons.find((addon) => addon.type === 'compute_instance')
@@ -1,7 +1,7 @@
import dayjs from 'dayjs'
import { ALL_TIMEZONES } from './PITR.constants'
import { Time, Timezone } from './PITR.types'
import { ProjectSelectedAddon } from 'data/subscriptions/project-addons-query'
import { Time } from './PITR.types'
import { ProjectSelectedAddon } from 'data/subscriptions/types'
export const getPITRRetentionDuration = (addons: ProjectSelectedAddon[]) => {
const pitrAddon = addons.find((addon) => addon.type === 'pitr')
@@ -1,7 +1,7 @@
import * as Tooltip from '@radix-ui/react-tooltip'
import Link from 'next/link'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import { OrgUsageResponse } from 'data/usage/org-usage-query'
import { Button, IconChevronRight, IconPieChart } from 'ui'
import { Metric, USAGE_APPROACHING_THRESHOLD } from './BillingBreakdown.constants'
@@ -1,4 +1,4 @@
import { OrgSubscription, ProjectAddon } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription, ProjectAddon } from 'data/subscriptions/types'
import { PricingInformation } from 'shared-data'
import { Alert, IconAlertOctagon, IconMinusCircle, IconPauseCircle, Modal } from 'ui'
@@ -4,7 +4,7 @@ import { useReducer, useRef, useState } from 'react'
import { useParams } from 'common'
import { useSendDowngradeFeedbackMutation } from 'data/feedback/exit-survey-send'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
import { useFlag, useStore } from 'hooks'
import { Alert, Button, Input, Modal } from 'ui'
@@ -10,7 +10,7 @@ import InformationBox from 'components/ui/InformationBox'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-limit-check-query'
import { useOrganizationBillingSubscriptionPreview } from 'data/organizations/organization-billing-subscription-preview'
import { useOrgPlansQuery } from 'data/subscriptions/org-plans-query'
import { OrgPlan } from 'data/subscriptions/types'
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
import { SubscriptionTier } from 'data/subscriptions/types'
@@ -34,6 +34,7 @@ import EnterpriseCard from './EnterpriseCard'
import ExitSurveyModal from './ExitSurveyModal'
import MembersExceedLimitModal from './MembersExceedLimitModal'
import PaymentMethodSelection from './PaymentMethodSelection'
import { useOrgPlansQuery } from 'data/subscriptions/org-plans-query'
const PlanUpdateSidePanel = () => {
const { ui } = useStore()
@@ -96,7 +97,7 @@ const PlanUpdateSidePanel = () => {
isSuccess: subscriptionPreviewInitialized,
} = useOrganizationBillingSubscriptionPreview({ tier: selectedTier, organizationSlug: slug })
const availablePlans = plans ?? []
const availablePlans: OrgPlan[] = plans?.plans ?? []
const hasMembersExceedingFreeTierLimit = (membersExceededLimit || []).length > 0
const subscriptionPlanMeta = subscriptionsPlans.find((tier) => tier.id === selectedTier)
@@ -104,12 +104,12 @@ const InvoicesSettings = () => {
<p>{x.number}</p>
</Table.td>
<Table.td>
<InvoiceStatusBadge status={x.status as any} />
<InvoiceStatusBadge status={x.status as InvoiceStatus} />
</Table.td>
<Table.td className="align-right">
<div className="flex items-center justify-end space-x-2">
{[InvoiceStatus.UNCOLLECTIBLE, InvoiceStatus.OPEN].includes(
x.status as any
x.status as InvoiceStatus
) && (
<Button asChild>
<Link
@@ -1,6 +1,6 @@
import { DataPoint } from 'data/analytics/constants'
import { PricingMetric, useOrgDailyStatsQuery } from 'data/analytics/org-daily-stats-query'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import UsageSection from './UsageSection/UsageSection'
export interface ActivityProps {
@@ -1,6 +1,6 @@
import { DataPoint } from 'data/analytics/constants'
import { PricingMetric, useOrgDailyStatsQuery } from 'data/analytics/org-daily-stats-query'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import UsageSection from './UsageSection/UsageSection'
export interface BandwidthProps {
@@ -1,6 +1,6 @@
import { DataPoint } from 'data/analytics/constants'
import { ComputeUsageMetric, computeUsageMetricLabel } from 'data/analytics/org-daily-stats-query'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import SectionContent from './SectionContent'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import AlertError from 'components/ui/AlertError'
@@ -1,6 +1,6 @@
import { DataPoint } from 'data/analytics/constants'
import { PricingMetric, useOrgDailyStatsQuery } from 'data/analytics/org-daily-stats-query'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import UsageSection from './UsageSection/UsageSection'
export interface SizeAndCountsProps {
@@ -1,4 +1,4 @@
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import SectionContent from './SectionContent'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import AlertError from 'components/ui/AlertError'
@@ -1,6 +1,6 @@
import { USAGE_APPROACHING_THRESHOLD } from 'components/interfaces/Billing/Billing.constants'
import { EgressType, PricingMetric } from 'data/analytics/org-daily-stats-query'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import { OrgUsageResponse } from 'data/usage/org-usage-query'
import { Alert } from 'ui'
@@ -1,5 +1,5 @@
import { DataPoint } from 'data/analytics/constants'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
// [Joshen] This is just for development to generate some test data for chart rendering
export const generateUsageData = (attribute: string, days: number): DataPoint[] => {
@@ -6,7 +6,7 @@ import AlertError from 'components/ui/AlertError'
import Panel from 'components/ui/Panel'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import SparkBar from 'components/ui/SparkBar'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import { OrgMetricsUsage, OrgUsageResponse } from 'data/usage/org-usage-query'
import { USAGE_APPROACHING_THRESHOLD } from 'lib/constants'
import { useMemo } from 'react'
@@ -1,6 +1,6 @@
import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold'
import { DataPoint } from 'data/analytics/constants'
import { OrgSubscription } from 'data/subscriptions/org-subscription-query'
import { OrgSubscription } from 'data/subscriptions/types'
import { useOrgUsageQuery } from 'data/usage/org-usage-query'
import SectionHeader from '../SectionHeader'
import { CategoryMetaKey, USAGE_CATEGORIES } from '../Usage.constants'
@@ -40,6 +40,7 @@ import Image from 'next/image'
import ComputeInstanceSidePanel from './ComputeInstanceSidePanel'
import PITRSidePanel from './PITRSidePanel'
import CustomDomainSidePanel from './CustomDomainSidePanel'
import { ProjectAddonVariantMeta } from 'data/subscriptions/types'
const Addons = () => {
const { resolvedTheme } = useTheme()
@@ -83,6 +84,8 @@ const Addons = () => {
const selectedAddons = addons?.selected_addons ?? []
const { computeInstance, pitr, customDomain } = getAddons(selectedAddons)
const meta = computeInstance?.variant?.meta as ProjectAddonVariantMeta | undefined
return (
<>
<ScaffoldContainer>
@@ -217,9 +220,8 @@ const Addons = () => {
>
<p>
Your workload is currently running at the baseline disk IO bandwidth at{' '}
{computeInstance?.variant?.meta?.baseline_disk_io_mbs?.toLocaleString() ??
87}{' '}
Mbps and may suffer degradation in performance.
{meta?.baseline_disk_io_mbs?.toLocaleString() ?? 87} Mbps and may suffer
degradation in performance.
</p>
<p className="mt-1">
Consider upgrading to a larger compute instance for a higher baseline
@@ -236,9 +238,8 @@ const Addons = () => {
<p>
If the disk IO budget drops to zero, your workload will run at the
baseline disk IO bandwidth at{' '}
{computeInstance?.variant?.meta?.baseline_disk_io_mbs?.toLocaleString() ??
87}{' '}
Mbps and may suffer degradation in performance.
{meta?.baseline_disk_io_mbs?.toLocaleString() ?? 87} Mbps and may suffer
degradation in performance.
</p>
<p className="mt-1">
Consider upgrading to a larger compute instance for a higher baseline
@@ -260,7 +261,7 @@ const Addons = () => {
/>
</div>
</Link>
<p className="text-sm">{computeInstance?.variant?.meta?.memory_gb ?? 1} GB</p>
<p className="text-sm">{meta?.memory_gb ?? 1} GB</p>
</div>
<div className="w-full flex items-center justify-between border-b py-2">
<Link href={`/project/${projectRef}/settings/infrastructure#cpu`}>
@@ -276,21 +277,17 @@ const Addons = () => {
</div>
</Link>
<p className="text-sm">
{computeInstance?.variant?.meta?.cpu_cores ?? 2}-core {cpuArchitecture}{' '}
{computeInstance?.variant?.meta?.cpu_dedicated ? '(Dedicated)' : '(Shared)'}
{meta?.cpu_cores ?? 2}-core {cpuArchitecture}{' '}
{meta?.cpu_dedicated ? '(Dedicated)' : '(Shared)'}
</p>
</div>
<div className="w-full flex items-center justify-between border-b py-2">
<p className="text-sm text-foreground-light">No. of direct connections</p>
<p className="text-sm">
{computeInstance?.variant?.meta?.connections_direct ?? 60}
</p>
<p className="text-sm">{meta?.connections_direct ?? 60}</p>
</div>
<div className="w-full flex items-center justify-between border-b py-2">
<p className="text-sm text-foreground-light">No. of pooler connections</p>
<p className="text-sm">
{computeInstance?.variant?.meta?.connections_pooler ?? 200}
</p>
<p className="text-sm">{meta?.connections_pooler ?? 200}</p>
</div>
<div className="w-full flex items-center justify-between border-b py-2">
<Link href={`/project/${projectRef}/settings/infrastructure#disk_io`}>
@@ -306,9 +303,7 @@ const Addons = () => {
</div>
</Link>
<p className="text-sm">
{computeInstance?.variant?.meta?.max_disk_io_mbs?.toLocaleString() ??
'2,085'}{' '}
Mbps
{meta?.max_disk_io_mbs?.toLocaleString() ?? '2,085'} Mbps
</p>
</div>
<div className="w-full flex items-center justify-between py-2">
@@ -325,9 +320,7 @@ const Addons = () => {
</div>
</Link>
<p className="text-sm">
{computeInstance?.variant?.meta?.baseline_disk_io_mbs?.toLocaleString() ??
87}{' '}
Mbps
{meta?.baseline_disk_io_mbs?.toLocaleString() ?? 87} Mbps
</p>
</div>
</div>
@@ -32,6 +32,7 @@ import {
import * as Tooltip from '@radix-ui/react-tooltip'
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
import { AddonVariantId } from 'data/subscriptions/types'
const COMPUTE_CATEGORY_OPTIONS: {
id: 'micro' | 'optimized'
@@ -170,7 +171,11 @@ const ComputeInstanceSidePanel = () => {
if (selectedOption === 'ci_micro' && subscriptionCompute !== undefined) {
removeAddon({ projectRef, variant: subscriptionCompute.variant.identifier })
} else {
updateAddon({ projectRef, type: 'compute_instance', variant: selectedOption })
updateAddon({
projectRef,
type: 'compute_instance',
variant: selectedOption as AddonVariantId,
})
}
}
@@ -22,6 +22,7 @@ import {
SidePanel,
} from 'ui'
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
import { AddonVariantId } from 'data/subscriptions/types'
const CustomDomainSidePanel = () => {
const { ui } = useStore()
@@ -121,7 +122,7 @@ const CustomDomainSidePanel = () => {
if (selectedOption === 'cd_none' && subscriptionCDOption !== undefined) {
removeAddon({ projectRef, variant: subscriptionCDOption.variant.identifier })
} else {
updateAddon({ projectRef, type: 'custom_domain', variant: selectedOption })
updateAddon({ projectRef, type: 'custom_domain', variant: selectedOption as AddonVariantId })
}
}
@@ -26,6 +26,7 @@ import {
} from 'ui'
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
import { AlertTriangleIcon } from 'lucide-react'
import { AddonVariantId } from 'data/subscriptions/types'
const PITR_CATEGORY_OPTIONS: {
id: 'off' | 'on'
@@ -149,7 +150,7 @@ const PITRSidePanel = () => {
if (selectedOption === 'pitr_0' && subscriptionPitr !== undefined) {
removeAddon({ projectRef, variant: subscriptionPitr.variant.identifier })
} else {
updateAddon({ projectRef, type: 'pitr', variant: selectedOption })
updateAddon({ projectRef, type: 'pitr', variant: selectedOption as AddonVariantId })
}
}
@@ -6,7 +6,7 @@ import logConstants from 'shared-data/logConstants'
import BackwardIterator from 'components/ui/CodeEditor/Providers/BackwardIterator'
import uniqBy from 'lodash/uniqBy'
import { useEffect } from 'react'
import { PlanId } from 'data/subscriptions/org-subscription-query'
import { PlanId } from 'data/subscriptions/types'
/**
* Convert a micro timestamp from number/string to iso timestamp
+148 -22
View File
@@ -236,7 +236,7 @@ export interface paths {
}
'/platform/organizations/{slug}/payments/setup-intent': {
/** Sets up a payment method */
post: operations['SetupIntentController_setUpPaymentMethod']
post: operations['SetupIntentOrgController_setUpPaymentMethod']
}
'/platform/organizations/{slug}/billing/subscription': {
/** Gets the current subscription */
@@ -467,6 +467,10 @@ export interface paths {
/** Updates project's content */
patch: operations['ContentController_updateContent']
}
'/platform/projects/{ref}/daily-stats': {
/** Gets daily project stats */
get: operations['DailyStatsController_getDailyStats']
}
'/platform/projects/{ref}/databases': {
/** Gets non-removed databases of a specified project */
get: operations['DatabasesController_getDatabases']
@@ -1659,6 +1663,10 @@ export interface paths {
/** List members of an organization */
get: operations['V1OrganizationMembersController_v1ListOrganizationMembers']
}
'/v1/organizations/{slug}': {
/** Gets information about the organization */
get: operations['V1OrganizationSlugController_getOrganization']
}
'/v1/oauth/authorize': {
/** Authorize user through oauth */
get: operations['OAuthController_authorize']
@@ -2713,6 +2721,9 @@ export interface components {
stripeAccount?: string
}
}
HCaptchaBody: {
hcaptchaToken: string
}
SetupIntentResponse: {
id: string
object: string
@@ -2746,8 +2757,10 @@ export interface components {
stripeAccount?: string
}
}
/** @enum {string} */
BillingPlanId: 'free' | 'pro' | 'team' | 'enterprise'
BillingSubscriptionPlan: {
id: Record<string, never>
id: components['schemas']['BillingPlanId']
name: string
price: number
}
@@ -2756,18 +2769,38 @@ export interface components {
supabase_prod_id: string
price: number
}
/** @enum {string} */
ProjectAddonType: 'custom_domain' | 'compute_instance' | 'pitr'
/** @enum {string} */
AddonVariantId:
| 'ci_small'
| 'ci_medium'
| 'ci_large'
| 'ci_xlarge'
| 'ci_2xlarge'
| 'ci_4xlarge'
| 'ci_8xlarge'
| 'ci_12xlarge'
| 'ci_16xlarge'
| 'cd_default'
| 'pitr_7'
| 'pitr_14'
| 'pitr_28'
/** @enum {string} */
ProjectAddonVariantPricingType: 'fixed' | 'usage'
/** @enum {string} */
ProjectAddonPricingInterval: 'monthly' | 'hourly'
ProjectAddonVariantResponse: {
identifier: string
identifier: components['schemas']['AddonVariantId']
price_type: components['schemas']['ProjectAddonVariantPricingType']
price_interval: components['schemas']['ProjectAddonPricingInterval']
name: string
price_description: string
price_type: Record<string, never>
price_interval: Record<string, never>
price: number
meta?: Record<string, never>
}
SelectedAddonResponse: {
/** @enum {string} */
type: 'custom_domain' | 'compute_instance' | 'pitr'
type: components['schemas']['ProjectAddonType']
variant: components['schemas']['ProjectAddonVariantResponse']
}
BillingProjectAddonResponse: {
@@ -2827,9 +2860,9 @@ export interface components {
expiry_year: number
}
ScheduledPlanChange: {
target_plan: components['schemas']['BillingPlanId']
/** Format: date-time */
at: string
target_plan: Record<string, never>
usage_billing_enabled: boolean
}
GetSubscriptionResponse: {
@@ -2856,6 +2889,21 @@ export interface components {
/** @enum {string} */
tier: 'tier_payg' | 'tier_pro' | 'tier_free' | 'tier_team' | 'tier_enterprise'
}
/** @enum {string} */
BillingPlanChangeType: 'upgrade' | 'downgrade' | 'none'
/** @enum {string} */
BillingPlanEffectiveAt: 'now' | 'end_of_billing_period' | 'none'
PlanResponse: {
id: components['schemas']['BillingPlanId']
change_type: components['schemas']['BillingPlanChangeType']
effective_at: components['schemas']['BillingPlanEffectiveAt']
name: string
price: number
is_current: boolean
}
PlansResponse: {
plans: components['schemas']['PlanResponse'][]
}
UpcomingInvoice: Record<string, never>
ColumnPrivilege: {
grantor: string
@@ -3749,6 +3797,8 @@ export interface components {
amount: number
}
PreviewProjectTransferResponse: {
source_subscription_plan: components['schemas']['BillingPlanId']
target_subscription_plan: components['schemas']['BillingPlanId']
valid: boolean
warnings: components['schemas']['PreviewTransferInfo'][]
errors: components['schemas']['PreviewTransferInfo'][]
@@ -3761,8 +3811,6 @@ export interface components {
credits_on_source_organization: number
costs_on_target_organization: number
charge_on_target_organization: number
source_subscription_plan: Record<string, never>
target_subscription_plan: Record<string, unknown> | null
source_invoice_items: components['schemas']['PreviewTransferInvoiceItem'][]
target_invoice_items: components['schemas']['PreviewTransferInvoiceItem'][]
}
@@ -3881,8 +3929,7 @@ export interface components {
fileSizeLimit: number
}
AvailableAddonResponse: {
/** @enum {string} */
type: 'custom_domain' | 'compute_instance' | 'pitr'
type: components['schemas']['ProjectAddonType']
name: string
variants: components['schemas']['ProjectAddonVariantResponse'][]
}
@@ -3892,9 +3939,8 @@ export interface components {
available_addons: components['schemas']['AvailableAddonResponse'][]
}
UpdateAddonBody: {
addon_variant: Record<string, never>
/** @enum {string} */
addon_type: 'custom_domain' | 'compute_instance' | 'pitr'
addon_variant: components['schemas']['AddonVariantId']
addon_type: components['schemas']['ProjectAddonType']
}
ServiceApiKey: {
api_key_encrypted?: string
@@ -4384,9 +4430,8 @@ export interface components {
expiry_time: string
}
UpdateAddonAdminBody: {
addon_variant: Record<string, never>
/** @enum {string} */
addon_type: 'custom_domain' | 'compute_instance' | 'pitr'
addon_variant: components['schemas']['AddonVariantId']
addon_type: components['schemas']['ProjectAddonType']
price_id?: string
}
DatabaseResponse: {
@@ -4775,6 +4820,12 @@ export interface components {
role_name: string
mfa_enabled: boolean
}
V1OrganizationSlugResponse: {
plan?: components['schemas']['BillingPlanId']
opt_in_tags: ('AI_SQL_GENERATOR_OPT_IN' | 'PREVIEW_BRANCHES_OPT_IN')[]
id: string
name: string
}
OAuthTokenBody: {
/** @enum {string} */
grant_type: 'authorization_code' | 'refresh_token'
@@ -4896,8 +4947,7 @@ export interface components {
supabase_org_id: string
}
FlyOrganization: {
/** @enum {string} */
plan: 'free' | 'pro' | 'team' | 'enterprise'
plan: components['schemas']['BillingPlanId']
id: string
supabase_org_id: string
name: string
@@ -6381,13 +6431,27 @@ export interface operations {
}
}
/** Sets up a payment method */
SetupIntentController_setUpPaymentMethod: {
SetupIntentOrgController_setUpPaymentMethod: {
parameters: {
path: {
/** @description Organization slug */
slug: string
}
}
requestBody: {
content: {
'application/json': components['schemas']['HCaptchaBody']
}
}
responses: {
201: {
content: {
'application/json': components['schemas']['SetupIntentResponse']
}
}
403: {
content: never
}
/** @description Failed to set up a payment method */
500: {
content: never
@@ -6501,7 +6565,7 @@ export interface operations {
responses: {
200: {
content: {
'application/json': Record<string, never>
'application/json': components['schemas']['PlansResponse']
}
}
403: {
@@ -8461,6 +8525,32 @@ export interface operations {
}
}
}
/** Gets daily project stats */
DailyStatsController_getDailyStats: {
parameters: {
query: {
attribute: string
interval: string
endDate: string
startDate: string
}
path: {
/** @description Project ref */
ref: string
}
}
responses: {
200: {
content: {
'application/json': Record<string, never>
}
}
/** @description Failed to get daily project stats */
500: {
content: never
}
}
}
/** Gets non-removed databases of a specified project */
DatabasesController_getDatabases: {
parameters: {
@@ -9328,6 +9418,7 @@ export interface operations {
path: {
/** @description Project ref */
ref: string
addon_variant: components['schemas']['AddonVariantId']
}
}
responses: {
@@ -9843,6 +9934,25 @@ export interface operations {
}
}
}
/** Sets up a payment method */
SetupIntentController_setUpPaymentMethod: {
requestBody: {
content: {
'application/json': components['schemas']['HCaptchaBody']
}
}
responses: {
201: {
content: {
'application/json': components['schemas']['SetupIntentResponse']
}
}
/** @description Failed to set up a payment method */
500: {
content: never
}
}
}
/** Sends analytics server event */
TelemetryEventController_sendServerEvent: {
requestBody: {
@@ -10871,6 +10981,7 @@ export interface operations {
path: {
/** @description Project ref */
ref: string
addon_variant: components['schemas']['AddonVariantId']
}
}
responses: {
@@ -12398,6 +12509,21 @@ export interface operations {
}
}
}
/** Gets information about the organization */
V1OrganizationSlugController_getOrganization: {
parameters: {
path: {
slug: string
}
}
responses: {
200: {
content: {
'application/json': components['schemas']['V1OrganizationSlugResponse']
}
}
}
}
/** Authorize user through oauth */
OAuthController_authorize: {
parameters: {
@@ -1,22 +1,19 @@
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
import { get } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { get } from 'data/fetchers'
import { invoicesKeys } from './keys'
import { components } from 'data/api'
export type OverdueInvoicesResponse = {
id: string
organization_id: number
}
export type OverdueInvoicesResponse = components['schemas']['OverdueInvoiceCount']
export async function getOverdueInvoices(signal?: AbortSignal) {
const response = await get(`${API_URL}/stripe/invoices/overdue`, {
const { data, error } = await get('/platform/stripe/invoices/overdue', {
signal,
})
if (response.error) {
throw response.error
if (error) {
throw error
}
return response as OverdueInvoicesResponse[]
return data
}
export type OverdueInvoicesData = Awaited<ReturnType<typeof getOverdueInvoices>>
@@ -10,7 +10,6 @@ export type SetupIntentVariables = {
export async function setupIntent({ hcaptchaToken }: SetupIntentVariables) {
const { data, error } = await post('/platform/stripe/setup-intent', {
// @ts-ignore [Joshen] API seems to be having the wrong spec
body: { hcaptchaToken },
})
if (error) throw error
-2
View File
@@ -1,5 +1,3 @@
// [Joshen TODO] To remove subscription V2 after v2 is launched and stable to deprecate old billing ui + endpoints
export const subscriptionKeys = {
orgSubscription: (orgSlug: string | undefined) =>
['organizations', orgSlug, 'subscription'] as const,
@@ -1,28 +1,21 @@
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
import { get } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { get } from 'data/fetchers'
import { subscriptionKeys } from './keys'
export type OrgPlansVariables = {
orgSlug?: string
}
export type OrgPlansResponse = {
id: 'free' | 'pro' | 'team' | 'enterprise'
name: string
price: number
is_current: boolean
change_type: 'downgrade' | 'upgrade' | 'none'
effective_at: string
}[]
export async function getOrgPlans({ orgSlug }: OrgPlansVariables, signal?: AbortSignal) {
if (!orgSlug) throw new Error('orgSlug is required')
const response = await get(`${API_URL}/organizations/${orgSlug}/billing/plans`, { signal })
if (response.error) throw response.error
const { error, data } = await get('/platform/organizations/{slug}/billing/plans', {
params: { path: { slug: orgSlug } },
signal,
})
if (error) throw error
return response.plans as OrgPlansResponse
return data
}
export type OrgPlansData = Awaited<ReturnType<typeof getOrgPlans>>
@@ -1,6 +1,5 @@
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
import { get } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { get } from 'data/fetchers'
import { subscriptionKeys } from './keys'
import { ResponseError } from 'types'
@@ -8,77 +7,19 @@ export type OrgSubscriptionVariables = {
orgSlug?: string
}
export type PlanId = 'free' | 'pro' | 'team' | 'enterprise'
export type ProjectAddon = {
addons: {
type: 'custom_domain' | 'compute_instance' | 'pitr'
variant: {
identifier: string
name: string
price: number
price_description: string
price_interval: string
price_type: string
}
}[]
name: string
ref: string
}
export type OrgSubscription = {
billing_cycle_anchor: number
current_period_start: number
current_period_end: number
next_invoice_at: number
usage_billing_enabled: boolean
plan: {
id: PlanId
name: string
price: number
}
addons: {
name: string
supabase_prod_id: string
price: number
}[]
usage_fees: {
metric: string
pricingStrategy: 'UNIT' | 'PACKAGE'
pricingOptions: {
perUnitPrice?: number
packagePrice?: number
packageSize?: number
freeUnits: number
}
}[]
payment_method_id?: string
payment_method_type: 'invoice' | 'card' | 'none'
payment_method_card_details?: {
last_4_digits: string
brand: string
expiry_month: number
expiry_year: number
}
project_addons: ProjectAddon[]
billing_via_partner?: boolean
scheduled_plan_change: {
at: string
target_plan: PlanId
usage_billing_enabled: boolean
} | null
}
export async function getOrgSubscription(
{ orgSlug }: OrgSubscriptionVariables,
signal?: AbortSignal
) {
if (!orgSlug) throw new Error('orgSlug is required')
const response = await get(`${API_URL}/organizations/${orgSlug}/billing/subscription`, { signal })
if (response.error) throw response.error
const { error, data } = await get('/platform/organizations/{slug}/billing/subscription', {
params: { path: { slug: orgSlug } },
signal,
})
if (error) throw error
return response as OrgSubscription
return data
}
export type OrgSubscriptionData = Awaited<ReturnType<typeof getOrgSubscription>>
@@ -1,6 +1,5 @@
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { isResponseOk, put } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { put } from 'data/fetchers'
import { toast } from 'react-hot-toast'
import { ResponseError } from 'types/base'
import { subscriptionKeys } from './keys'
@@ -22,15 +21,22 @@ export async function updateOrgSubscription({
if (!slug) throw new Error('slug is required')
if (!tier) throw new Error('tier is required')
const payload: { tier: string; payment_method?: string } = { tier }
const payload: { tier: SubscriptionTier; payment_method?: string } = { tier }
if (paymentMethod !== undefined) payload.payment_method = paymentMethod
const response = await put<void>(`${API_URL}/organizations/${slug}/billing/subscription`, payload)
if (!isResponseOk(response)) {
throw response.error
const { error, data } = await put(`/platform/organizations/{slug}/billing/subscription`, {
body: {
payment_method: payload.payment_method,
tier: payload.tier,
},
params: { path: { slug } },
})
if (error) {
throw error
}
return response
return data
}
type OrgSubscriptionUpdateData = Awaited<ReturnType<typeof updateOrgSubscription>>
@@ -1,18 +1,14 @@
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { toast } from 'react-hot-toast'
import { delete_ } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { del } from 'data/fetchers'
import { ResponseError } from 'types'
import { subscriptionKeys } from './keys'
import { AddonVariantId } from './types'
export type ProjectAddonRemoveVariables = {
projectRef: string
variant: string
}
export type ProjectAddonRemoveResponse = {
error?: any
variant: AddonVariantId
}
export async function removeSubscriptionAddon({
@@ -22,12 +18,18 @@ export async function removeSubscriptionAddon({
if (!projectRef) throw new Error('projectRef is required')
if (!variant) throw new Error('variant is required')
const response = (await delete_(
`${API_URL}/projects/${projectRef}/billing/addons/${variant}`
)) as ProjectAddonRemoveResponse
if (response.error) throw response.error
const { data, error } = await del(`/platform/projects/{ref}/billing/addons/{addon_variant}`, {
params: {
path: {
ref: projectRef,
addon_variant: variant,
},
},
})
return response
if (error) throw error
return data
}
type ProjectAddonRemoveData = Awaited<ReturnType<typeof removeSubscriptionAddon>>
@@ -1,19 +1,15 @@
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { toast } from 'react-hot-toast'
import { post } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { post } from 'data/fetchers'
import { ResponseError } from 'types'
import { subscriptionKeys } from './keys'
import { AddonVariantId, ProjectAddonType } from './types'
export type ProjectAddonUpdateVariables = {
projectRef: string
variant: string
type: 'custom_domain' | 'compute_instance' | 'pitr'
}
export type ProjectAddonUpdateResponse = {
error?: any
variant: AddonVariantId
type: ProjectAddonType
}
export async function updateSubscriptionAddon({
@@ -25,13 +21,21 @@ export async function updateSubscriptionAddon({
if (!variant) throw new Error('variant is required')
if (!type) throw new Error('type is required')
const response = (await post(`${API_URL}/projects/${projectRef}/billing/addons`, {
addon_type: type,
addon_variant: variant,
})) as ProjectAddonUpdateResponse
if (response.error) throw response.error
const { data, error } = await post(`/platform/projects/{ref}/billing/addons`, {
params: {
path: {
ref: projectRef,
},
},
body: {
addon_type: type,
addon_variant: variant,
},
})
return response
if (error) throw error
return data
}
type ProjectAddonUpdateData = Awaited<ReturnType<typeof updateSubscriptionAddon>>
@@ -1,6 +1,5 @@
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
import { get } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { get } from 'data/fetchers'
import { subscriptionKeys } from './keys'
import { ResponseError } from 'types'
@@ -8,54 +7,20 @@ export type ProjectAddonsVariables = {
projectRef?: string
}
export type ProjectAddonType = 'compute_instance' | 'pitr' | 'custom_domain'
export type ProjectAddonVariant = {
identifier: string
name: string
price: number
price_description: string
price_interval: 'monthly' | 'hourly'
price_type: 'fixed' | 'usage'
meta?: ProjectAddonVariantMeta
}
export interface ProjectAddonVariantMeta {
cpu_cores?: number
cpu_dedicated?: boolean
baseline_disk_io_mbs?: number
max_disk_io_mbs?: number
memory_gb?: number
connections_direct?: number
connections_pooler?: number
backup_duration_days?: number
}
export type ProjectSelectedAddon = {
type: ProjectAddonType
variant: ProjectAddonVariant
}
export type ProjectAddonsResponse = {
ref: string
selected_addons: ProjectSelectedAddon[]
available_addons: {
name: string
type: ProjectAddonType
variants: ProjectAddonVariant[]
}[]
}
export async function getProjectAddons(
{ projectRef }: ProjectAddonsVariables,
signal?: AbortSignal
) {
if (!projectRef) throw new Error('projectRef is required')
const response = await get(`${API_URL}/projects/${projectRef}/billing/addons`, { signal })
if (response.error) throw response.error
const { error, data } = await get(`/platform/projects/{ref}/billing/addons`, {
params: { path: { ref: projectRef } },
signal,
})
return response as ProjectAddonsResponse
if (error) throw error
return data
}
export type ProjectAddonsData = Awaited<ReturnType<typeof getProjectAddons>>
+28
View File
@@ -1,6 +1,34 @@
import { components } from 'data/api'
export type SubscriptionTier =
| 'tier_free'
| 'tier_pro'
| 'tier_payg'
| 'tier_team'
| 'tier_enterprise'
export type AddonVariantId = components['schemas']['AddonVariantId']
export type OrgSubscription = components['schemas']['GetSubscriptionResponse']
export type ProjectAddon = components['schemas']['BillingProjectAddonResponse']
export type PlanId = components['schemas']['BillingPlanId']
export type OrgPlan = components['schemas']['PlanResponse']
export type ProjectAddonType = components['schemas']['ProjectAddonType']
export interface ProjectAddonVariantMeta {
cpu_cores?: number
cpu_dedicated?: boolean
baseline_disk_io_mbs?: number
max_disk_io_mbs?: number
memory_gb?: number
connections_direct?: number
connections_pooler?: number
backup_duration_days?: number
}
export type ProjectSelectedAddon = components['schemas']['SelectedAddonResponse']
export type ProjectAvailableAddon = components['schemas']['AvailableAddonResponse']