QueryError.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import styles from '@ui/layout/ai-icon-animation/ai-icon-animation-style.module.css'
  2. import { initial, last } from 'lodash'
  3. import { Dispatch, SetStateAction } from 'react'
  4. import {
  5. Alert,
  6. AlertTitle,
  7. Button,
  8. cn,
  9. Collapsible,
  10. CollapsibleContent,
  11. CollapsibleTrigger,
  12. } from 'ui'
  13. import { QueryResponseError } from '@/data/sql/execute-sql-mutation'
  14. export const QueryError = ({
  15. error,
  16. open,
  17. setOpen,
  18. }: {
  19. error: QueryResponseError
  20. open: boolean
  21. setOpen: Dispatch<SetStateAction<boolean>>
  22. }) => {
  23. const formattedError =
  24. (error?.message?.split('\n') ?? [])?.filter((x: string) => x.length > 0) ?? []
  25. return (
  26. <div className="flex flex-col gap-y-3 px-5">
  27. <Alert variant="destructive">
  28. <svg
  29. xmlns="http://www.w3.org/2000/svg"
  30. viewBox="0 0 20 20"
  31. fill="currentColor"
  32. className="w-5 h-5"
  33. >
  34. <path
  35. fillRule="evenodd"
  36. clipRule="evenodd"
  37. d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z"
  38. />
  39. </svg>
  40. <div className="flex flex-col gap-3">
  41. <AlertTitle className="m-0">Error running SQL query</AlertTitle>
  42. <Collapsible
  43. defaultOpen
  44. className="flex flex-col gap-3"
  45. open={open}
  46. onOpenChange={() => setOpen(!open)}
  47. >
  48. <div className="flex gap-2">
  49. <CollapsibleTrigger asChild>
  50. <Button
  51. size="tiny"
  52. type="outline"
  53. className={cn('group', styles['ai-icon__container--allow-hover-effect'])}
  54. >
  55. {open ? 'Hide error details' : 'Show error details'}
  56. </Button>
  57. </CollapsibleTrigger>
  58. </div>
  59. <CollapsibleContent className="overflow-auto">
  60. {formattedError.length > 0 ? (
  61. formattedError.map((x: string, i: number) => (
  62. <pre key={`error-${i}`} className="font-mono text-xs whitespace-pre-wrap">
  63. {x
  64. .split(' ')
  65. .reduce((arr, cur) => {
  66. // Split the ERROR string so that it can be wrapped in a red span
  67. const l = last(arr)
  68. if (l && l !== 'ERROR:') {
  69. return initial(arr).concat([[l, cur].join(' ')])
  70. }
  71. if (l === '') {
  72. return arr.concat([' '])
  73. }
  74. return arr.concat([cur])
  75. }, [] as string[])
  76. .map((str, index) => {
  77. return (
  78. <span
  79. key={index}
  80. className={cn('break-all', str === 'ERROR:' && 'text-destructive')}
  81. >
  82. {str}
  83. </span>
  84. )
  85. })}
  86. </pre>
  87. ))
  88. ) : (
  89. <p className="font-mono text-xs">{error.error}</p>
  90. )}
  91. </CollapsibleContent>
  92. </Collapsible>
  93. </div>
  94. </Alert>
  95. <div className="overflow-x-auto"></div>
  96. </div>
  97. )
  98. }