Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a2e07fb

Browse files
committed
Show logs on error
1 parent 2d8430b commit a2e07fb

File tree

6 files changed

+125
-26
lines changed

6 files changed

+125
-26
lines changed

site/src/api/api.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,3 +754,12 @@ export const uploadTemplateFile = async (
754754
})
755755
return response.data
756756
}
757+
758+
export const getTemplateVersionLogs = async (
759+
versionId: string,
760+
): Promise<TypesGen.ProvisionerJobLog[]> => {
761+
const response = await axios.get<TypesGen.ProvisionerJobLog[]>(
762+
`/api/v2/templateversions/${versionId}/logs`,
763+
)
764+
return response.data
765+
}

site/src/components/Logs/Logs.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { makeStyles } from "@material-ui/core/styles"
2+
import { LogLevel } from "api/typesGenerated"
23
import dayjs from "dayjs"
34
import { FC } from "react"
45
import { MONOSPACE_FONT_FAMILY } from "../../theme/constants"
@@ -7,6 +8,7 @@ import { combineClasses } from "../../util/combineClasses"
78
interface Line {
89
time: string
910
output: string
11+
level: LogLevel
1012
}
1113

1214
export interface LogsProps {
@@ -22,15 +24,17 @@ export const Logs: FC<React.PropsWithChildren<LogsProps>> = ({
2224

2325
return (
2426
<div className={combineClasses([className, styles.root])}>
25-
{lines.map((line, idx) => (
26-
<div className={styles.line} key={idx}>
27-
<span className={styles.time}>
28-
{dayjs(line.time).format(`HH:mm:ss.SSS`)}
29-
</span>
30-
<span className={styles.space}>&nbsp;&nbsp;&nbsp;&nbsp;</span>
31-
<span>{line.output}</span>
32-
</div>
33-
))}
27+
<div className={styles.scrollWrapper}>
28+
{lines.map((line, idx) => (
29+
<div className={combineClasses([styles.line, line.level])} key={idx}>
30+
<span className={styles.time}>
31+
{dayjs(line.time).format(`HH:mm:ss.SSS`)}
32+
</span>
33+
<span className={styles.space}>&nbsp;&nbsp;&nbsp;&nbsp;</span>
34+
<span>{line.output}</span>
35+
</div>
36+
))}
37+
</div>
3438
</div>
3539
)
3640
}
@@ -43,13 +47,25 @@ const useStyles = makeStyles((theme) => ({
4347
fontFamily: MONOSPACE_FONT_FAMILY,
4448
fontSize: 13,
4549
wordBreak: "break-all",
46-
padding: theme.spacing(2),
50+
padding: theme.spacing(2, 0),
4751
borderRadius: theme.shape.borderRadius,
4852
overflowX: "auto",
4953
},
54+
scrollWrapper: {
55+
width: "fit-content",
56+
},
5057
line: {
5158
// Whitespace is significant in terminal output for alignment
5259
whiteSpace: "pre",
60+
padding: theme.spacing(0, 3),
61+
62+
"&.error": {
63+
backgroundColor: theme.palette.error.dark,
64+
},
65+
66+
"&.warning": {
67+
backgroundColor: theme.palette.warning.dark,
68+
},
5369
},
5470
space: {
5571
userSelect: "none",

site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({ logs }) => {
5454
const lines = logs.map((log) => ({
5555
time: log.created_at,
5656
output: log.output,
57+
level: log.log_level,
5758
}))
5859
const duration = getStageDurationInSeconds(logs)
5960
const shouldDisplayDuration = duration !== undefined
@@ -68,7 +69,7 @@ export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({ logs }) => {
6869
</div>
6970
)}
7071
</div>
71-
{!isEmpty && <Logs lines={lines} className={styles.codeBlock} />}
72+
{!isEmpty && <Logs lines={lines} />}
7273
</Fragment>
7374
)
7475
})}
@@ -86,8 +87,8 @@ const useStyles = makeStyles((theme) => ({
8687
header: {
8788
fontSize: 14,
8889
padding: theme.spacing(2),
89-
paddingLeft: theme.spacing(4),
90-
paddingRight: theme.spacing(4),
90+
paddingLeft: theme.spacing(3),
91+
paddingRight: theme.spacing(3),
9192
borderBottom: `1px solid ${theme.palette.divider}`,
9293
backgroundColor: theme.palette.background.paper,
9394
display: "flex",
@@ -112,9 +113,4 @@ const useStyles = makeStyles((theme) => ({
112113
color: theme.palette.text.secondary,
113114
fontSize: theme.typography.body2.fontSize,
114115
},
115-
116-
codeBlock: {
117-
padding: theme.spacing(2),
118-
paddingLeft: theme.spacing(4),
119-
},
120116
}))

site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import Checkbox from "@material-ui/core/Checkbox"
22
import { makeStyles } from "@material-ui/core/styles"
33
import TextField from "@material-ui/core/TextField"
4-
import { ParameterSchema, TemplateExample } from "api/typesGenerated"
4+
import {
5+
ParameterSchema,
6+
ProvisionerJobLog,
7+
TemplateExample,
8+
} from "api/typesGenerated"
59
import { FormFooter } from "components/FormFooter/FormFooter"
610
import { IconField } from "components/IconField/IconField"
711
import { ParameterInput } from "components/ParameterInput/ParameterInput"
@@ -17,6 +21,7 @@ import { useTranslation } from "react-i18next"
1721
import { nameValidator, getFormHelpers, onChangeTrimmed } from "util/formUtils"
1822
import { CreateTemplateData } from "xServices/createTemplate/createTemplateXService"
1923
import * as Yup from "yup"
24+
import { WorkspaceBuildLogs } from "components/WorkspaceBuildLogs/WorkspaceBuildLogs"
2025

2126
const validationSchema = Yup.object({
2227
name: nameValidator("Name"),
@@ -60,6 +65,8 @@ interface CreateTemplateFormProps {
6065
onCancel: () => void
6166
onSubmit: (data: CreateTemplateData) => void
6267
upload: TemplateUploadProps
68+
jobError?: string
69+
logs?: ProvisionerJobLog[]
6370
}
6471

6572
export const CreateTemplateForm: FC<CreateTemplateFormProps> = ({
@@ -70,6 +77,8 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = ({
7077
onCancel,
7178
onSubmit,
7279
upload,
80+
jobError,
81+
logs,
7382
}) => {
7483
const styles = useStyles()
7584
const formFooterStyles = useFormFooterStyles()
@@ -249,11 +258,27 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = ({
249258
</div>
250259
)}
251260

261+
{jobError && (
262+
<Stack>
263+
<div className={styles.error}>
264+
<h5 className={styles.errorTitle}>Error during provisioning</h5>
265+
<p className={styles.errorDescription}>
266+
Looks like we found an error during the template provisioning.
267+
You can see the logs bellow.
268+
</p>
269+
270+
<code className={styles.errorDetails}>{jobError}</code>
271+
</div>
272+
273+
<WorkspaceBuildLogs logs={logs ?? []} />
274+
</Stack>
275+
)}
276+
252277
<FormFooter
253278
styles={formFooterStyles}
254279
onCancel={onCancel}
255280
isLoading={isSubmitting}
256-
submitLabel="Create template"
281+
submitLabel={jobError ? "Retry" : "Create template"}
257282
/>
258283
</Stack>
259284
</form>
@@ -318,6 +343,31 @@ const useStyles = makeStyles((theme) => ({
318343
fontSize: theme.spacing(1.5),
319344
color: theme.palette.text.secondary,
320345
},
346+
347+
error: {
348+
padding: theme.spacing(3),
349+
borderRadius: theme.spacing(1),
350+
background: theme.palette.background.paper,
351+
border: `1px solid ${theme.palette.error.main}`,
352+
},
353+
354+
errorTitle: {
355+
fontSize: 16,
356+
margin: 0,
357+
},
358+
359+
errorDescription: {
360+
margin: 0,
361+
color: theme.palette.text.secondary,
362+
marginTop: theme.spacing(0.5),
363+
},
364+
365+
errorDetails: {
366+
display: "block",
367+
marginTop: theme.spacing(1),
368+
color: theme.palette.error.light,
369+
fontSize: theme.spacing(2),
370+
},
321371
}))
322372

323373
const useFormFooterStyles = makeStyles((theme) => ({

site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ const CreateTemplatePage: FC = () => {
2727
},
2828
},
2929
})
30-
const { starterTemplate, parameters, error, file } = state.context
30+
const { starterTemplate, parameters, error, file, jobError, jobLogs } =
31+
state.context
3132
const shouldDisplayForm = !state.hasTag("loading")
3233

3334
const onCancel = () => {
@@ -68,6 +69,8 @@ const CreateTemplatePage: FC = () => {
6869
send({ type: "UPLOAD_FILE", file })
6970
},
7071
}}
72+
jobError={jobError}
73+
logs={jobLogs}
7174
/>
7275
)}
7376
</FullPageHorizontalForm>

site/src/xServices/createTemplate/createTemplateXService.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import {
55
createTemplate,
66
getTemplateVersionSchema,
77
uploadTemplateFile,
8+
getTemplateVersionLogs,
89
} from "api/api"
910
import {
1011
CreateTemplateVersionRequest,
1112
ParameterSchema,
13+
ProvisionerJobLog,
1214
Template,
1315
TemplateExample,
1416
TemplateVersion,
@@ -41,6 +43,7 @@ interface CreateTemplateContext {
4143
organizationId: string
4244
error?: unknown
4345
jobError?: string
46+
jobLogs?: ProvisionerJobLog[]
4447
starterTemplate?: TemplateExample
4548
exampleId?: string | null // It can be null because it is being passed from query string
4649
version?: TemplateVersion
@@ -86,6 +89,9 @@ export const createTemplateMachine =
8689
createTemplate: {
8790
data: Template
8891
}
92+
loadVersionLogs: {
93+
data: ProvisionerJobLog[]
94+
}
8995
},
9096
},
9197
tsTypes: {} as import("./createTemplateXService.typegen").Typegen0,
@@ -169,8 +175,8 @@ export const createTemplateMachine =
169175
actions: ["assignVersion"],
170176
},
171177
{
172-
target: "#createTemplate.idle",
173-
actions: ["displayJobError"],
178+
target: "loadingVersionLogs",
179+
actions: ["assignJobError", "assignVersion"],
174180
cond: "hasFailed",
175181
},
176182
{ target: "creatingTemplate", actions: ["assignVersion"] },
@@ -182,6 +188,19 @@ export const createTemplateMachine =
182188
},
183189
tags: ["submitting"],
184190
},
191+
loadingVersionLogs: {
192+
invoke: {
193+
src: "loadVersionLogs",
194+
onDone: {
195+
target: "#createTemplate.idle",
196+
actions: ["assignJobLogs"],
197+
},
198+
onError: {
199+
target: "#createTemplate.idle",
200+
actions: ["assignError"],
201+
},
202+
},
203+
},
185204
loadingMissingParameters: {
186205
invoke: {
187206
src: "loadParameterSchema",
@@ -357,12 +376,17 @@ export const createTemplateMachine =
357376
template_version_id: version.id,
358377
})
359378
},
379+
loadVersionLogs: ({ version }) => {
380+
if (!version) {
381+
throw new Error("Version is not set")
382+
}
383+
384+
return getTemplateVersionLogs(version.id)
385+
},
360386
},
361387
actions: {
362388
assignError: assign({ error: (_, { data }) => data }),
363-
displayJobError: (_, { data }) => {
364-
displayError("Provisioner job failed.", data.job.error)
365-
},
389+
assignJobError: assign({ jobError: (_, { data }) => data.job.error }),
366390
displayUploadError: () => {
367391
displayError("Error on upload the file.")
368392
},
@@ -378,6 +402,7 @@ export const createTemplateMachine =
378402
file: (_) => undefined,
379403
uploadResponse: (_) => undefined,
380404
}),
405+
assignJobLogs: assign({ jobLogs: (_, { data }) => data }),
381406
},
382407
guards: {
383408
isExampleProvided: ({ exampleId }) => exampleId !== undefined,

0 commit comments

Comments
 (0)