forked from tangled.org/core
Monorepo for Tangled

improve branch-pr ux

Changed files
+149 -51
appview
+17
appview/pages/pages.go
··· 634 634 return p.execute("repo/pulls/patch", w, params) 635 635 } 636 636 637 + type PullPatchUploadParams struct { 638 + RepoInfo RepoInfo 639 + } 640 + 641 + func (p *Pages) PullPatchUploadFragment(w io.Writer, params PullPatchUploadParams) error { 642 + return p.executePlain("fragments/pullPatchUpload", w, params) 643 + } 644 + 645 + type PullCompareBranchesParams struct { 646 + RepoInfo RepoInfo 647 + Branches []types.Branch 648 + } 649 + 650 + func (p *Pages) PullCompareBranchesFragment(w io.Writer, params PullCompareBranchesParams) error { 651 + return p.executePlain("fragments/pullCompareBranches", w, params) 652 + } 653 + 637 654 type PullResubmitParams struct { 638 655 LoggedInUser *auth.User 639 656 RepoInfo RepoInfo
+46
appview/pages/templates/fragments/pullCompareBranches.html
··· 1 + {{ define "fragments/pullCompareBranches" }} 2 + <div id="patch-upload"> 3 + <label for="targetBranch" class="dark:text-white">configure branches</label> 4 + <div class="flex flex-wrap gap-2 items-center"> 5 + <select 6 + required 7 + name="targetBranch" 8 + class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 9 + > 10 + <option disabled selected>target branch</option> 11 + {{ range .Branches }} 12 + <option value="{{ .Reference.Name }}" class="py-1"> 13 + {{ .Reference.Name }} 14 + </option> 15 + {{ end }} 16 + </select> 17 + 18 + {{ i "move-left" "w-5 h-5" }} 19 + 20 + <select 21 + name="sourceBranch" 22 + class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 23 + > 24 + <option disabled selected>source branch</option> 25 + {{ range .Branches }} 26 + <option value="{{ .Reference.Name }}" class="py-1"> 27 + {{ .Reference.Name }} 28 + </option> 29 + {{ end }} 30 + </select> 31 + 32 + <span class="text-sm"> 33 + ... or upload a patch 34 + <button 35 + class="btn text-sm" 36 + hx-get="/{{ .RepoInfo.FullName }}/pulls/new/patch-upload" 37 + hx-swap="outerHTML" 38 + hx-target="#patch-upload" 39 + > 40 + upload patch 41 + </button> 42 + </span> 43 + </div> 44 + 45 + </div> 46 + {{ end }}
+26
appview/pages/templates/fragments/pullPatchUpload.html
··· 1 + {{ define "fragments/pullPatchUpload" }} 2 + <div id="patch-upload"> 3 + <label for="patch" class="dark:text-white">paste your patch here</label> 4 + <textarea 5 + name="patch" 6 + id="patch" 7 + rows="10" 8 + class="w-full resize-y font-mono dark:bg-gray-700 dark:text-white dark:border-gray-600" 9 + placeholder="Paste your git diff output here." 10 + ></textarea> 11 + 12 + {{ if .RepoInfo.Roles.IsPushAllowed }} 13 + <div class="mt-4 text-sm"> 14 + you can also submit a pull request from a branch 15 + <button 16 + class="btn text-sm" 17 + hx-get="/{{ .RepoInfo.FullName }}/pulls/new/compare-branches" 18 + hx-swap="outerHTML" 19 + hx-target="#patch-upload" 20 + > 21 + compare branches 22 + </button> 23 + </div> 24 + {{ end }} 25 + </div> 26 + {{ end }}
+5 -51
appview/pages/templates/repo/pulls/new.html
··· 35 35 ></textarea> 36 36 </div> 37 37 38 - <div> 39 - <label for="targetBranch" class="dark:text-white">configure branches</label> 40 - <div class="flex flex-wrap gap-2 items-center"> 41 - <select 42 - required 43 - name="targetBranch" 44 - class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 45 - > 46 - <option disabled selected>target branch</option> 47 - {{ range .Branches }} 48 - <option value="{{ .Reference.Name }}" class="py-1"> 49 - {{ .Reference.Name }} 50 - </option> 51 - {{ end }} 52 - </select> 53 - 54 - {{ if .RepoInfo.Roles.IsPushAllowed }} 55 - {{ i "move-left" "w-5 h-5" }} 56 - <select 57 - name="sourceBranch" 58 - class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 59 - > 60 - <option disabled selected>source branch</option> 61 - {{ range .Branches }} 62 - <option value="{{ .Reference.Name }}" class="py-1"> 63 - {{ .Reference.Name }} 64 - </option> 65 - {{ end }} 66 - </select> 67 - {{ end }} 68 - 69 - </div> 70 - </div> 71 - 72 - <div class="mt-4"> 73 - {{ $label := "paste your patch here" }} 74 - {{ $rows := 10 }} 75 - {{ if .RepoInfo.Roles.IsPushAllowed }} 76 - {{ $label = "or paste your patch here" }} 77 - {{ $rows = 4 }} 78 - {{ end }} 79 - 80 - <label for="patch" class="dark:text-white">{{ $label }}</label> 81 - <textarea 82 - name="patch" 83 - id="patch" 84 - rows="{{$rows}}" 85 - class="w-full resize-y font-mono dark:bg-gray-700 dark:text-white dark:border-gray-600" 86 - placeholder="Paste your git diff output here." 87 - ></textarea> 88 - </div> 38 + {{ if not .RepoInfo.Roles.IsPushAllowed }} 39 + {{ template "fragments/pullPatchUpload" . }} 40 + {{ else }} 41 + {{ template "fragments/pullCompareBranches" . }} 42 + {{ end }} 89 43 90 44 <div class="flex justify-end items-center gap-2"> 91 45 <button type="submit" class="btn">create</button>
+53
appview/state/pull.go
··· 643 643 } 644 644 } 645 645 646 + func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) { 647 + user := s.auth.GetUser(r) 648 + f, err := fullyResolvedRepo(r) 649 + if err != nil { 650 + log.Println("failed to get repo and knot", err) 651 + return 652 + } 653 + 654 + s.pages.PullPatchUploadFragment(w, pages.PullPatchUploadParams{ 655 + RepoInfo: f.RepoInfo(s, user), 656 + }) 657 + } 658 + 659 + func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) { 660 + user := s.auth.GetUser(r) 661 + f, err := fullyResolvedRepo(r) 662 + if err != nil { 663 + log.Println("failed to get repo and knot", err) 664 + return 665 + } 666 + 667 + us, err := NewUnsignedClient(f.Knot, s.config.Dev) 668 + if err != nil { 669 + log.Printf("failed to create unsigned client for %s", f.Knot) 670 + s.pages.Error503(w) 671 + return 672 + } 673 + 674 + resp, err := us.Branches(f.OwnerDid(), f.RepoName) 675 + if err != nil { 676 + log.Println("failed to reach knotserver", err) 677 + return 678 + } 679 + 680 + body, err := io.ReadAll(resp.Body) 681 + if err != nil { 682 + log.Printf("Error reading response body: %v", err) 683 + return 684 + } 685 + 686 + var result types.RepoBranchesResponse 687 + err = json.Unmarshal(body, &result) 688 + if err != nil { 689 + log.Println("failed to parse response:", err) 690 + return 691 + } 692 + 693 + s.pages.PullCompareBranchesFragment(w, pages.PullCompareBranchesParams{ 694 + RepoInfo: f.RepoInfo(s, user), 695 + Branches: result.Branches, 696 + }) 697 + } 698 + 646 699 func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) { 647 700 user := s.auth.GetUser(r) 648 701 f, err := fullyResolvedRepo(r)
+2
appview/state/router.go
··· 89 89 r.Get("/", s.RepoPulls) 90 90 r.With(AuthMiddleware(s)).Route("/new", func(r chi.Router) { 91 91 r.Get("/", s.NewPull) 92 + r.Get("/patch-upload", s.PatchUploadFragment) 93 + r.Get("/compare-branches", s.CompareBranchesFragment) 92 94 r.Post("/", s.NewPull) 93 95 }) 94 96