Monorepo for Tangled tangled.org

appview: pulls: make target branch picking generic

anirudh.fi 6379061a c2e3b7a7

verified
Changed files
+99 -96
appview
-1
appview/pages/pages.go
··· 575 575 type RepoNewPullParams struct { 576 576 LoggedInUser *auth.User 577 577 RepoInfo RepoInfo 578 - Forks []db.Repo 579 578 Branches []types.Branch 580 579 Active string 581 580 }
+17 -32
appview/pages/templates/fragments/pullCompareBranches.html
··· 1 1 {{ define "fragments/pullCompareBranches" }} 2 - 3 - <div id="patch-upload"> 4 - <label for="targetBranch" class="dark:text-white">configure branches</label> 5 - <div class="flex flex-wrap gap-2 items-center"> 6 - <select 7 - required 8 - name="targetBranch" 9 - class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 2 + <div id="patch-upload"> 3 + <label for="targetBranch" class="dark:text-white" 4 + >select a branch</label 10 5 > 11 - <option disabled selected>target branch</option> 12 - {{ range .Branches }} 13 - <option value="{{ .Reference.Name }}" class="py-1"> 14 - {{ .Reference.Name }} 15 - </option> 16 - {{ end }} 17 - </select> 18 - 19 - {{ i "move-left" "w-5 h-5" }} 20 - 21 - <select 22 - name="sourceBranch" 23 - class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 24 - > 25 - <option disabled selected>source branch</option> 26 - {{ range .Branches }} 27 - <option value="{{ .Reference.Name }}" class="py-1"> 28 - {{ .Reference.Name }} 29 - </option> 30 - {{ end }} 31 - </select> 32 - </div> 33 - 34 - </div> 6 + <div class="flex flex-wrap gap-2 items-center"> 7 + <select 8 + name="sourceBranch" 9 + class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 10 + > 11 + <option disabled selected>source branch</option> 12 + {{ range .Branches }} 13 + <option value="{{ .Reference.Name }}" class="py-1"> 14 + {{ .Reference.Name }} 15 + </option> 16 + {{ end }} 17 + </select> 18 + </div> 19 + </div> 35 20 {{ end }}
+32 -25
appview/pages/templates/fragments/pullCompareForks.html
··· 3 3 <label for="forkSelect" class="dark:text-white" 4 4 >select a fork to compare</label 5 5 > 6 - <div class="flex flex-wrap gap-2 items-center mb-4"> 7 - <select 8 - id="forkSelect" 9 - name="fork" 10 - required 11 - class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 12 - hx-get="/{{ $.RepoInfo.FullName }}/pulls/new/fork-branches" 13 - hx-target="#branch-selection" 14 - hx-vals='{"fork": this.value}' 15 - hx-swap="innerHTML" 16 - onchange="document.getElementById('hiddenForkInput').value = this.value;" 17 - > 18 - <option disabled selected>select a fork</option> 19 - {{ range .Forks }} 20 - <option value="{{ .Name }}" class="py-1"> 21 - {{ .Name }} 22 - </option> 23 - {{ end }} 24 - </select> 25 - 26 - <input type="hidden" id="hiddenForkInput" name="fork" value=""> 27 - </div> 6 + <div class="flex flex-wrap gap-4 items-center mb-4"> 7 + <div class="flex flex-wrap gap-2 items-center"> 8 + <select 9 + id="forkSelect" 10 + name="fork" 11 + required 12 + class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 13 + hx-get="/{{ $.RepoInfo.FullName }}/pulls/new/fork-branches" 14 + hx-target="#branch-selection" 15 + hx-vals='{"fork": this.value}' 16 + hx-swap="innerHTML" 17 + onchange="document.getElementById('hiddenForkInput').value = this.value;" 18 + > 19 + <option disabled selected>select a fork</option> 20 + {{ range .Forks }} 21 + <option value="{{ .Name }}" class="py-1"> 22 + {{ .Name }} 23 + </option> 24 + {{ end }} 25 + </select> 26 + 27 + <input 28 + type="hidden" 29 + id="hiddenForkInput" 30 + name="fork" 31 + value="" 32 + /> 33 + </div> 28 34 29 - <div id="branch-selection" class="mt-2"> 30 - <div class="text-sm text-gray-500 dark:text-gray-400"> 31 - Select a fork first to view available branches 35 + <div id="branch-selection"> 36 + <div class="text-sm text-gray-500 dark:text-gray-400"> 37 + Select a fork first to view available branches 38 + </div> 32 39 </div> 33 40 </div> 34 41 </div>
-16
appview/pages/templates/fragments/pullCompareForksBranches.html
··· 1 1 {{ define "fragments/pullCompareForksBranches" }} 2 2 <div class="flex flex-wrap gap-2 items-center"> 3 3 <select 4 - required 5 - name="targetBranch" 6 - class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 7 - > 8 - <option disabled selected>target branch</option> 9 - {{ range .TargetBranches }} 10 - <option value="{{ .Reference.Name }}" class="py-1"> 11 - {{ .Reference.Name }} 12 - </option> 13 - {{ end }} 14 - </select> 15 - 16 - {{ i "move-left" "w-5 h-5" }} 17 - 18 - 19 - <select 20 4 name="sourceBranch" 21 5 class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 22 6 >
+30 -5
appview/pages/templates/repo/pulls/new.html
··· 36 36 </div> 37 37 38 38 39 - <label>choose your pull strategy</label> 40 - <nav class="flex space-x-4"> 39 + <label>configure your pull request</label> 40 + 41 + <p>First, choose a target branch on {{ .RepoInfo.FullName }}.</p> 42 + <div class="pb-2"> 43 + <select 44 + required 45 + name="targetBranch" 46 + class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600" 47 + > 48 + <option disabled selected>target branch</option> 49 + {{ range .Branches }} 50 + <option value="{{ .Reference.Name }}" class="py-1"> 51 + {{ .Reference.Name }} 52 + </option> 53 + {{ end }} 54 + </select> 55 + </div> 56 + 57 + <p>Then, choose a pull strategy.</p> 58 + <nav class="flex space-x-4 items-end"> 41 59 <button 42 60 type="button" 43 61 class="px-3 py-2 pb-2 btn" ··· 49 67 </button> 50 68 51 69 {{ if .RepoInfo.Roles.IsPushAllowed }} 70 + <span class="text-sm text-gray-500 dark:text-gray-400 pb-2"> 71 + or 72 + </span> 52 73 <button 53 74 type="button" 54 75 class="px-3 py-2 pb-2 btn" ··· 59 80 compare branches 60 81 </button> 61 82 {{ end }} 83 + 84 + <span class="text-sm text-gray-500 dark:text-gray-400 pb-2"> 85 + or 86 + </span> 62 87 <button 63 88 type="button" 64 89 class="px-3 py-2 pb-2 btn" ··· 70 95 </button> 71 96 </nav> 72 97 73 - <section id="patch-strategy"> 98 + <section id="patch-strategy"> 74 99 {{ template "fragments/pullPatchUpload" . }} 75 100 </section> 76 101 77 - <div class="flex justify-start items-center gap-2"> 102 + <div class="flex justify-start items-center gap-2 mt-4"> 78 103 <button type="submit" class="btn flex items-center gap-2"> 79 104 {{ i "git-pull-request-create" "w-4 h-4" }} 80 105 create pull 81 106 </button> 82 - </div> 107 + </div> 83 108 84 109 </div> 85 110 <div id="pull" class="error dark:text-red-300"></div>
+6 -1
appview/pages/templates/repo/pulls/pull.html
··· 50 50 {{ if not .Pull.IsSameRepoBranch }} 51 51 <a href="/{{ $owner }}/{{ .PullSourceRepo.Name }}" class="no-underline hover:underline">{{ $owner }}/{{ .PullSourceRepo.Name }}</a> 52 52 {{ end }} 53 + 54 + {{ $fullRepo := .RepoInfo.FullName }} 55 + {{ if not .Pull.IsSameRepoBranch }} 56 + {{ $fullRepo = printf "%s/%s" $owner .PullSourceRepo.Name }} 57 + {{ end }} 53 58 <span class="text-xs rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white font-mono px-2 mx-1/2 inline-flex items-center"> 54 - <a href="/{{ $owner }}/{{ .PullSourceRepo.Name }}/tree/{{ .Pull.PullSource.Branch }}" class="no-underline hover:underline">{{ .Pull.PullSource.Branch }}</a> 59 + <a href="/{{ $fullRepo }}/tree/{{ .Pull.PullSource.Branch }}" class="no-underline hover:underline">{{ .Pull.PullSource.Branch }}</a> 55 60 </span> 56 61 </span> 57 62 {{ end }}
+14 -16
appview/state/pull.go
··· 501 501 return 502 502 } 503 503 504 - forks, err := db.GetForksByDid(s.db, user.Did) 505 - if err != nil { 506 - log.Println("failed to get forks", err) 507 - return 508 - } 509 - 510 504 switch r.Method { 511 505 case http.MethodGet: 512 506 us, err := NewUnsignedClient(f.Knot, s.config.Dev) ··· 538 532 s.pages.RepoNewPull(w, pages.RepoNewPullParams{ 539 533 LoggedInUser: user, 540 534 RepoInfo: f.RepoInfo(s, user), 541 - Forks: forks, 542 535 Branches: result.Branches, 543 536 }) 544 537 case http.MethodPost: ··· 549 542 sourceBranch := r.FormValue("sourceBranch") 550 543 patch := r.FormValue("patch") 551 544 545 + // Validate required fields for all PR types 546 + if title == "" || body == "" || targetBranch == "" { 547 + s.pages.Notice(w, "pull", "Title, body and target branch are required.") 548 + return 549 + } 550 + 551 + // Determine PR type based on input parameters 552 552 isPushAllowed := f.RepoInfo(s, user).Roles.IsPushAllowed() 553 553 isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == "" 554 - isPatchBased := patch != "" 555 554 isForkBased := fromFork != "" && sourceBranch != "" 555 + isPatchBased := patch != "" && !isBranchBased && !isForkBased 556 556 557 + // Validate we have at least one valid PR creation method 557 558 if !isBranchBased && !isPatchBased && !isForkBased { 558 559 s.pages.Notice(w, "pull", "Neither source branch nor patch supplied.") 559 560 return 560 561 } 561 562 562 - if isBranchBased && isPatchBased { 563 + // Can't mix branch-based and patch-based approaches 564 + if isBranchBased && patch != "" { 563 565 s.pages.Notice(w, "pull", "Cannot select both patch and source branch.") 564 566 return 565 567 } 566 568 567 - if title == "" || body == "" || targetBranch == "" { 568 - s.pages.Notice(w, "pull", "Title, body and target branch are required.") 569 - return 570 - } 571 - 569 + // Handle the PR creation based on the type 572 570 if isBranchBased { 573 571 s.handleBranchBasedPull(w, r, f, user, title, body, targetBranch, sourceBranch) 572 + } else if isForkBased { 573 + s.handleForkBasedPull(w, r, f, user, fromFork, title, body, targetBranch, sourceBranch) 574 574 } else if isPatchBased { 575 575 s.handlePatchBasedPull(w, r, f, user, title, body, targetBranch, patch) 576 - } else if isForkBased { 577 - s.handleForkBasedPull(w, r, f, user, fromFork, title, body, targetBranch, sourceBranch) 578 576 } 579 577 return 580 578 }