11import {
2- Alert ,
3- AlertDescription ,
4- AlertIcon ,
5- AlertTitle ,
62 Box ,
73 Button ,
84 Code ,
95 Collapse ,
106 HStack ,
7+ Icon ,
8+ Link ,
9+ Spacer ,
10+ Text ,
1111 Tooltip ,
1212 useClipboard ,
13+ useColorModeValue ,
1314 useDisclosure ,
1415 VStack ,
1516} from '@chakra-ui/react' ;
16- import { ChevronDownIcon , ChevronRightIcon , CopyIcon } from '@chakra-ui/icons' ;
17+ import { CopyIcon , WarningIcon } from '@chakra-ui/icons' ;
1718import { AxiosError } from 'axios' ;
1819import { IADSApiSearchResponse } from '@/api/search/types' ;
20+ import { SimpleLink } from '@/components/SimpleLink' ;
1921import { ParsedSolrError , SOLR_ERROR , useSolrError } from '@/lib/useSolrError' ;
2022
2123interface ISolrErrorAlertProps {
@@ -26,56 +28,138 @@ interface ISolrErrorAlertProps {
2628
2729export const SearchErrorAlert = ( { error, onRetry, isRetrying = false } : ISolrErrorAlertProps ) => {
2830 const data = useSolrError ( error ) ;
29- const { isOpen, onToggle } = useDisclosure ( { defaultIsOpen : true } ) ;
31+ const { isOpen, onToggle } = useDisclosure ( { defaultIsOpen : false } ) ;
3032 const detailsId = 'search-error-details' ;
3133 const { onCopy, hasCopied } = useClipboard (
3234 typeof data ?. originalMsg === 'string' ? data . originalMsg : String ( data ?. originalMsg ?? '' ) ,
3335 ) ;
3436 const { title, message } = solrErrorToCopy ( data , { includeFieldName : ! ! data . field } ) ;
3537
38+ const errorMsg = typeof data ?. originalMsg === 'string' ? data . originalMsg : String ( data ?. originalMsg ?? '' ) ;
39+ const feedbackUrl = errorMsg
40+ ? `/feedback/general?${ new URLSearchParams ( {
41+ from : 'search' ,
42+ error_details : errorMsg . slice ( 0 , 2000 ) ,
43+ } ) . toString ( ) } `
44+ : '/feedback/general?from=search' ;
45+
46+ const bgColor = useColorModeValue ( 'white' , 'gray.800' ) ;
47+ const borderColor = useColorModeValue ( 'red.100' , 'whiteAlpha.200' ) ;
48+ const accentBarColor = useColorModeValue ( 'red.500' , 'red.400' ) ;
49+ const titleColor = useColorModeValue ( 'blue.800' , 'white' ) ;
50+ const descColor = useColorModeValue ( 'gray.900' , 'gray.400' ) ;
51+ const shadow = useColorModeValue ( 'md' , '2xl' ) ;
52+ const codeBg = useColorModeValue ( 'gray.100' , 'whiteAlpha.300' ) ;
53+ const linkColor = useColorModeValue ( 'gray.800' , 'gray.500' ) ;
54+ const tryAgainBorderColor = useColorModeValue ( 'red.200' , 'red.600' ) ;
55+ const tryAgainColor = useColorModeValue ( 'red.600' , 'red.300' ) ;
56+ const tryAgainBg = useColorModeValue ( 'white' , 'gray.700' ) ;
57+ const tryAgainHoverBg = useColorModeValue ( 'red.50' , 'whiteAlpha.100' ) ;
58+ const copyBorderColor = useColorModeValue ( 'gray.300' , 'whiteAlpha.300' ) ;
59+ const copyHoverBg = useColorModeValue ( 'gray.50' , 'whiteAlpha.100' ) ;
60+
3661 return (
37- < Box w = "full" >
38- < Alert status = "error" variant = "subtle" alignItems = "flex-start" borderRadius = "md" >
39- < VStack align = "stretch" spacing = { 2 } w = "full" >
40- < HStack align = "start" w = "full" >
41- < AlertIcon />
42- < VStack align = "start" spacing = { 1 } flex = "1" >
43- < AlertTitle > { title } </ AlertTitle >
44- < AlertDescription > { message } </ AlertDescription >
45- </ VStack >
46-
47- < HStack >
48- { onRetry && (
49- < Button onClick = { onRetry } colorScheme = "blue" size = "sm" isLoading = { isRetrying } >
50- Try Again
51- </ Button >
52- ) }
53- < Tooltip label = { hasCopied ? 'Copied!' : 'Copy full error' } >
54- < Button onClick = { onCopy } leftIcon = { < CopyIcon /> } variant = "ghost" size = "sm" >
55- { hasCopied ? 'Copied' : 'Copy' }
56- </ Button >
57- </ Tooltip >
58-
59- < Button
60- rightIcon = { isOpen ? < ChevronDownIcon /> : < ChevronRightIcon /> }
61- aria-label = "toggle error details"
62- aria-controls = { detailsId }
63- onClick = { onToggle }
64- variant = "ghost"
65- size = "sm"
66- >
67- { isOpen ? 'Hide' : 'Show' } Details
68- </ Button >
69- </ HStack >
62+ < Box
63+ w = "full"
64+ bg = { bgColor }
65+ border = "1px solid"
66+ borderColor = { borderColor }
67+ borderRadius = "md"
68+ shadow = { shadow }
69+ overflow = "hidden"
70+ position = "relative"
71+ role = "alert"
72+ >
73+ < Box position = "absolute" left = { 0 } top = { 0 } bottom = { 0 } w = "4px" bg = { accentBarColor } />
74+
75+ < VStack align = "start" p = { 5 } spacing = { 3 } pl = { 8 } >
76+ < HStack spacing = { 3 } >
77+ < Icon as = { WarningIcon } color = { accentBarColor } boxSize = { 4 } />
78+ < Text fontWeight = "600" color = { titleColor } fontSize = "md" >
79+ { title }
80+ </ Text >
81+ </ HStack >
82+
83+ < Text color = { descColor } fontSize = "sm" lineHeight = "1.6" >
84+ { message }
85+ </ Text >
86+
87+ < HStack w = "full" spacing = { 3 } pt = { 2 } wrap = "wrap" align = "center" >
88+ { onRetry && (
89+ < Button
90+ onClick = { onRetry }
91+ variant = "outline"
92+ size = "sm"
93+ borderColor = { tryAgainBorderColor }
94+ color = { tryAgainColor }
95+ bg = { tryAgainBg }
96+ borderRadius = "4px"
97+ px = { 5 }
98+ isLoading = { isRetrying }
99+ _hover = { { bg : tryAgainHoverBg } }
100+ >
101+ Try Again
102+ </ Button >
103+ ) }
104+ < Tooltip label = { hasCopied ? 'Copied!' : 'Copy full error' } >
105+ < Button
106+ onClick = { onCopy }
107+ leftIcon = { < CopyIcon /> }
108+ variant = "outline"
109+ size = "sm"
110+ borderColor = { copyBorderColor }
111+ color = { titleColor }
112+ borderRadius = "4px"
113+ px = { 5 }
114+ _hover = { { bg : copyHoverBg } }
115+ >
116+ { hasCopied ? 'Copied' : 'Copy' }
117+ </ Button >
118+ </ Tooltip >
119+
120+ < Spacer />
121+
122+ < HStack spacing = { 4 } >
123+ < Link
124+ as = "button"
125+ fontSize = "xs"
126+ color = { linkColor }
127+ aria-label = "toggle error details"
128+ aria-controls = { detailsId }
129+ onClick = { onToggle }
130+ _hover = { { color : 'red.400' , textDecoration : 'underline' } }
131+ >
132+ { isOpen ? 'Hide' : 'Show' } Details
133+ </ Link >
134+ < SimpleLink
135+ href = { feedbackUrl }
136+ fontSize = "xs"
137+ color = { linkColor }
138+ display = "inline-flex"
139+ alignItems = "center"
140+ gap = { 1 }
141+ _hover = { { color : 'red.400' , textDecoration : 'underline' } }
142+ >
143+ Report this issue
144+ </ SimpleLink >
70145 </ HStack >
146+ </ HStack >
71147
72- < Collapse in = { isOpen } animateOpacity >
73- < Code id = { detailsId } p = "2" display = "block" whiteSpace = "pre-wrap" w = "full" >
74- { data ?. originalMsg }
75- </ Code >
76- </ Collapse >
77- </ VStack >
78- </ Alert >
148+ < Collapse in = { isOpen } animateOpacity >
149+ < Code
150+ id = { detailsId }
151+ p = { 3 }
152+ display = "block"
153+ whiteSpace = "pre-wrap"
154+ w = "full"
155+ fontSize = "xs"
156+ bg = { codeBg }
157+ borderRadius = "md"
158+ >
159+ { data ?. originalMsg }
160+ </ Code >
161+ </ Collapse >
162+ </ VStack >
79163 </ Box >
80164 ) ;
81165} ;
0 commit comments