| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- import { PermissionAction } from '@supabase/shared-types/out/constants'
- import { useFlag } from 'common'
- import { ChevronDown, RefreshCw } from 'lucide-react'
- import { useRouter } from 'next/router'
- import { useState } from 'react'
- import { toast } from 'sonner'
- import {
- Button,
- cn,
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
- } from 'ui'
- import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
- import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
- import { useSetProjectStatus } from '@/data/projects/project-detail-query'
- import { useProjectRestartMutation } from '@/data/projects/project-restart-mutation'
- import { useProjectRestartServicesMutation } from '@/data/projects/project-restart-services-mutation'
- import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
- import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
- import {
- useIsAwsK8sCloudProvider,
- useIsProjectActive,
- useSelectedProjectQuery,
- } from '@/hooks/misc/useSelectedProject'
- import { PROJECT_STATUS } from '@/lib/constants'
- import { type ResponseError } from '@/types'
- const RestartServerButton = () => {
- const router = useRouter()
- const { data: project } = useSelectedProjectQuery()
- const isProjectActive = useIsProjectActive()
- const canRestart = isProjectActive || project?.status === PROJECT_STATUS.ACTIVE_UNHEALTHY
- const isAwsK8s = useIsAwsK8sCloudProvider()
- const { setProjectStatus } = useSetProjectStatus()
- const [serviceToRestart, setServiceToRestart] = useState<'project' | 'database'>()
- const { projectSettingsRestartProject } = useIsFeatureEnabled([
- 'project_settings:restart_project',
- ])
- const projectRef = project?.ref ?? ''
- const projectRegion = project?.region ?? ''
- const projectRestartDisabled = useFlag('disableProjectRestarts')
- const { can: canRestartProject } = useAsyncCheckPermissions(
- PermissionAction.INFRA_EXECUTE,
- 'reboot'
- )
- const { mutate: restartProject, isPending: isRestartingProject } = useProjectRestartMutation({
- onSuccess: () => {
- onRestartSuccess()
- },
- onError: (error) => {
- onRestartFailed(error, 'project')
- },
- })
- const { mutate: restartProjectServices, isPending: isRestartingServices } =
- useProjectRestartServicesMutation({
- onSuccess: () => {
- onRestartSuccess()
- },
- onError: (error) => {
- onRestartFailed(error, 'database')
- },
- })
- const isLoading = isRestartingProject || isRestartingServices
- const hasRestartDropdown = canRestartProject && canRestart && !projectRestartDisabled
- const requestProjectRestart = () => {
- if (!canRestartProject) {
- return toast.error('You do not have the required permissions to restart this project')
- }
- restartProject({ ref: projectRef })
- }
- const requestDatabaseRestart = async () => {
- if (!canRestartProject) {
- return toast.error('You do not have the required permissions to restart this project')
- }
- restartProjectServices({ ref: projectRef, region: projectRegion, services: ['postgresql'] })
- }
- const onRestartFailed = (error: ResponseError, type: string) => {
- toast.error(`Unable to restart ${type}: ${error.message}`)
- setServiceToRestart(undefined)
- }
- const onRestartSuccess = () => {
- setProjectStatus({ ref: projectRef, status: PROJECT_STATUS.RESTARTING })
- toast.success('Restarting server...')
- router.push(`/project/${projectRef}`)
- setServiceToRestart(undefined)
- }
- return (
- <>
- {projectSettingsRestartProject ? (
- <div className="flex w-full @lg:w-auto">
- <ButtonTooltip
- type="default"
- className={cn(
- 'flex-1 px-3 hover:z-10 @lg:flex-none',
- canRestartProject && canRestart ? 'rounded-r-none' : ''
- )}
- disabled={
- project === undefined ||
- !canRestartProject ||
- !canRestart ||
- projectRestartDisabled ||
- isAwsK8s
- }
- onClick={() => setServiceToRestart('project')}
- tooltip={{
- content: {
- side: 'bottom',
- text: projectRestartDisabled
- ? 'Project restart is currently disabled'
- : !canRestartProject
- ? 'You need additional permissions to restart this project'
- : !canRestart
- ? 'Unable to restart project as project is not active'
- : isAwsK8s
- ? 'Project restart is not supported for AWS (Revamped) projects'
- : undefined,
- },
- }}
- >
- Restart project
- </ButtonTooltip>
- {hasRestartDropdown && (
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Button
- type="default"
- className="shrink-0 rounded-l-none px-[4px] py-[5px] -ml-px"
- icon={<ChevronDown />}
- disabled={!canRestartProject}
- />
- </DropdownMenuTrigger>
- <DropdownMenuContent align="end" side="bottom">
- <DropdownMenuItem
- key="database"
- disabled={isLoading}
- onClick={() => {
- setServiceToRestart('database')
- }}
- >
- <div className="space-y-0.5">
- <p className="block text-foreground">Fast database reboot</p>
- <p className="block text-foreground-light">
- Restarts only the database. Faster, but may not be able to recover from all
- failure modes.
- </p>
- </div>
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
- )}
- </div>
- ) : (
- <Button
- type="default"
- icon={<RefreshCw />}
- className="w-full @lg:w-auto"
- disabled={isLoading}
- onClick={() => {
- setServiceToRestart('database')
- }}
- >
- Restart database
- </Button>
- )}
- <ConfirmationModal
- visible={serviceToRestart !== undefined}
- variant="destructive"
- title={`Restart ${serviceToRestart}`}
- description={
- <>
- Are you sure you want to restart your {serviceToRestart}? There will be a few minutes of
- downtime.
- </>
- }
- confirmLabel="Restart"
- confirmLabelLoading="Restarting"
- loading={isLoading}
- onCancel={() => setServiceToRestart(undefined)}
- onConfirm={async () => {
- if (serviceToRestart === 'project') {
- await requestProjectRestart()
- } else if (serviceToRestart === 'database') {
- await requestDatabaseRestart()
- }
- }}
- />
- </>
- )
- }
- export default RestartServerButton
|