Files
supabase/apps/studio/components/ui/ErrorBoundary/ErrorBoundary.tsx
Gildas Garcia 96d43099bb chore: refactor Button API so that it can be used a standard button (#46880)
## Problem

Our `<Button>` component breaks the default `button` contract by
redefining the `type` prop to set its variant (`primary`, `default`,
etc) instead of the button type (`submit`, `button`, etc).
This is confusing and forces to write more code when using it with
shadcn components that expect/inject the standard button props.

## Solution

- rename the `type` prop to `variant`
- rename the `htmlType` prop to `type`
- propagate the changes where necessary
- format code

## How to test

As this is just prop renaming, if it builds it's ok

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-06-16 23:59:58 +02:00

96 lines
2.4 KiB
TypeScript

import * as Sentry from '@sentry/nextjs'
import { AlertCircle } from 'lucide-react'
import { ErrorInfo } from 'react'
import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary'
import { Alert, AlertDescription, AlertTitle, Button } from 'ui'
interface ErrorFallbackProps {
error: Error
resetErrorBoundary: () => void
message?: string
actions?: {
label: string
onClick: () => void
}[]
sentryContext?: Record<string, any>
}
const ErrorFallback = ({
error: _error,
resetErrorBoundary,
message = 'Something went wrong',
actions = [],
}: ErrorFallbackProps) => {
return (
<div className="p-4 bg-destructive-foreground h-full flex flex-col justify-center items-center">
<Alert variant="destructive">
<AlertCircle />
<AlertTitle>{message}</AlertTitle>
<AlertDescription>We've been notified and will review and fix this issue.</AlertDescription>
<div className="mt-4 flex gap-2">
<Button variant="default" onClick={resetErrorBoundary} className="text-sm">
Try again
</Button>
{actions?.map((action, index) => (
<Button key={index} variant="default" onClick={action.onClick} className="text-sm">
{action.label}
</Button>
))}
</div>
</Alert>
</div>
)
}
interface ErrorBoundaryProps {
children: React.ReactNode
message?: string
actions?: {
label: string
onClick: () => void
}[]
sentryContext?: Record<string, any>
onReset?: () => void
}
export const ErrorBoundary = ({
children,
message,
actions,
sentryContext,
onReset,
}: ErrorBoundaryProps) => {
const handleError = (error: Error, info: ErrorInfo) => {
Sentry.withScope((scope) => {
scope.setExtra('componentStack', info.componentStack)
if (sentryContext) {
Object.entries(sentryContext).forEach(([key, value]) => {
scope.setExtra(key, value)
})
}
Sentry.captureException(error)
})
}
const handleReset = () => {
onReset?.()
}
return (
<ReactErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<ErrorFallback
error={error}
resetErrorBoundary={resetErrorBoundary}
message={message}
actions={actions}
/>
)}
onError={handleError}
onReset={handleReset}
>
{children}
</ReactErrorBoundary>
)
}