+22
appview/db/pulls.go
+22
appview/db/pulls.go
···
1063
1063
return nil
1064
1064
}
1065
1065
1066
+
// all pulls above this pull (including self) in this stack
1067
+
func (stack Stack) Above(pull *Pull) Stack {
1068
+
position := stack.Position(pull)
1069
+
1070
+
if position < 0 {
1071
+
return nil
1072
+
}
1073
+
1074
+
return stack[:position+1]
1075
+
}
1076
+
1077
+
// all pulls below this pull (excluding self) in this stack
1078
+
func (stack Stack) StrictlyAbove(pull *Pull) Stack {
1079
+
above := stack.Above(pull)
1080
+
1081
+
if len(above) > 0 {
1082
+
return above[:len(above)-1]
1083
+
}
1084
+
1085
+
return nil
1086
+
}
1087
+
1066
1088
// the combined format-patches of all the newest submissions in this stack
1067
1089
func (stack Stack) CombinedPatch() string {
1068
1090
// go in reverse order because the bottom of the stack is the last element in the slice
+2
appview/pages/pages.go
+2
appview/pages/pages.go
···
743
743
Active string
744
744
DidHandleMap map[string]string
745
745
Pull *db.Pull
746
+
Stack db.Stack
746
747
MergeCheck types.MergeCheckResponse
747
748
ResubmitCheck ResubmitResult
748
749
}
···
757
758
DidHandleMap map[string]string
758
759
RepoInfo repoinfo.RepoInfo
759
760
Pull *db.Pull
761
+
Stack db.Stack
760
762
Diff *types.NiceDiff
761
763
Round int
762
764
Submission *db.PullSubmission
+94
-57
appview/pages/templates/repo/pulls/fragments/pullHeader.html
+94
-57
appview/pages/templates/repo/pulls/fragments/pullHeader.html
···
1
1
{{ define "repo/pulls/fragments/pullHeader" }}
2
-
<header class="pb-4">
3
-
<h1 class="text-2xl dark:text-white">
4
-
{{ .Pull.Title }}
5
-
<span class="text-gray-500 dark:text-gray-400">#{{ .Pull.PullId }}</span>
6
-
</h1>
7
-
</header>
2
+
<header class="flex items-center gap-2 pb-2">
3
+
{{ block "pullState" .Pull }} {{ end }}
4
+
<h1 class="text-2xl dark:text-white">
5
+
<span class="text-gray-500 dark:text-gray-400">#{{ .Pull.PullId }}</span>
6
+
{{ .Pull.Title }}
7
+
</h1>
8
+
</header>
8
9
9
-
{{ $bgColor := "bg-gray-800 dark:bg-gray-700" }}
10
-
{{ $icon := "ban" }}
10
+
<section class="">
11
+
<div class="flex items-center gap-2">
12
+
<span class="text-gray-500 dark:text-gray-400 text-sm">
13
+
opened by
14
+
{{ $owner := index $.DidHandleMap .Pull.OwnerDid }}
15
+
<a href="/{{ $owner }}" class="no-underline hover:underline">{{ $owner }}</a>
16
+
<span class="select-none before:content-['\00B7']"></span>
17
+
<time>{{ .Pull.Created | timeFmt }}</time>
18
+
<span class="select-none before:content-['\00B7']"></span>
19
+
<span>
20
+
targeting
21
+
<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">
22
+
<a href="/{{ .RepoInfo.FullName }}/tree/{{ .Pull.TargetBranch }}" class="no-underline hover:underline">{{ .Pull.TargetBranch }}</a>
23
+
</span>
24
+
</span>
25
+
{{ if not .Pull.IsPatchBased }}
26
+
from
27
+
<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">
28
+
{{ if .Pull.IsForkBased }}
29
+
{{ if .Pull.PullSource.Repo }}
30
+
<a href="/{{ $owner }}/{{ .Pull.PullSource.Repo.Name }}" class="no-underline hover:underline">{{ $owner }}/{{ .Pull.PullSource.Repo.Name }}</a>:
31
+
{{- else -}}
32
+
<span class="italic">[deleted fork]</span>
33
+
{{- end -}}
34
+
{{- end -}}
35
+
{{- .Pull.PullSource.Branch -}}
36
+
</span>
37
+
{{ end }}
38
+
</span>
39
+
</div>
11
40
12
-
{{ if .Pull.State.IsOpen }}
13
-
{{ $bgColor = "bg-green-600 dark:bg-green-700" }}
14
-
{{ $icon = "git-pull-request" }}
15
-
{{ else if .Pull.State.IsMerged }}
16
-
{{ $bgColor = "bg-purple-600 dark:bg-purple-700" }}
17
-
{{ $icon = "git-merge" }}
41
+
{{ if .Pull.Body }}
42
+
<article id="body" class="mt-2 prose dark:prose-invert">
43
+
{{ .Pull.Body | markdown }}
44
+
</article>
45
+
{{ end }}
46
+
</section>
47
+
48
+
{{ end }}
49
+
50
+
{{ define "singlePullHeader" }}
51
+
{{ end }}
52
+
53
+
{{ define "stackedPullHeader" }}
54
+
<div class="border border-gray-200 dark:border-gray-700 rounded-sm">
55
+
{{ block "stackedPullHeaderAbove" . }} {{ end }}
56
+
<div class="p-2">
57
+
{{ block "singlePullHeader" . }} {{ end }}
58
+
</div>
59
+
{{ block "stackedPullHeaderBelow" . }} {{ end }}
60
+
</div>
61
+
{{ end }}
62
+
63
+
{{ define "stackedPullHeaderAbove" }}
64
+
{{ if .Pull.IsStacked }}
65
+
{{ $above := .Stack.StrictlyAbove .Pull }}
66
+
<div class="flex flex-col">
67
+
{{ range $pull := $above }}
68
+
<div class="border-b border-gray-200 dark:border-gray-700 p-2">
69
+
{{ block "summarizedHeader" (list $pull $) }} {{ end }}
70
+
</div>
71
+
{{ end }}
72
+
</div>
73
+
{{ end }}
18
74
{{ end }}
19
75
20
-
<section class="mt-2">
21
-
<div class="flex items-center gap-2">
22
-
<div
23
-
id="state"
24
-
class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}"
25
-
>
26
-
{{ i $icon "w-4 h-4 mr-1.5 text-white" }}
27
-
<span class="text-white">{{ .Pull.State.String }}</span>
76
+
{{ define "stackedPullHeaderBelow" }}
77
+
{{ if .Pull.IsStacked }}
78
+
{{ $below := .Stack.StrictlyBelow .Pull }}
79
+
<div class="flex flex-col">
80
+
{{ range $pull := $below }}
81
+
<div class="border-t border-gray-200 dark:border-gray-700 p-2">
82
+
{{ block "summarizedHeader" (list $pull $) }} {{ end }}
28
83
</div>
29
-
<span class="text-gray-500 dark:text-gray-400 text-sm">
30
-
opened by
31
-
{{ $owner := index $.DidHandleMap .Pull.OwnerDid }}
32
-
<a href="/{{ $owner }}" class="no-underline hover:underline"
33
-
>{{ $owner }}</a
34
-
>
35
-
<span class="select-none before:content-['\00B7']"></span>
36
-
<time>{{ .Pull.Created | timeFmt }}</time>
37
-
<span class="select-none before:content-['\00B7']"></span>
38
-
<span>
39
-
targeting
40
-
<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">
41
-
<a href="/{{ .RepoInfo.FullName }}/tree/{{ .Pull.TargetBranch }}" class="no-underline hover:underline">{{ .Pull.TargetBranch }}</a>
42
-
</span>
43
-
</span>
44
-
{{ if not .Pull.IsPatchBased }}
45
-
from
46
-
<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">
47
-
{{ if .Pull.IsForkBased }}
48
-
{{ if .Pull.PullSource.Repo }}
49
-
<a href="/{{ $owner }}/{{ .Pull.PullSource.Repo.Name }}" class="no-underline hover:underline">{{ $owner }}/{{ .Pull.PullSource.Repo.Name }}</a>:
50
-
{{- else -}}
51
-
<span class="italic">[deleted fork]</span>
52
-
{{- end -}}
53
-
{{- end -}}
54
-
{{- .Pull.PullSource.Branch -}}
55
-
</span>
56
-
{{ end }}
57
-
</span>
84
+
{{ end }}
58
85
</div>
86
+
{{ end }}
87
+
{{ end }}
59
88
60
-
{{ if .Pull.Body }}
61
-
<article id="body" class="mt-8 prose dark:prose-invert">
62
-
{{ .Pull.Body | markdown }}
63
-
</article>
64
-
{{ end }}
65
-
</section>
89
+
{{ define "pullState" }}
90
+
{{ $bgColor := "bg-gray-800 dark:bg-gray-700" }}
91
+
{{ $icon := "ban" }}
66
92
93
+
{{ if .State.IsOpen }}
94
+
{{ $bgColor = "bg-green-600 dark:bg-green-700" }}
95
+
{{ $icon = "git-pull-request" }}
96
+
{{ else if .State.IsMerged }}
97
+
{{ $bgColor = "bg-purple-600 dark:bg-purple-700" }}
98
+
{{ $icon = "git-merge" }}
99
+
{{ end }}
67
100
101
+
<div id="state" class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}" >
102
+
{{ i $icon "w-4 h-4 mr-1.5 text-white" }}
103
+
<span class="text-white ">{{ .State.String }}</span>
104
+
</div>
68
105
{{ end }}
+47
appview/pages/templates/repo/pulls/fragments/pullStack.html
+47
appview/pages/templates/repo/pulls/fragments/pullStack.html
···
1
+
{{ define "repo/pulls/fragments/pullStack" }}
2
+
<div class="grid grid-cols-1 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700">
3
+
{{ range $pull := .Stack }}
4
+
{{ $isCurrent := false }}
5
+
{{ with $.Pull }}
6
+
{{ $isCurrent = eq $pull.PullId $.Pull.PullId }}
7
+
{{ end }}
8
+
<div class="flex gap-2 items-center p-2">
9
+
{{ block "summarizedHeader" (list $pull $) }} {{ end }}
10
+
{{ if $isCurrent }}
11
+
{{ i "arrow-left" "w-4 h-4" }}
12
+
{{ end }}
13
+
</div>
14
+
{{ end }}
15
+
</div>
16
+
{{ end }}
17
+
18
+
{{ define "summarizedHeader" }}
19
+
{{ $pull := index . 0 }}
20
+
{{ $root := index . 1 }}
21
+
<a href="/{{ $root.RepoInfo.FullName }}/pulls/{{ $pull.PullId }}" class="no-underline hover:no-underline">
22
+
<div class="flex text-sm items-center gap-2">
23
+
{{ block "summarizedPullState" $pull }} {{ end }}
24
+
<span class="dark:text-white">
25
+
<span class="text-gray-500 dark:text-gray-400">#{{ $pull.PullId }}</span>
26
+
{{ $pull.Title }}
27
+
</span>
28
+
</div>
29
+
</a>
30
+
{{ end }}
31
+
32
+
{{ define "summarizedPullState" }}
33
+
{{ $fgColor := "text-gray-600 dark:text-gray-300" }}
34
+
{{ $icon := "ban" }}
35
+
36
+
{{ if .State.IsOpen }}
37
+
{{ $fgColor = "text-green-600 dark:text-green-500" }}
38
+
{{ $icon = "git-pull-request" }}
39
+
{{ else if .State.IsMerged }}
40
+
{{ $fgColor = "text-purple-600 dark:text-purple-500" }}
41
+
{{ $icon = "git-merge" }}
42
+
{{ end }}
43
+
44
+
{{ $style := printf "w-4 h-4 %s" $fgColor }}
45
+
46
+
{{ i $icon $style }}
47
+
{{ end }}
+8
-1
appview/pages/templates/repo/pulls/pull.html
+8
-1
appview/pages/templates/repo/pulls/pull.html
···
11
11
12
12
13
13
{{ define "repoContent" }}
14
-
{{ template "repo/pulls/fragments/pullHeader" . }}
14
+
{{ template "repo/pulls/fragments/pullHeader" . }}
15
+
16
+
{{ if .Pull.IsStacked }}
17
+
<div class="mt-8">
18
+
<p class="text-sm font-bold p-2 dark:text-white">STACK</p>
19
+
{{ template "repo/pulls/fragments/pullStack" . }}
20
+
</div>
21
+
{{ end }}
15
22
{{ end }}
16
23
17
24
{{ define "repoAfter" }}
+11
-3
appview/state/pull.go
+11
-3
appview/state/pull.go
···
136
136
RepoInfo: f.RepoInfo(s, user),
137
137
DidHandleMap: didHandleMap,
138
138
Pull: pull,
139
+
Stack: stack,
139
140
MergeCheck: mergeCheckResponse,
140
141
ResubmitCheck: resubmitResult,
141
142
})
···
303
304
return
304
305
}
305
306
307
+
stack, _ := r.Context().Value("stack").(db.Stack)
308
+
306
309
roundId := chi.URLParam(r, "round")
307
310
roundIdInt, err := strconv.Atoi(roundId)
308
311
if err != nil || roundIdInt >= len(pull.Submissions) {
···
329
332
DidHandleMap: didHandleMap,
330
333
RepoInfo: f.RepoInfo(s, user),
331
334
Pull: pull,
335
+
Stack: stack,
332
336
Round: roundIdInt,
333
337
Submission: pull.Submissions[roundIdInt],
334
338
Diff: &diff,
···
1647
1651
if op, ok := origById[np.ChangeId]; ok {
1648
1652
// pull exists in both stacks
1649
1653
// TODO: can we avoid reparse?
1650
-
origFiles, _, _ := gitdiff.Parse(strings.NewReader(op.LatestPatch()))
1651
-
newFiles, _, _ := gitdiff.Parse(strings.NewReader(np.LatestPatch()))
1654
+
origFiles, origHeaderStr, _ := gitdiff.Parse(strings.NewReader(op.LatestPatch()))
1655
+
newFiles, newHeaderStr, _ := gitdiff.Parse(strings.NewReader(np.LatestPatch()))
1656
+
1657
+
origHeader, _ := gitdiff.ParsePatchHeader(origHeaderStr)
1658
+
newHeader, _ := gitdiff.ParsePatchHeader(newHeaderStr)
1652
1659
1653
1660
patchutil.SortPatch(newFiles)
1654
1661
patchutil.SortPatch(origFiles)
1655
1662
1656
-
if patchutil.Equal(newFiles, origFiles) {
1663
+
// text content of patch may be identical, but a jj rebase might have forwarded it
1664
+
if patchutil.Equal(newFiles, origFiles) && origHeader.SHA == newHeader.SHA {
1657
1665
unchanged[op.ChangeId] = struct{}{}
1658
1666
} else {
1659
1667
updated[op.ChangeId] = struct{}{}