Skip to content

Commit

Permalink
[webui] Various UI improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Weichel committed Dec 23, 2019
1 parent 8ac8d07 commit a09f381
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 12 deletions.
36 changes: 35 additions & 1 deletion cmd/server/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,20 @@ func startWeb(srv *werft.Service, grpcServer *grpc.Server, addr string, debugPro
log.WithField("target", tgt).Debug("proxying to webui server")
webuiServer = httputil.NewSingleHostReverseProxy(tgt)
} else {
webuiServer = http.FileServer(rice.MustFindBox("../../pkg/webui/build").HTTPBox())
// WebUI is a single-page app, hence any path that does not resolve to a static file must result in /index.html.
// As a (rather crude) fix we intercept the response writer to find out if the FileServer returned an error. If so
// we return /index.html instead.
dws := http.FileServer(rice.MustFindBox("../../pkg/webui/build").HTTPBox())
webuiServer = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
dws.ServeHTTP(&interceptResponseWriter{
ResponseWriter: w,
errH: func(rw http.ResponseWriter, code int) {
r.URL.Path = "/"
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
dws.ServeHTTP(rw, r)
},
}, r)
})
}

grpcWebServer := grpcweb.WrapServer(grpcServer)
Expand Down Expand Up @@ -231,6 +244,27 @@ func grpcTrafficSplitter(fallback http.Handler, wrappedGrpc *grpcweb.WrappedGrpc
})
}

type interceptResponseWriter struct {
http.ResponseWriter
errH func(http.ResponseWriter, int)
}

func (w *interceptResponseWriter) WriteHeader(status int) {
if status >= http.StatusBadRequest {
w.errH(w.ResponseWriter, status)
w.errH = nil
} else {
w.ResponseWriter.WriteHeader(status)
}
}

func (w *interceptResponseWriter) Write(p []byte) (n int, err error) {
if w.errH == nil {
return len(p), nil
}
return w.ResponseWriter.Write(p)
}

