Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0b1a35f

Browse files
feat: Add workspace build logs page (#1598)
1 parentd72c45e commit0b1a35f

File tree

18 files changed

+839
-35
lines changed

18 files changed

+839
-35
lines changed

‎.vscode/settings.json‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"cSpell.words": [
3+
"buildname",
34
"circbuf",
45
"cliflag",
56
"cliui",
@@ -55,6 +56,7 @@
5556
"TCGETS",
5657
"tcpip",
5758
"TCSETS",
59+
"testid",
5860
"tfexec",
5961
"tfjson",
6062
"tfstate",
@@ -76,7 +78,7 @@
7678
},
7779
{
7880
"match":"provisionerd/proto/provisionerd.proto",
79-
"cmd":"make provisionerd/proto/provisionerd.pb.go",
81+
"cmd":"make provisionerd/proto/provisionerd.pb.go"
8082
}
8183
]
8284
},
@@ -104,5 +106,5 @@
104106
},
105107
// We often use a version of TypeScript that's ahead of the version shipped
106108
// with VS Code.
107-
"typescript.tsdk":"./site/node_modules/typescript/lib",
109+
"typescript.tsdk":"./site/node_modules/typescript/lib"
108110
}

‎site/src/AppRouter.tsx‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { SSHKeysPage } from "./pages/SettingsPages/SSHKeysPage/SSHKeysPage"
1515
importTemplatesPagefrom"./pages/TemplatesPage/TemplatesPage"
1616
import{CreateUserPage}from"./pages/UsersPage/CreateUserPage/CreateUserPage"
1717
import{UsersPage}from"./pages/UsersPage/UsersPage"
18+
import{WorkspaceBuildPage}from"./pages/WorkspaceBuildPage/WorkspaceBuildPage"
1819
import{WorkspacePage}from"./pages/WorkspacePage/WorkspacePage"
1920
import{WorkspaceSettingsPage}from"./pages/WorkspaceSettingsPage/WorkspaceSettingsPage"
2021

@@ -138,6 +139,15 @@ export const AppRouter: React.FC = () => (
138139
</Route>
139140
</Route>
140141

142+
<Route
143+
path="builds/:buildId"
144+
element={
145+
<AuthAndFrame>
146+
<WorkspaceBuildPage/>
147+
</AuthAndFrame>
148+
}
149+
/>
150+
141151
{/* Using path="*"" means "match anything", so this route
142152
acts like a catch-all for URLs that we don't have explicit
143153
routes for. */}

‎site/src/api/api.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,13 @@ export const getWorkspaceBuilds = async (workspaceId: string): Promise<TypesGen.
248248
constresponse=awaitaxios.get<TypesGen.WorkspaceBuild[]>(`/api/v2/workspaces/${workspaceId}/builds`)
249249
returnresponse.data
250250
}
251+
252+
exportconstgetWorkspaceBuild=async(workspaceId:string):Promise<TypesGen.WorkspaceBuild>=>{
253+
constresponse=awaitaxios.get<TypesGen.WorkspaceBuild>(`/api/v2/workspacebuilds/${workspaceId}`)
254+
returnresponse.data
255+
}
256+
257+
exportconstgetWorkspaceBuildLogs=async(buildname:string):Promise<TypesGen.ProvisionerJobLog[]>=>{
258+
constresponse=awaitaxios.get<TypesGen.ProvisionerJobLog[]>(`/api/v2/workspacebuilds/${buildname}/logs`)
259+
returnresponse.data
260+
}
Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
importBoxfrom"@material-ui/core/Box"
2-
import{Theme}from"@material-ui/core/styles"
2+
import{makeStyles,Theme}from"@material-ui/core/styles"
33
importTablefrom"@material-ui/core/Table"
44
importTableBodyfrom"@material-ui/core/TableBody"
55
importTableCellfrom"@material-ui/core/TableCell"
66
importTableHeadfrom"@material-ui/core/TableHead"
77
importTableRowfrom"@material-ui/core/TableRow"
88
importuseThemefrom"@material-ui/styles/useTheme"
9-
importdayjsfrom"dayjs"
10-
importdurationfrom"dayjs/plugin/duration"
11-
importrelativeTimefrom"dayjs/plugin/relativeTime"
129
importReactfrom"react"
10+
import{useNavigate}from"react-router-dom"
1311
import*asTypesGenfrom"../../api/typesGenerated"
14-
import{getDisplayStatus}from"../../util/workspace"
12+
import{displayWorkspaceBuildDuration,getDisplayStatus}from"../../util/workspace"
1513
import{EmptyState}from"../EmptyState/EmptyState"
1614
import{TableLoader}from"../TableLoader/TableLoader"
1715

