mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 15:49:09 +03:00
* Update the design of the sonner toasts. Add the close button by default. * Migrate studio and www apps to use the SonnerToaster. * Migrate all toasts from studio. * Migrate all leftover toasts in studio. * Add a new toast component with progress. Use it in studio. * Migrate the design-system app. * Refactor the consent toast to use sonner. * Switch docs to use the new sonner toasts. * Remove toast examples from the design-system app. * Remove all toast-related components and old code. * Fix the progress bar in the toast progress component. Also make the bottom components vertically centered. * Fix the width of the toast progress. * Use text-foreground-lighter instead of muted for ToastProgress text * Rename ToastProgress to SonnerProgress. * Shorten the text in sonner progress. * Use the correct classes for the close button. Add a const var for the default toast duration. Remove the custom width class from sonner. * Set the position for all progress toasts to bottom right. Set the duration for all toasts to the default (when reusing a toast id from loading/progress toast, the duration is set to infinity). * Fix the playwright tests. * Refactor imports to use ui instead of @ui. * Change all imports of react-hot-toast with sonner. These components were merged since the last commit to this branch. * Remove react-hot-toast lib. --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com> Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com>
179 lines
6.1 KiB
TypeScript
179 lines
6.1 KiB
TypeScript
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
|
import { useQueryClient } from '@tanstack/react-query'
|
|
import { useRouter } from 'next/router'
|
|
import { useState } from 'react'
|
|
import { toast } from 'sonner'
|
|
|
|
import {
|
|
useIsProjectActive,
|
|
useProjectContext,
|
|
} from 'components/layouts/ProjectLayout/ProjectContext'
|
|
import { useProjectRestartMutation } from 'data/projects/project-restart-mutation'
|
|
import { useProjectRestartServicesMutation } from 'data/projects/project-restart-services-mutation'
|
|
import { setProjectStatus } from 'data/projects/projects-query'
|
|
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
|
import { useFlag } from 'hooks/ui/useFlag'
|
|
import { ChevronDown } from 'lucide-react'
|
|
import {
|
|
Button,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
TooltipContent_Shadcn_,
|
|
TooltipTrigger_Shadcn_,
|
|
Tooltip_Shadcn_,
|
|
} from 'ui'
|
|
import ConfirmModal from 'ui-patterns/Dialogs/ConfirmDialog'
|
|
|
|
const RestartServerButton = () => {
|
|
const router = useRouter()
|
|
const queryClient = useQueryClient()
|
|
const { project } = useProjectContext()
|
|
const isProjectActive = useIsProjectActive()
|
|
const [serviceToRestart, setServiceToRestart] = useState<'project' | 'database'>()
|
|
|
|
const projectRef = project?.ref ?? ''
|
|
const projectRegion = project?.region ?? ''
|
|
|
|
const projectRestartDisabled = useFlag('disableProjectRestarts')
|
|
const canRestartProject = useCheckPermissions(PermissionAction.INFRA_EXECUTE, 'reboot')
|
|
|
|
const { mutate: restartProject, isLoading: isRestartingProject } = useProjectRestartMutation({
|
|
onSuccess: () => {
|
|
onRestartSuccess()
|
|
},
|
|
onError: (error) => {
|
|
onRestartFailed(error, 'project')
|
|
},
|
|
})
|
|
const { mutate: restartProjectServices, isLoading: isRestartingServices } =
|
|
useProjectRestartServicesMutation({
|
|
onSuccess: () => {
|
|
onRestartSuccess()
|
|
},
|
|
onError: (error) => {
|
|
onRestartFailed(error, 'database')
|
|
},
|
|
})
|
|
|
|
const isLoading = isRestartingProject || isRestartingServices
|
|
|
|
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: any, type: string) => {
|
|
toast.error(`Unable to restart ${type}: ${error.message}`)
|
|
setServiceToRestart(undefined)
|
|
}
|
|
|
|
const onRestartSuccess = () => {
|
|
setProjectStatus(queryClient, projectRef, 'RESTARTING')
|
|
toast.success('Restarting server...')
|
|
router.push(`/project/${projectRef}`)
|
|
setServiceToRestart(undefined)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Tooltip_Shadcn_>
|
|
<TooltipTrigger_Shadcn_ asChild>
|
|
<div className="flex items-center">
|
|
<Button
|
|
type="default"
|
|
className={`px-3 ${canRestartProject && isProjectActive ? 'rounded-r-none' : ''}`}
|
|
disabled={
|
|
project === undefined ||
|
|
!canRestartProject ||
|
|
!isProjectActive ||
|
|
projectRestartDisabled
|
|
}
|
|
onClick={() => setServiceToRestart('project')}
|
|
>
|
|
Restart project
|
|
</Button>
|
|
{canRestartProject && isProjectActive && !projectRestartDisabled && (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
type="default"
|
|
className="rounded-l-none px-[4px] py-[5px]"
|
|
icon={<ChevronDown />}
|
|
disabled={!canRestartProject}
|
|
/>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" side="bottom">
|
|
<DropdownMenuItem
|
|
key="database"
|
|
disabled={isLoading}
|
|
onClick={() => {
|
|
setServiceToRestart('database')
|
|
}}
|
|
>
|
|
<div className="space-y-1">
|
|
<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>
|
|
</TooltipTrigger_Shadcn_>
|
|
{((project !== undefined && (!canRestartProject || !isProjectActive)) ||
|
|
projectRestartDisabled) && (
|
|
<TooltipContent_Shadcn_ side="bottom">
|
|
{projectRestartDisabled
|
|
? 'Project restart is currently disabled'
|
|
: !canRestartProject
|
|
? 'You need additional permissions to restart this project'
|
|
: !isProjectActive
|
|
? 'Unable to restart project as project is not active'
|
|
: ''}
|
|
</TooltipContent_Shadcn_>
|
|
)}
|
|
</Tooltip_Shadcn_>
|
|
|
|
<ConfirmModal
|
|
danger
|
|
visible={serviceToRestart !== undefined}
|
|
title={`Restart ${serviceToRestart}`}
|
|
// @ts-ignore
|
|
description={
|
|
<>
|
|
Are you sure you want to restart the{' '}
|
|
<span className="text-foreground">{serviceToRestart}</span>? There will be a few minutes
|
|
of downtime.
|
|
</>
|
|
}
|
|
buttonLabel="Restart"
|
|
buttonLoadingLabel="Restarting"
|
|
onSelectCancel={() => setServiceToRestart(undefined)}
|
|
onSelectConfirm={async () => {
|
|
if (serviceToRestart === 'project') {
|
|
await requestProjectRestart()
|
|
} else if (serviceToRestart === 'database') {
|
|
await requestDatabaseRestart()
|
|
}
|
|
}}
|
|
/>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default RestartServerButton
|