mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 11:25:06 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Bug fix (regression). ## What is the current behavior? #44172 replaced the old `isAwsK8s`-based check with an entitlement-based check (`useCheckEntitlements('project_pausing', ...)`) for the pause project button. In doing so, it also introduced an explicit `isBranch` condition that unconditionally disables the pause button and shows "Branch projects cannot be paused" for any branch project. Prior to #44172, branches were exempt from the paid-plan pause restriction entirely — the old `isPaidAndNotAwsK8s` computation (`!isBranch && !isFreePlan && !isAwsK8s`) evaluated to `false` whenever `isBranch` was `true`, so branch projects were never blocked by that check. The new code changed this exemption into a hard block, which is the regression: branches can no longer be paused at all. ## What is the new behavior? Restore the original exemption: branch projects bypass the `project_pausing` entitlement check (as they did the old AWS K8s check), instead of being unconditionally blocked. The pause button and tooltip for branches now only take into account permissions, project status, and whether the project is active — matching pre-#44172 behavior. ```tsx const buttonDisabled = (!isBranch && !projectPausingAllowedInOrg) || project === undefined || isPaused || !canPauseProject || !isProjectActive ``` ## Additional context Regression introduced in https://github.com/supabase/supabase/pull/44172. --- _Generated by [Claude Code](https://claude.ai/code/session_01VdtDMaXzz8zgqQHSMbtMAA)_ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Updated project pause availability so the button now reflects the correct conditions for branch and non-branch projects. * Improved pause-related tooltips to show more accurate messaging based on plan type and project status, including when pausing may not be available on free plans. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
123 lines
4.3 KiB
TypeScript
123 lines
4.3 KiB
TypeScript
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 { useIsProjectActive, useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
|
import { PROJECT_STATUS } from '@/lib/constants'
|
|
|
|
const PauseProjectButton = () => {
|
|
const router = useRouter()
|
|
const { data: project } = useSelectedProjectQuery()
|
|
const { data: organization } = useSelectedOrganizationQuery()
|
|
const { setProjectStatus } = useSetProjectStatus()
|
|
|
|
const isProjectActive = useIsProjectActive()
|
|
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 { 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 project')
|
|
}
|
|
pauseProject({ ref: projectRef })
|
|
}
|
|
|
|
const buttonDisabled =
|
|
(!isBranch && !projectPausingAllowedInOrg) ||
|
|
project === undefined ||
|
|
isPaused ||
|
|
!canPauseProject ||
|
|
!isProjectActive
|
|
|
|
function getTooltipText() {
|
|
if (isPaused) return 'Your project is already paused'
|
|
if (!canPauseProject) return 'You need additional permissions to pause this project'
|
|
if (isProjectUnhealthy)
|
|
return 'Your project is unhealthy — restart it instead to restore normal operation'
|
|
if (!isProjectActive) return 'Unable to pause project as project is not active'
|
|
if (!isBranch && !projectPausingAllowedInOrg && !isFreePlan)
|
|
return 'Projects on a paid plan will always be running'
|
|
return undefined
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<ButtonTooltip
|
|
variant="default"
|
|
icon={<CirclePause />}
|
|
onClick={() => setIsModalOpen(true)}
|
|
loading={isPausing}
|
|
disabled={buttonDisabled}
|
|
tooltip={{
|
|
content: {
|
|
side: 'bottom',
|
|
text: getTooltipText(),
|
|
},
|
|
}}
|
|
>
|
|
Pause project
|
|
</ButtonTooltip>
|
|
|
|
<AlertDialog open={isModalOpen} onOpenChange={setIsModalOpen}>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Pause project?</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
This project will be unavailable while paused. Paused projects can be resumed for 90
|
|
days. After that, backups remain available to download.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel disabled={isPausing}>Cancel</AlertDialogCancel>
|
|
<AlertDialogAction disabled={isPausing} onClick={requestPauseProject} variant="danger">
|
|
{isPausing ? 'Pausing project...' : 'Pause project'}
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default PauseProjectButton
|