mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 05:39:11 +03:00
fix: improve error rendering for logs
This commit is contained in:
1 parent
eb831ef650
commit
996fc0751c
2 files changed
+99
-53
No files matched your search
@@ -1,25 +1,22 @@
|
||||
import dayjs from 'dayjs'
|
||||
import { useEffect, useState, useMemo } from 'react'
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
IconDownloadCloud,
|
||||
IconEye,
|
||||
IconEyeOff,
|
||||
IconLoader,
|
||||
Input,
|
||||
Typography,
|
||||
} from '@supabase/ui'
|
||||
import { Alert, Button, IconEye, IconEyeOff, Input } from '@supabase/ui'
|
||||
import DataGrid from '@supabase/react-data-grid'
|
||||
|
||||
import LogSelection from './LogSelection'
|
||||
import { LogData, QueryType } from './Logs.types'
|
||||
import { SeverityFormatter, ResponseCodeFormatter, HeaderFormmater } from './LogsFormatters'
|
||||
import {
|
||||
SeverityFormatter,
|
||||
ResponseCodeFormatter,
|
||||
HeaderFormmater,
|
||||
jsonSyntaxHighlight,
|
||||
} from './LogsFormatters'
|
||||
|
||||
// column renders
|
||||
import DatabaseApiColumnRender from './LogColumnRenderers/DatabaseApiColumnRender'
|
||||
import DatabasePostgresColumnRender from './LogColumnRenderers/DatabasePostgresColumnRender'
|
||||
import CSVButton from 'components/ui/CSVButton'
|
||||
import { copyToClipboard } from 'lib/helpers'
|
||||
|
||||
interface Props {
|
||||
data?: Array<LogData | Object>
|
||||
@@ -262,57 +259,92 @@ const LogTable = ({
|
||||
!isLoading ? (
|
||||
<>
|
||||
<div className="py-4 w-full h-full flex-col space-y-12">
|
||||
<div
|
||||
className={[
|
||||
'transition-all duration-500 delay-200',
|
||||
'flex flex-col items-center gap-6 text-center',
|
||||
'mt-16 opacity-100 scale-100 justify-center',
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="relative border border-scale-600 border-dashed dark:border-scale-400 w-32 h-4 rounded px-2 flex items-center"></div>
|
||||
<div className="relative border border-scale-600 border-dashed dark:border-scale-400 w-32 h-4 rounded px-2 flex items-center">
|
||||
<div className="absolute right-1 -bottom-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
{!error && (
|
||||
<div
|
||||
className={`transition-all
|
||||
duration-500
|
||||
delay-200
|
||||
|
||||
flex
|
||||
flex-col
|
||||
items-center
|
||||
|
||||
gap-6
|
||||
text-center
|
||||
mt-16
|
||||
opacity-100
|
||||
scale-100
|
||||
|
||||
justify-center
|
||||
`}
|
||||
>
|
||||
<>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="relative border border-scale-600 border-dashed dark:border-scale-400 w-32 h-4 rounded px-2 flex items-center"></div>
|
||||
<div className="relative border border-scale-600 border-dashed dark:border-scale-400 w-32 h-4 rounded px-2 flex items-center">
|
||||
<div className="absolute right-1 -bottom-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 px-5">
|
||||
<h3 className="text-lg text-scale-1200">No results</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
Try another search, or adjusting the filters
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 px-5">
|
||||
<h3 className="text-lg text-scale-1200">No results</h3>
|
||||
<p className="text-sm text-scale-900">
|
||||
Try another search, or adjusting the filters
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<div className="flex justify-center px-5">
|
||||
<Alert
|
||||
variant="danger"
|
||||
title="Sorry! An error occured when fetching data."
|
||||
withIcon
|
||||
className="max-w-xl"
|
||||
className="w-1/2"
|
||||
>
|
||||
<Input.TextArea
|
||||
size="small"
|
||||
value={JSON.stringify(error, null, 2)}
|
||||
borderless
|
||||
className="font-mono w-full mt-4"
|
||||
copy
|
||||
rows={12}
|
||||
/>
|
||||
{typeof error === 'string' && (
|
||||
<Input.TextArea
|
||||
size="small"
|
||||
value={error}
|
||||
borderless
|
||||
className="font-mono w-full mt-4"
|
||||
copy
|
||||
rows={12}
|
||||
/>
|
||||
)}
|
||||
{typeof error === 'object' && (
|
||||
<>
|
||||
<pre
|
||||
className="font-mono w-full mt-4 bg-red-300 rounded p-2"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: jsonSyntaxHighlight(error),
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={() => copyToClipboard(JSON.stringify(error, null, 2))}
|
||||
type="default"
|
||||
className="mt-2"
|
||||
>
|
||||
Copy
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Alert>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -63,3 +63,17 @@ test('toggle histogram', async () => {
|
||||
userEvent.click(toggle)
|
||||
expect(mockFn).toBeCalled()
|
||||
})
|
||||
|
||||
|
||||
test('error message handling', async () => {
|
||||
const {rerender} = render(<LogTable error="some \nstring" />)
|
||||
await expect(screen.findByText("some \nstring")).rejects.toThrow()
|
||||
await screen.findByDisplayValue(/some/)
|
||||
await screen.findByDisplayValue(/string/)
|
||||
|
||||
rerender(<LogTable error={{my_error: "some \nstring"}} />)
|
||||
await screen.findByText(/some \\nstring/)
|
||||
await screen.findByText(/some/)
|
||||
await screen.findByText(/string/)
|
||||
await screen.findByText(/my_error/)
|
||||
})
|
||||
Reference in new issue
Block a user