Files
supabase/apps/studio/components/layouts/ProjectLayout/RestoreFailedState.tsx
Danny White 476d4a5851 refactor(ui): drop redundant Button variant="default" props (#50161)
## What kind of change does this PR introduce?

Mechanical cleanup on top of the Button default-variant change (#50160).

## What is the current behavior?

Many callsites still pass `variant="default"` even though that is now
the component default.

## What is the new behavior?

Removes redundant static `variant="default"` from legacy `Button` and
`ButtonTooltip` callsites. Keeps explicit defaults where they document
the API:

- `button-default.tsx` and `button-sizes.tsx` demos
- `DocsButton`, which pins neutral styling at the wrapper boundary

## To test

Studio:

- [Auth → Rate
Limits](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/auth/rate-limits):
dirty the form so Cancel appears; Cancel stays neutral, Save stays green
- [Project Settings → API
Keys](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/settings/api-keys):
`DocsButton` in the header actions stays neutral

Design system:

- [Design system →
Button](https://design-system-git-dnywh-dc924ac1-supabase.vercel.app/design-system/docs/components/button):
`button-default` / `button-sizes` still show explicit default styling;
Primary (green) is restricted to the Primary section (and `asChild`)

WWW:

- [www → Brand
assets](https://zone-www-dot-com-git-dnywh-dc924ac1-supabase.vercel.app/brand-assets):
Download logo kit / Download button kit stay neutral
2026-09-11 17:05:26 +10:00

174 lines
6.6 KiB
TypeScript

import { PermissionAction, SupportCategories } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { Download, MoreVertical, Trash } from 'lucide-react'
import { useState } from 'react'
import {
Button,
CriticalIcon,
Dialog,
DialogContent,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
} from 'ui'
import { DeleteProjectModal } from '@/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal'
import { SupportLink } from '@/components/interfaces/Support/SupportLink'
import { LogicalBackupCliInstructions } from '@/components/layouts/ProjectLayout/LogicalBackupCliInstructions'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { DropdownMenuItemTooltip } from '@/components/ui/DropdownMenuItemTooltip'
import { InlineLink } from '@/components/ui/InlineLink'
import { useBackupDownloadMutation } from '@/data/database/backup-download-mutation'
import { useDownloadableBackupQuery } from '@/data/database/backup-query'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
export const RestoreFailedState = () => {
const { ref } = useParams()
const { data: project } = useSelectedProjectQuery()
const [visible, setVisible] = useState(false)
const [showCliBackup, setShowCliBackup] = useState(false)
const { can: canDeleteProject } = useAsyncCheckPermissions(PermissionAction.UPDATE, 'projects', {
resource: { project_id: project?.id },
})
const { data, isPending: isLoadingBackups } = useDownloadableBackupQuery({ projectRef: ref })
const backups = data?.backups ?? []
const { mutate: downloadBackup, isPending: isDownloading } = useBackupDownloadMutation({
onSuccess: (res) => {
const { fileUrl } = res
// Trigger browser download by create,trigger and remove tempLink
const tempLink = document.createElement('a')
tempLink.href = fileUrl
document.body.appendChild(tempLink)
tempLink.click()
document.body.removeChild(tempLink)
},
})
const onClickDownloadBackup = () => {
if (!ref) return console.error('Project ref is required')
if (backups.length === 0 || data?.status === 'physical-backups-enabled')
return setShowCliBackup(true)
downloadBackup({ ref, backup: backups[0] })
}
const downloadBackupTooltipText = isLoadingBackups
? undefined
: data?.status === 'physical-backups-enabled'
? 'Project uses physical backups — click to see CLI backup instructions'
: backups.length === 0
? 'No downloadable backup available — click to see CLI backup instructions'
: undefined
return (
<>
<div className="flex items-center justify-center h-full">
<div className="bg-surface-100 border border-overlay rounded-md w-3/4 lg:w-1/2">
<div className="space-y-6 pt-6">
<div className="flex px-8 space-x-8">
<div className="mt-1">
<CriticalIcon className="w-5 h-5" />
</div>
<div className="space-y-1">
<p>Something went wrong while restoring your project</p>
<p className="text-sm text-foreground-light">
Your project's data is intact, but your project is inaccessible due to a
restoration failure. Database backups for this project can still be accessed{' '}
<InlineLink href={`/project/${ref}/database/backups/scheduled`}>here</InlineLink>.
</p>
<p className="text-sm text-foreground-light">
Please contact support for assistance.
</p>
</div>
</div>
<div className="border-t border-overlay flex items-center justify-end py-4 px-8 gap-x-2">
<Button asChild>
<SupportLink
queryParams={{
category: SupportCategories.DATABASE_UNRESPONSIVE,
projectRef: project?.ref,
subject: 'Restoration failed for project',
}}
>
Contact support
</SupportLink>
</Button>
<ButtonTooltip
icon={<Download />}
disabled={isLoadingBackups}
loading={isDownloading || isLoadingBackups}
tooltip={{
content: {
side: 'bottom',
text: downloadBackupTooltipText,
},
}}
onClick={onClickDownloadBackup}
>
Download backup
</ButtonTooltip>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="w-7" icon={<MoreVertical />} />
</DropdownMenuTrigger>
<DropdownMenuContent className="w-72" align="end">
<DropdownMenuItemTooltip
onClick={() => setVisible(true)}
className="items-start gap-x-2"
disabled={!canDeleteProject}
tooltip={{
content: {
side: 'right',
text: !canDeleteProject
? 'You need additional permissions to delete this project'
: undefined,
},
}}
>
<div className="translate-y-0.5">
<Trash size={14} />
</div>
<div className="">
<p>Delete project</p>
<p className="text-foreground-lighter">
Project cannot be restored once it is deleted
</p>
</div>
</DropdownMenuItemTooltip>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
</div>
<Dialog open={showCliBackup} onOpenChange={setShowCliBackup}>
<DialogContent size="medium" onOpenAutoFocus={(e) => e.preventDefault()}>
<DialogHeader>
<DialogTitle>Back up your database with the Supabase CLI</DialogTitle>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection>
<LogicalBackupCliInstructions showResetPassword={false} />
</DialogSection>
</DialogContent>
</Dialog>
<DeleteProjectModal visible={visible} onClose={() => setVisible(false)} />
</>
)
}