+27
-7
appview/pages/pages.go
+27
-7
appview/pages/pages.go
···
618
618
}
619
619
620
620
type RepoSinglePullParams struct {
621
-
LoggedInUser *auth.User
622
-
RepoInfo RepoInfo
623
-
Active string
624
-
DidHandleMap map[string]string
625
-
Pull *db.Pull
626
-
MergeCheck types.MergeCheckResponse
627
-
ResubmitCheck ResubmitResult
621
+
LoggedInUser *auth.User
622
+
RepoInfo RepoInfo
623
+
Active string
624
+
DidHandleMap map[string]string
625
+
Pull *db.Pull
626
+
PullSourceRepo *db.Repo
627
+
MergeCheck types.MergeCheckResponse
628
+
ResubmitCheck ResubmitResult
628
629
}
629
630
630
631
func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error {
···
662
663
663
664
func (p *Pages) PullCompareBranchesFragment(w io.Writer, params PullCompareBranchesParams) error {
664
665
return p.executePlain("fragments/pullCompareBranches", w, params)
666
+
}
667
+
668
+
type PullCompareForkParams struct {
669
+
RepoInfo RepoInfo
670
+
Forks []db.Repo
671
+
}
672
+
673
+
func (p *Pages) PullCompareForkFragment(w io.Writer, params PullCompareForkParams) error {
674
+
return p.executePlain("fragments/pullCompareForks", w, params)
675
+
}
676
+
677
+
type PullCompareForkBranchesParams struct {
678
+
RepoInfo RepoInfo
679
+
SourceBranches []types.Branch
680
+
TargetBranches []types.Branch
681
+
}
682
+
683
+
func (p *Pages) PullCompareForkBranchesFragment(w io.Writer, params PullCompareForkBranchesParams) error {
684
+
return p.executePlain("fragments/pullCompareForksBranches", w, params)
665
685
}
666
686
667
687
type PullResubmitParams struct {
+1
-12
appview/pages/templates/fragments/pullCompareBranches.html
+1
-12
appview/pages/templates/fragments/pullCompareBranches.html
···
1
1
{{ define "fragments/pullCompareBranches" }}
2
+
2
3
<div id="patch-upload">
3
4
<label for="targetBranch" class="dark:text-white">configure branches</label>
4
5
<div class="flex flex-wrap gap-2 items-center">
···
28
29
</option>
29
30
{{ end }}
30
31
</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
32
</div>
44
33
45
34
</div>
+35
appview/pages/templates/fragments/pullCompareForks.html
+35
appview/pages/templates/fragments/pullCompareForks.html
···
1
+
{{ define "fragments/pullCompareForks" }}
2
+
<div id="patch-upload">
3
+
<label for="forkSelect" class="dark:text-white"
4
+
>select a fork to compare</label
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>
28
+
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
32
+
</div>
33
+
</div>
34
+
</div>
35
+
{{ end }}
+31
appview/pages/templates/fragments/pullCompareForksBranches.html
+31
appview/pages/templates/fragments/pullCompareForksBranches.html
···
1
+
{{ define "fragments/pullCompareForksBranches" }}
2
+
<div class="flex flex-wrap gap-2 items-center">
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
+
name="sourceBranch"
21
+
class="p-1 border border-gray-200 bg-white dark:bg-gray-700 dark:text-white dark:border-gray-600"
22
+
>
23
+
<option disabled selected>source branch</option>
24
+
{{ range .SourceBranches }}
25
+
<option value="{{ .Reference.Name }}" class="py-1">
26
+
{{ .Reference.Name }}
27
+
</option>
28
+
{{ end }}
29
+
</select>
30
+
</div>
31
+
{{ end }}
+11
-23
appview/pages/templates/fragments/pullPatchUpload.html
+11
-23
appview/pages/templates/fragments/pullPatchUpload.html
···
1
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>
2
+
<div id="patch-upload">
3
+
<textarea
4
+
name="patch"
5
+
id="patch"
6
+
rows="12"
7
+
class="w-full resize-y font-mono dark:bg-gray-700 dark:text-white dark:border-gray-600"
8
+
placeholder="diff --git a/file.txt b/file.txt
9
+
index 1234567..abcdefg 100644
10
+
--- a/file.txt
11
+
+++ b/file.txt"
12
+
></textarea>
23
13
</div>
24
-
{{ end }}
25
-
</div>
26
14
{{ end }}
+41
-7
appview/pages/templates/repo/pulls/new.html
+41
-7
appview/pages/templates/repo/pulls/new.html
···
35
35
></textarea>
36
36
</div>
37
37
38
-
{{ if not .RepoInfo.Roles.IsPushAllowed }}
39
-
{{ template "fragments/pullPatchUpload" . }}
40
-
{{ else }}
41
-
{{ template "fragments/pullCompareBranches" . }}
42
-
{{ end }}
43
38
44
-
Or, select a fork to create a pull request from.
39
+
<label>choose your pull strategy</label>
40
+
<nav class="flex space-x-4">
41
+
<button
42
+
type="button"
43
+
class="px-3 py-2 pb-2 btn"
44
+
hx-get="/{{ .RepoInfo.FullName }}/pulls/new/patch-upload"
45
+
hx-target="#patch-strategy"
46
+
hx-swap="innerHTML"
47
+
>
48
+
paste patch
49
+
</button>
50
+
51
+
{{ if .RepoInfo.Roles.IsPushAllowed }}
52
+
<button
53
+
type="button"
54
+
class="px-3 py-2 pb-2 btn"
55
+
hx-get="/{{ .RepoInfo.FullName }}/pulls/new/compare-branches"
56
+
hx-target="#patch-strategy"
57
+
hx-swap="innerHTML"
58
+
>
59
+
compare branches
60
+
</button>
61
+
{{ end }}
62
+
<button
63
+
type="button"
64
+
class="px-3 py-2 pb-2 btn"
65
+
hx-get="/{{ .RepoInfo.FullName }}/pulls/new/compare-forks"
66
+
hx-target="#patch-strategy"
67
+
hx-swap="innerHTML"
68
+
>
69
+
compare forks
70
+
</button>
71
+
</nav>
72
+
73
+
<section id="patch-strategy">
74
+
{{ template "fragments/pullPatchUpload" . }}
75
+
</section>
45
76
46
77
<div class="flex justify-start items-center gap-2">
47
-
<button type="submit" class="btn">create pull</button>
78
+
<button type="submit" class="btn flex items-center gap-2">
79
+
{{ i "git-pull-request-create" "w-4 h-4" }}
80
+
create pull
81
+
</button>
48
82
</div>
49
83
50
84
</div>
+3
-6
appview/pages/templates/repo/pulls/pull.html
+3
-6
appview/pages/templates/repo/pulls/pull.html
···
42
42
<span>
43
43
targeting
44
44
<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">
45
-
{{ .Pull.TargetBranch }}
45
+
<a href="/{{ .RepoInfo.FullName }}/tree/{{ .Pull.TargetBranch }}" class="no-underline hover:underline">{{ .Pull.TargetBranch }}</a>
46
46
</span>
47
47
</span>
48
48
{{ if not .Pull.IsPatch }}
49
49
<span>from
50
50
{{ if not .Pull.IsSameRepoBranch }}
51
-
<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">
52
-
{{ .Pull.PullSource.Repo }}
53
-
</span>
54
-
<span class="select-none">/</span>
51
+
<a href="/{{ $owner }}/{{ .PullSourceRepo.Name }}" class="no-underline hover:underline">{{ $owner }}/{{ .PullSourceRepo.Name }}</a>
55
52
{{ end }}
56
53
<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">
57
-
{{ .Pull.PullSource.Branch }}
54
+
<a href="/{{ $owner }}/{{ .PullSourceRepo.Name }}/tree/{{ .Pull.PullSource.Branch }}" class="no-underline hover:underline">{{ .Pull.PullSource.Branch }}</a>
58
55
</span>
59
56
</span>
60
57
{{ end }}
+118
-7
appview/state/pull.go
+118
-7
appview/state/pull.go
···
120
120
resubmitResult = s.resubmitCheck(f, pull)
121
121
}
122
122
123
+
var pullSourceRepo *db.Repo
124
+
if pull.PullSource != nil {
125
+
if pull.PullSource.Repo != nil {
126
+
pullSourceRepo, err = db.GetRepoByAtUri(s.db, pull.PullSource.Repo.String())
127
+
if err != nil {
128
+
log.Printf("failed to get repo by at uri: %v", err)
129
+
return
130
+
}
131
+
}
132
+
}
133
+
123
134
s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
124
-
LoggedInUser: user,
125
-
RepoInfo: f.RepoInfo(s, user),
126
-
DidHandleMap: didHandleMap,
127
-
Pull: pull,
128
-
MergeCheck: mergeCheckResponse,
129
-
ResubmitCheck: resubmitResult,
135
+
LoggedInUser: user,
136
+
RepoInfo: f.RepoInfo(s, user),
137
+
DidHandleMap: didHandleMap,
138
+
Pull: pull,
139
+
PullSourceRepo: pullSourceRepo,
140
+
MergeCheck: mergeCheckResponse,
141
+
ResubmitCheck: resubmitResult,
130
142
})
131
143
}
132
144
···
533
545
title := r.FormValue("title")
534
546
body := r.FormValue("body")
535
547
targetBranch := r.FormValue("targetBranch")
536
-
fromFork := r.FormValue("fromFork")
548
+
fromFork := r.FormValue("fork")
537
549
sourceBranch := r.FormValue("sourceBranch")
538
550
patch := r.FormValue("patch")
539
551
···
840
852
s.pages.PullCompareBranchesFragment(w, pages.PullCompareBranchesParams{
841
853
RepoInfo: f.RepoInfo(s, user),
842
854
Branches: result.Branches,
855
+
})
856
+
}
857
+
858
+
func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
859
+
user := s.auth.GetUser(r)
860
+
f, err := fullyResolvedRepo(r)
861
+
if err != nil {
862
+
log.Println("failed to get repo and knot", err)
863
+
return
864
+
}
865
+
866
+
forks, err := db.GetForksByDid(s.db, user.Did)
867
+
if err != nil {
868
+
log.Println("failed to get forks", err)
869
+
return
870
+
}
871
+
872
+
s.pages.PullCompareForkFragment(w, pages.PullCompareForkParams{
873
+
RepoInfo: f.RepoInfo(s, user),
874
+
Forks: forks,
875
+
})
876
+
}
877
+
878
+
func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
879
+
user := s.auth.GetUser(r)
880
+
881
+
f, err := fullyResolvedRepo(r)
882
+
if err != nil {
883
+
log.Println("failed to get repo and knot", err)
884
+
return
885
+
}
886
+
887
+
forkVal := r.URL.Query().Get("fork")
888
+
889
+
// fork repo
890
+
repo, err := db.GetRepo(s.db, user.Did, forkVal)
891
+
if err != nil {
892
+
log.Println("failed to get repo", user.Did, forkVal)
893
+
return
894
+
}
895
+
896
+
sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Dev)
897
+
if err != nil {
898
+
log.Printf("failed to create unsigned client for %s", repo.Knot)
899
+
s.pages.Error503(w)
900
+
return
901
+
}
902
+
903
+
sourceResp, err := sourceBranchesClient.Branches(user.Did, repo.Name)
904
+
if err != nil {
905
+
log.Println("failed to reach knotserver for source branches", err)
906
+
return
907
+
}
908
+
909
+
sourceBody, err := io.ReadAll(sourceResp.Body)
910
+
if err != nil {
911
+
log.Println("failed to read source response body", err)
912
+
return
913
+
}
914
+
defer sourceResp.Body.Close()
915
+
916
+
var sourceResult types.RepoBranchesResponse
917
+
err = json.Unmarshal(sourceBody, &sourceResult)
918
+
if err != nil {
919
+
log.Println("failed to parse source branches response:", err)
920
+
return
921
+
}
922
+
923
+
targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
924
+
if err != nil {
925
+
log.Printf("failed to create unsigned client for target knot %s", f.Knot)
926
+
s.pages.Error503(w)
927
+
return
928
+
}
929
+
930
+
targetResp, err := targetBranchesClient.Branches(f.OwnerDid(), f.RepoName)
931
+
if err != nil {
932
+
log.Println("failed to reach knotserver for target branches", err)
933
+
return
934
+
}
935
+
936
+
targetBody, err := io.ReadAll(targetResp.Body)
937
+
if err != nil {
938
+
log.Println("failed to read target response body", err)
939
+
return
940
+
}
941
+
defer targetResp.Body.Close()
942
+
943
+
var targetResult types.RepoBranchesResponse
944
+
err = json.Unmarshal(targetBody, &targetResult)
945
+
if err != nil {
946
+
log.Println("failed to parse target branches response:", err)
947
+
return
948
+
}
949
+
950
+
s.pages.PullCompareForkBranchesFragment(w, pages.PullCompareForkBranchesParams{
951
+
RepoInfo: f.RepoInfo(s, user),
952
+
SourceBranches: sourceResult.Branches,
953
+
TargetBranches: targetResult.Branches,
843
954
})
844
955
}
845
956
+2
appview/state/router.go
+2
appview/state/router.go
···
97
97
r.Get("/", s.NewPull)
98
98
r.Get("/patch-upload", s.PatchUploadFragment)
99
99
r.Get("/compare-branches", s.CompareBranchesFragment)
100
+
r.Get("/compare-forks", s.CompareForksFragment)
101
+
r.Get("/fork-branches", s.CompareForksBranchesFragment)
100
102
r.Post("/", s.NewPull)
101
103
})
102
104