import { PermissionAction } from '@supabase/shared-types/out/constants' import { CirclePause } from 'lucide-react' import { useRouter } from 'next/router' import { useState } from 'react' import { toast } from 'sonner' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from 'ui' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { useSetProjectStatus } from '@/data/projects/project-detail-query' import { useProjectPauseMutation } from '@/data/projects/project-pause-mutation' import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { useIsHighAvailability, useIsProjectActive, useSelectedProjectQuery, } from '@/hooks/misc/useSelectedProject' import { PROJECT_STATUS } from '@/lib/constants' export const PauseProjectButton = () => { const router = useRouter() const { data: project } = useSelectedProjectQuery() const { data: organization } = useSelectedOrganizationQuery() const { setProjectStatus } = useSetProjectStatus() const isProjectActive = useIsProjectActive() const isHighAvailability = useIsHighAvailability() const isProjectUnhealthy = project?.status === PROJECT_STATUS.ACTIVE_UNHEALTHY const [isModalOpen, setIsModalOpen] = useState(false) const projectRef = project?.ref ?? '' const isPaused = project?.status === PROJECT_STATUS.INACTIVE const { can: canPauseProject } = useAsyncCheckPermissions( PermissionAction.INFRA_EXECUTE, 'queue_jobs.projects.pause' ) const isFreePlan = organization?.plan.id === 'free' const isBranch = Boolean(project?.parent_project_ref) const entityLabel = isBranch ? 'branch' : 'project' const { hasAccess: projectPausingAllowedInOrg } = useCheckEntitlements( 'project_pausing', organization?.slug ) const { mutate: pauseProject, isPending: isPausing } = useProjectPauseMutation({ onSuccess: (_, variables) => { setProjectStatus({ ref: variables.ref, status: PROJECT_STATUS.PAUSING }) toast.success('Pausing project...') router.push(`/project/${projectRef}`) }, }) const requestPauseProject = () => { if (!canPauseProject) { return toast.error(`You do not have the required permissions to pause this ${entityLabel}`) } pauseProject({ ref: projectRef }) } const buttonDisabled = (!isBranch && !projectPausingAllowedInOrg) || project === undefined || isPaused || !canPauseProject || !isProjectActive || isHighAvailability function getTooltipText() { if (isPaused) { return `Your ${entityLabel} is already paused` } else if (isHighAvailability) { return 'Pausing is unavailable on High Availability projects' } else if (!canPauseProject) { return `You need additional permissions to pause this ${entityLabel}` } else if (isProjectUnhealthy) { return `Your ${entityLabel} is unhealthy — restart it instead to restore normal operation` } else if (!isProjectActive) { return `Unable to pause ${entityLabel} as ${entityLabel} is not active` } else if (!isBranch && !projectPausingAllowedInOrg && !isFreePlan) { return 'Projects on a paid plan will always be running' } else { return undefined } } return ( <> } onClick={() => setIsModalOpen(true)} loading={isPausing} disabled={buttonDisabled} tooltip={{ content: { side: 'bottom', text: getTooltipText(), }, }} > Pause {entityLabel} Pause {entityLabel}? This {entityLabel} will be unavailable while paused. Paused {entityLabel} can be resumed for up to 1 year. After that, backups remain available to download. Cancel {isPausing ? `Pausing ${entityLabel}...` : `Pause ${entityLabel}`} ) }