1{{ define "title" }}
2 {{ .Pull.Title }} · pull #{{ .Pull.PullId }} · {{ .RepoInfo.FullName }}
3{{ end }}
4
5{{ define "repoContent" }}
6 <header class="pb-4">
7 <h1 class="text-2xl">
8 {{ .Pull.Title }}
9 <span class="text-gray-500">#{{ .Pull.PullId }}</span>
10 </h1>
11 </header>
12
13 {{ $bgColor := "bg-gray-800" }}
14 {{ $icon := "ban" }}
15
16 {{ if .Pull.State.IsOpen }}
17 {{ $bgColor = "bg-green-600" }}
18 {{ $icon = "git-pull-request" }}
19 {{ else if .Pull.State.IsMerged }}
20 {{ $bgColor = "bg-purple-600" }}
21 {{ $icon = "git-merge" }}
22 {{ end }}
23
24 <section>
25 <div class="flex items-center gap-2">
26 <div
27 id="state"
28 class="inline-flex items-center rounded px-3 py-1 {{ $bgColor }}"
29 >
30 <i
31 data-lucide="{{ $icon }}"
32 class="w-4 h-4 mr-1.5 text-white"
33 ></i>
34 <span class="text-white">{{ .Pull.State.String }}</span>
35 </div>
36 <span class="text-gray-500 text-sm">
37 opened by
38 {{ $owner := index $.DidHandleMap .Pull.OwnerDid }}
39 <a href="/{{ $owner }}" class="no-underline hover:underline"
40 >{{ $owner }}</a
41 >
42 <span class="select-none before:content-['\00B7']"></span>
43 <time>{{ .Pull.Created | timeFmt }}</time>
44 <span class="select-none before:content-['\00B7']"></span>
45 <span>targeting branch
46 <span class="text-xs rounded bg-gray-100 text-black font-mono px-2 mx-1/2 inline-flex items-center">
47 {{ .Pull.TargetBranch }}
48 </span>
49 </span>
50 </span>
51 </div>
52
53 {{ if .Pull.Body }}
54 <article id="body" class="mt-2 prose">
55 {{ .Pull.Body | markdown }}
56 </article>
57 {{ end }}
58 </section>
59
60{{ end }}
61
62{{ define "repoAfter" }}
63 <section id="submissions" class="mt-4">
64 <div class="flex flex-col gap-4">
65 {{ block "submissions" . }} {{ end }}
66 </div>
67 </section>
68
69 {{ $isPullAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Pull.OwnerDid) }}
70 {{ $isPushAllowed := .RepoInfo.Roles.IsPushAllowed }}
71
72 {{ if and $isPullAuthor (not .Pull.State.IsMerged) }}
73 <section id="update-card" class="mt-8 space-y-4 relative">
74 {{ block "resubmitCard" . }} {{ end }}
75 </section>
76 {{ end }}
77
78 <section id="merge-card" class="mt-8 space-y-4 relative">
79 {{ if .Pull.State.IsMerged }}
80 {{ block "alreadyMergedCard" . }} {{ end }}
81 {{ else if .MergeCheck }}
82 {{ if .MergeCheck.IsConflicted }}
83 {{ block "isConflictedCard" $ }} {{ end }}
84 {{ else }}
85 {{ block "noConflictsCard" $ }} {{ end }}
86 {{ end }}
87 {{ end }}
88 </section>
89
90 <div id="pull-close"></div>
91 <div id="pull-reopen"></div>
92{{ end }}
93
94{{ define "submissions" }}
95 {{ $lastIdx := sub (len .Pull.Submissions) 1 }}
96 {{ $targetBranch := .Pull.TargetBranch }}
97 {{ $repoName := .RepoInfo.FullName }}
98 {{ range $idx, $item := .Pull.Submissions }}
99 {{ $diff := $item.AsNiceDiff $targetBranch }}
100 {{ with $item }}
101 {{ $oneIndexedRound := add .RoundNumber 1 }}
102 <details {{ if eq $idx $lastIdx }}open{{ end }}>
103 <summary id="round-#{{ $oneIndexedRound }}" class="list-none cursor-pointer text-sm">
104 <div class="flex gap-2 items-center">
105 <div class="rounded bg-white drop-shadow-sm p-3">
106 #{{ $oneIndexedRound }}
107 </div>
108 <div class="rounded drop-shadow-sm bg-white p-3 text-gray-500">
109 <span>
110 {{ $owner := index $.DidHandleMap $.Pull.OwnerDid }}
111 submitted by <a href="/{{ $owner }}">{{ $owner }}</a>
112 <span class="select-none before:content-['\00B7']"></span>
113 <a href="#round-#{{ $oneIndexedRound }}"><time>{{ .Created | timeFmt }}</time></a>
114 <span class="select-none before:content-['·']"></span>
115 {{ $s := "s" }}
116 {{ if eq (len .Comments) 1 }}
117 {{ $s = "" }}
118 {{ end }}
119 {{ len .Comments }} comment{{$s}}
120 <span class="before:content-['·']"></span>
121 <a href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{.RoundNumber}}">view patch</a>
122 </span>
123 </div>
124 </div>
125 </summary>
126 <div class="pl-12 flex flex-col gap-2 mt-2 relative">
127 {{ range .Comments }}
128 <div id="comment-{{.ID}}" class="bg-white rounded drop-shadow-sm py-2 px-4 relative w-fit">
129 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
130 <div class="text-sm text-gray-500">
131 {{ $owner := index $.DidHandleMap .OwnerDid }}
132 <a href="/{{$owner}}">{{$owner}}</a>
133 <span class="before:content-['·']"></span>
134 <a href="#comment-{{.ID}}"><time>{{ .Created | timeFmt }}</time></a>
135 </div>
136 <div class="prose">
137 {{ .Body }}
138 </div>
139 </div>
140 {{ end }}
141 {{ block "newComment" (list $ .ID) }} {{ end }}
142 </div>
143 </details>
144 <hr />
145 {{ end }}
146 {{ end }}
147{{ end }}
148
149{{ define "newComment" }}
150 {{ $rootObj := index . 0 }}
151 {{ $submissionId := index . 1 }}
152
153 {{ with $rootObj }}
154 {{ if .LoggedInUser }}
155 <div class="bg-white rounded drop-shadow-sm py-2 px-4 relative w-full md:w-96">
156 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
157 <div class="text-sm text-gray-500">
158 {{ index .DidHandleMap .LoggedInUser.Did }}
159 </div>
160 <form
161 hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/comment"
162 hx-swap="none">
163 <input type="hidden" name="submissionId" value="{{ $submissionId }}">
164 <textarea
165 name="body"
166 class="w-full border-0 h-8 focus:outline-none focus:ring-0 px-0 py-1"
167 placeholder="Add to the discussion..." /></textarea>
168 <div class="flex justify-end">
169 <button type="submit" class="btn text-sm mt-2">comment</button>
170 </div>
171 <div id="pull-comment"></div>
172 </form>
173 </div>
174 {{ else }}
175 <div class="bg-white rounded drop-shadow-sm px-6 py-4 text-sm w-fit">
176 <div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
177 <a href="/login" class="underline">login</a> to join the discussion
178 </div>
179 {{ end }}
180 {{ end }}
181{{ end }}
182
183{{ define "alreadyMergedCard" }}
184 <div
185 id="merge-status-card"
186 class="rounded relative bg-purple-50 border border-purple-200 p-4">
187
188 <div class="flex items-center gap-2 text-purple-500">
189 <i data-lucide="git-merge" class="w-4 h-4"></i>
190 <span class="font-medium"
191 >pull request successfully merged</span
192 >
193 </div>
194
195 <div class="mt-2 text-sm text-gray-700">
196 <p>This pull request has been merged into the base branch.</p>
197 </div>
198 </div>
199{{ end }}
200
201{{ define "isConflictedCard" }}
202 <div
203 id="merge-status-card"
204 class="rounded relative border bg-red-50 border-red-200 p-4">
205
206 <div class="flex items-center gap-2 text-red-500">
207 <i data-lucide="alert-triangle" class="w-4 h-4"></i>
208 <span class="font-medium">merge conflicts detected</span>
209 </div>
210
211 <div class="mt-2">
212 <ul class="text-sm space-y-1">
213 {{ range .MergeCheck.Conflicts }}
214 <li class="flex items-center">
215 <i
216 data-lucide="file-warning"
217 class="w-3 h-3 mr-1.5 text-red-500"
218 ></i>
219 <span class="font-mono"
220 >{{ slice .Filename 0 (sub (len .Filename) 2) }}</span
221 >
222 </li>
223 {{ end }}
224 </ul>
225 </div>
226 <div class="mt-3 text-sm text-gray-700">
227 <p>
228 Please resolve these conflicts locally and update
229 the patch to continue with the merge.
230 </p>
231 </div>
232 </div>
233{{ end }}
234
235
236{{ define "noConflictsCard" }}
237 {{ $isPushAllowed := .RepoInfo.Roles.IsPushAllowed }}
238 {{ $isPullAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Pull.OwnerDid) }}
239 <div
240 id="merge-status-card"
241 class="rounded relative border bg-green-50 border-green-200 p-4">
242
243 <div class="flex items-center gap-2 text-green-500">
244 <i data-lucide="check-circle" class="w-4 h-4"></i>
245 <span class="font-medium">ready to merge</span>
246 </div>
247
248 <div class="mt-2 text-sm text-gray-700">
249 No conflicts detected with the base branch. This
250 pull request can be merged safely.
251 </div>
252
253 <div class="flex items-center gap-2">
254 {{ if $isPushAllowed }}
255 <button
256 class="btn mt-4 flex items-center gap-2"
257 hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
258 hx-swap="none"
259 {{ if or .Pull.State.IsClosed .MergeCheck.IsConflicted }}
260 disabled
261 {{ end }}>
262 <i data-lucide="git-merge" class="w-4 h-4"></i>
263 <span>merge</span>
264 </button>
265 {{ end }}
266
267 {{ if and (or $isPullAuthor $isPushAllowed) (not .Pull.State.IsMerged) }}
268 {{ $action := "close" }}
269 {{ $icon := "circle-x" }}
270 {{ $hoverColor := "red" }}
271 {{ if .Pull.State.IsClosed }}
272 {{ $action = "reopen" }}
273 {{ $icon = "circle-dot" }}
274 {{ $hoverColor = "green" }}
275 {{ end }}
276 <button
277 hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/{{ $action }}"
278 hx-swap="none"
279 class="btn mt-4 flex items-center gap-2">
280 <i data-lucide="{{ $icon }}" class="w-4 h-4 text-{{ $hoverColor }}-400"></i>
281 <span class="text-black">{{ $action }}</span>
282 </button>
283 {{ end }}
284
285 <div id="pull-merge-error" class="error"></div>
286 <div id="pull-merge-success" class="success"></div>
287 </div>
288 </div>
289{{ end }}
290
291{{ define "resubmitCard" }}
292 <div
293 id="resubmit-pull-card"
294 class="rounded relative border bg-amber-50 border-amber-200 p-4">
295
296 <div class="flex items-center gap-2 text-amber-500">
297 <i data-lucide="edit" class="w-4 h-4"></i>
298 <span class="font-medium">resubmit your patch</span>
299 </div>
300
301 <div class="mt-2 text-sm text-gray-700">
302 You can update this patch to address any reviews.
303 This will begin a new round of reviews,
304 but you'll still be able to view your previous submissions and feedback.
305 </div>
306
307 <div class="mt-4 flex flex-col">
308 <form hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/resubmit" class="w-full" hx-swap="none">
309 <textarea
310 name="patch"
311 class="w-full p-2 mb-2 rounded border border-gray-200"
312 placeholder="Paste your updated patch here."
313 ></textarea>
314 <button
315 type="submit"
316 class="btn flex items-center gap-2"
317 {{ if or .Pull.State.IsClosed }}
318 disabled
319 {{ end }}>
320 <i data-lucide="refresh-ccw" class="w-4 h-4"></i>
321 <span>resubmit</span>
322 </button>
323 </form>
324
325 <div id="resubmit-error" class="error"></div>
326 <div id="resubmit-success" class="success"></div>
327 </div>
328 </div>
329{{ end }}