tangled
alpha
login
or
join now
julien.rbrt.fr
/
tangled-core
forked from
tangled.org/core
0
fork
atom
Monorepo for Tangled — https://tangled.org
0
fork
atom
overview
issues
pulls
pipelines
appview: pages: initial htmxing of compare page
anirudh.fi
9 months ago
c83c2259
abf6b940
verified
This commit was signed with the committer's
known signature
.
anirudh.fi
SSH Key Fingerprint:
SHA256:cz35vdbiWEzCNEfuL9fMC2JVIhtXavXBHrRjv8gxpAk=
+193
-92
5 changed files
expand all
collapse all
unified
split
appview
pages
pages.go
templates
repo
compare
new.html
compare.html
state
repo.go
router.go
+5
-6
appview/pages/pages.go
···
863
863
Forks []db.Repo
864
864
Branches []types.Branch
865
865
Tags []*types.TagReference
866
866
+
Base string
867
867
+
Head string
866
868
867
869
Active string
868
870
}
869
871
870
872
func (p *Pages) RepoCompare(w io.Writer, params RepoCompareParams) error {
871
873
params.Active = "overview"
872
872
-
return p.executeRepo("repo/compare/new", w, params)
874
874
+
return p.executeRepo("repo/compare", w, params)
873
875
}
874
876
875
877
type RepoCompareDiffParams struct {
876
878
LoggedInUser *oauth.User
877
879
RepoInfo repoinfo.RepoInfo
878
878
-
FormatPatch types.RepoFormatPatchResponse
879
879
-
880
880
-
Active string
880
880
+
Diff types.NiceDiff
881
881
}
882
882
883
883
func (p *Pages) RepoCompareDiff(w io.Writer, params RepoCompareDiffParams) error {
884
884
-
params.Active = "overview"
885
885
-
return p.executeRepo("repo/compare/new", w, params)
884
884
+
return p.executePlain("repo/fragments/diff", w, []any{params.RepoInfo.FullName, ¶ms.Diff})
886
885
}
887
886
888
887
func (p *Pages) Static() http.Handler {
+157
appview/pages/templates/repo/compare.html
···
1
1
+
{{ define "title" }}new comparison{{ end }}
2
2
+
3
3
+
{{ define "repoContent" }}
4
4
+
<section>
5
5
+
<h2 class="font-bold text-sm mb-4 uppercase dark:text-white">
6
6
+
Compare changes
7
7
+
</h2>
8
8
+
<p>Choose any two refs to compare.</p>
9
9
+
10
10
+
<form id="compare-form">
11
11
+
<div class="flex items-center gap-2 py-4">
12
12
+
<div>
13
13
+
base:
14
14
+
15
15
+
<select
16
16
+
name="base"
17
17
+
id="base-select"
18
18
+
class="p-1 border max-w-32 border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
19
19
+
onchange="triggerCompare()"
20
20
+
>
21
21
+
<optgroup
22
22
+
label="branches ({{ len .Branches }})"
23
23
+
class="bold text-sm"
24
24
+
>
25
25
+
{{ range .Branches }}
26
26
+
<option
27
27
+
value="{{ .Reference.Name }}"
28
28
+
class="py-1"
29
29
+
{{ if .IsDefault }}
30
30
+
selected
31
31
+
{{ end }}
32
32
+
>
33
33
+
{{ .Reference.Name }}
34
34
+
</option>
35
35
+
{{ end }}
36
36
+
</optgroup>
37
37
+
<optgroup
38
38
+
label="tags ({{ len .Tags }})"
39
39
+
class="bold text-sm"
40
40
+
>
41
41
+
{{ range .Tags }}
42
42
+
<option
43
43
+
value="{{ .Reference.Name }}"
44
44
+
class="py-1"
45
45
+
>
46
46
+
{{ .Reference.Name }}
47
47
+
</option>
48
48
+
{{ else }}
49
49
+
<option class="py-1" disabled>
50
50
+
no tags found
51
51
+
</option>
52
52
+
{{ end }}
53
53
+
</optgroup>
54
54
+
</select>
55
55
+
</div>
56
56
+
57
57
+
{{ i "arrow-left" "w-4 h-4" }}
58
58
+
59
59
+
60
60
+
<div>
61
61
+
compare:
62
62
+
63
63
+
<select
64
64
+
name="head"
65
65
+
id="head-select"
66
66
+
class="p-1 border max-w-32 border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
67
67
+
onchange="triggerCompare()"
68
68
+
>
69
69
+
<option value="" selected disabled hidden>
70
70
+
select a branch or tag
71
71
+
</option>
72
72
+
<optgroup
73
73
+
label="branches ({{ len .Branches }})"
74
74
+
class="bold text-sm"
75
75
+
>
76
76
+
{{ range .Branches }}
77
77
+
<option
78
78
+
value="{{ .Reference.Name }}"
79
79
+
class="py-1"
80
80
+
>
81
81
+
{{ .Reference.Name }}
82
82
+
</option>
83
83
+
{{ end }}
84
84
+
</optgroup>
85
85
+
<optgroup
86
86
+
label="tags ({{ len .Tags }})"
87
87
+
class="bold text-sm"
88
88
+
>
89
89
+
{{ range .Tags }}
90
90
+
<option
91
91
+
value="{{ .Reference.Name }}"
92
92
+
class="py-1"
93
93
+
>
94
94
+
{{ .Reference.Name }}
95
95
+
</option>
96
96
+
{{ else }}
97
97
+
<option class="py-1" disabled>
98
98
+
no tags found
99
99
+
</option>
100
100
+
{{ end }}
101
101
+
</optgroup>
102
102
+
</select>
103
103
+
</div>
104
104
+
</div>
105
105
+
</form>
106
106
+
</section>
107
107
+
<section class="hidden"></section>
108
108
+
109
109
+
<script>
110
110
+
var templatedBase = `{{ .Base }}`;
111
111
+
var templatedHead = `{{ .Head }}`;
112
112
+
var selectedBase = "";
113
113
+
var selectedHead = "";
114
114
+
115
115
+
document.addEventListener('DOMContentLoaded', function() {
116
116
+
if (templatedBase && templatedHead) {
117
117
+
const baseSelect = document.getElementById('base-select');
118
118
+
const headSelect = document.getElementById('head-select');
119
119
+
120
120
+
// select the option that matches templated values
121
121
+
for(let i = 0; i < baseSelect.options.length; i++) {
122
122
+
if(baseSelect.options[i].value === templatedBase) {
123
123
+
baseSelect.selectedIndex = i;
124
124
+
break;
125
125
+
}
126
126
+
}
127
127
+
128
128
+
for(let i = 0; i < headSelect.options.length; i++) {
129
129
+
if(headSelect.options[i].value === templatedHead) {
130
130
+
headSelect.selectedIndex = i;
131
131
+
break;
132
132
+
}
133
133
+
}
134
134
+
135
135
+
triggerCompare();
136
136
+
}
137
137
+
});
138
138
+
139
139
+
function triggerCompare() {
140
140
+
// if user has selected values, use those
141
141
+
selectedBase = document.getElementById('base-select').value;
142
142
+
selectedHead = document.getElementById('head-select').value;
143
143
+
144
144
+
const baseToUse = templatedBase && !selectedBase ? templatedBase : selectedBase;
145
145
+
const headToUse = templatedHead && !selectedHead ? templatedHead : selectedHead;
146
146
+
147
147
+
if (baseToUse && headToUse) {
148
148
+
const url = `/{{ .RepoInfo.FullName }}/compare/diff/${baseToUse}/${headToUse}`;
149
149
+
htmx.ajax('GET', url, { target: '#compare-diff' });
150
150
+
}
151
151
+
}
152
152
+
</script>
153
153
+
{{ end }}
154
154
+
155
155
+
{{ define "repoAfter" }}
156
156
+
<div id="compare-diff"></div>
157
157
+
{{ end }}
-74
appview/pages/templates/repo/compare/new.html
···
1
1
-
{{ define "title" }}new comparison{{ end }}
2
2
-
3
3
-
{{ define "repoContent" }}
4
4
-
<h2 class="font-bold text-sm mb-4 uppercase dark:text-white">
5
5
-
Compare changes
6
6
-
</h2>
7
7
-
<p>Choose any two refs to compare.</p>
8
8
-
9
9
-
<div class="flex items-center gap-2 py-4">
10
10
-
<div>
11
11
-
base:
12
12
-
<select
13
13
-
class="p-1 border max-w-32 border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
14
14
-
>
15
15
-
<optgroup
16
16
-
label="branches ({{ len .Branches }})"
17
17
-
class="bold text-sm"
18
18
-
>
19
19
-
{{ range .Branches }}
20
20
-
<option
21
21
-
value="{{ .Reference.Name }}"
22
22
-
class="py-1"
23
23
-
{{ if .IsDefault }}
24
24
-
selected
25
25
-
{{ end }}
26
26
-
>
27
27
-
{{ .Reference.Name }}
28
28
-
</option>
29
29
-
{{ end }}
30
30
-
</optgroup>
31
31
-
<optgroup label="tags ({{ len .Tags }})" class="bold text-sm">
32
32
-
{{ range .Tags }}
33
33
-
<option value="{{ .Reference.Name }}" class="py-1">
34
34
-
{{ .Reference.Name }}
35
35
-
</option>
36
36
-
{{ else }}
37
37
-
<option class="py-1" disabled>no tags found</option>
38
38
-
{{ end }}
39
39
-
</optgroup>
40
40
-
</select>
41
41
-
</div>
42
42
-
{{ i "arrow-left" "w-4 h-4" }}
43
43
-
<div>
44
44
-
compare:
45
45
-
<select
46
46
-
class="p-1 border max-w-32 border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
47
47
-
>
48
48
-
<optgroup
49
49
-
label="branches ({{ len .Branches }})"
50
50
-
class="bold text-sm"
51
51
-
>
52
52
-
{{ range .Branches }}
53
53
-
<option value="{{ .Reference.Name }}" class="py-1">
54
54
-
{{ .Reference.Name }}
55
55
-
</option>
56
56
-
{{ end }}
57
57
-
</optgroup>
58
58
-
<optgroup label="tags ({{ len .Tags }})" class="bold text-sm">
59
59
-
{{ range .Tags }}
60
60
-
<option value="{{ .Reference.Name }}" class="py-1">
61
61
-
{{ .Reference.Name }}
62
62
-
</option>
63
63
-
{{ else }}
64
64
-
<option class="py-1" disabled>no tags found</option>
65
65
-
{{ end }}
66
66
-
</optgroup>
67
67
-
</select>
68
68
-
</div>
69
69
-
</div>
70
70
-
{{ end }}
71
71
-
72
72
-
{{ define "repoAfter" }}
73
73
-
<div id="compare-diff"></div>
74
74
-
{{ end }}
+28
-11
appview/state/repo.go
···
25
25
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
26
26
"tangled.sh/tangled.sh/core/appview/pagination"
27
27
"tangled.sh/tangled.sh/core/knotclient"
28
28
+
"tangled.sh/tangled.sh/core/patchutil"
28
29
"tangled.sh/tangled.sh/core/types"
29
30
30
31
"github.com/bluesky-social/indigo/atproto/data"
···
185
186
return nil, err
186
187
}
187
188
188
188
-
if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool {
189
189
+
if !slices.ContainsFunc(result.Branches, func(branch types.Branch) bool {
189
190
return branch.Name == f.Ref
190
191
}) {
191
192
forkInfo.Status = types.MissingBranch
···
556
557
return
557
558
}
558
559
559
559
-
slices.SortFunc(result.Branches, func(a, b types.Branch) int {
560
560
+
slices.SortFunc(result.Branches, func(a, b types.Branch) int {
560
561
if a.IsDefault {
561
562
return -1
562
563
}
···
2063
2064
return
2064
2065
}
2065
2066
2067
2067
+
// if user is navigating to one of
2068
2068
+
// /compare/{base}/{head}
2069
2069
+
// /compare/{base}...{head}
2070
2070
+
base := chi.URLParam(r, "base")
2071
2071
+
head := chi.URLParam(r, "head")
2072
2072
+
if base == "" && head == "" {
2073
2073
+
rest := chi.URLParam(r, "*") // master...feature/xyz
2074
2074
+
parts := strings.SplitN(rest, "...", 2)
2075
2075
+
if len(parts) == 2 {
2076
2076
+
base = parts[0]
2077
2077
+
head = parts[1]
2078
2078
+
}
2079
2079
+
}
2080
2080
+
2066
2081
us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
2067
2082
if err != nil {
2068
2083
log.Printf("failed to create unsigned client for %s", f.Knot)
···
2101
2116
Forks: forks,
2102
2117
Branches: branches.Branches,
2103
2118
Tags: tags.Tags,
2119
2119
+
Base: base,
2120
2120
+
Head: head,
2104
2121
})
2105
2122
}
2106
2123
2107
2107
-
func (s *State) RepoCompareDiff(w http.ResponseWriter, r *http.Request) {
2124
2124
+
func (s *State) RepoCompareDiffFragment(w http.ResponseWriter, r *http.Request) {
2108
2125
f, err := s.fullyResolvedRepo(r)
2109
2126
if err != nil {
2110
2127
log.Println("failed to get repo and knot", err)
···
2112
2129
}
2113
2130
user := s.oauth.GetUser(r)
2114
2131
2115
2115
-
rest := chi.URLParam(r, "*") // master...feature/xyz
2116
2116
-
parts := strings.SplitN(rest, "...", 2)
2117
2117
-
if len(parts) != 2 {
2132
2132
+
base := chi.URLParam(r, "base")
2133
2133
+
head := chi.URLParam(r, "head")
2134
2134
+
2135
2135
+
if base == "" || head == "" {
2118
2136
s.pages.Notice(w, "compare-error", "Invalid ref format.")
2119
2137
return
2120
2138
}
2121
2139
2122
2122
-
ref1 := parts[0]
2123
2123
-
ref2 := parts[1]
2124
2124
-
2125
2140
us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)
2126
2141
if err != nil {
2127
2142
s.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
···
2129
2144
return
2130
2145
}
2131
2146
2132
2132
-
formatPatch, err := us.Compare(f.OwnerDid(), f.RepoName, ref1, ref2)
2147
2147
+
formatPatch, err := us.Compare(f.OwnerDid(), f.RepoName, base, head)
2133
2148
if err != nil {
2134
2149
s.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")
2135
2150
log.Println("failed to compare", err)
2136
2151
return
2137
2152
}
2153
2153
+
diff := patchutil.AsNiceDiff(formatPatch.Patch, base)
2138
2154
2155
2155
+
w.Header().Add("Hx-Push-Url", fmt.Sprintf("/%s/compare/%s...%s", f.OwnerSlashRepo(), base, head))
2139
2156
s.pages.RepoCompareDiff(w, pages.RepoCompareDiffParams{
2140
2157
LoggedInUser: user,
2141
2158
RepoInfo: f.RepoInfo(s, user),
2142
2142
-
FormatPatch: *formatPatch,
2159
2159
+
Diff: diff,
2143
2160
})
2144
2161
}
+3
-1
appview/state/router.go
···
126
126
// for example:
127
127
// /compare/master...some/feature
128
128
// /compare/master...example.com:another/feature <- this is a fork
129
129
-
r.Get("/*", s.RepoCompareDiff)
129
129
+
r.Get("/{base}/{head}", s.RepoCompare)
130
130
+
r.Get("/*", s.RepoCompare)
131
131
+
r.Get("/diff/{base}/{head}", s.RepoCompareDiffFragment)
130
132
})
131
133
132
134
r.Route("/pulls", func(r chi.Router) {