mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
perf: use subscription plan from org response (#34993)
This commit is contained in:
1 parent
82ee7403d8
commit
d05bbb669f
55 files changed
+193
-785
No files matched your search
@@ -11,7 +11,6 @@ import NoPermission from 'components/ui/NoPermission'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
@@ -57,16 +56,10 @@ export const AdvancedAuthSettingsForm = () => {
|
||||
isError,
|
||||
} = useAuthConfigQuery({ projectRef })
|
||||
|
||||
const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: organization?.slug,
|
||||
})
|
||||
|
||||
const { mutate: updateAuthConfig } = useAuthConfigUpdateMutation()
|
||||
|
||||
const isTeamsEnterprisePlan =
|
||||
isSuccessSubscription && subscription?.plan.id !== 'free' && subscription?.plan.id !== 'pro'
|
||||
const promptTeamsEnterpriseUpgrade =
|
||||
IS_PLATFORM && isSuccessSubscription && !isTeamsEnterprisePlan
|
||||
const isTeamsEnterprisePlan = organization?.plan.id !== 'free' && organization?.plan.id !== 'pro'
|
||||
const promptTeamsEnterpriseUpgrade = IS_PLATFORM && !isTeamsEnterprisePlan
|
||||
|
||||
const requestDurationForm = useForm({
|
||||
resolver: zodResolver(
|
||||
|
||||
@@ -4,7 +4,6 @@ import { ChevronDown } from 'lucide-react'
|
||||
import { useParams } from 'common'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
@@ -32,10 +31,6 @@ export const AddHookDropdown = ({
|
||||
const { ref: projectRef } = useParams()
|
||||
const organization = useSelectedOrganization()
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery(
|
||||
{ orgSlug: organization?.slug },
|
||||
{ enabled: IS_PLATFORM }
|
||||
)
|
||||
const { data: authConfig } = useAuthConfigQuery({ projectRef })
|
||||
const canUpdateAuthHook = useCheckPermissions(PermissionAction.AUTH_EXECUTE, '*')
|
||||
|
||||
@@ -54,7 +49,7 @@ export const AddHookDropdown = ({
|
||||
const enterpriseHookOptions = hooks.filter((h) => !isValidHook(h) && h.enterprise)
|
||||
|
||||
const isTeamsOrEnterprisePlan =
|
||||
subscription?.plan.id === 'team' || subscription?.plan.id === 'enterprise'
|
||||
organization?.plan.id === 'team' || organization?.plan.id === 'enterprise'
|
||||
|
||||
if (!canUpdateAuthHook) {
|
||||
return (
|
||||
|
||||
@@ -11,7 +11,6 @@ import NoPermission from 'components/ui/NoPermission'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
@@ -81,12 +80,7 @@ const phoneSchema = object({
|
||||
|
||||
const MfaAuthSettingsForm = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const {
|
||||
data: authConfig,
|
||||
error: authConfigError,
|
||||
isLoading,
|
||||
isError,
|
||||
} = useAuthConfigQuery({ projectRef })
|
||||
const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
|
||||
const { mutate: updateAuthConfig } = useAuthConfigUpdateMutation()
|
||||
|
||||
// Separate loading states for each form
|
||||
@@ -97,18 +91,9 @@ const MfaAuthSettingsForm = () => {
|
||||
const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue')
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: organization?.slug,
|
||||
})
|
||||
|
||||
const isProPlanAndUp = isSuccessSubscription && subscription?.plan?.id !== 'free'
|
||||
const isProPlanAndUp = organization?.plan?.id !== 'free'
|
||||
const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp
|
||||
|
||||
const projectAddons = subscription?.project_addons.find((addon) => addon.ref === projectRef)
|
||||
const hasPurchasedAuthMFAAddOn = projectAddons?.addons.some(
|
||||
(addon) => addon.type === 'auth_mfa_phone'
|
||||
)
|
||||
|
||||
// For now, we support Twilio and Vonage. Twilio Verify is not supported and the remaining providers are community maintained.
|
||||
const sendSMSHookIsEnabled =
|
||||
authConfig?.HOOK_SEND_SMS_URI !== null && authConfig?.HOOK_SEND_SMS_ENABLED === true
|
||||
|
||||
+1
-6
@@ -11,7 +11,6 @@ import NoPermission from 'components/ui/NoPermission'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
@@ -73,11 +72,7 @@ const SessionsAuthSettingsForm = () => {
|
||||
const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue')
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: organization?.slug,
|
||||
})
|
||||
|
||||
const isProPlanAndUp = isSuccessSubscription && subscription?.plan?.id !== 'free'
|
||||
const isProPlanAndUp = organization?.plan?.id !== 'free'
|
||||
const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp
|
||||
|
||||
const refreshTokenForm = useForm<z.infer<typeof RefreshTokenSchema>>({
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import type { Organization } from 'types'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
import Link from 'next/link'
|
||||
@@ -13,20 +12,18 @@ export const NoProjectsOnPaidOrgInfo = ({ organization }: NoProjectsOnPaidOrgInf
|
||||
const projectCount =
|
||||
allProjects?.filter((project) => project.organization_id === organization?.id).length ?? 0
|
||||
|
||||
const { data: orgSubscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
|
||||
if (
|
||||
projectCount > 0 ||
|
||||
orgSubscription?.plan === undefined ||
|
||||
orgSubscription.plan.id === 'free' ||
|
||||
orgSubscription.plan.id === 'enterprise'
|
||||
organization?.plan === undefined ||
|
||||
organization.plan.id === 'free' ||
|
||||
organization.plan.id === 'enterprise'
|
||||
)
|
||||
return null
|
||||
|
||||
return (
|
||||
<Admonition
|
||||
type="default"
|
||||
title={`Your organization is on the ${orgSubscription.plan.name} plan with no projects running`}
|
||||
title={`Your organization is on the ${organization.plan.name} plan with no projects running`}
|
||||
description={
|
||||
<div className="!max-w-full prose text-sm">
|
||||
The monthly fees for the paid plan still apply. To cancel your subscription, head over to
|
||||
|
||||
@@ -10,7 +10,6 @@ import { pluckObjectFields } from 'lib/helpers'
|
||||
import { cn } from 'ui'
|
||||
import type { projectKeys } from './Connect.types'
|
||||
import { getConnectionStrings as getConnectionStringsV2 } from './DatabaseSettings.utils'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { getAddons } from '../Billing/Subscription/Subscription.utils'
|
||||
@@ -31,8 +30,7 @@ const ConnectTabContent = forwardRef<HTMLDivElement, ConnectContentTabProps>(
|
||||
({ projectKeys, filePath, ...props }, ref) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const selectedOrg = useSelectedOrganization()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: selectedOrg?.slug })
|
||||
const allowPgBouncerSelection = useMemo(() => subscription?.plan.id !== 'free', [subscription])
|
||||
const allowPgBouncerSelection = useMemo(() => selectedOrg?.plan.id !== 'free', [selectedOrg])
|
||||
|
||||
const { data: settings } = useProjectSettingsV2Query({ projectRef })
|
||||
const { data: pgbouncerConfig } = usePgbouncerConfigQuery({ projectRef })
|
||||
|
||||
@@ -9,7 +9,6 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { usePgbouncerConfigQuery } from 'data/database/pgbouncer-config-query'
|
||||
import { useSupavisorConfigurationQuery } from 'data/database/supavisor-configuration-query'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
@@ -67,10 +66,9 @@ export const DatabaseConnectionString = () => {
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState<DatabaseConnectionType>('uri')
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: org?.slug })
|
||||
const sharedPoolerPreferred = useMemo(() => {
|
||||
return subscription?.plan?.id === 'free'
|
||||
}, [subscription])
|
||||
return org?.plan?.id === 'free'
|
||||
}, [org])
|
||||
|
||||
const {
|
||||
data: pgbouncerConfig,
|
||||
|
||||
+1
-3
@@ -1,7 +1,6 @@
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useCloneBackupsQuery } from 'data/projects/clone-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { Badge, Button } from 'ui'
|
||||
import { TimestampInfo } from 'ui-patterns'
|
||||
@@ -16,8 +15,7 @@ export const BackupsList = ({ onSelectRestore, disabled }: BackupsListProps) =>
|
||||
const { project } = useProjectContext()
|
||||
const organization = useSelectedOrganization()
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isFreePlan = organization?.plan?.id === 'free'
|
||||
|
||||
const { data: cloneBackups } = useCloneBackupsQuery(
|
||||
{ projectRef: project?.ref },
|
||||
|
||||
+1
-3
@@ -9,7 +9,6 @@ import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectConte
|
||||
import PasswordStrengthBar from 'components/ui/PasswordStrengthBar'
|
||||
import { useProjectCloneMutation } from 'data/projects/clone-mutation'
|
||||
import { useCloneBackupsQuery } from 'data/projects/clone-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { passwordStrength } from 'lib/helpers'
|
||||
import { generateStrongPassword } from 'lib/project'
|
||||
@@ -68,8 +67,7 @@ export const CreateNewProjectDialog = ({
|
||||
},
|
||||
})
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isFreePlan = organization?.plan?.id === 'free'
|
||||
|
||||
const { data: cloneBackups } = useCloneBackupsQuery(
|
||||
{ projectRef: project?.ref },
|
||||
|
||||
@@ -22,7 +22,6 @@ import { useUpdateDiskAutoscaleConfigMutation } from 'data/config/disk-autoscale
|
||||
import { useDiskUtilizationQuery } from 'data/config/disk-utilization-query'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { AddonVariantId } from 'data/subscriptions/types'
|
||||
@@ -132,9 +131,7 @@ export function DiskManagementForm() {
|
||||
},
|
||||
{ enabled: project != null && !isFlyArchitecture }
|
||||
)
|
||||
const { data: subscription, isSuccess: isSubscriptionSuccess } = useOrgSubscriptionQuery({
|
||||
orgSlug: org?.slug,
|
||||
})
|
||||
|
||||
const { data: diskAutoscaleConfig, isSuccess: isDiskAutoscaleConfigSuccess } =
|
||||
useDiskAutoscaleCustomConfigQuery(
|
||||
{ projectRef },
|
||||
@@ -178,13 +175,12 @@ export function DiskManagementForm() {
|
||||
isDiskAttributesSuccess &&
|
||||
isDiskUtilizationSuccess &&
|
||||
isReadReplicasSuccess &&
|
||||
isSubscriptionSuccess &&
|
||||
isDiskAutoscaleConfigSuccess &&
|
||||
isCooldownSuccess
|
||||
|
||||
const isRequestingChanges = data?.requested_modification !== undefined
|
||||
const readReplicas = (databases ?? []).filter((db) => db.identifier !== projectRef)
|
||||
const isPlanUpgradeRequired = subscription?.plan.id === 'free'
|
||||
const isPlanUpgradeRequired = org?.plan.id === 'free'
|
||||
|
||||
const { formState } = form
|
||||
const usedSize = Math.round(((diskUtil?.metrics.fs_used_bytes ?? 0) / GB) * 100) / 100
|
||||
@@ -193,7 +189,7 @@ export function DiskManagementForm() {
|
||||
|
||||
const disableIopsThroughputConfig =
|
||||
RESTRICTED_COMPUTE_FOR_THROUGHPUT_ON_GP3.includes(form.watch('computeSize')) &&
|
||||
subscription?.plan.id !== 'free'
|
||||
org?.plan.id !== 'free'
|
||||
|
||||
const isBranch = project?.parent_project_ref !== undefined
|
||||
|
||||
|
||||
+3
-8
@@ -5,7 +5,6 @@ import { UseFormReturn } from 'react-hook-form'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
@@ -161,16 +160,12 @@ export const DiskManagementReviewAndSubmitDialog = ({
|
||||
/**
|
||||
* Queries
|
||||
* */
|
||||
const {
|
||||
data: subscription,
|
||||
// request deps in Form handle errors and loading
|
||||
} = useOrgSubscriptionQuery({ orgSlug: org?.slug })
|
||||
const {
|
||||
data: addons,
|
||||
// request deps in Form handle errors and loading
|
||||
} = useProjectAddonsQuery({ projectRef: project?.ref })
|
||||
|
||||
const planId = subscription?.plan.id ?? 'free'
|
||||
const planId = org?.plan.id ?? 'free'
|
||||
const isDirty = !!Object.keys(form.formState.dirtyFields).length
|
||||
const replicaTooltipText = `Price change includes primary database and ${numReplicas} replica${numReplicas > 1 ? 's' : ''}`
|
||||
|
||||
@@ -185,7 +180,7 @@ export const DiskManagementReviewAndSubmitDialog = ({
|
||||
availableOptions,
|
||||
oldComputeSize: form.formState.defaultValues?.computeSize || 'ci_micro',
|
||||
newComputeSize: form.getValues('computeSize'),
|
||||
plan: subscription?.plan.id ?? 'free',
|
||||
plan: org?.plan.id ?? 'free',
|
||||
})
|
||||
const diskSizePrice = calculateDiskSizePrice({
|
||||
planId: planId,
|
||||
@@ -293,7 +288,7 @@ export const DiskManagementReviewAndSubmitDialog = ({
|
||||
beforePrice={Number(computeSizePrice.oldPrice)}
|
||||
afterPrice={Number(computeSizePrice.newPrice)}
|
||||
upgradeIncluded={
|
||||
subscription?.plan.id !== 'free' &&
|
||||
org?.plan.id !== 'free' &&
|
||||
project?.infra_compute_size === 'nano' &&
|
||||
form.getValues('computeSize') === 'ci_micro'
|
||||
}
|
||||
|
||||
@@ -2,12 +2,10 @@ import { CpuIcon, Lock, Microchip } from 'lucide-react'
|
||||
import { useMemo } from 'react'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
|
||||
import { components } from 'api-types'
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import { InlineLink } from 'components/ui/InlineLink'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { getCloudProviderArchitecture } from 'lib/cloudprovider-utils'
|
||||
@@ -26,11 +24,7 @@ import {
|
||||
import { ComputeBadge } from 'ui-patterns'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { DiskStorageSchemaType } from '../DiskManagement.schema'
|
||||
import {
|
||||
ComputeInstanceAddonVariantId,
|
||||
ComputeInstanceSize,
|
||||
InfraInstanceSize,
|
||||
} from '../DiskManagement.types'
|
||||
import { ComputeInstanceAddonVariantId, InfraInstanceSize } from '../DiskManagement.types'
|
||||
import {
|
||||
calculateComputeSizePrice,
|
||||
getAvailableComputeOptions,
|
||||
@@ -61,8 +55,6 @@ export function ComputeSizeField({ form, disabled }: ComputeSizeFieldProps) {
|
||||
const org = useSelectedOrganization()
|
||||
const { control, formState, setValue, trigger } = form
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: org?.slug })
|
||||
|
||||
const { project, isLoading: isProjectLoading } = useProjectContext()
|
||||
const {
|
||||
data: addons,
|
||||
@@ -90,11 +82,11 @@ export function ComputeSizeField({ form, disabled }: ComputeSizeFieldProps) {
|
||||
availableOptions: availableOptions,
|
||||
oldComputeSize: form.formState.defaultValues?.computeSize || 'ci_micro',
|
||||
newComputeSize: form.getValues('computeSize'),
|
||||
plan: subscription?.plan.id ?? 'free',
|
||||
plan: org?.plan.id ?? 'free',
|
||||
})
|
||||
|
||||
const showUpgradeBadge = showMicroUpgrade(
|
||||
subscription?.plan.id ?? 'free',
|
||||
org?.plan.id ?? 'free',
|
||||
project?.infra_compute_size ?? 'nano'
|
||||
)
|
||||
|
||||
@@ -179,14 +171,14 @@ export function ComputeSizeField({ form, disabled }: ComputeSizeFieldProps) {
|
||||
const lockedMicroDueToPITR =
|
||||
compute.identifier === 'ci_micro' && !!subscriptionPitr
|
||||
const lockedNanoDueToPlan =
|
||||
subscription?.plan.id !== 'free' &&
|
||||
org?.plan.id !== 'free' &&
|
||||
project?.infra_compute_size !== 'nano' &&
|
||||
compute.identifier === 'ci_nano'
|
||||
|
||||
const lockedOption = lockedNanoDueToPlan || lockedMicroDueToPITR
|
||||
|
||||
const price =
|
||||
subscription?.plan.id !== 'free' &&
|
||||
org?.plan.id !== 'free' &&
|
||||
project?.infra_compute_size === 'nano' &&
|
||||
compute.identifier === 'ci_nano'
|
||||
? availableOptions.find(
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useParams } from 'common'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import { useDiskAttributesQuery } from 'data/config/disk-attributes-query'
|
||||
import { useDiskUtilizationQuery } from 'data/config/disk-utilization-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import dayjs from 'dayjs'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
@@ -47,13 +46,7 @@ export function DiskSizeField({
|
||||
{ projectRef },
|
||||
{ enabled: project && project.cloud_provider !== 'FLY' }
|
||||
)
|
||||
const {
|
||||
data: subscription,
|
||||
error: subscriptionError,
|
||||
isError: isSubscriptionError,
|
||||
} = useOrgSubscriptionQuery({
|
||||
orgSlug: org?.slug,
|
||||
})
|
||||
|
||||
const {
|
||||
data: diskUtil,
|
||||
error: diskUtilError,
|
||||
@@ -65,8 +58,8 @@ export function DiskSizeField({
|
||||
{ enabled: project && project.cloud_provider !== 'FLY' }
|
||||
)
|
||||
|
||||
const error = subscriptionError || diskUtilError || diskAttributesError
|
||||
const isError = isSubscriptionError || isDiskUtilizationError || isDiskAttributesError
|
||||
const error = diskUtilError || diskAttributesError
|
||||
const isError = isDiskUtilizationError || isDiskAttributesError
|
||||
|
||||
// coming up typically takes 5 minutes, and the request is cached for 5 mins
|
||||
// so doing less than 10 mins to account for both
|
||||
@@ -77,7 +70,7 @@ export function DiskSizeField({
|
||||
const watchedStorageType = watch('storageType')
|
||||
const watchedTotalSize = watch('totalSize')
|
||||
|
||||
const planId = subscription?.plan.id ?? 'free'
|
||||
const planId = org?.plan.id ?? 'free'
|
||||
|
||||
const { includedDiskGB: includedDiskGBMeta } =
|
||||
PLAN_DETAILS?.[planId as keyof typeof PLAN_DETAILS] ?? {}
|
||||
@@ -159,7 +152,7 @@ export function DiskSizeField({
|
||||
/>
|
||||
<span className="text-foreground-lighter text-sm">
|
||||
{includedDiskGB > 0 &&
|
||||
subscription?.plan.id &&
|
||||
org?.plan.id &&
|
||||
`Your plan includes ${includedDiskGB} GB of disk size for ${watchedStorageType}.`}
|
||||
|
||||
<div className="mt-3">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import {
|
||||
AlertDescription_Shadcn_ as AlertDescription,
|
||||
@@ -16,20 +15,8 @@ export function SpendCapDisabledSection() {
|
||||
const org = useSelectedOrganization()
|
||||
const project = useSelectedProject()
|
||||
|
||||
const {
|
||||
data,
|
||||
// no error/isError states handled here, as a parent component handles them
|
||||
// we rely on this to check if the subscription has loaded
|
||||
isSuccess,
|
||||
} = useOrgSubscriptionQuery({
|
||||
orgSlug: org?.slug,
|
||||
})
|
||||
|
||||
const isSpendCapEnabled =
|
||||
isSuccess &&
|
||||
data?.plan.id !== 'free' &&
|
||||
!data?.usage_billing_enabled &&
|
||||
project?.cloud_provider !== 'FLY'
|
||||
org?.plan.id !== 'free' && !org?.usage_billing_enabled && project?.cloud_provider !== 'FLY'
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useParams } from 'common'
|
||||
import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold'
|
||||
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
|
||||
import { useOrgSubscriptionQuery } from '../../../../data/subscriptions/org-subscription-query'
|
||||
@@ -10,6 +9,7 @@ import CreditBalance from './CreditBalance'
|
||||
import PaymentMethods from './PaymentMethods/PaymentMethods'
|
||||
import Subscription from './Subscription/Subscription'
|
||||
import TaxID from './TaxID/TaxID'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
|
||||
const BillingSettings = () => {
|
||||
const {
|
||||
@@ -18,8 +18,8 @@ const BillingSettings = () => {
|
||||
billingCredits: isBillingCreditsEnabledOnProfileLevel,
|
||||
} = useIsFeatureEnabled(['billing:account_data', 'billing:payment_methods', 'billing:credits'])
|
||||
|
||||
const { slug: orgSlug } = useParams()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug })
|
||||
const org = useSelectedOrganization()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: org?.slug })
|
||||
const isNotOrgWithPartnerBilling = !subscription?.billing_via_partner
|
||||
|
||||
const billingAccountDataEnabled =
|
||||
@@ -41,7 +41,7 @@ const BillingSettings = () => {
|
||||
|
||||
<ScaffoldDivider />
|
||||
|
||||
{subscription?.plan.id !== 'free' && (
|
||||
{org?.plan.id !== 'free' && (
|
||||
<ScaffoldContainer id="breakdown">
|
||||
<BillingBreakdown />
|
||||
</ScaffoldContainer>
|
||||
|
||||
@@ -2,7 +2,6 @@ import dayjs from 'dayjs'
|
||||
import { ExternalLink } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useOrgUsageQuery } from 'data/usage/org-usage-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button } from 'ui'
|
||||
@@ -12,9 +11,6 @@ import { PricingMetric } from 'data/analytics/org-daily-stats-query'
|
||||
export const Restriction = () => {
|
||||
const org = useSelectedOrganization()
|
||||
const { data: usage, isSuccess: isSuccessOrgUsage } = useOrgUsageQuery({ orgSlug: org?.slug })
|
||||
const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: org?.slug,
|
||||
})
|
||||
|
||||
const hasExceededAnyLimits = Boolean(
|
||||
usage?.usages.find(
|
||||
@@ -27,13 +23,13 @@ export const Restriction = () => {
|
||||
)
|
||||
|
||||
// don't show any alerts until everything has been fetched
|
||||
if (!isSuccessOrgUsage || !isSuccessSubscription || !org) {
|
||||
if (!isSuccessOrgUsage || !org) {
|
||||
return null
|
||||
}
|
||||
|
||||
let shownAlert: 'exceededLimits' | 'gracePeriod' | 'gracePeriodOver' | 'restricted' | null = null
|
||||
|
||||
if (subscription && hasExceededAnyLimits && !org?.restriction_status) {
|
||||
if (hasExceededAnyLimits && !org?.restriction_status) {
|
||||
shownAlert = 'exceededLimits'
|
||||
} else if (org?.restriction_status === 'grace_period') {
|
||||
shownAlert = 'gracePeriod'
|
||||
@@ -59,7 +55,7 @@ export const Restriction = () => {
|
||||
<AlertDescription_Shadcn_>
|
||||
<p>
|
||||
Your projects can become unresponsive or enter read-only mode.{' '}
|
||||
{subscription.plan.id === 'free'
|
||||
{org.plan.id === 'free'
|
||||
? 'Please upgrade to the Pro Plan to ensure that your projects remain available.'
|
||||
: 'Please disable spend cap to ensure that your projects remain available.'}
|
||||
</p>
|
||||
@@ -67,10 +63,10 @@ export const Restriction = () => {
|
||||
<Button key="upgrade-button" asChild type="default">
|
||||
<Link
|
||||
href={`/org/${org?.slug}/billing?panel=${
|
||||
subscription.plan.id === 'free' ? 'subscriptionPlan' : 'costControl'
|
||||
org.plan.id === 'free' ? 'subscriptionPlan' : 'costControl'
|
||||
}`}
|
||||
>
|
||||
{subscription.plan.id === 'free' ? 'Upgrade plan' : 'Change spend cap'}
|
||||
{org.plan.id === 'free' ? 'Upgrade plan' : 'Change spend cap'}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button asChild type="default" icon={<ExternalLink />}>
|
||||
|
||||
+1
-3
@@ -1,6 +1,5 @@
|
||||
import { Check } from 'lucide-react'
|
||||
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { PricingInformation } from 'shared-data'
|
||||
@@ -18,8 +17,7 @@ export const EnterpriseCard = ({ plan, isCurrentPlan, billingPartner }: Enterpri
|
||||
const orgSlug = selectedOrganization?.slug
|
||||
|
||||
const features = pickFeatures(plan, billingPartner)
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug })
|
||||
const currentPlan = subscription?.plan.name
|
||||
const currentPlan = selectedOrganization?.plan.name
|
||||
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
|
||||
|
||||
-3
@@ -1,7 +1,5 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import dayjs from 'dayjs'
|
||||
import { ExternalLink } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
|
||||
import {
|
||||
@@ -12,7 +10,6 @@ import {
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import SparkBar from 'components/ui/SparkBar'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
|
||||
@@ -4,36 +4,27 @@ import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
ScaffoldSection,
|
||||
ScaffoldSectionContent,
|
||||
ScaffoldSectionDetail,
|
||||
} from 'components/layouts/Scaffold'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { getDocument } from 'data/documents/document-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { Button } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
|
||||
const SOC2 = () => {
|
||||
const { slug } = useParams()
|
||||
const organization = useSelectedOrganization()
|
||||
const slug = organization?.slug
|
||||
const canReadSubscriptions = useCheckPermissions(
|
||||
PermissionAction.BILLING_READ,
|
||||
'stripe.subscriptions'
|
||||
)
|
||||
|
||||
const {
|
||||
data: subscription,
|
||||
error,
|
||||
isLoading,
|
||||
isError,
|
||||
isSuccess,
|
||||
} = useOrgSubscriptionQuery({ orgSlug: slug }, { enabled: canReadSubscriptions })
|
||||
const currentPlan = subscription?.plan
|
||||
const currentPlan = organization?.plan
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
@@ -61,31 +52,17 @@ const SOC2 = () => {
|
||||
{!canReadSubscriptions ? (
|
||||
<NoPermission resourceText="access our SOC2 Type 2 report" />
|
||||
) : (
|
||||
<>
|
||||
{isLoading && (
|
||||
<div className="space-y-2">
|
||||
<ShimmeringLoader />
|
||||
<ShimmeringLoader className="w-3/4" />
|
||||
<ShimmeringLoader className="w-1/2" />
|
||||
</div>
|
||||
<div className="flex items-center justify-center h-full">
|
||||
{currentPlan?.id === 'free' || currentPlan?.id === 'pro' ? (
|
||||
<Link href={`/org/${slug}/billing?panel=subscriptionPlan&source=soc2`}>
|
||||
<Button type="default">Upgrade to Team</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Button type="default" icon={<Download />} onClick={() => setIsOpen(true)}>
|
||||
Download SOC2 Type 2 Report
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{isError && <AlertError subject="Failed to retrieve subscription" error={error} />}
|
||||
|
||||
{isSuccess && (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
{currentPlan?.id === 'free' || currentPlan?.id === 'pro' ? (
|
||||
<Link href={`/org/${slug}/billing?panel=subscriptionPlan&source=soc2`}>
|
||||
<Button type="default">Upgrade to Team</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Button type="default" icon={<Download />} onClick={() => setIsOpen(true)}>
|
||||
Download SOC2 Type 2 Report
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
<ConfirmationModal
|
||||
visible={isOpen}
|
||||
|
||||
+24
-44
@@ -1,5 +1,4 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { Download } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { toast } from 'sonner'
|
||||
@@ -10,27 +9,20 @@ import {
|
||||
ScaffoldSectionContent,
|
||||
ScaffoldSectionDetail,
|
||||
} from 'components/layouts/Scaffold'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { getDocument } from 'data/documents/document-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
|
||||
const SecurityQuestionnaire = () => {
|
||||
const { slug } = useParams()
|
||||
const organization = useSelectedOrganization()
|
||||
const slug = organization?.slug
|
||||
const canReadSubscriptions = useCheckPermissions(
|
||||
PermissionAction.BILLING_READ,
|
||||
'stripe.subscriptions'
|
||||
)
|
||||
const {
|
||||
data: subscription,
|
||||
error,
|
||||
isLoading,
|
||||
isError,
|
||||
isSuccess,
|
||||
} = useOrgSubscriptionQuery({ orgSlug: slug }, { enabled: canReadSubscriptions })
|
||||
const currentPlan = subscription?.plan
|
||||
|
||||
const currentPlan = organization?.plan
|
||||
|
||||
const fetchQuestionnaire = async (orgSlug: string) => {
|
||||
try {
|
||||
@@ -61,37 +53,25 @@ const SecurityQuestionnaire = () => {
|
||||
<NoPermission resourceText="access our security questionnaire" />
|
||||
) : (
|
||||
<>
|
||||
{isLoading && (
|
||||
<div className="space-y-2">
|
||||
<ShimmeringLoader />
|
||||
<ShimmeringLoader className="w-3/4" />
|
||||
<ShimmeringLoader className="w-1/2" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isError && <AlertError subject="Failed to retrieve subscription" error={error} />}
|
||||
|
||||
{isSuccess && (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
{currentPlan?.id === 'free' || currentPlan?.id === 'pro' ? (
|
||||
<Link
|
||||
href={`/org/${slug}/billing?panel=subscriptionPlan&source=securityQuestionnaire`}
|
||||
>
|
||||
<Button type="default">Upgrade to Team</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Button
|
||||
type="default"
|
||||
icon={<Download />}
|
||||
onClick={() => {
|
||||
if (slug) fetchQuestionnaire(slug)
|
||||
}}
|
||||
>
|
||||
Download Questionnaire
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-center h-full">
|
||||
{currentPlan?.id === 'free' || currentPlan?.id === 'pro' ? (
|
||||
<Link
|
||||
href={`/org/${slug}/billing?panel=subscriptionPlan&source=securityQuestionnaire`}
|
||||
>
|
||||
<Button type="default">Upgrade to Team</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Button
|
||||
type="default"
|
||||
icon={<Download />}
|
||||
onClick={() => {
|
||||
if (slug) fetchQuestionnaire(slug)
|
||||
}}
|
||||
>
|
||||
Download Questionnaire
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</ScaffoldSectionContent>
|
||||
|
||||
+12
-19
@@ -13,10 +13,7 @@ import { useOrganizationCreateInvitationMutation } from 'data/organization-membe
|
||||
import { useOrganizationRolesV2Query } from 'data/organization-members/organization-roles-query'
|
||||
import { useOrganizationMembersQuery } from 'data/organizations/organization-members-query'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import {
|
||||
useHasAccessToProjectLevelPermissions,
|
||||
useOrgSubscriptionQuery,
|
||||
} from 'data/subscriptions/org-subscription-query'
|
||||
import { useHasAccessToProjectLevelPermissions } from 'data/subscriptions/org-subscription-query'
|
||||
import {
|
||||
doPermissionsCheck,
|
||||
useCheckPermissions,
|
||||
@@ -82,11 +79,8 @@ export const InviteMemberButton = () => {
|
||||
PermissionAction.BILLING_READ,
|
||||
'stripe.subscriptions'
|
||||
)
|
||||
const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery(
|
||||
{ orgSlug: slug },
|
||||
{ enabled: canReadSubscriptions }
|
||||
)
|
||||
const currentPlan = subscription?.plan
|
||||
|
||||
const currentPlan = organization?.plan
|
||||
const hasAccessToProjectLevelPermissions = useHasAccessToProjectLevelPermissions(slug as string)
|
||||
|
||||
const userMemberData = members?.find((m) => m.gotrue_id === profile?.gotrue_id)
|
||||
@@ -405,16 +399,15 @@ export const InviteMemberButton = () => {
|
||||
Learn more
|
||||
</Link>
|
||||
</Button>
|
||||
{isSuccessSubscription &&
|
||||
(currentPlan?.id === 'free' || currentPlan?.id === 'pro') && (
|
||||
<Button asChild type="default">
|
||||
<Link
|
||||
href={`/org/${slug}/billing?panel=subscriptionPlan&source=inviteMemberSSO`}
|
||||
>
|
||||
Upgrade to Team
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
{(currentPlan?.id === 'free' || currentPlan?.id === 'pro') && (
|
||||
<Button asChild type="default">
|
||||
<Link
|
||||
href={`/org/${slug}/billing?panel=subscriptionPlan&source=inviteMemberSSO`}
|
||||
>
|
||||
Upgrade to Team
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import DateRangePicker from 'components/ui/DateRangePicker'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
REALTIME_DEFAULT_CONFIG,
|
||||
useRealtimeConfigurationQuery,
|
||||
} from 'data/realtime/realtime-config-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import {
|
||||
@@ -30,10 +29,8 @@ import {
|
||||
FormField_Shadcn_,
|
||||
FormMessage_Shadcn_,
|
||||
Input_Shadcn_,
|
||||
Switch,
|
||||
} from 'ui'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
|
||||
const formId = 'realtime-configuration-form'
|
||||
|
||||
@@ -50,10 +47,8 @@ export const RealtimeSettings = () => {
|
||||
const { data, error, isLoading, isSuccess, isError } = useRealtimeConfigurationQuery({
|
||||
projectRef,
|
||||
})
|
||||
const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: organization?.slug,
|
||||
})
|
||||
const isUsageBillingEnabled = subscription?.usage_billing_enabled
|
||||
|
||||
const isUsageBillingEnabled = organization?.usage_billing_enabled
|
||||
|
||||
const { mutate: updateRealtimeConfig, isLoading: isUpdatingConfig } =
|
||||
useRealtimeConfigurationUpdateMutation({
|
||||
@@ -219,7 +214,7 @@ export const RealtimeSettings = () => {
|
||||
/>
|
||||
</FormControl_Shadcn_>
|
||||
<FormMessage_Shadcn_ />
|
||||
{isSuccessSubscription && !isUsageBillingEnabled && (
|
||||
{!isUsageBillingEnabled && (
|
||||
<Admonition
|
||||
showIcon={false}
|
||||
type="default"
|
||||
|
||||
@@ -58,7 +58,6 @@ const Addons = () => {
|
||||
const { data: settings } = useProjectSettingsV2Query({ projectRef })
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: selectedOrg?.slug })
|
||||
|
||||
const computeSizeChangesDisabled = useFlag('disableComputeSizeChanges')
|
||||
const projectUpdateDisabled = useFlag('disableProjectCreationAndUpdate')
|
||||
|
||||
const hasHipaaAddon = subscriptionHasHipaaAddon(subscription)
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useEffect, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation'
|
||||
import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
@@ -24,7 +23,7 @@ import {
|
||||
SidePanel,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { ExternalLink, AlertCircle, AlertTriangle } from 'lucide-react'
|
||||
import { ExternalLink, AlertCircle } from 'lucide-react'
|
||||
|
||||
const CustomDomainSidePanel = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
@@ -42,7 +41,6 @@ const CustomDomainSidePanel = () => {
|
||||
const visible = panel === 'customDomain'
|
||||
|
||||
const { data: addons, isLoading } = useProjectAddonsQuery({ projectRef })
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const { mutate: updateAddon, isLoading: isUpdating } = useProjectAddonUpdateMutation({
|
||||
onSuccess: () => {
|
||||
toast.success(`Successfully enabled custom domain`)
|
||||
@@ -69,7 +67,7 @@ const CustomDomainSidePanel = () => {
|
||||
const availableOptions =
|
||||
(addons?.available_addons ?? []).find((addon) => addon.type === 'custom_domain')?.variants ?? []
|
||||
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isFreePlan = organization?.plan?.id === 'free'
|
||||
const hasChanges = selectedOption !== (subscriptionCDOption?.variant.identifier ?? 'cd_none')
|
||||
const selectedCustomDomain = availableOptions.find(
|
||||
(option) => option.identifier === selectedOption
|
||||
|
||||
@@ -5,7 +5,6 @@ import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { InlineLink } from 'components/ui/InlineLink'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation'
|
||||
import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
@@ -30,7 +29,6 @@ const IPv4SidePanel = () => {
|
||||
const visible = panel === 'ipv4'
|
||||
|
||||
const { data: addons, isLoading } = useProjectAddonsQuery({ projectRef })
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const { mutate: updateAddon, isLoading: isUpdating } = useProjectAddonUpdateMutation({
|
||||
onSuccess: () => {
|
||||
toast.success(`Successfully enabled IPv4`)
|
||||
@@ -57,7 +55,7 @@ const IPv4SidePanel = () => {
|
||||
const availableOptions =
|
||||
(addons?.available_addons ?? []).find((addon) => addon.type === 'ipv4')?.variants ?? []
|
||||
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isFreePlan = organization?.plan?.id === 'free'
|
||||
const hasChanges = selectedOption !== (subscriptionIpV4Option?.variant.identifier ?? 'ipv4_none')
|
||||
const selectedIPv4 = availableOptions.find((option) => option.identifier === selectedOption)
|
||||
const isPgBouncerEnabled = !isFreePlan
|
||||
@@ -219,12 +217,10 @@ const IPv4SidePanel = () => {
|
||||
charge.
|
||||
</p>
|
||||
)}
|
||||
{!subscription?.billing_via_partner && (
|
||||
<p className="text-sm text-foreground-light">
|
||||
There are no immediate charges. The addon is billed at the end of your billing
|
||||
cycle based on your usage and prorated to the hour.
|
||||
</p>
|
||||
)}
|
||||
<p className="text-sm text-foreground-light">
|
||||
There are no immediate charges. The addon is billed at the end of your billing cycle
|
||||
based on your usage and prorated to the hour.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
+2
-5
@@ -17,7 +17,6 @@ import Panel from 'components/ui/Panel'
|
||||
import { useMaxConnectionsQuery } from 'data/database/max-connections-query'
|
||||
import { usePgbouncerConfigQuery } from 'data/database/pgbouncer-config-query'
|
||||
import { usePgbouncerConfigurationUpdateMutation } from 'data/database/pgbouncer-config-update-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
@@ -68,11 +67,9 @@ export const ConnectionPooling = () => {
|
||||
isSuccess: isSuccessPgbouncerConfig,
|
||||
} = usePgbouncerConfigQuery({ projectRef })
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: org?.slug })
|
||||
|
||||
const disablePoolModeSelection = useMemo(() => {
|
||||
return subscription?.plan?.id === 'free'
|
||||
}, [subscription])
|
||||
return org?.plan?.id === 'free'
|
||||
}, [org])
|
||||
|
||||
const { data: maxConnData } = useMaxConnectionsQuery({
|
||||
projectRef: project?.ref,
|
||||
|
||||
@@ -3,7 +3,6 @@ import { AlertTriangle, ExternalLink } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useResourceWarningsQuery } from 'data/usage/resource-warnings-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button } from 'ui'
|
||||
@@ -15,7 +14,6 @@ export const DatabaseReadOnlyAlert = () => {
|
||||
const [showConfirmationModal, setShowConfirmationModal] = useState(false)
|
||||
|
||||
const { data: resourceWarnings } = useResourceWarningsQuery()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
|
||||
const isReadOnlyMode =
|
||||
(resourceWarnings ?? [])?.find((warning) => warning.project === projectRef)
|
||||
@@ -37,7 +35,7 @@ export const DatabaseReadOnlyAlert = () => {
|
||||
<li>
|
||||
Temporarily disable read-only mode to free up space and reduce your database size
|
||||
</li>
|
||||
{subscription?.plan.id === 'free' ? (
|
||||
{organization?.plan.id === 'free' ? (
|
||||
<li>
|
||||
<Link
|
||||
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=databaseReadOnlyAlertUpgradePlan`}
|
||||
@@ -46,7 +44,7 @@ export const DatabaseReadOnlyAlert = () => {
|
||||
</Link>{' '}
|
||||
to increase your database size limit to 8GB.
|
||||
</li>
|
||||
) : subscription?.plan.id === 'pro' && subscription?.usage_billing_enabled ? (
|
||||
) : organization?.plan.id === 'pro' && organization?.usage_billing_enabled ? (
|
||||
<li>
|
||||
<Link
|
||||
href={`/org/${organization?.slug}/billing?panel=subscriptionPlan&source=databaseReadOnlyAlertSpendCap`}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import dayjs from 'dayjs'
|
||||
import { ExternalLink, Info } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { SetStateAction } from 'react'
|
||||
@@ -14,7 +13,6 @@ import { FormHeader } from 'components/ui/Forms/FormHeader'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useProjectDiskResizeMutation } from 'data/config/project-disk-resize-mutation'
|
||||
import { useDatabaseSizeQuery } from 'data/database/database-size-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useUrlState } from 'hooks/ui/useUrlState'
|
||||
@@ -28,13 +26,9 @@ export interface DiskSizeConfigurationProps {
|
||||
const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfigurationProps) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const { lastDatabaseResizeAt } = project ?? {}
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
|
||||
const timeTillNextAvailableDatabaseResize =
|
||||
lastDatabaseResizeAt === null ? 0 : 6 * 60 - dayjs().diff(lastDatabaseResizeAt, 'minutes')
|
||||
|
||||
const [{ show_increase_disk_size_modal }, setUrlParams] = useUrlState()
|
||||
const showIncreaseDiskSizeModal = show_increase_disk_size_modal === 'true'
|
||||
const setShowIncreaseDiskSizeModal = (value: SetStateAction<boolean>) => {
|
||||
@@ -48,7 +42,6 @@ const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfigurationProps)
|
||||
},
|
||||
})
|
||||
|
||||
const { data: projectSubscriptionData } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const { isLoading: isUpdatingDiskSize } = useProjectDiskResizeMutation({
|
||||
onSuccess: (_, variables) => {
|
||||
toast.success(`Successfully updated disk size to ${variables.volumeSize} GB`)
|
||||
@@ -67,7 +60,7 @@ const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfigurationProps)
|
||||
return (
|
||||
<div id="diskManagement">
|
||||
<FormHeader title="Disk Management" />
|
||||
{projectSubscriptionData?.usage_billing_enabled === true ? (
|
||||
{organization?.usage_billing_enabled === true ? (
|
||||
<div className="flex flex-col gap-3">
|
||||
<Panel className="!m-0">
|
||||
<Panel.Content>
|
||||
@@ -155,12 +148,12 @@ Read more about [disk management](https://supabase.com/docs/guides/platform/data
|
||||
<Alert_Shadcn_>
|
||||
<InfoIcon />
|
||||
<AlertTitle_Shadcn_>
|
||||
{projectSubscriptionData?.plan?.id === 'free'
|
||||
{organization?.plan?.id === 'free'
|
||||
? 'Disk size configuration is not available for projects on the Free Plan'
|
||||
: 'Disk size configuration is only available when the spend cap has been disabled'}
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_>
|
||||
{projectSubscriptionData?.plan?.id === 'free' ? (
|
||||
{organization?.plan?.id === 'free' ? (
|
||||
<p>
|
||||
If you are intending to use more than 500MB of disk space, then you will need to
|
||||
upgrade to at least the Pro Plan.
|
||||
@@ -174,13 +167,11 @@ Read more about [disk management](https://supabase.com/docs/guides/platform/data
|
||||
<Button asChild type="default" className="mt-3">
|
||||
<Link
|
||||
href={`/org/${organization?.slug}/billing?panel=${
|
||||
projectSubscriptionData?.plan?.id === 'free' ? 'subscriptionPlan' : 'costControl'
|
||||
organization?.plan?.id === 'free' ? 'subscriptionPlan' : 'costControl'
|
||||
}`}
|
||||
target="_blank"
|
||||
>
|
||||
{projectSubscriptionData?.plan?.id === 'free'
|
||||
? 'Upgrade subscription'
|
||||
: 'Disable spend cap'}
|
||||
{organization?.plan?.id === 'free' ? 'Upgrade subscription' : 'Disable spend cap'}
|
||||
</Link>
|
||||
</Button>
|
||||
</AlertDescription_Shadcn_>
|
||||
|
||||
+1
-3
@@ -6,7 +6,6 @@ import { FormHeader } from 'components/ui/Forms/FormHeader'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useCustomDomainsQuery } from 'data/custom-domains/custom-domains-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
@@ -22,8 +21,7 @@ const CustomDomainConfig = () => {
|
||||
|
||||
const customDomainsDisabledDueToQuota = useFlag('customDomainsDisabledDueToQuota')
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const plan = subscription?.plan?.id
|
||||
const plan = organization?.plan?.id
|
||||
|
||||
const { data: addons, isLoading: isLoadingAddons } = useProjectAddonsQuery({ projectRef: ref })
|
||||
const hasCustomDomainAddon = !!addons?.selected_addons.find((x) => x.type === 'custom_domain')
|
||||
|
||||
+1
-3
@@ -12,7 +12,6 @@ import {
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useProjectPauseMutation } from 'data/projects/project-pause-mutation'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
@@ -33,8 +32,7 @@ const PauseProjectButton = () => {
|
||||
'queue_jobs.projects.pause'
|
||||
)
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const isFreePlan = subscription?.plan.id === 'free'
|
||||
const isFreePlan = organization?.plan.id === 'free'
|
||||
|
||||
const { mutate: pauseProject, isLoading: isPausing } = useProjectPauseMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
|
||||
+1
-3
@@ -18,7 +18,6 @@ import {
|
||||
} from 'data/config/project-upgrade-eligibility-query'
|
||||
import { ReleaseChannel, useProjectUpgradeMutation } from 'data/projects/project-upgrade-mutation'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
@@ -72,8 +71,7 @@ const ProjectUpgradeAlert = () => {
|
||||
|
||||
const projectUpgradeDisabled = useFlag('disableProjectUpgrade')
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: org?.slug })
|
||||
const planId = subscription?.plan.id ?? 'free'
|
||||
const planId = org?.plan.id ?? 'free'
|
||||
|
||||
const { data: diskAttributes } = useDiskAttributesQuery({ projectRef: ref })
|
||||
const { includedDiskGB: includedDiskGBMeta } = PLAN_DETAILS[planId]
|
||||
|
||||
+5
-5
@@ -56,7 +56,7 @@ const InfrastructureActivity = () => {
|
||||
const { data: subscription, isLoading: isLoadingSubscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: organization?.slug,
|
||||
})
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isFreePlan = organization?.plan?.id === 'free'
|
||||
|
||||
const { data: resourceWarnings } = useResourceWarningsQuery()
|
||||
const projectResourceWarnings = resourceWarnings?.find((x) => x.project === projectRef)
|
||||
@@ -94,9 +94,9 @@ const InfrastructureActivity = () => {
|
||||
}, [dateRange, subscription])
|
||||
|
||||
const upgradeUrl =
|
||||
subscription === undefined
|
||||
organization === undefined
|
||||
? `/`
|
||||
: subscription.plan.id === 'free'
|
||||
: organization.plan.id === 'free'
|
||||
? `/org/${organization?.slug ?? '[slug]'}/billing#subscription`
|
||||
: `/project/${projectRef}/settings/addons`
|
||||
|
||||
@@ -112,7 +112,7 @@ const InfrastructureActivity = () => {
|
||||
// LF seems to have an issue with the milliseconds, causes infinite loading sometimes
|
||||
return new Date(dateRange?.period_start?.date ?? 0).toISOString().slice(0, -5) + 'Z'
|
||||
}
|
||||
}, [dateRange, subscription])
|
||||
}, [dateRange])
|
||||
|
||||
const endDate = useMemo(() => {
|
||||
if (dateRange?.period_end?.date === 'Invalid Date') return undefined
|
||||
@@ -127,7 +127,7 @@ const InfrastructureActivity = () => {
|
||||
// LF seems to have an issue with the milliseconds, causes infinite loading sometimes
|
||||
return new Date(dateRange.period_end.date ?? 0).toISOString().slice(0, -5) + 'Z'
|
||||
}
|
||||
}, [dateRange, subscription])
|
||||
}, [dateRange])
|
||||
|
||||
// Switch to hourly interval, if the timeframe is <48 hours
|
||||
let interval: '1d' | '1h' = '1d'
|
||||
|
||||
+4
-7
@@ -23,7 +23,6 @@ import {
|
||||
MAX_REPLICAS_BELOW_XL,
|
||||
useReadReplicasQuery,
|
||||
} from 'data/read-replicas/replicas-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
@@ -73,12 +72,11 @@ const DeployNewReplicaPanel = ({
|
||||
|
||||
const { data } = useReadReplicasQuery({ projectRef })
|
||||
const { data: addons, isSuccess } = useProjectAddonsQuery({ projectRef })
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: org?.slug })
|
||||
const { data: diskConfiguration } = useDiskAttributesQuery({ projectRef })
|
||||
|
||||
const isNotOnTeamOrEnterprisePlan = useMemo(
|
||||
() => !['team', 'enterprise'].includes(subscription?.plan.id ?? ''),
|
||||
[subscription]
|
||||
() => !['team', 'enterprise'].includes(org?.plan.id ?? ''),
|
||||
[org]
|
||||
)
|
||||
const { data: allOverdueInvoices } = useOverdueInvoicesQuery({
|
||||
enabled: isNotOnTeamOrEnterprisePlan,
|
||||
@@ -166,14 +164,13 @@ const DeployNewReplicaPanel = ({
|
||||
: MAX_REPLICAS_ABOVE_XL
|
||||
const reachedMaxReplicas =
|
||||
(data ?? []).filter((db) => db.identifier !== projectRef).length >= maxNumberOfReplicas
|
||||
const isFreePlan = subscription?.plan.id === 'free'
|
||||
const isFreePlan = org?.plan.id === 'free'
|
||||
const isAWSProvider = project?.cloud_provider === 'AWS'
|
||||
const isWalgEnabled = project?.is_physical_backups_enabled
|
||||
const currentComputeAddon = addons?.selected_addons.find(
|
||||
(addon) => addon.type === 'compute_instance'
|
||||
)
|
||||
const isProWithSpendCapEnabled =
|
||||
subscription?.plan.id === 'pro' && !subscription.usage_billing_enabled
|
||||
const isProWithSpendCapEnabled = org?.plan.id === 'pro' && !org.usage_billing_enabled
|
||||
const isMinimallyOnSmallCompute =
|
||||
currentComputeAddon?.variant.identifier !== undefined &&
|
||||
currentComputeAddon?.variant.identifier !== 'ci_micro'
|
||||
|
||||
@@ -8,7 +8,6 @@ import PreviewFilterPanel from 'components/interfaces/Settings/Logs/PreviewFilte
|
||||
import LoadingOpacity from 'components/ui/LoadingOpacity'
|
||||
import ShimmerLine from 'components/ui/ShimmerLine'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import useLogsPreview from 'hooks/analytics/useLogsPreview'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt'
|
||||
@@ -65,7 +64,6 @@ export const LogsPreviewer = ({
|
||||
const [selectedLogId, setSelectedLogId] = useSelectedLog()
|
||||
|
||||
const { data: databases, isSuccess } = useReadReplicasQuery({ projectRef })
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
|
||||
const table = !tableName ? LOGS_TABLES[queryType] : tableName
|
||||
|
||||
@@ -97,12 +95,12 @@ export const LogsPreviewer = ({
|
||||
// Show the prompt on page load based on query params
|
||||
useEffect(() => {
|
||||
if (timestampStart) {
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(timestampStart, subscription?.plan?.id)
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(timestampStart, organization?.plan?.id)
|
||||
if (shouldShowUpgradePrompt) {
|
||||
setShowUpgradePrompt(!showUpgradePrompt)
|
||||
}
|
||||
}
|
||||
}, [timestampStart, subscription])
|
||||
}, [timestampStart, organization])
|
||||
|
||||
useEffect(() => {
|
||||
if (db !== undefined) {
|
||||
@@ -137,7 +135,7 @@ export const LogsPreviewer = ({
|
||||
} else if (event === 'event-chart-bar-click') {
|
||||
setTimeRange(from || '', to || '')
|
||||
} else if (event === 'datepicker-change') {
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from || '', subscription?.plan?.id)
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from || '', organization?.plan?.id)
|
||||
|
||||
if (shouldShowUpgradePrompt) {
|
||||
setShowUpgradePrompt(!showUpgradePrompt)
|
||||
|
||||
@@ -2,7 +2,7 @@ import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
import { ChevronRight, ExternalLink, Loader2, Mail, Plus, X } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { ChangeEvent, useEffect, useRef, useState } from 'react'
|
||||
import { ChangeEvent, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { SubmitHandler, useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import * as z from 'zod'
|
||||
@@ -14,7 +14,6 @@ import { useSendSupportTicketMutation } from 'data/feedback/support-ticket-send'
|
||||
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import type { Project } from 'data/projects/project-detail-query'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { detectBrowser } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import {
|
||||
@@ -133,14 +132,10 @@ export const SupportFormV2 = ({ setSentCategory, setSelectedProject }: SupportFo
|
||||
isSuccess: isSuccessOrganizations,
|
||||
} = useOrganizationsQuery()
|
||||
|
||||
const {
|
||||
data: subscription,
|
||||
isLoading: isLoadingSubscription,
|
||||
isSuccess: isSuccessSubscription,
|
||||
} = useOrgSubscriptionQuery({
|
||||
orgSlug: organizationSlug === 'no-org' ? undefined : organizationSlug,
|
||||
})
|
||||
|
||||
const selectedOrganization = useMemo(
|
||||
() => organizations?.find((org) => org.slug === organizationSlug),
|
||||
[organizationSlug, organizations]
|
||||
)
|
||||
const {
|
||||
data: allProjects,
|
||||
isLoading: isLoadingProjects,
|
||||
@@ -161,7 +156,8 @@ export const SupportFormV2 = ({ setSentCategory, setSelectedProject }: SupportFo
|
||||
})
|
||||
|
||||
const respondToEmail = profile?.primary_email ?? 'your email'
|
||||
const subscriptionPlanId = subscription?.plan.id
|
||||
const subscriptionPlanId = selectedOrganization?.plan.id
|
||||
|
||||
const projects = [
|
||||
...(allProjects ?? []).filter((project) => project.organization_slug === organizationSlug),
|
||||
{ ref: 'no-project', name: 'No specific project' } as Partial<Project>,
|
||||
@@ -268,9 +264,8 @@ export const SupportFormV2 = ({ setSentCategory, setSelectedProject }: SupportFo
|
||||
form.setValue('projectRef', selectedProject.ref)
|
||||
}
|
||||
} else if (slug) {
|
||||
const selectedOrganization = organizations?.find((org) => org.slug === slug)
|
||||
if (selectedOrganization !== undefined) {
|
||||
form.setValue('organizationSlug', selectedOrganization.slug)
|
||||
if (organizations.some((it) => it.slug === slug)) {
|
||||
form.setValue('organizationSlug', slug)
|
||||
}
|
||||
} else if (ref === undefined && slug === undefined) {
|
||||
const firstOrganization = organizations?.[0]
|
||||
@@ -333,10 +328,7 @@ export const SupportFormV2 = ({ setSentCategory, setSelectedProject }: SupportFo
|
||||
) : (
|
||||
(organizations ?? []).find((o) => o.slug === field.value)?.name
|
||||
)}
|
||||
{organizationSlug !== 'no-org' && isLoadingSubscription && (
|
||||
<Loader2 size={14} className="animate-spin" />
|
||||
)}
|
||||
{isSuccessSubscription && (
|
||||
{subscriptionPlanId && (
|
||||
<Badge variant="outline" className="capitalize">
|
||||
{subscriptionPlanId}
|
||||
</Badge>
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useNewLayout } from 'components/interfaces/App/FeaturePreview/FeaturePr
|
||||
import PartnerIcon from 'components/ui/PartnerIcon'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import {
|
||||
@@ -40,7 +39,6 @@ const OrganizationDropdown = () => {
|
||||
|
||||
const slug = selectedOrganization?.slug
|
||||
const orgName = selectedOrganization?.name
|
||||
const { data: subscription, isSuccess } = useOrgSubscriptionQuery({ orgSlug: slug })
|
||||
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
@@ -56,7 +54,7 @@ const OrganizationDropdown = () => {
|
||||
<span className="text-foreground max-w-32 lg:max-w-none truncate hidden md:block">
|
||||
{orgName}
|
||||
</span>
|
||||
{isSuccess && <Badge variant="default">{subscription?.plan.name}</Badge>}
|
||||
<Badge variant="default">{selectedOrganization?.plan.name}</Badge>
|
||||
</Link>
|
||||
)}
|
||||
<Popover_Shadcn_ open={open} onOpenChange={setOpen} modal={false}>
|
||||
@@ -71,7 +69,7 @@ const OrganizationDropdown = () => {
|
||||
<Button type="text" className="pr-2" iconRight={<ChevronsUpDown />}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className={'text-xs'}>{orgName}</p>
|
||||
{isSuccess && <Badge variant="default">{subscription?.plan.name}</Badge>}
|
||||
<Badge variant="default">{selectedOrganization?.plan.name}</Badge>
|
||||
</div>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -14,7 +14,6 @@ import InlineEditorButton from 'components/layouts/AppLayout/InlineEditorButton'
|
||||
import OrganizationDropdown from 'components/layouts/AppLayout/OrganizationDropdown'
|
||||
import ProjectDropdown from 'components/layouts/AppLayout/ProjectDropdown'
|
||||
import { getResourcesExceededLimitsOrg } from 'components/ui/OveragesBanner/OveragesBanner.utils'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useOrgUsageQuery } from 'data/usage/org-usage-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
@@ -69,14 +68,10 @@ const LayoutHeader = ({
|
||||
const isBranchingEnabled = selectedProject?.is_branch_enabled === true
|
||||
const { setMobileMenuOpen } = useAppStateSnapshot()
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: selectedOrganization?.slug,
|
||||
})
|
||||
|
||||
// We only want to query the org usage and check for possible over-ages for plans without usage billing enabled (free or pro with spend cap)
|
||||
const { data: orgUsage } = useOrgUsageQuery(
|
||||
{ orgSlug: selectedOrganization?.slug },
|
||||
{ enabled: subscription?.usage_billing_enabled === false }
|
||||
{ enabled: selectedOrganization?.usage_billing_enabled === false }
|
||||
)
|
||||
|
||||
const exceedingLimits = useMemo(() => {
|
||||
|
||||
@@ -22,7 +22,6 @@ import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-l
|
||||
import { useProjectPauseStatusQuery } from 'data/projects/project-pause-status-query'
|
||||
import { useProjectRestoreMutation } from 'data/projects/project-restore-mutation'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag, usePHFlag } from 'hooks/ui/useFlag'
|
||||
@@ -78,7 +77,6 @@ export const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
const enableProBenefitWording = usePHFlag('proBenefitWording')
|
||||
|
||||
const orgSlug = selectedOrganization?.slug
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug })
|
||||
const {
|
||||
data: pauseStatus,
|
||||
error: pauseStatusError,
|
||||
@@ -97,7 +95,7 @@ export const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
pauseStatus?.max_days_till_restore_disabled ??
|
||||
0
|
||||
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isFreePlan = selectedOrganization?.plan?.id === 'free'
|
||||
const isRestoreDisabled = enforceNinetyDayUnpauseExpiry && isSuccess && !pauseStatus.can_restore
|
||||
|
||||
const { data: membersExceededLimit } = useFreeProjectLimitCheckQuery(
|
||||
|
||||
@@ -14,7 +14,6 @@ import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useProjectStorageConfigQuery } from 'data/config/project-storage-config-query'
|
||||
import { useProjectStorageConfigUpdateUpdateMutation } from 'data/config/project-storage-config-update-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import {
|
||||
@@ -56,10 +55,7 @@ const StorageSettings = () => {
|
||||
} = useProjectStorageConfigQuery({ projectRef })
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({
|
||||
orgSlug: organization?.slug,
|
||||
})
|
||||
const isFreeTier = isSuccessSubscription && subscription.plan.id === 'free'
|
||||
const isFreeTier = organization?.plan.id === 'free'
|
||||
|
||||
const [initialValues, setInitialValues] = useState<StorageSettingsState>({
|
||||
fileSizeLimit: 0,
|
||||
|
||||
@@ -2,7 +2,6 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import Link from 'next/link'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
@@ -31,8 +30,7 @@ const UpgradeToPro = ({
|
||||
}: UpgradeToProProps) => {
|
||||
const project = useSelectedProject()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const plan = subscription?.plan?.id
|
||||
const plan = organization?.plan?.id
|
||||
|
||||
const canUpdateSubscription = useCheckPermissions(
|
||||
PermissionAction.BILLING_WRITE,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { toast } from 'sonner'
|
||||
import type { ResponseError } from 'types/base'
|
||||
import { subscriptionKeys } from './keys'
|
||||
import type { SubscriptionTier } from './types'
|
||||
import { organizationKeys } from 'data/organizations/keys'
|
||||
|
||||
export type OrgSubscriptionUpdateVariables = {
|
||||
slug: string
|
||||
@@ -63,6 +64,8 @@ export const useOrgSubscriptionUpdateMutation = ({
|
||||
queryClient.invalidateQueries(subscriptionKeys.orgPlans(slug)),
|
||||
queryClient.invalidateQueries(usageKeys.orgUsage(slug)),
|
||||
queryClient.invalidateQueries(invoicesKeys.orgUpcomingPreview(slug)),
|
||||
queryClient.invalidateQueries(organizationKeys.detail(slug)),
|
||||
queryClient.invalidateQueries(organizationKeys.list()),
|
||||
])
|
||||
|
||||
await onSuccess?.(data, variables, context)
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from './useSelectedOrganization'
|
||||
|
||||
export function useCurrentOrgPlan() {
|
||||
const currentOrg = useSelectedOrganization()
|
||||
const { data, isLoading, isSuccess } = useOrgSubscriptionQuery({
|
||||
orgSlug: currentOrg?.slug,
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
if (!currentOrg) {
|
||||
return {
|
||||
plan: null,
|
||||
usageBillingEnabled: null,
|
||||
isLoading,
|
||||
isLoading: true,
|
||||
isSuccess: false,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
plan: data?.plan,
|
||||
usageBillingEnabled: data?.usage_billing_enabled,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
plan: currentOrg?.plan,
|
||||
usageBillingEnabled: currentOrg?.usage_billing_enabled,
|
||||
isLoading: false,
|
||||
isSuccess: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
import { maybeShowUpgradePrompt } from 'components/interfaces/Settings/Logs/Logs.utils'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useSelectedOrganization } from './useSelectedOrganization'
|
||||
|
||||
export const useUpgradePrompt = (from: string) => {
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const [showUpgradePrompt, setShowUpgradePrompt] = useState(false)
|
||||
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from, subscription?.plan?.id)
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from, organization?.plan?.id)
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldShowUpgradePrompt) {
|
||||
|
||||
@@ -24,6 +24,10 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
name: process.env.DEFAULT_ORGANIZATION_NAME || 'Default Organization',
|
||||
slug: 'default-org-slug',
|
||||
billing_email: 'billing@supabase.co',
|
||||
plan: {
|
||||
id: 'enterprise',
|
||||
name: 'Enterprise',
|
||||
},
|
||||
},
|
||||
]
|
||||
return res.status(200).json(response)
|
||||
|
||||
@@ -41,7 +41,6 @@ import {
|
||||
useProjectCreateMutation,
|
||||
} from 'data/projects/project-create-mutation'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { withAuth } from 'hooks/misc/withAuth'
|
||||
@@ -161,11 +160,9 @@ const Wizard: NextPageWithLayout = () => {
|
||||
}
|
||||
}, [currentOrg, projectCreationExperimentGroup, router])
|
||||
|
||||
const { data: orgSubscription } = useOrgSubscriptionQuery({ orgSlug: slug })
|
||||
|
||||
const isNotOnTeamOrEnterprisePlan = useMemo(
|
||||
() => !['team', 'enterprise'].includes(orgSubscription?.plan.id ?? ''),
|
||||
[orgSubscription]
|
||||
() => !['team', 'enterprise'].includes(currentOrg?.plan.id ?? ''),
|
||||
[currentOrg]
|
||||
)
|
||||
|
||||
const { data: allOverdueInvoices } = useOverdueInvoicesQuery({
|
||||
@@ -220,7 +217,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
const showNonProdFields = process.env.NEXT_PUBLIC_ENVIRONMENT !== 'prod'
|
||||
|
||||
const freePlanWithExceedingLimits =
|
||||
orgSubscription?.plan?.id === 'free' && hasMembersExceedingFreeTierLimit
|
||||
currentOrg?.plan?.id === 'free' && hasMembersExceedingFreeTierLimit
|
||||
|
||||
const isManagedByVercel = currentOrg?.managed_by === 'vercel-marketplace'
|
||||
|
||||
@@ -348,7 +345,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
dbPricingTierId: 'tier_free',
|
||||
// only set the compute size on pro+ plans. Free plans always use micro (nano in the future) size.
|
||||
dbInstanceSize:
|
||||
orgSubscription?.plan.id === 'free' ? undefined : (instanceSize as DesiredInstanceSize),
|
||||
currentOrg?.plan.id === 'free' ? undefined : (instanceSize as DesiredInstanceSize),
|
||||
dataApiExposedSchemas: !dataApi ? [] : undefined,
|
||||
dataApiUseApiSchema: !dataApi ? false : useApiSchema,
|
||||
postgresEngine: useOrioleDb ? availableOrioleVersion?.postgres_engine : postgresEngine,
|
||||
@@ -565,7 +562,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
</Panel.Content>
|
||||
)}
|
||||
|
||||
{orgSubscription?.plan && orgSubscription?.plan.id !== 'free' && (
|
||||
{currentOrg?.plan && currentOrg?.plan.id !== 'free' && (
|
||||
<Panel.Content>
|
||||
<FormField_Shadcn_
|
||||
control={form.control}
|
||||
|
||||
@@ -46,7 +46,6 @@ import {
|
||||
useProjectCreateMutation,
|
||||
} from 'data/projects/project-create-mutation'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { withAuth } from 'hooks/misc/withAuth'
|
||||
@@ -172,12 +171,8 @@ const WizardForm = () => {
|
||||
const { data: organizations, isSuccess: isOrganizationsSuccess } = useOrganizationsQuery()
|
||||
const currentOrg = organizations?.find((o: any) => o.slug === slug)
|
||||
|
||||
const { data: orgSubscription } = useOrgSubscriptionQuery({ orgSlug: slug })
|
||||
|
||||
const { data: allOverdueInvoices } = useOverdueInvoicesQuery({
|
||||
enabled:
|
||||
orgSubscription !== undefined &&
|
||||
!['team', 'enterprise'].includes(orgSubscription?.plan.id ?? ''),
|
||||
enabled: currentOrg !== undefined && !['team', 'enterprise'].includes(currentOrg.plan.id ?? ''),
|
||||
})
|
||||
const overdueInvoices = (allOverdueInvoices ?? []).filter(
|
||||
(x) => x.organization_id === currentOrg?.id
|
||||
@@ -221,7 +216,7 @@ const WizardForm = () => {
|
||||
const showNonProdFields = process.env.NEXT_PUBLIC_ENVIRONMENT !== 'prod'
|
||||
|
||||
const freePlanWithExceedingLimits =
|
||||
orgSubscription?.plan?.id === 'free' && hasMembersExceedingFreeTierLimit
|
||||
currentOrg?.plan?.id === 'free' && hasMembersExceedingFreeTierLimit
|
||||
|
||||
const isManagedByVercel = currentOrg?.managed_by === 'vercel-marketplace'
|
||||
|
||||
@@ -342,7 +337,7 @@ const WizardForm = () => {
|
||||
dbSql: sql,
|
||||
// only set the compute size on pro+ plans. Free plans always use micro (nano in the future) size.
|
||||
dbInstanceSize:
|
||||
orgSubscription?.plan.id === 'free' ? undefined : (instanceSize as DesiredInstanceSize),
|
||||
currentOrg?.plan.id === 'free' ? undefined : (instanceSize as DesiredInstanceSize),
|
||||
dataApiExposedSchemas: !dataApi ? [] : undefined,
|
||||
dataApiUseApiSchema: !dataApi ? false : useApiSchema,
|
||||
postgresEngine: useOrioleDb ? availableOrioleVersion?.postgres_engine : postgresEngine,
|
||||
@@ -782,7 +777,7 @@ const WizardForm = () => {
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{orgSubscription?.plan && orgSubscription?.plan.id !== 'free' && (
|
||||
{currentOrg?.plan.id !== 'free' && (
|
||||
<div className="py-5 border-b">
|
||||
<FormField_Shadcn_
|
||||
control={form.control}
|
||||
@@ -795,7 +790,7 @@ const WizardForm = () => {
|
||||
</div>
|
||||
}
|
||||
description={
|
||||
<div className="flex flex gap-2">
|
||||
<div className="flex gap-2">
|
||||
<Link
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
@@ -14,7 +14,6 @@ import NoPermission from 'components/ui/NoPermission'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useBackupsQuery } from 'data/database/backups-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useIsOrioleDb } from 'hooks/misc/useSelectedProject'
|
||||
@@ -55,9 +54,7 @@ const PITR = () => {
|
||||
const isOrioleDb = useIsOrioleDb()
|
||||
const { data: backups, error, isLoading, isError, isSuccess } = useBackupsQuery({ projectRef })
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
|
||||
const plan = subscription?.plan?.id
|
||||
const plan = organization?.plan?.id
|
||||
const isEnabled = backups?.pitr_enabled
|
||||
const isActiveHealthy = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useCloneBackupsQuery } from 'data/projects/clone-query'
|
||||
import { useCloneStatusQuery } from 'data/projects/clone-status-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useIsOrioleDb } from 'hooks/misc/useSelectedProject'
|
||||
@@ -33,7 +32,6 @@ import Panel from 'components/ui/Panel'
|
||||
import { projectSpecToMonthlyPrice } from 'components/interfaces/Database/Backups/RestoreToNewProject/RestoreToNewProject.utils'
|
||||
import { useDiskAttributesQuery } from 'data/config/disk-attributes-query'
|
||||
import { DiskType } from 'components/interfaces/DiskManagement/ui/DiskManagement.constants'
|
||||
import { InfraInstanceSize } from 'components/interfaces/DiskManagement/DiskManagement.types'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
|
||||
const RestoreToNewProjectPage: NextPageWithLayout = () => {
|
||||
@@ -63,8 +61,7 @@ RestoreToNewProjectPage.getLayout = (page) => (
|
||||
const RestoreToNewProject = () => {
|
||||
const { project } = useProjectContext()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isFreePlan = organization?.plan?.id === 'free'
|
||||
const isOrioleDb = useIsOrioleDb()
|
||||
|
||||
const [refetchInterval, setRefetchInterval] = useState<number | false>(false)
|
||||
@@ -80,7 +77,7 @@ const RestoreToNewProject = () => {
|
||||
isError,
|
||||
} = useCloneBackupsQuery({ projectRef: project?.ref }, { enabled: !isFreePlan })
|
||||
|
||||
const plan = subscription?.plan?.id
|
||||
const plan = organization?.plan?.id
|
||||
const isActiveHealthy = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
|
||||
|
||||
const isPermissionsLoaded = usePermissionsLoaded()
|
||||
@@ -95,7 +92,7 @@ const RestoreToNewProject = () => {
|
||||
const IS_PG15_OR_ABOVE = dbVersion >= 15
|
||||
const targetVolumeSizeGb = cloneBackups?.target_volume_size_gb
|
||||
const targetComputeSize = cloneBackups?.target_compute_size
|
||||
const planId = subscription?.plan?.id ?? 'free'
|
||||
const planId = organization?.plan?.id ?? 'free'
|
||||
const { data } = useDiskAttributesQuery({ projectRef: project?.ref })
|
||||
const storageType = data?.attributes?.type ?? 'gp3'
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ import {
|
||||
UpsertContentPayload,
|
||||
useContentUpsertMutation,
|
||||
} from 'data/content/content-upsert-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import useLogsQuery from 'hooks/analytics/useLogsQuery'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt'
|
||||
@@ -95,7 +94,6 @@ export const LogsExplorerPage: NextPageWithLayout = () => {
|
||||
})
|
||||
const query = content?.content.find((x) => x.id === queryId)
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const {
|
||||
params,
|
||||
logData,
|
||||
@@ -287,7 +285,7 @@ export const LogsExplorerPage: NextPageWithLayout = () => {
|
||||
}
|
||||
|
||||
const handleDateChange = ({ to, from }: DatePickerToFrom) => {
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from, subscription?.plan?.id)
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(from, organization?.plan?.id)
|
||||
|
||||
if (shouldShowUpgradePrompt) {
|
||||
setShowUpgradePrompt(!showUpgradePrompt)
|
||||
@@ -347,12 +345,12 @@ export const LogsExplorerPage: NextPageWithLayout = () => {
|
||||
// Show the prompt on page load based on query params
|
||||
useEffect(() => {
|
||||
if (its) {
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(its as string, subscription?.plan?.id)
|
||||
const shouldShowUpgradePrompt = maybeShowUpgradePrompt(its as string, organization?.plan?.id)
|
||||
if (shouldShowUpgradePrompt) {
|
||||
setShowUpgradePrompt(!showUpgradePrompt)
|
||||
}
|
||||
}
|
||||
}, [its, subscription])
|
||||
}, [its, organization])
|
||||
|
||||
return (
|
||||
<div className="w-full h-full mx-auto">
|
||||
|
||||
@@ -15,7 +15,6 @@ import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import ReportsLayout from 'components/layouts/ReportsLayout/ReportsLayout'
|
||||
import ShimmerLine from 'components/ui/ShimmerLine'
|
||||
import { useApiReport } from 'data/reports/api-report-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
|
||||
@@ -35,8 +34,7 @@ export const ApiReport: NextPageWithLayout = () => {
|
||||
refresh,
|
||||
} = report
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const plan = subscription?.plan
|
||||
const plan = organization?.plan
|
||||
|
||||
const handleDatepickerChange = ({ from, to }: DatePickerToFrom) => {
|
||||
mergeParams({
|
||||
|
||||
@@ -12,7 +12,6 @@ import ReportsLayout from 'components/layouts/ReportsLayout/ReportsLayout'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import ShimmerLine from 'components/ui/ShimmerLine'
|
||||
import { useStorageReport } from 'data/reports/storage-report-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { RefreshCw } from 'lucide-react'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
@@ -24,8 +23,7 @@ export const StorageReport: NextPageWithLayout = () => {
|
||||
|
||||
const { isLoading, refresh } = report
|
||||
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug })
|
||||
const plan = subscription?.plan
|
||||
const plan = organization?.plan
|
||||
|
||||
const handleDatepickerChange = ({ from, to }: DatePickerToFrom) => {
|
||||
report.mergeParams({
|
||||
|
||||
@@ -26,150 +26,6 @@ vi.mock('lib/gotrue', () => ({
|
||||
auth: { onAuthStateChange: vi.fn() },
|
||||
}))
|
||||
|
||||
// in the event that log metadata is not available, fall back to default renderer
|
||||
// generate test cases for each query type
|
||||
// const defaultRendererFallbacksCases = [
|
||||
// 'api',
|
||||
// 'database',
|
||||
// 'auth',
|
||||
// 'supavisor',
|
||||
// 'postgrest',
|
||||
// 'storage',
|
||||
// 'realtime',
|
||||
// ].map((queryType) => ({
|
||||
// testName: 'fallback to default render',
|
||||
// queryType,
|
||||
// tableName: undefined,
|
||||
// tableLog: logDataFixture({
|
||||
// event_message: 'some message',
|
||||
// metadata: undefined,
|
||||
// }),
|
||||
// selectionLog: logDataFixture({
|
||||
// metadata: undefined,
|
||||
// }),
|
||||
// tableTexts: [/some message/],
|
||||
// selectionTexts: [/some message/],
|
||||
// }))
|
||||
|
||||
// test.skip.each([
|
||||
// {
|
||||
// queryType: 'api',
|
||||
// tableName: undefined,
|
||||
// tableLog: logDataFixture({
|
||||
// path: 'some-path',
|
||||
// method: 'POST',
|
||||
// status_code: '400',
|
||||
// metadata: undefined,
|
||||
// }),
|
||||
// selectionLog: logDataFixture({
|
||||
// metadata: [{ request: [{ method: 'POST' }] }],
|
||||
// }),
|
||||
// tableTexts: [/POST/, /some\-path/, /400/],
|
||||
// selectionTexts: [/POST/, /Timestamp/, RegExp(`${new Date().getFullYear()}.+`, 'g')],
|
||||
// },
|
||||
|
||||
// {
|
||||
// queryType: 'database',
|
||||
// tableName: undefined,
|
||||
// tableLog: logDataFixture({
|
||||
// error_severity: 'ERROR',
|
||||
// event_message: 'some db event',
|
||||
// metadata: undefined,
|
||||
// }),
|
||||
// selectionLog: logDataFixture({
|
||||
// metadata: [
|
||||
// {
|
||||
// parsed: [
|
||||
// {
|
||||
// application_type: 'client backend',
|
||||
// error_severity: 'ERROR',
|
||||
// hint: 'some pg hint',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// }),
|
||||
// tableTexts: [/ERROR/, /some db event/],
|
||||
// selectionTexts: [
|
||||
// /client backend/,
|
||||
// /some pg hint/,
|
||||
// /ERROR/,
|
||||
// /Timestamp/,
|
||||
// RegExp(`${new Date().getFullYear()}.+`, 'g'),
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// queryType: 'auth',
|
||||
// tableName: undefined,
|
||||
// tableLog: logDataFixture({
|
||||
// event_message: 'some event_message',
|
||||
// level: 'info',
|
||||
// path: '/auth-path',
|
||||
// msg: 'some metadata_msg',
|
||||
// status: 300,
|
||||
// metadata: undefined,
|
||||
// }),
|
||||
// selectionLog: logDataFixture({
|
||||
// event_message: 'some event_message',
|
||||
// metadata: {
|
||||
// msg: 'some metadata_msg',
|
||||
// path: '/auth-path',
|
||||
// level: 'info',
|
||||
// status: 300,
|
||||
// },
|
||||
// }),
|
||||
// tableTexts: [/auth\-path/, /some metadata_msg/, /INFO/],
|
||||
// selectionTexts: [
|
||||
// /auth\-path/,
|
||||
// /some metadata_msg/,
|
||||
// /INFO/,
|
||||
// /300/,
|
||||
// /Timestamp/,
|
||||
// RegExp(`${new Date().getFullYear()}.+`, 'g'),
|
||||
// ],
|
||||
// },
|
||||
// ...defaultRendererFallbacksCases,
|
||||
// // these all use teh default selection/table renderers
|
||||
// ...['supavisor', 'postgrest', 'storage', 'realtime', 'supavisor'].map((queryType) => ({
|
||||
// queryType,
|
||||
// tableName: undefined,
|
||||
// tableLog: logDataFixture({
|
||||
// event_message: 'some message',
|
||||
// metadata: undefined,
|
||||
// }),
|
||||
// selectionLog: logDataFixture({
|
||||
// metadata: [{ some: [{ nested: 'value' }] }],
|
||||
// }),
|
||||
// tableTexts: [/some message/],
|
||||
// selectionTexts: [/some/, /nested/, /value/, RegExp(`${new Date().getFullYear()}.+`, 'g')],
|
||||
// })),
|
||||
// ])(
|
||||
// 'selection $queryType $queryType, $tableName , can display log data and metadata $testName',
|
||||
// async ({ queryType, tableName, tableLog, selectionLog, tableTexts, selectionTexts }) => {
|
||||
// render(<LogsPreviewer projectRef="123" queryType={queryType} tableName={tableName} />)
|
||||
// // reset mock so that we can check for selection call
|
||||
// get.mockClear()
|
||||
// for (const text of tableTexts) {
|
||||
// await screen.findByText(text)
|
||||
// }
|
||||
// const row = await screen.findByText(tableTexts[0])
|
||||
// fireEvent.click(row)
|
||||
// await waitFor(() => {
|
||||
// expect(get).toHaveBeenCalledWith(
|
||||
// expect.stringContaining('iso_timestamp_start'),
|
||||
// expect.anything()
|
||||
// )
|
||||
// expect(get).not.toHaveBeenCalledWith(
|
||||
// expect.stringContaining('iso_timestamp_end'),
|
||||
// expect.anything()
|
||||
// )
|
||||
// })
|
||||
// for (const text of selectionTexts) {
|
||||
// await screen.findAllByText(text)
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
|
||||
test.skip('Search will trigger a log refresh', async () => {
|
||||
render(<LogsPreviewer projectRef="123" queryType="auth" />)
|
||||
|
||||
@@ -220,249 +76,3 @@ test.skip('log event chart', async () => {
|
||||
|
||||
await waitFor(() => screen.queryByText(/some-uuid123/) === null)
|
||||
})
|
||||
|
||||
test.skip('s= query param will populate the search bar', async () => {
|
||||
// const router = routerMock
|
||||
})
|
||||
|
||||
test.skip('te= query param will populate the timestamp to input', async () => {
|
||||
// get time 20 mins before
|
||||
// const newDate = new Date()
|
||||
// newDate.setMinutes(new Date().getMinutes() - 20)
|
||||
// const iso = newDate.toISOString()
|
||||
// const router = defaultRouterMock()
|
||||
// router.query = { ...router.query, ite: iso }
|
||||
// useRouter.mockReturnValue(router)
|
||||
// useParams.mockReturnValue(router.query)
|
||||
// render(<LogsPreviewer projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// await waitFor(() => {
|
||||
// expect(get).toHaveBeenCalledWith(
|
||||
// expect.stringContaining(`iso_timestamp_end=${encodeURIComponent(iso)}`),
|
||||
// expect.anything()
|
||||
// )
|
||||
// })
|
||||
})
|
||||
|
||||
// test.skip('ts= query param will populate the timestamp from input', async () => {
|
||||
// // get time 20 mins before
|
||||
// const newDate = new Date()
|
||||
// newDate.setMinutes(new Date().getMinutes() - 20)
|
||||
// const iso = newDate.toISOString()
|
||||
// const router = defaultRouterMock()
|
||||
// router.query = { ...router.query, its: iso }
|
||||
// useRouter.mockReturnValue(router)
|
||||
// useParams.mockReturnValue(router.query)
|
||||
// render(<LogsPreviewer projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
|
||||
// await waitFor(() => {
|
||||
// expect(get).toHaveBeenCalledWith(
|
||||
// expect.stringContaining(`iso_timestamp_start=${encodeURIComponent(iso)}`),
|
||||
// expect.anything()
|
||||
// )
|
||||
// })
|
||||
// })
|
||||
|
||||
// test.skip('load older btn will fetch older logs', async () => {
|
||||
// get.mockImplementation((url) => {
|
||||
// if (url.includes('count')) {
|
||||
// return {}
|
||||
// }
|
||||
// return {
|
||||
// result: [logDataFixture({ id: 'some-uuid123', status_code: 200, method: 'GET' })],
|
||||
// }
|
||||
// })
|
||||
// render(<LogsPreviewer queryType="api" projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// // should display first log but not second
|
||||
// await waitFor(() => screen.getByText('GET'))
|
||||
// await expect(screen.findByText('POST')).rejects.toThrow()
|
||||
// get.mockResolvedValueOnce({
|
||||
// result: [logDataFixture({ id: 'some-uuid234', status_code: 203, method: 'POST' })],
|
||||
// })
|
||||
// // should display first and second log
|
||||
// userEvent.click(await screen.findByText('Load older'))
|
||||
// await screen.findByText('GET')
|
||||
// await screen.findByText('POST')
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('timestamp_end='), expect.anything())
|
||||
// })
|
||||
|
||||
// test.skip('bug: load older btn does not error out when previous page is empty', async () => {
|
||||
// // bugfix for https://sentry.io/organizations/supabase/issues/2903331460/?project=5459134&referrer=slack
|
||||
// get.mockImplementation((url) => {
|
||||
// if (url.includes('count')) {
|
||||
// return {}
|
||||
// }
|
||||
// return { result: [] }
|
||||
// })
|
||||
// render(<LogsPreviewer queryType="api" projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// userEvent.click(await screen.findByText('Load older'))
|
||||
// // NOTE: potential race condition, since we are asserting that something DOES NOT EXIST
|
||||
// // wait for 500s to make sure all ui logic is complete
|
||||
// // need to wrap in act because internal react state is changing during this time.
|
||||
// await act(async () => await wait(100))
|
||||
// // clicking load older multiple times should not give error
|
||||
// await waitFor(() => {
|
||||
// expect(screen.queryByText(/Sorry/)).toBeNull()
|
||||
// expect(screen.queryByText(/An error occurred/)).toBeNull()
|
||||
// expect(screen.queryByText(/undefined/)).toBeNull()
|
||||
// })
|
||||
// })
|
||||
|
||||
// test.skip('log event chart hide', async () => {
|
||||
// get.mockImplementation((url) => {
|
||||
// return { result: [] }
|
||||
// })
|
||||
// render(<LogsPreviewer projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// await screen.findByText(/No data/)
|
||||
// const toggle = await screen.findByText(/Chart/)
|
||||
// userEvent.click(toggle)
|
||||
// await expect(screen.findByText('Events')).rejects.toThrow()
|
||||
// })
|
||||
|
||||
// test.skip('bug: nav backwards with params change results in ui changing', async () => {
|
||||
// // bugfix for https://sentry.io/organizations/supabase/issues/2903331460/?project=5459134&referrer=slack
|
||||
// get.mockImplementation((url) => {
|
||||
// if (url.includes('count')) {
|
||||
// return {}
|
||||
// }
|
||||
// return { data: [] }
|
||||
// })
|
||||
// const { container, rerender } = render(
|
||||
// <LogsPreviewer projectRef="123" tableName={LogsTableName.EDGE} />
|
||||
// )
|
||||
// await expect(screen.findByDisplayValue('simple-query')).rejects.toThrow()
|
||||
// const router = defaultRouterMock()
|
||||
// router.query = { ...router.query, s: 'simple-query' }
|
||||
// useRouter.mockReturnValue(router)
|
||||
// useParams.mockReturnValue(router.query)
|
||||
// rerender(<LogsPreviewer projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// await screen.findByDisplayValue('simple-query')
|
||||
// })
|
||||
|
||||
// test.skip('bug: nav to explorer preserves newlines', async () => {
|
||||
// get.mockImplementation((url) => {
|
||||
// return { result: [] }
|
||||
// })
|
||||
// render(<LogsPreviewer queryType="api" projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// const button = screen.getByRole('link', { name: 'Explore via query' })
|
||||
// expect(button.href).toContain(encodeURIComponent('\n'))
|
||||
// })
|
||||
|
||||
// test.skip('filters alter generated query', async () => {
|
||||
// render(<LogsPreviewer queryType="api" projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// userEvent.click(await screen.findByRole('button', { name: 'Status' }))
|
||||
// userEvent.click(await screen.findByText(/500 error codes/))
|
||||
// userEvent.click(await screen.findByText(/200 codes/))
|
||||
// userEvent.click(await screen.findByText(/Apply/))
|
||||
// await waitFor(() => {
|
||||
// // counts are adjusted
|
||||
// expect(get).toHaveBeenCalledWith(
|
||||
// expect.stringMatching(/count.+\*.+as.count.+where.+500.+599/),
|
||||
// expect.anything()
|
||||
// )
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('500'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('599'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('200'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('299'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('where'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('and'), expect.anything())
|
||||
// })
|
||||
|
||||
// // should be able to clear the filters
|
||||
// userEvent.click(await screen.findByRole('button', { name: 'Status' }))
|
||||
// userEvent.click(await screen.findByRole('button', { name: 'Clear' }))
|
||||
// // get.mockClear()
|
||||
|
||||
// userEvent.click(await screen.findByRole('button', { name: 'Status' }))
|
||||
// userEvent.click(await screen.findByText(/400 codes/))
|
||||
// userEvent.click(await screen.findByText(/Apply/))
|
||||
|
||||
// await waitFor(() => {
|
||||
// // counts are adjusted
|
||||
// expect(get).not.toHaveBeenCalledWith(
|
||||
// expect.stringMatching(/count.+\*.+as.count.+where.+500.+599/),
|
||||
// expect.anything()
|
||||
// )
|
||||
// expect(get).toHaveBeenCalledWith(
|
||||
// expect.stringMatching(/count.+\*.+as.count.+where.+400.+499/),
|
||||
// expect.anything()
|
||||
// )
|
||||
// expect(get).not.toHaveBeenCalledWith(expect.stringContaining('500'), expect.anything())
|
||||
// expect(get).not.toHaveBeenCalledWith(expect.stringContaining('599'), expect.anything())
|
||||
// expect(get).not.toHaveBeenCalledWith(expect.stringContaining('200'), expect.anything())
|
||||
// expect(get).not.toHaveBeenCalledWith(expect.stringContaining('299'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('400'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('499'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('where'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('and'), expect.anything())
|
||||
// })
|
||||
// })
|
||||
|
||||
// test.skip('filters accept filterOverride', async () => {
|
||||
// render(
|
||||
// <LogsPreviewer
|
||||
// queryType="api"
|
||||
// projectRef="123"
|
||||
// tableName={LogsTableName.FUNCTIONS}
|
||||
// filterOverride={{ 'my.nestedkey': 'myvalue' }}
|
||||
// />
|
||||
// )
|
||||
|
||||
// await waitFor(() => {
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('my.nestedkey'), expect.anything())
|
||||
// expect(get).toHaveBeenCalledWith(expect.stringContaining('myvalue'), expect.anything())
|
||||
// })
|
||||
// })
|
||||
|
||||
// describe.each(['free', 'pro', 'team', 'enterprise'])('upgrade modal for %s', (key) => {
|
||||
// beforeEach(() => {
|
||||
// useOrgSubscriptionQuery.mockReturnValue({
|
||||
// data: {
|
||||
// plan: {
|
||||
// id: key,
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// })
|
||||
// test.skip('based on query params', async () => {
|
||||
// const router = defaultRouterMock()
|
||||
// router.query = {
|
||||
// ...router.query,
|
||||
// q: 'some_query',
|
||||
// its: dayjs().subtract(4, 'months').toISOString(),
|
||||
// ite: dayjs().toISOString(),
|
||||
// }
|
||||
// useRouter.mockReturnValue(router)
|
||||
// useParams.mockReturnValue(router.query)
|
||||
// render(<LogsPreviewer projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// // await screen.findByText('Log retention') // assert modal title is present
|
||||
// })
|
||||
// })
|
||||
|
||||
// test.skip('datepicker onChange will set the query params for outbound api request', async () => {
|
||||
// useOrgSubscriptionQuery.mockReturnValue({
|
||||
// data: {
|
||||
// plan: {
|
||||
// id: 'enterprise',
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// get.mockImplementation((url) => {
|
||||
// return { result: [] }
|
||||
// })
|
||||
// render(<LogsPreviewer queryType="api" projectRef="123" tableName={LogsTableName.EDGE} />)
|
||||
// // renders time locally
|
||||
// userEvent.click(await screen.findByText('Custom'))
|
||||
// // inputs with local time
|
||||
// const toHH = await screen.findByDisplayValue('23')
|
||||
// userEvent.clear(toHH)
|
||||
// userEvent.type(toHH, '12')
|
||||
// userEvent.click(await screen.findByText('20'), { selector: '.react-datepicker__day' })
|
||||
// userEvent.click(await screen.findByText('21'), { selector: '.react-datepicker__day' })
|
||||
// userEvent.click(await screen.findByText('Apply'))
|
||||
// await waitFor(() => {
|
||||
// expect(get).toHaveBeenCalledWith(
|
||||
// expect.stringMatching(/.+select.+event_message.+iso_timestamp_end=/),
|
||||
// expect.anything()
|
||||
// )
|
||||
// })
|
||||
// })
|
||||
@@ -13,6 +13,11 @@ export interface Organization {
|
||||
restriction_data: Record<string, string> | null
|
||||
managed_by: 'supabase' | 'vercel-marketplace' | 'aws-marketplace'
|
||||
partner_id?: string
|
||||
plan: {
|
||||
id: 'free' | 'pro' | 'team' | 'enterprise'
|
||||
name: string
|
||||
}
|
||||
usage_billing_enabled: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-1
@@ -5963,6 +5963,11 @@ export interface components {
|
||||
is_owner: boolean
|
||||
name: string
|
||||
opt_in_tags: string[]
|
||||
plan: {
|
||||
/** @enum {string} */
|
||||
id: 'free' | 'pro' | 'team' | 'enterprise'
|
||||
name: string
|
||||
}
|
||||
restriction_data: {
|
||||
[key: string]: string
|
||||
} | null
|
||||
@@ -5971,6 +5976,7 @@ export interface components {
|
||||
slug: string
|
||||
stripe_customer_id: string | null
|
||||
subscription_id: string | null
|
||||
usage_billing_enabled: boolean
|
||||
}
|
||||
OrganizationRoleResponse: {
|
||||
org_scoped_roles: {
|
||||
@@ -6033,10 +6039,16 @@ export interface components {
|
||||
id: number
|
||||
name: string
|
||||
opt_in_tags: string[]
|
||||
plan: {
|
||||
/** @enum {string} */
|
||||
id?: 'free' | 'pro' | 'team' | 'enterprise'
|
||||
name?: string
|
||||
}
|
||||
projects: components['schemas']['OrganizationSlugProject'][]
|
||||
restriction_data: Record<string, never> | null
|
||||
restriction_status: Record<string, never> | null
|
||||
slug: string
|
||||
usage_billing_enabled: boolean
|
||||
}
|
||||
OrgDocumentUrlResponse: {
|
||||
fileUrl: string
|
||||
@@ -13785,7 +13797,7 @@ export interface operations {
|
||||
UsageApiController_getApiCounts: {
|
||||
parameters: {
|
||||
query: {
|
||||
interval: 'minutely' | 'hourly' | 'daily'
|
||||
interval: 'minutely' | 'hourly' | 'daily' | '15min' | '30min' | '1hr' | '3hr' | '1day'
|
||||
}
|
||||
header?: never
|
||||
path: {
|
||||
|
||||
Reference in new issue
Block a user