@@ -83,11 +83,11 @@ div.commit-message.list-entry-border { code { font-family: "Go Mono"; font-size: 12px; } /* Needed in changesapp only because of something in parent containers... */ /* Needed in changes only because of something in parent containers... */ .markdown-body { word-break: break-word; } /* GFM style overrides. */
@@ -9,14 +9,14 @@ import ( "github.com/shurcooL/go/gopherjs_http" "github.com/shurcooL/httpfs/union" ) // Assets contains assets for changesapp. // Assets contains assets for changes. var Assets = union.New(map[string]http.FileSystem{ "/script.js": gopherjs_http.Package("dmitri.shuralyov.com/changes/app/frontend"), "/assets": http.Dir(importPathToDir("dmitri.shuralyov.com/changes/app/_data")), "/script.js": gopherjs_http.Package("dmitri.shuralyov.com/app/changes/frontend"), "/assets": http.Dir(importPathToDir("dmitri.shuralyov.com/app/changes/_data")), }) func importPathToDir(importPath string) string { p, err := build.Import(importPath, "", build.FindOnly) if err != nil {
@@ -1,4 +1,4 @@ //go:generate vfsgendev -source="dmitri.shuralyov.com/changes/app/assets".Assets //go:generate vfsgendev -source="dmitri.shuralyov.com/app/changes/assets".Assets // Package assets contains assets for changesapp. // Package assets contains assets for changes. package assets
@@ -30,15 +30,15 @@ import ( "log" "net/http" "os" "strings" "dmitri.shuralyov.com/changes" "dmitri.shuralyov.com/changes/app" "dmitri.shuralyov.com/changes/fs" "dmitri.shuralyov.com/changes/gerritapi" "dmitri.shuralyov.com/changes/githubapi" "dmitri.shuralyov.com/app/changes" "dmitri.shuralyov.com/service/change" "dmitri.shuralyov.com/service/change/fs" "dmitri.shuralyov.com/service/change/gerritapi" "dmitri.shuralyov.com/service/change/githubapi" "github.com/andygrunwald/go-gerrit" "github.com/google/go-github/github" "github.com/gregjones/httpcache" "github.com/shurcooL/githubql" "github.com/shurcooL/httpgzip" @@ -49,12 +49,12 @@ import ( var httpFlag = flag.String("http", ":8080", "Listen for HTTP connections on this address.") func main() { flag.Parse() var service changes.Service switch 3 { var service change.Service switch 0 { case 0: // Perform GitHub API authentication with provided token. token := os.Getenv("CHANGES_GITHUB_TOKEN") if token == "" { log.Fatalln("CHANGES_GITHUB_TOKEN env var is empty") @@ -96,11 +96,11 @@ func main() { case 3: service = &fs.Service{} } changesOpt := changesapp.Options{ changesOpt := changes.Options{ HeadPre: `<style type="text/css"> body { margin: 20px; font-family: Go; font-size: 14px; @@ -114,13 +114,12 @@ func main() { border: solid #d2d2d2 1px; background-color: #fff; box-shadow: 0 1px 1px rgba(0, 0, 0, .05); } </style>`, DisableReactions: true, } changesApp := changesapp.New(service, nil, changesOpt) changesApp := changes.New(service, nil, changesOpt) issuesHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { prefixLen := len("/changes") if prefix := req.URL.Path[:prefixLen]; req.URL.Path == prefix+"/" { baseURL := prefix @@ -132,20 +131,21 @@ func main() { } req.URL.Path = req.URL.Path[prefixLen:] if req.URL.Path == "" { req.URL.Path = "/" } //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "github.com/google/go-github")) //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "github.com/dustin/go-humanize")) //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "github.com/neugram/ng")) //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "github.com/golang/scratch")) //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "go.googlesource.com/go")) //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "go.googlesource.com/tools")) //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "go.googlesource.com/build")) //req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "upspin.googlesource.com/upspin")) req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, "dmitri.shuralyov.com/font/woff2")) req = req.WithContext(context.WithValue(req.Context(), changesapp.BaseURIContextKey, "/changes")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "github.com/google/go-github")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "github.com/dustin/go-humanize")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "github.com/neugram/ng")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "github.com/golang/scratch")) req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "github.com/bradleyfalzon/ghinstallation")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "go.googlesource.com/go")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "go.googlesource.com/tools")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "go.googlesource.com/build")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "upspin.googlesource.com/upspin")) //req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, "dmitri.shuralyov.com/font/woff2")) req = req.WithContext(context.WithValue(req.Context(), changes.BaseURIContextKey, "/changes")) changesApp.ServeHTTP(w, req) }) http.Handle("/changes", issuesHandler) http.Handle("/changes/", issuesHandler)
@@ -1,12 +1,12 @@ package changesapp package changes import ( "strings" "dmitri.shuralyov.com/changes" "dmitri.shuralyov.com/changes/app/component" "dmitri.shuralyov.com/app/changes/component" "dmitri.shuralyov.com/service/change" homecomponent "github.com/shurcooL/home/component" "github.com/shurcooL/htmlg" "golang.org/x/net/html" "golang.org/x/net/html/atom" ) @@ -32,11 +32,11 @@ func (cs Commits) Render() []*html.Node { } return []*html.Node{htmlg.DivClass("list-entry-border", nodes...)} } type Commit struct { changes.Commit change.Commit } func (c Commit) Render() []*html.Node { div := &html.Node{ Type: html.ElementNode, Data: atom.Div.String(),
@@ -1,11 +1,11 @@ package component import ( "fmt" "dmitri.shuralyov.com/changes" "dmitri.shuralyov.com/service/change" "github.com/shurcooL/htmlg" issuescomponent "github.com/shurcooL/issuesapp/component" "github.com/shurcooL/octiconssvg" "golang.org/x/net/html" "golang.org/x/net/html/atom" @@ -13,11 +13,11 @@ import ( // Changes is a component that displays a page of changes, // with a navigation bar on top. type Changes struct { IssuesNav IssuesNav Filter changes.StateFilter Filter change.StateFilter Entries []ChangeEntry } func (i Changes) Render() []*html.Node { // TODO: Make this much nicer. @@ -40,15 +40,15 @@ func (i Changes) Render() []*html.Node { div := &html.Node{ Type: html.ElementNode, Data: atom.Div.String(), Attr: []html.Attribute{{Key: atom.Style.String(), Val: "text-align: center; margin-top: 80px; margin-bottom: 80px;"}}, } switch i.Filter { case changes.FilterOpen: case change.FilterOpen: div.AppendChild(htmlg.Text("There are no open changes.")) case changes.FilterClosedMerged: case change.FilterClosedMerged: div.AppendChild(htmlg.Text("There are no closed/merged changes.")) case changes.FilterAll: case change.FilterAll: div.AppendChild(htmlg.Text("There are no changes.")) } ns = append(ns, div) } @@ -56,11 +56,11 @@ func (i Changes) Render() []*html.Node { return []*html.Node{div} } // ChangeEntry is an entry within the list of changes. type ChangeEntry struct { Change changes.Change Change change.Change Unread bool // Unread indicates whether the change contains unread notifications for authenticated user. // TODO, THINK: This is router details, can it be factored out or cleaned up? BaseURI string }
@@ -3,11 +3,11 @@ package component import ( "fmt" "time" "dmitri.shuralyov.com/changes" "dmitri.shuralyov.com/service/change" "github.com/dustin/go-humanize" "github.com/shurcooL/htmlg" issuescomponent "github.com/shurcooL/issuesapp/component" "github.com/shurcooL/octiconssvg" "github.com/shurcooL/users" @@ -15,11 +15,11 @@ import ( "golang.org/x/net/html/atom" ) // Event is an event component. type Event struct { Event changes.TimelineItem Event change.TimelineItem } func (e Event) Render() []*html.Node { // TODO: Make this much nicer. // <div class="list-entry event event-{{.Type}}"> @@ -49,41 +49,41 @@ func (e Event) icon() *html.Node { icon *html.Node color = "#767676" backgroundColor = "#f3f3f3" ) switch p := e.Event.Payload.(type) { case changes.ClosedEvent: case change.ClosedEvent: icon = octiconssvg.CircleSlash() color, backgroundColor = "#fff", "#bd2c00" case changes.ReopenedEvent: case change.ReopenedEvent: icon = octiconssvg.PrimitiveDot() color, backgroundColor = "#fff", "#6cc644" case changes.RenamedEvent: case change.RenamedEvent: icon = octiconssvg.Pencil() case changes.LabeledEvent, changes.UnlabeledEvent: case change.LabeledEvent, change.UnlabeledEvent: icon = octiconssvg.Tag() case changes.ReviewRequestedEvent: case change.ReviewRequestedEvent: icon = octiconssvg.Eye() case changes.ReviewRequestRemovedEvent: case change.ReviewRequestRemovedEvent: icon = octiconssvg.X() case changes.MergedEvent: case change.MergedEvent: icon = octiconssvg.GitMerge() color, backgroundColor = "#fff", "#6f42c1" case changes.DeletedEvent: case change.DeletedEvent: switch p.Type { case "branch": icon = octiconssvg.GitBranch() color, backgroundColor = "#fff", "#767676" case "comment": icon = octiconssvg.X() default: panic("unreachable") } case changes.ApprovedEvent: case change.ApprovedEvent: icon = octiconssvg.Check() color, backgroundColor = "#fff", "#6cc644" case changes.ChangesRequestedEvent: case change.ChangesRequestedEvent: icon = octiconssvg.X() color, backgroundColor = "#fff", "#bd2c00" default: icon = octiconssvg.PrimitiveDot() } @@ -97,46 +97,46 @@ func (e Event) icon() *html.Node { } } func (e Event) text() []*html.Node { switch p := e.Event.Payload.(type) { case changes.ClosedEvent: case change.ClosedEvent: return []*html.Node{htmlg.Text("closed this")} case changes.ReopenedEvent: case change.ReopenedEvent: return []*html.Node{htmlg.Text("reopened this")} case changes.RenamedEvent: case change.RenamedEvent: return []*html.Node{htmlg.Text("changed the title from "), htmlg.Strong(p.From), htmlg.Text(" to "), htmlg.Strong(p.To)} case changes.LabeledEvent: case change.LabeledEvent: var ns []*html.Node ns = append(ns, htmlg.Text("added the ")) ns = append(ns, issuescomponent.Label{Label: p.Label}.Render()...) ns = append(ns, htmlg.Text(" label")) return ns case changes.UnlabeledEvent: case change.UnlabeledEvent: var ns []*html.Node ns = append(ns, htmlg.Text("removed the ")) ns = append(ns, issuescomponent.Label{Label: p.Label}.Render()...) ns = append(ns, htmlg.Text(" label")) return ns case changes.ReviewRequestedEvent: case change.ReviewRequestedEvent: ns := []*html.Node{htmlg.Text("requested a review from ")} ns = append(ns, Avatar{User: p.RequestedReviewer, Size: 16, inline: true}.Render()...) ns = append(ns, User{p.RequestedReviewer}.Render()...) return ns case changes.ReviewRequestRemovedEvent: case change.ReviewRequestRemovedEvent: ns := []*html.Node{htmlg.Text("removed the review request from ")} ns = append(ns, Avatar{User: p.RequestedReviewer, Size: 16, inline: true}.Render()...) ns = append(ns, User{p.RequestedReviewer}.Render()...) return ns case changes.MergedEvent: case change.MergedEvent: var ns []*html.Node ns = append(ns, htmlg.Text("merged commit ")) ns = append(ns, htmlg.Strong(p.CommitID)) // TODO: Code{}, use CommitHTMLURL. ns = append(ns, htmlg.Text(" into ")) ns = append(ns, htmlg.Strong(p.RefName)) // TODO: Code{}. return ns case changes.DeletedEvent: case change.DeletedEvent: switch p.Type { case "branch": var ns []*html.Node ns = append(ns, htmlg.Text("deleted the ")) ns = append(ns, htmlg.Strong(p.Name)) // TODO: Code{}. @@ -145,23 +145,23 @@ func (e Event) text() []*html.Node { case "comment": return []*html.Node{htmlg.Text("deleted a comment")} default: panic("unreachable") } case changes.ApprovedEvent: case change.ApprovedEvent: return []*html.Node{htmlg.Text("approved this change")} case changes.ChangesRequestedEvent: case change.ChangesRequestedEvent: return []*html.Node{htmlg.Text("requested changes")} default: return []*html.Node{htmlg.Text("unknown event")} // TODO: See if this is optimal. } } // ChangeStateBadge is a component that displays the state of a change // with a badge, who opened it, and when it was opened. type ChangeStateBadge struct { Change changes.Change Change change.Change } func (i ChangeStateBadge) Render() []*html.Node { var ns []*html.Node ns = append(ns, ChangeBadge{State: i.Change.State}.Render()...) @@ -178,29 +178,29 @@ func (i ChangeStateBadge) Render() []*html.Node { return ns } // ChangeBadge is a change badge, displaying the change's state. type ChangeBadge struct { State changes.State State change.State } func (cb ChangeBadge) Render() []*html.Node { var ( icon *html.Node text string color string ) switch cb.State { case changes.OpenState: case change.OpenState: icon = octiconssvg.GitPullRequest() text = "Open" color = "#6cc644" case changes.ClosedState: case change.ClosedState: icon = octiconssvg.GitPullRequest() text = "Closed" color = "#bd2c00" case changes.MergedState: case change.MergedState: icon = octiconssvg.GitMerge() text = "Merged" color = "#6f42c1" default: return []*html.Node{htmlg.Text(string(cb.State))} @@ -225,11 +225,11 @@ background-color: ` + color + `;`, return []*html.Node{span} } // ChangeIcon is a change icon, displaying the change's state. type ChangeIcon struct { State changes.State State change.State } func (ii ChangeIcon) Render() []*html.Node { // TODO: Make this much nicer. // {{if eq . "open"}} @@ -240,17 +240,17 @@ func (ii ChangeIcon) Render() []*html.Node { var ( icon *html.Node color string ) switch ii.State { case changes.OpenState: case change.OpenState: icon = octiconssvg.GitPullRequest() color = "#6cc644" case changes.ClosedState: case change.ClosedState: icon = octiconssvg.GitPullRequest() color = "#bd2c00" case changes.MergedState: case change.MergedState: icon = octiconssvg.GitMerge() color = "#6f42c1" } span := &html.Node{ Type: html.ElementNode, Data: atom.Span.String(),
@@ -1,17 +1,17 @@ package changesapp package changes import ( "bytes" "fmt" "html/template" "sort" "strings" "time" "dmitri.shuralyov.com/changes" "dmitri.shuralyov.com/changes/app/component" "dmitri.shuralyov.com/app/changes/component" "dmitri.shuralyov.com/service/change" "github.com/shurcooL/highlight_diff" "github.com/shurcooL/htmlg" "github.com/shurcooL/users" "github.com/sourcegraph/annotate" "golang.org/x/net/html" @@ -25,41 +25,41 @@ type timelineItem struct { TimelineItem interface{} } func (i timelineItem) TemplateName() string { switch i.TimelineItem.(type) { case changes.Comment: case change.Comment: return "comment" case changes.Review: case change.Review: return "review" case changes.TimelineItem: case change.TimelineItem: return "event" default: panic(fmt.Errorf("unknown item type %T", i.TimelineItem)) } } func (i timelineItem) CreatedAt() time.Time { switch i := i.TimelineItem.(type) { case changes.Comment: case change.Comment: return i.CreatedAt case changes.Review: case change.Review: return i.CreatedAt case changes.TimelineItem: case change.TimelineItem: return i.CreatedAt default: panic(fmt.Errorf("unknown item type %T", i)) } } func (i timelineItem) ID() uint64 { switch i := i.TimelineItem.(type) { case changes.Comment: case change.Comment: return i.ID case changes.Review: case change.Review: return i.ID case changes.TimelineItem: case change.TimelineItem: return i.ID default: panic(fmt.Errorf("unknown item type %T", i)) } }
@@ -1,2 +1,2 @@ // Package changesapp is a web frontend for a changes service. package changesapp // Package changes is a web frontend for a change tracking service. package changes
@@ -1,6 +1,6 @@ package changesapp package changes import ( "context" "errors" "fmt"
@@ -1,6 +1,6 @@ // frontend script for changesapp. // frontend script for changes. // // It's a Go package meant to be compiled with GOARCH=js // and executed in a browser, where the DOM is available. package main
@@ -1,6 +1,6 @@ package changesapp package changes import ( "bytes" "context" "encoding/json" @@ -15,14 +15,14 @@ import ( "sort" "strconv" "strings" "time" "dmitri.shuralyov.com/changes" "dmitri.shuralyov.com/changes/app/assets" "dmitri.shuralyov.com/changes/app/common" "dmitri.shuralyov.com/changes/app/component" "dmitri.shuralyov.com/app/changes/assets" "dmitri.shuralyov.com/app/changes/common" "dmitri.shuralyov.com/app/changes/component" "dmitri.shuralyov.com/service/change" "github.com/dustin/go-humanize" "github.com/shurcooL/github_flavored_markdown" "github.com/shurcooL/htmlg" "github.com/shurcooL/httperror" "github.com/shurcooL/httpfs/html/vfstemplate" @@ -34,11 +34,11 @@ import ( "github.com/shurcooL/users" "golang.org/x/net/html" "sourcegraph.com/sourcegraph/go-diff/diff" ) // TODO: Find a better way for changesapp to be able to ensure registration of a top-level route: // TODO: Find a better way for changes to be able to ensure registration of a top-level route: // // emojisHandler := httpgzip.FileServer(emojis.Assets, httpgzip.FileServerOptions{ServeError: httpgzip.Detailed}) // http.Handle("/emojis/", http.StripPrefix("/emojis", emojisHandler)) // // So that it can depend on it. @@ -50,18 +50,18 @@ import ( // // In order to serve HTTP requests, the returned http.Handler expects each incoming // request to have 2 parameters provided to it via RepoSpecContextKey and BaseURIContextKey // context keys. For example: // // changesApp := changesapp.New(...) // changesApp := changes.New(...) // // http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { // req = req.WithContext(context.WithValue(req.Context(), changesapp.RepoSpecContextKey, string(...))) // req = req.WithContext(context.WithValue(req.Context(), changesapp.BaseURIContextKey, string(...))) // req = req.WithContext(context.WithValue(req.Context(), changes.RepoSpecContextKey, string(...))) // req = req.WithContext(context.WithValue(req.Context(), changes.BaseURIContextKey, string(...))) // changesApp.ServeHTTP(w, req) // }) func New(service changes.Service, users users.Service, opt Options) http.Handler { func New(service change.Service, users users.Service, opt Options) http.Handler { static, err := loadTemplates(common.State{}, opt.BodyPre) if err != nil { log.Fatalln("loadTemplates failed:", err) } h := handler{ @@ -98,14 +98,14 @@ type Options struct { // BodyTop provides components to include on top of <body> of page rendered for req. It can be nil. BodyTop func(*http.Request, common.State) ([]htmlg.Component, error) } // handler handles all requests to changesapp. It acts like a request multiplexer, // handler handles all requests to changes. It acts like a request multiplexer, // choosing from various endpoints and parsing the repository ID from URL. type handler struct { is changes.Service is change.Service us users.Service // May be nil if there's no users service. assetsFileServer http.Handler gfmFileServer http.Handler @@ -115,14 +115,14 @@ type handler struct { Options } func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) error { if _, ok := req.Context().Value(RepoSpecContextKey).(string); !ok { return fmt.Errorf("request to %v doesn't have changesapp.RepoSpecContextKey context key set", req.URL.Path) return fmt.Errorf("request to %v doesn't have changes.RepoSpecContextKey context key set", req.URL.Path) } if _, ok := req.Context().Value(BaseURIContextKey).(string); !ok { return fmt.Errorf("request to %v doesn't have changesapp.BaseURIContextKey context key set", req.URL.Path) return fmt.Errorf("request to %v doesn't have changes.BaseURIContextKey context key set", req.URL.Path) } // Handle "/assets/gfm/...". if strings.HasPrefix(req.URL.Path, "/assets/gfm/") { req = stripPrefix(req, len("/assets/gfm")) @@ -192,19 +192,19 @@ func (h *handler) ChangesHandler(w http.ResponseWriter, req *http.Request) error } filter, err := stateFilter(req.URL.Query()) if err != nil { return httperror.BadRequest{Err: err} } is, err := h.is.List(req.Context(), state.RepoSpec, changes.ListOptions{Filter: filter}) is, err := h.is.List(req.Context(), state.RepoSpec, change.ListOptions{Filter: filter}) if err != nil { return err } openCount, err := h.is.Count(req.Context(), state.RepoSpec, changes.ListOptions{Filter: changes.FilterOpen}) openCount, err := h.is.Count(req.Context(), state.RepoSpec, change.ListOptions{Filter: change.FilterOpen}) if err != nil { return fmt.Errorf("changes.Count(open): %v", err) } closedCount, err := h.is.Count(req.Context(), state.RepoSpec, changes.ListOptions{Filter: changes.FilterClosedMerged}) closedCount, err := h.is.Count(req.Context(), state.RepoSpec, change.ListOptions{Filter: change.FilterClosedMerged}) if err != nil { return fmt.Errorf("changes.Count(closed): %v", err) } var es []component.ChangeEntry for _, i := range is { @@ -235,25 +235,25 @@ const ( stateQueryKey = "state" ) // stateFilter parses the change state filter from query, // returning an error if the value is unsupported. func stateFilter(query url.Values) (changes.StateFilter, error) { func stateFilter(query url.Values) (change.StateFilter, error) { selectedTabName := query.Get(stateQueryKey) switch selectedTabName { case "": return changes.FilterOpen, nil return change.FilterOpen, nil case "closed": return changes.FilterClosedMerged, nil return change.FilterClosedMerged, nil case "all": return changes.FilterAll, nil return change.FilterAll, nil default: return "", fmt.Errorf("unsupported state filter value: %q", selectedTabName) } } func (s state) augmentUnread(ctx context.Context, es []component.ChangeEntry, is changes.Service, notificationsService notifications.Service) []component.ChangeEntry { func (s state) augmentUnread(ctx context.Context, es []component.ChangeEntry, is change.Service, notificationsService notifications.Service) []component.ChangeEntry { if notificationsService == nil { return es } tt, ok := is.(interface { @@ -307,23 +307,23 @@ func (h *handler) MockHandler(w http.ResponseWriter, req *http.Request) error { return fmt.Errorf("loadTemplates: %v", err) } w.Header().Set("Content-Type", "text/html; charset=utf-8") err = t.ExecuteTemplate(w, "review-mock", struct { state Review changes.Review Review change.Review }{ state: st, Review: changes.Review{ Review: change.Review{ ID: 0, User: users.User{Login: "Eric Grosse", AvatarURL: "https://lh6.googleusercontent.com/-_sdEtv2PRxk/AAAAAAAAAAI/AAAAAAAAAAA/aE1Q66Cuvb4/s100-p/photo.jpg"}, CreatedAt: time.Now().UTC(), Edited: nil, State: changes.Approved, State: change.Approved, Body: "", Reactions: []reactions.Reaction{}, Editable: true, Comments: []changes.InlineComment{ Comments: []change.InlineComment{ { File: "rpc/keyserver/server.go", Line: 26, Body: "Ok by me, but how was this chosen?", }, @@ -446,13 +446,13 @@ func (h *handler) ChangeFilesHandler(w http.ResponseWriter, req *http.Request, c } if next := i + 1; next < len(cs) { commit.NextSHA = cs[next].SHA } } var opt *changes.GetDiffOptions var opt *change.GetDiffOptions if commitID != "" { opt = &changes.GetDiffOptions{Commit: commitID} opt = &change.GetDiffOptions{Commit: commitID} } rawDiff, err := h.is.GetDiff(req.Context(), state.RepoSpec, state.ChangeID, opt) if err != nil { return err } @@ -481,11 +481,11 @@ func (h *handler) ChangeFilesHandler(w http.ResponseWriter, req *http.Request, c return err } // commitIndex returns the index of commit with SHA equal to commitID, // or -1 if not found. func commitIndex(cs []changes.Commit, commitID string) int { func commitIndex(cs []change.Commit, commitID string) int { for i := range cs { if cs[i].SHA == commitID { return i } } @@ -543,11 +543,11 @@ type state struct { BodyTop template.HTML common.State Changes component.Changes Change changes.Change Change change.Change Timeline []timelineItem } func (s state) Tabnav(selected string) template.HTML { // Render the tabnav. @@ -622,12 +622,12 @@ func loadTemplates(state common.State, bodyPre string) (*template.Template, erro }, "render": func(c htmlg.Component) template.HTML { return template.HTML(htmlg.Render(c.Render()...)) }, "event": func(e changes.TimelineItem) htmlg.Component { return component.Event{Event: e} }, "changeStateBadge": func(c changes.Change) htmlg.Component { return component.ChangeStateBadge{Change: c} }, "event": func(e change.TimelineItem) htmlg.Component { return component.Event{Event: e} }, "changeStateBadge": func(c change.Change) htmlg.Component { return component.ChangeStateBadge{Change: c} }, "time": func(t time.Time) htmlg.Component { return component.Time{Time: t} }, "user": func(u users.User) htmlg.Component { return component.User{User: u} }, "avatar": func(u users.User) htmlg.Component { return component.Avatar{User: u, Size: 48} }, }) t, err := vfstemplate.ParseGlob(assets.Assets, t, "/assets/*.tmpl") @@ -642,11 +642,11 @@ func loadTemplates(state common.State, bodyPre string) (*template.Template, erro type contextKey struct { name string } func (k *contextKey) String() string { return "dmitri.shuralyov.com/changes/app context value " + k.name return "dmitri.shuralyov.com/app/changes context value " + k.name } // stripPrefix returns request r with prefix of length prefixLen stripped from r.URL.Path. // prefixLen must not be longer than len(r.URL.Path), otherwise stripPrefix panics. // If r.URL.Path is empty after the prefix is stripped, the path is changed to "/".