func init() {
rootCmd.AddCommand(runCmd)

Expand Down
1 change: 1 addition & 0 deletions logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions logo_background.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions logo_path.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion pkg/logcutter/logcutter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestDefaultCutterSlice(t *testing.T) {
v1.LogSliceEvent{Name: "otherproc", Type: v1.LogSliceType_SLICE_START},
v1.LogSliceEvent{Name: "otherproc", Type: v1.LogSliceType_SLICE_CONTENT, Payload: "Some other process"},
v1.LogSliceEvent{Name: "foobar", Type: v1.LogSliceType_SLICE_CONTENT, Payload: "More output"},
v1.LogSliceEvent{Name: "foobar", Type: v1.LogSliceType_SLICE_END},
v1.LogSliceEvent{Name: "foobar", Type: v1.LogSliceType_SLICE_DONE},
v1.LogSliceEvent{Name: "otherproc", Type: v1.LogSliceType_SLICE_CONTENT, Payload: "Cool beans"},
v1.LogSliceEvent{Name: "otherproc", Type: v1.LogSliceType_SLICE_ABANDONED},
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/webui/src/JobList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { WerftServiceClient } from './api/werft_pb_service';
import { JobStatus, ListJobsResponse, ListJobsRequest, JobPhase, SubscribeRequest, FilterExpression, FilterTerm, FilterOp, OrderExpression } from './api/werft_pb';
import { JobStatus, ListJobsResponse, ListJobsRequest, JobPhase, SubscribeRequest, FilterExpression, OrderExpression } from './api/werft_pb';
import { Header, headerStyles } from './components/header';
import { createStyles, Theme, Button, Table, TableHead, TableRow, TableCell, TableSortLabel, TableBody, Link, Grid, TablePagination } from '@material-ui/core';
import { WithStyles, withStyles } from '@material-ui/styles';
Expand Down
8 changes: 6 additions & 2 deletions pkg/webui/src/StartJob.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ class StartJobImpl extends React.Component<StartJobProps, StartJobState> {
const repo = s.toObject().repo!;
return (

<ListItem key={i} button component="a" onClick={() => this.setState({active: s, targetRefRev: s.getRepo()!.getRevision()})}>
<ListItem key={i} button component="a" onClick={() => this.setState({
active: s,
useRef: !!s.getRepo()!.getRef(),
targetRefRev: s.getRepo()!.getRef() || s.getRepo()!.getRevision()
})}>
{ this.state.active === s && <ListItemIcon><CheckIcon /></ListItemIcon> }
<ListItemText primary={s.getName()} secondary={`${repo.owner}/${repo.repo}`} />
</ListItem>
Expand All @@ -111,7 +115,7 @@ class StartJobImpl extends React.Component<StartJobProps, StartJobState> {
<Typography variant="h5">Arguments</Typography>
<List>
<ListItem>
<Switch onChange={e => this.setState({useRef: e.target.checked})} />
<Switch defaultChecked={this.state.useRef} onChange={e => this.setState({useRef: e.target.checked})} />
<TextField
className={classes.arg}
label={this.state.useRef ? "Ref" : "Revision"}
Expand Down
22 changes: 17 additions & 5 deletions pkg/webui/src/components/LogView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ interface Content {
type: "content"
name: string
lines: string[]
status: "running" | "done" | "failed"
status: "running" | "done" | "failed" | "unknown"
}

function isContent(c: Chunk): c is Content {
Expand All @@ -73,7 +73,7 @@ class LogViewImpl extends React.Component<LogViewProps, LogViewState> {
this.state = {
chunks: new Map<string, Chunk>(),
autoscroll: true,
showKubeUpdates: true,
showKubeUpdates: false,
}

this.updateChunks();
Expand Down Expand Up @@ -116,12 +116,21 @@ class LogViewImpl extends React.Component<LogViewProps, LogViewState> {
content.lines.push(le.getPayload());
chunks.set(id, content);
} else if (le.getType() === LogSliceType.SLICE_PHASE) {
chunks.set("phase:"+le.getName(), {
const id = "phase:"+le.getName();
if (chunks.has(id)) {
return;
}

chunks.set(id, {
type: "phase",
desc: le.getPayload(),
name: le.getName()
})
phase = le.getName();

Array.from(chunks.entries())
.filter(([id, chunk]) => !id.startsWith(phase) && isContent(chunk) && chunk.status === "running")
.forEach(([id, chunk]) => { console.log("ending", phase, id, chunk); (chunk as Content).status = "unknown"; chunks.set(id, chunk); })
}
});
}
Expand Down Expand Up @@ -173,7 +182,7 @@ class LogViewImpl extends React.Component<LogViewProps, LogViewState> {
{ chunk.status === "done" && <DoneIcon /> }
{ chunk.status === "failed" && <ErrorIcon /> }
{ chunk.status === "running" && !this.props.finished && <CircularProgress style={{width:'24px', height:'24px'}} /> }
{ chunk.status === "running" && this.props.finished && <DoneIcon style={{opacity:0.25}} /> }
{ ((chunk.status === "running" && this.props.finished) || chunk.status === "unknown") && <DoneIcon style={{opacity:0.25}} /> }
<span className={classes.sectionTitle}>{ chunk.name }</span>
<span dangerouslySetInnerHTML={{__html: chunk.lines[chunk.lines.length - 1]}}></span>
</ExpansionPanelSummary>
Expand Down Expand Up @@ -211,7 +220,10 @@ class LogViewImpl extends React.Component<LogViewProps, LogViewState> {
protected getRawLogs() {
let rawLog = this.props.logs.map(c => c.getPayload());
if (!this.state.showKubeUpdates) {
rawLog = this.props.logs.filter(c => !c.getPayload().trim().startsWith("[werft:kubernetes]")).map(c => c.getPayload());
rawLog = this.props.logs.filter(c =>
!c.getPayload().trim().startsWith("[werft:kubernetes]")
&& !c.getPayload().trim().startsWith("[werft:status]")
).map(c => c.getPayload());
}
return rawLog.join("");
}
Expand Down
1 change: 0 additions & 1 deletion pkg/webui/src/components/SearchBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ class SearchBoxImpl extends React.Component<SearchBoxProps, SearchBoxState> {
console.log(this.props.defaultValue);

if (!!this.props.defaultValue) {
debugger;
this.updateChips(this.props.defaultValue);
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/webui/src/components/terminal.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* https://raw.githubusercontent.com/buildkite/terminal-to-html/master/assets/terminal.css */

.term-container {
background: #171717;
background: #333333;
border-radius: 5px;
color: white;
word-break: break-word;
Expand Down
1 change: 1 addition & 0 deletions pkg/werft/uiservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ func (uis *UIService) updateJobSpecs() error {
Host: "github.com",
Owner: repo.Owner,
Repo: repo.Repo,
Ref: repo.Ref,
Revision: repo.Revision,
},
Name: jobName,
Expand Down

0 comments on commit a09f381

Please sign in to comment.