import { useRouter } from 'next/router' import { MouseEvent, useState } from 'react' import { components } from 'api-types' import { getAddons } from 'components/interfaces/Billing/Subscription/Subscription.utils' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query' import { ProjectAddonVariantMeta } from 'data/subscriptions/types' import { getCloudProviderArchitecture } from 'lib/cloudprovider-utils' import { INSTANCE_MICRO_SPECS } from 'lib/constants' import { Button, HoverCard, HoverCardContent, HoverCardTrigger, Separator } from 'ui' import { ComputeBadge } from 'ui-patterns/ComputeBadge' import ShimmeringLoader from './ShimmeringLoader' import { useFlag } from 'hooks/ui/useFlag' const Row = ({ label, stat }: { label: string; stat: React.ReactNode | string }) => { return (
{label} {stat}
) } interface ComputeBadgeWrapperProps { project: { ref?: string organization_slug?: string cloud_provider?: string infra_compute_size?: components['schemas']['DbInstanceSize'] } } export const ComputeBadgeWrapper = ({ project }: ComputeBadgeWrapperProps) => { const router = useRouter() // handles the state of the hover card // once open it will fetch the addons const [open, setOpenState] = useState(false) const diskAndComputeFormEnabled = useFlag('diskAndComputeForm') // returns hardcoded values for infra const cpuArchitecture = getCloudProviderArchitecture(project.cloud_provider) // fetches addons const { data: addons, isLoading: isLoadingAddons } = useProjectAddonsQuery( { projectRef: project.ref, }, { enabled: open } ) const selectedAddons = addons?.selected_addons ?? [] const { computeInstance } = getAddons(selectedAddons) const computeInstanceMeta = computeInstance?.variant?.meta const meta = ( computeInstanceMeta === undefined && project.infra_compute_size === 'micro' ? INSTANCE_MICRO_SPECS : computeInstanceMeta ) as ProjectAddonVariantMeta const availableCompute = addons?.available_addons.find( (addon) => addon.name === 'Compute Instance' )?.variants const navigateToAddons = (e: MouseEvent) => { // These are required as the button is inside an a tag // side note: not the best idea to nest clickables 🥲 e.preventDefault() e.stopPropagation() if (diskAndComputeFormEnabled) { router.push(`/project/${project?.ref}/settings/compute-and-disk`) } else { router.push(`/project/${project?.ref}/settings/addons?panel=computeInstance`) } } const highestComputeAvailable = availableCompute?.[availableCompute.length - 1].identifier const isHighestCompute = project?.infra_compute_size === highestComputeAvailable?.replace('ci_', '') const { data, isLoading: isLoadingSubscriptions } = useOrgSubscriptionQuery( { orgSlug: project?.organization_slug }, { enabled: open } ) const isEligibleForFreeUpgrade = data?.plan.id !== 'free' && project?.infra_compute_size === 'nano' const isLoading = isLoadingAddons || isLoadingSubscriptions if (!project?.infra_compute_size) return null return ( <> setOpenState(!open)} openDelay={280}>
Compute size
{isLoading ? ( <>
) : ( <>
{meta !== undefined ? ( <> ) : ( <> {/* meta is only undefined for nano sized compute */} )}
)}
{(!isHighestCompute || isEligibleForFreeUpgrade) && ( <>

{isEligibleForFreeUpgrade ? 'Free upgrade to Micro available' : 'Unlock more compute'}

{isEligibleForFreeUpgrade ? 'Paid plans include a free upgrade to Micro compute.' : 'Scale your project up to 64 cores and 256 GB RAM.'}

)}
) }