forked from tangled.org/core
Monorepo for Tangled

appview: tags and branches pages

Changed files
+220 -54
appview
knotserver
types
+20
appview/pages/pages.go
··· 185 185 func (p *Pages) RepoTree(w io.Writer, params RepoTreeParams) error { 186 186 return p.execute("repo/tree", w, params) 187 187 } 188 + 189 + type RepoBranchesParams struct { 190 + LoggedInUser *auth.User 191 + RepoInfo RepoInfo 192 + types.RepoBranchesResponse 193 + } 194 + 195 + func (p *Pages) RepoBranches(w io.Writer, params RepoBranchesParams) error { 196 + return p.execute("repo/branches", w, params) 197 + } 198 + 199 + type RepoTagsParams struct { 200 + LoggedInUser *auth.User 201 + RepoInfo RepoInfo 202 + types.RepoTagsResponse 203 + } 204 + 205 + func (p *Pages) RepoTags(w io.Writer, params RepoTagsParams) error { 206 + return p.execute("repo/tags", w, params) 207 + }
+18
appview/pages/templates/repo/branches.html
··· 1 + {{ define "title" }} 2 + branches | {{ .RepoInfo.OwnerWithAt }} / 3 + {{ .RepoInfo.Name }} 4 + {{ end }} 5 + 6 + {{ define "content" }} 7 + {{ $name := .RepoInfo.Name }} 8 + <h3>branches</h3> 9 + <div class="refs"> 10 + {{ range .Branches }} 11 + <div> 12 + <strong>{{ .Name }}</strong> 13 + <a href="/{{ $name }}/tree/{{ .Name }}/">browse</a> 14 + <a href="/{{ $name }}/log/{{ .Name }}">log</a> 15 + </div> 16 + {{ end }} 17 + </div> 18 + {{ end }}
+6 -8
appview/pages/templates/repo/empty.html
··· 1 - <html> 2 - {{ template "layouts/head" . }} 1 + {{ define "title" }}{{ .RepoInfo.OwnerWithAt }} / {{ .RepoInfo.Name }}{{ end }} 3 2 4 - <body> 5 - <main></main> 6 - <p>This is an empty Git repository. Push some commits here.</p> 7 - </main> 8 - </body> 9 - </html> 3 + {{ define "content" }} 4 + <main> 5 + <p>This is an empty Git repository. Push some commits here.</p> 6 + </main> 7 + {{ end }}
-38
appview/pages/templates/repo/refs.html
··· 1 - <html> 2 - {{ template "layouts/head" . }} 3 - 4 - {{ template "layouts/repo-header" . }} 5 - <body> 6 - {{ template "layouts/nav" . }} 7 - <main> 8 - {{ $name := .name }} 9 - <h3>branches</h3> 10 - <div class="refs"> 11 - {{ range .branches }} 12 - <div> 13 - <strong>{{ .Name.Short }}</strong> 14 - <a href="/{{ $name }}/tree/{{ .Name.Short }}/">browse</a> 15 - <a href="/{{ $name }}/log/{{ .Name.Short }}">log</a> 16 - <a href="/{{ $name }}/archive/{{ .Name.Short }}.tar.gz">tar.gz</a> 17 - </div> 18 - {{ end }} 19 - </div> 20 - {{ if .tags }} 21 - <h3>tags</h3> 22 - <div class="refs"> 23 - {{ range .tags }} 24 - <div> 25 - <strong>{{ .Name }}</strong> 26 - <a href="/{{ $name }}/tree/{{ .Name }}/">browse</a> 27 - <a href="/{{ $name }}/log/{{ .Name }}">log</a> 28 - <a href="/{{ $name }}/archive/{{ .Name }}.tar.gz">tar.gz</a> 29 - {{ if .Message }} 30 - <pre>{{ .Message }}</pre> 31 - </div> 32 - {{ end }} 33 - {{ end }} 34 - </div> 35 - {{ end }} 36 - </main> 37 - </body> 38 - </html>
+22
appview/pages/templates/repo/tags.html
··· 1 + {{ define "title" }} 2 + tags | {{ .RepoInfo.OwnerWithAt }} / 3 + {{ .RepoInfo.Name }} 4 + {{ end }} 5 + 6 + {{ define "content" }} 7 + {{ $name := .RepoInfo.Name }} 8 + <h3>tags</h3> 9 + <div class="refs"> 10 + {{ range .Tags }} 11 + <div> 12 + <strong>{{ .Ref.Name }}</strong> 13 + <a href="/{{ $name }}/tree/{{ .Ref.Name }}/">browse</a> 14 + <a href="/{{ $name }}/log/{{ .Ref.Name }}">log</a> 15 + <a href="/{{ $name }}/archive/{{ .Ref.Name }}.tar.gz">tar.gz</a> 16 + {{ if .Message }} 17 + <pre>{{ .Message }}</pre> 18 + {{ end }} 19 + </div> 20 + {{ end }} 21 + </div> 22 + {{ end }}
+76
appview/state/repo.go
··· 175 175 return 176 176 } 177 177 178 + func (s *State) RepoTags(w http.ResponseWriter, r *http.Request) { 179 + repoName, knot, id, err := repoKnotAndId(r) 180 + if err != nil { 181 + log.Println("failed to get repo and knot", err) 182 + return 183 + } 184 + 185 + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/tags", knot, id.DID.String(), repoName)) 186 + if err != nil { 187 + log.Println("failed to reach knotserver", err) 188 + return 189 + } 190 + 191 + body, err := io.ReadAll(resp.Body) 192 + if err != nil { 193 + log.Fatalf("Error reading response body: %v", err) 194 + return 195 + } 196 + 197 + var result types.RepoTagsResponse 198 + err = json.Unmarshal(body, &result) 199 + if err != nil { 200 + log.Println("failed to parse response:", err) 201 + return 202 + } 203 + 204 + s.pages.RepoTags(w, pages.RepoTagsParams{ 205 + LoggedInUser: s.auth.GetUser(r), 206 + RepoInfo: pages.RepoInfo{ 207 + OwnerDid: id.DID.String(), 208 + OwnerHandle: id.Handle.String(), 209 + Name: repoName, 210 + }, 211 + RepoTagsResponse: result, 212 + }) 213 + return 214 + } 215 + 216 + func (s *State) RepoBranches(w http.ResponseWriter, r *http.Request) { 217 + repoName, knot, id, err := repoKnotAndId(r) 218 + if err != nil { 219 + log.Println("failed to get repo and knot", err) 220 + return 221 + } 222 + 223 + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/branches", knot, id.DID.String(), repoName)) 224 + if err != nil { 225 + log.Println("failed to reach knotserver", err) 226 + return 227 + } 228 + 229 + body, err := io.ReadAll(resp.Body) 230 + if err != nil { 231 + log.Fatalf("Error reading response body: %v", err) 232 + return 233 + } 234 + 235 + var result types.RepoBranchesResponse 236 + err = json.Unmarshal(body, &result) 237 + if err != nil { 238 + log.Println("failed to parse response:", err) 239 + return 240 + } 241 + 242 + s.pages.RepoBranches(w, pages.RepoBranchesParams{ 243 + LoggedInUser: s.auth.GetUser(r), 244 + RepoInfo: pages.RepoInfo{ 245 + OwnerDid: id.DID.String(), 246 + OwnerHandle: id.Handle.String(), 247 + Name: repoName, 248 + }, 249 + RepoBranchesResponse: result, 250 + }) 251 + return 252 + } 253 + 178 254 func repoKnotAndId(r *http.Request) (string, string, identity.Identity, error) { 179 255 repoName := chi.URLParam(r, "repo") 180 256 knot, ok := r.Context().Value("knot").(string)
+2
appview/state/state.go
··· 614 614 r.Get("/*", s.RepoTree) 615 615 }) 616 616 r.Get("/commit/{ref}", s.RepoCommit) 617 + r.Get("/branches", s.RepoBranches) 618 + r.Get("/tags", s.RepoTags) 617 619 618 620 // These routes get proxied to the knot 619 621 r.Get("/info/refs", s.InfoRefs)
+8
knotserver/git/git.go
··· 347 347 } 348 348 return "" 349 349 } 350 + 351 + func (t *TagReference) TagObject() *object.Tag { 352 + return t.tag 353 + } 354 + 355 + func (t *TagReference) Hash() plumbing.Hash { 356 + return t.ref.Hash() 357 + }
+2 -1
knotserver/handler.go
··· 84 84 r.Get("/log/{ref}", h.Log) 85 85 r.Get("/archive/{file}", h.Archive) 86 86 r.Get("/commit/{ref}", h.Diff) 87 - r.Get("/refs/", h.Refs) 87 + r.Get("/tags", h.Tags) 88 + r.Get("/branches", h.Branches) 88 89 }) 89 90 }) 90 91
+43 -7
knotserver/routes.go
··· 316 316 return 317 317 } 318 318 319 - func (h *Handle) Refs(w http.ResponseWriter, r *http.Request) { 319 + func (h *Handle) Tags(w http.ResponseWriter, r *http.Request) { 320 320 path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 321 321 l := h.l.With("handler", "Refs") 322 322 ··· 329 329 tags, err := gr.Tags() 330 330 if err != nil { 331 331 // Non-fatal, we *should* have at least one branch to show. 332 - l.Error("getting tags", "error", err.Error()) 332 + l.Warn("getting tags", "error", err.Error()) 333 + } 334 + 335 + rtags := []*types.TagReference{} 336 + for _, tag := range tags { 337 + tr := types.TagReference{ 338 + Ref: types.Reference{ 339 + Name: tag.Name(), 340 + Hash: tag.Hash().String(), 341 + }, 342 + Tag: tag.TagObject(), 343 + } 344 + rtags = append(rtags, &tr) 345 + } 346 + 347 + resp := types.RepoTagsResponse{ 348 + Tags: rtags, 349 + } 350 + 351 + writeJSON(w, resp) 352 + return 353 + } 354 + 355 + func (h *Handle) Branches(w http.ResponseWriter, r *http.Request) { 356 + path := filepath.Join(h.c.Repo.ScanPath, didPath(r)) 357 + l := h.l.With("handler", "Branches") 358 + 359 + gr, err := git.Open(path, "") 360 + if err != nil { 361 + notFound(w) 362 + return 333 363 } 334 364 335 365 branches, err := gr.Branches() ··· 339 369 return 340 370 } 341 371 342 - data := make(map[string]interface{}) 372 + bs := []types.Branch{} 373 + for _, branch := range branches { 374 + b := types.Branch{} 375 + b.Hash = branch.Hash().String() 376 + b.Name = branch.Name().Short() 377 + bs = append(bs, b) 378 + } 343 379 344 - data["branches"] = branches 345 - data["tags"] = tags 346 - data["desc"] = getDescription(path) 380 + resp := types.RepoBranchesResponse{ 381 + Branches: bs, 382 + } 347 383 348 - writeJSON(w, data) 384 + writeJSON(w, resp) 349 385 return 350 386 } 351 387
+23
types/repo.go
··· 36 36 DotDot string `json:"dotdot,omitempty"` 37 37 Files []NiceTree `json:"files,omitempty"` 38 38 } 39 + 40 + type TagReference struct { 41 + Ref Reference `json:"ref,omitempty"` 42 + Tag *object.Tag `json:"tag,omitempty"` 43 + Message string `json:"message,omitempty"` 44 + } 45 + 46 + type Reference struct { 47 + Name string `json:"name"` 48 + Hash string `json:"hash"` 49 + } 50 + 51 + type Branch struct { 52 + Reference `json:"reference"` 53 + } 54 + 55 + type RepoTagsResponse struct { 56 + Tags []*TagReference `json:"tags,omitempty"` 57 + } 58 + 59 + type RepoBranchesResponse struct { 60 + Branches []Branch `json:"branches,omitempty"` 61 + }