@@ -3,6 +3,7 @@ import Link from "@material-ui/core/Link"
3
3
import { makeStyles } from "@material-ui/core/styles"
4
4
import RefreshOutlined from "@material-ui/icons/RefreshOutlined"
5
5
import { BuildInfoResponse } from "api/typesGenerated"
6
+ import { CopyButton } from "components/CopyButton/CopyButton"
6
7
import { CoderIcon } from "components/Icons/CoderIcon"
7
8
import { FullScreenLoader } from "components/Loader/FullScreenLoader"
8
9
import { Stack } from "components/Stack/Stack"
@@ -17,7 +18,9 @@ export type RuntimeErrorStateProps = { error: Error }
17
18
18
19
export const RuntimeErrorState : FC < RuntimeErrorStateProps > = ( { error } ) => {
19
20
const styles = useStyles ( )
20
- const [ shouldDisplayMessage , setShouldDisplayMessage ] = useState ( false )
21
+ const [ checkingError , setCheckingError ] = useState ( true )
22
+ const [ staticBuildInfo , setStaticBuildInfo ] = useState < BuildInfoResponse > ( )
23
+ const coderVersion = staticBuildInfo ?. version
21
24
22
25
// We use an effect to show a loading state if the page is trying to reload
23
26
useEffect ( ( ) => {
@@ -34,17 +37,23 @@ export const RuntimeErrorState: FC<RuntimeErrorStateProps> = ({ error }) => {
34
37
return
35
38
}
36
39
37
- setShouldDisplayMessage ( true )
40
+ setCheckingError ( false )
38
41
} , [ error . message ] )
39
42
43
+ useEffect ( ( ) => {
44
+ if ( ! checkingError ) {
45
+ setStaticBuildInfo ( getStaticBuildInfo ( ) )
46
+ }
47
+ } , [ checkingError ] )
48
+
40
49
return (
41
50
< >
42
51
< Helmet >
43
52
< title > Something went wrong...</ title >
44
53
</ Helmet >
45
- { shouldDisplayMessage ? (
46
- < Margins size = "small" className = { styles . root } >
47
- < div >
54
+ { ! checkingError ? (
55
+ < Margins className = { styles . root } >
56
+ < div className = { styles . innerRoot } >
48
57
< CoderIcon className = { styles . logo } />
49
58
< h1 className = { styles . title } > Something went wrong...</ h1 >
50
59
< p className = { styles . text } >
@@ -57,7 +66,9 @@ export const RuntimeErrorState: FC<RuntimeErrorStateProps> = ({ error }) => {
57
66
< Link
58
67
href = { `https://github.com/coder/coder/issues/new?body=${ encodeURIComponent (
59
68
[
60
- [ "**Version**" , getStaticBuildInfo ( ) ] . join ( "\n" ) ,
69
+ [ "**Version**" , coderVersion ?? "-- Set version --" ] . join (
70
+ "\n" ,
71
+ ) ,
61
72
[ "**Path**" , "`" + location . pathname + "`" ] . join ( "\n" ) ,
62
73
[ "**Error**" , "```\n" + error . stack + "\n```" ] . join ( "\n" ) ,
63
74
] . join ( "\n\n" ) ,
@@ -81,6 +92,22 @@ export const RuntimeErrorState: FC<RuntimeErrorStateProps> = ({ error }) => {
81
92
Go to dashboard
82
93
</ Button >
83
94
</ Stack >
95
+ { error . stack && (
96
+ < div className = { styles . stack } >
97
+ < div className = { styles . stackHeader } >
98
+ Stacktrace
99
+ < CopyButton
100
+ buttonClassName = { styles . copyButton }
101
+ text = { error . stack }
102
+ tooltipTitle = "Copy stacktrace"
103
+ />
104
+ </ div >
105
+ < pre className = { styles . stackCode } > { error . stack } </ pre >
106
+ </ div >
107
+ ) }
108
+ { coderVersion && (
109
+ < div className = { styles . version } > Version: { coderVersion } </ div >
110
+ ) }
84
111
</ div >
85
112
</ Margins >
86
113
) : (
@@ -100,7 +127,7 @@ const getStaticBuildInfo = () => {
100
127
try {
101
128
return JSON . parse ( buildInfoJson ) as BuildInfoResponse
102
129
} catch {
103
- return "-- Set the version --"
130
+ return undefined
104
131
}
105
132
}
106
133
}
@@ -114,8 +141,11 @@ const useStyles = makeStyles((theme) => ({
114
141
alignItems : "center" ,
115
142
justifyContent : "center" ,
116
143
minHeight : "100vh" ,
144
+ maxWidth : theme . spacing ( 75 ) ,
117
145
} ,
118
146
147
+ innerRoot : { width : "100%" } ,
148
+
119
149
logo : {
120
150
fontSize : theme . spacing ( 8 ) ,
121
151
} ,
@@ -131,4 +161,56 @@ const useStyles = makeStyles((theme) => ({
131
161
lineHeight : "160%" ,
132
162
marginBottom : theme . spacing ( 4 ) ,
133
163
} ,
164
+
165
+ stack : {
166
+ backgroundColor : theme . palette . background . paper ,
167
+ border : `1px solid ${ theme . palette . divider } ` ,
168
+ borderRadius : 4 ,
169
+ marginTop : theme . spacing ( 8 ) ,
170
+ display : "block" ,
171
+ textAlign : "left" ,
172
+ } ,
173
+
174
+ stackHeader : {
175
+ fontSize : 10 ,
176
+ textTransform : "uppercase" ,
177
+ fontWeight : 600 ,
178
+ letterSpacing : 1 ,
179
+ padding : theme . spacing ( 1 , 1 , 1 , 2 ) ,
180
+ backgroundColor : theme . palette . background . paperLight ,
181
+ borderBottom : `1px solid ${ theme . palette . divider } ` ,
182
+ color : theme . palette . text . secondary ,
183
+ display : "flex" ,
184
+ flexAlign : "center" ,
185
+ justifyContent : "space-between" ,
186
+ alignItems : "center" ,
187
+ } ,
188
+
189
+ stackCode : {
190
+ padding : theme . spacing ( 2 ) ,
191
+ margin : 0 ,
192
+ wordWrap : "break-word" ,
193
+ whiteSpace : "break-spaces" ,
194
+ } ,
195
+
196
+ copyButton : {
197
+ backgroundColor : "transparent" ,
198
+ border : 0 ,
199
+ borderRadius : 999 ,
200
+ minHeight : theme . spacing ( 4 ) ,
201
+ minWidth : theme . spacing ( 4 ) ,
202
+ height : theme . spacing ( 4 ) ,
203
+ width : theme . spacing ( 4 ) ,
204
+
205
+ "& svg" : {
206
+ width : 16 ,
207
+ height : 16 ,
208
+ } ,
209
+ } ,
210
+
211
+ version : {
212
+ marginTop : theme . spacing ( 4 ) ,
213
+ fontSize : 12 ,
214
+ color : theme . palette . text . secondary ,
215
+ } ,
134
216
} ) )
0 commit comments