18-
dayjs.extend(relativeTime)
19-
dayjs.extend(duration)
20-
2116
exportconstLanguage={
2217
emptyMessage:"No builds found",
2318
inProgressLabel:"In progress",
@@ -27,19 +22,6 @@ export const Language = {
2722
statusLabel:"Status",
2823
}
2924

30-
constgetDurationInSeconds=(build:TypesGen.WorkspaceBuild)=>{
31-
letdisplay=Language.inProgressLabel
32-
33-
if(build.job.started_at&&build.job.completed_at){
34-
conststartedAt=dayjs(build.job.started_at)
35-
constcompletedAt=dayjs(build.job.completed_at)
36-
constdiff=completedAt.diff(startedAt,"seconds")
37-
display=`${diff} seconds`
38-
}
39-
40-
returndisplay
41-
}
42-
4325
exportinterfaceBuildsTableProps{
4426
builds?:TypesGen.WorkspaceBuild[]
4527
className?:string
@@ -48,6 +30,8 @@ export interface BuildsTableProps {
4830
exportconstBuildsTable:React.FC<BuildsTableProps>=({ builds, className})=>{
4931
constisLoading=!builds
5032
consttheme:Theme=useTheme()
33+
constnavigate=useNavigate()
34+
conststyles=useStyles()
5135

5236
return(
5337
<TableclassName={className}>
@@ -62,18 +46,35 @@ export const BuildsTable: React.FC<BuildsTableProps> = ({ builds, className }) =
6246
<TableBody>
6347
{isLoading&&<TableLoader/>}
6448
{builds&&
65-
builds.map((b)=>{
66-
conststatus=getDisplayStatus(theme,b)
67-
constduration=getDurationInSeconds(b)
49+
builds.map((build)=>{
50+
conststatus=getDisplayStatus(theme,build)
51+
52+
constnavigateToBuildPage=()=>{
53+
navigate(`/builds/${build.id}`)
54+
}
6855

6956
return(
70-
<TableRowkey={b.id}data-testid={`build-${b.id}`}>
71-
<TableCell>{b.transition}</TableCell>
57+
<TableRow
58+
hover
59+
key={build.id}
60+
data-testid={`build-${build.id}`}
61+
tabIndex={0}
62+
onClick={navigateToBuildPage}
63+
onKeyDown={(event)=>{
64+
if(event.key==="Enter"){
65+
navigateToBuildPage()
66+
}
67+
}}
68+
className={styles.clickableTableRow}
69+
>
70+
<TableCell>{build.transition}</TableCell>
7271
<TableCell>
73-
<spanstyle={{color:theme.palette.text.secondary}}>{duration}</span>
72+
<spanstyle={{color:theme.palette.text.secondary}}>{displayWorkspaceBuildDuration(build)}</span>
7473
</TableCell>
7574
<TableCell>
76-
<spanstyle={{color:theme.palette.text.secondary}}>{newDate(b.created_at).toLocaleString()}</span>
75+
<spanstyle={{color:theme.palette.text.secondary}}>
76+
{newDate(build.created_at).toLocaleString()}
77+
</span>
7778
</TableCell>
7879
<TableCell>
7980
<spanstyle={{color:status.color}}>{status.status}</span>
@@ -95,3 +96,17 @@ export const BuildsTable: React.FC<BuildsTableProps> = ({ builds, className }) =
9596
</Table>
9697
)
9798
}
99+
100+
constuseStyles=makeStyles((theme)=>({
101+
clickableTableRow:{
102+
cursor:"pointer",
103+
104+
"&:hover td":{
105+
backgroundColor:theme.palette.background.default,
106+
},
107+
108+
"&:focus":{
109+
outline:`1px solid${theme.palette.primary.dark}`,
110+
},
111+
},
112+
}))
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
importBoxfrom"@material-ui/core/Box"
2+
importCircularProgressfrom"@material-ui/core/CircularProgress"
3+
importReactfrom"react"
4+
5+
exportconstLoader:React.FC<{size?:number}>=({ size=26})=>{
6+
return(
7+
<Boxp={4}width="100%"display="flex"alignItems="center"justifyContent="center">
8+
<CircularProgresssize={size}/>
9+
</Box>
10+
)
11+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import{ComponentMeta,Story}from"@storybook/react"
2+
importReactfrom"react"
3+
import{MockWorkspaceBuildLogs}from"../../testHelpers/entities"
4+
import{Logs,LogsProps}from"./Logs"
5+
6+
exportdefault{
7+
title:"components/Logs",
8+
component:Logs,
9+
}asComponentMeta<typeofLogs>
10+
11+
constTemplate:Story<LogsProps>=(args)=><Logs{...args}/>
12+
13+
constlines=MockWorkspaceBuildLogs.map((log)=>({
14+
time:log.created_at,
15+
output:log.output,
16+
}))
17+
exportconstExample=Template.bind({})
18+
Example.args={
19+
lines,
20+
}

‎site/src/components/Logs/Logs.tsx‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import{makeStyles}from"@material-ui/core/styles"
2+
importdayjsfrom"dayjs"
3+
importReactfrom"react"
4+
import{MONOSPACE_FONT_FAMILY}from"../../theme/constants"
5+
import{combineClasses}from"../../util/combineClasses"
6+
7+
interfaceLine{
8+
time:string
9+
output:string
10+
}
11+
12+
exportinterfaceLogsProps{
13+
lines:Line[]
14+
className?:string
15+
}
16+
17+
exportconstLogs:React.FC<LogsProps>=({ lines, className=""})=>{
18+
conststyles=useStyles()
19+
20+
return(
21+
<divclassName={combineClasses([className,styles.root])}>
22+
{lines.map((line,idx)=>(
23+
<divclassName={styles.line}key={idx}>
24+
<divclassName={styles.time}>{dayjs(line.time).format(`HH:mm:ss.SSS`)}</div>
25+
<div>{line.output}</div>
26+
</div>
27+
))}
28+
</div>
29+
)
30+
}
31+
32+
constuseStyles=makeStyles((theme)=>({
33+
root:{
34+
minHeight:156,
35+
background:theme.palette.background.default,
36+
color:theme.palette.text.primary,
37+
fontFamily:MONOSPACE_FONT_FAMILY,
38+
fontSize:13,
39+
wordBreak:"break-all",
40+
padding:theme.spacing(2),
41+
borderRadius:theme.shape.borderRadius,
42+
overflowX:"auto",
43+
},
44+
line:{
45+
display:"flex",
46+
alignItems:"baseline",
47+
},
48+
time:{
49+
width:theme.spacing(12.5),
50+
marginRight:theme.spacing(3),
51+
flexShrink:0,
52+
},
53+
}))

‎site/src/components/TableLoader/TableLoader.tsx‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
importBoxfrom"@material-ui/core/Box"
2-
importCircularProgressfrom"@material-ui/core/CircularProgress"
31
import{makeStyles}from"@material-ui/core/styles"
42
importTableCellfrom"@material-ui/core/TableCell"
53
importTableRowfrom"@material-ui/core/TableRow"
64
importReactfrom"react"
5+
import{Loader}from"../Loader/Loader"
76

87
exportconstTableLoader:React.FC=()=>{
98
conststyles=useStyles()
109

1110
return(
1211
<TableRow>
1312
<TableCellcolSpan={999}className={styles.cell}>
14-
<Boxp={4}>
15-
<CircularProgresssize={26}/>
16-
</Box>
13+
<Loader/>
1714
</TableCell>
1815
</TableRow>
1916
)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import{ComponentMeta,Story}from"@storybook/react"
2+
importReactfrom"react"
3+
import{MockWorkspaceBuildLogs}from"../../testHelpers/entities"
4+
import{WorkspaceBuildLogs,WorkspaceBuildLogsProps}from"./WorkspaceBuildLogs"
5+
6+
exportdefault{
7+
title:"components/WorkspaceBuildLogs",
8+
component:WorkspaceBuildLogs,
9+
}asComponentMeta<typeofWorkspaceBuildLogs>
10+
11+
constTemplate:Story<WorkspaceBuildLogsProps>=(args)=><WorkspaceBuildLogs{...args}/>
12+
13+
exportconstExample=Template.bind({})
14+
Example.args={
15+
logs:MockWorkspaceBuildLogs,
16+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp