+21
appview/pages/funcmap.go
+21
appview/pages/funcmap.go
···
6
"html"
7
"html/template"
8
"log"
9
+
"math"
10
"path/filepath"
11
"reflect"
12
"strings"
13
+
"time"
14
15
"github.com/dustin/go-humanize"
16
)
···
68
return s
69
},
70
"timeFmt": humanize.Time,
71
+
"shortTimeFmt": func(t time.Time) string {
72
+
return humanize.CustomRelTime(t, time.Now(), "", "", []humanize.RelTimeMagnitude{
73
+
{time.Second, "now", time.Second},
74
+
{2 * time.Second, "1s %s", 1},
75
+
{time.Minute, "%ds %s", time.Second},
76
+
{2 * time.Minute, "1min %s", 1},
77
+
{time.Hour, "%dmin %s", time.Minute},
78
+
{2 * time.Hour, "1hr %s", 1},
79
+
{humanize.Day, "%dhrs %s", time.Hour},
80
+
{2 * humanize.Day, "1d %s", 1},
81
+
{20 * humanize.Day, "%dd %s", humanize.Day},
82
+
{8 * humanize.Week, "%dw %s", humanize.Week},
83
+
{humanize.Year, "%dmo %s", humanize.Month},
84
+
{18 * humanize.Month, "1y %s", 1},
85
+
{2 * humanize.Year, "2y %s", 1},
86
+
{humanize.LongTime, "%dy %s", humanize.Year},
87
+
{math.MaxInt64, "a long while %s", 1},
88
+
})
89
+
},
90
"byteFmt": humanize.Bytes,
91
"length": func(slice any) int {
92
v := reflect.ValueOf(slice)
+2
-2
appview/pages/templates/fragments/diff.html
+2
-2
appview/pages/templates/fragments/diff.html
···
84
<div class="bg-gray-100 text-gray-500 select-none">{{ .Header }}</div>
85
{{- range .Lines -}}
86
{{- if eq .Op.String "+" -}}
87
-
<div class="bg-green-100 text-green-700 p-1"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div>
88
{{- end -}}
89
90
{{- if eq .Op.String "-" -}}
91
-
<div class="bg-red-100 text-red-700 p-1"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div>
92
{{- end -}}
93
94
{{- if eq .Op.String " " -}}
···
84
<div class="bg-gray-100 text-gray-500 select-none">{{ .Header }}</div>
85
{{- range .Lines -}}
86
{{- if eq .Op.String "+" -}}
87
+
<div class="bg-green-100 text-green-700 p-1 w-full min-w-fit"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div>
88
{{- end -}}
89
90
{{- if eq .Op.String "-" -}}
91
+
<div class="bg-red-100 text-red-700 p-1 w-full min-w-fit"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div>
92
{{- end -}}
93
94
{{- if eq .Op.String " " -}}
+1
-1
appview/pages/templates/fragments/pullActions.html
+1
-1
appview/pages/templates/fragments/pullActions.html
···
28
<button
29
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
30
hx-swap="none"
31
+
hx-confirm="Are you sure you want to merge pull #{{ .Pull.PullId }} into the `{{ .Pull.TargetBranch }}` branch?"
32
class="btn p-2 flex items-center gap-2" {{ $disabled }}>
33
{{ i "git-merge" "w-4 h-4" }}
34
<span>merge</span>
+1
-1
appview/pages/templates/fragments/pullNewComment.html
+1
-1
appview/pages/templates/fragments/pullNewComment.html
+1
-1
appview/pages/templates/fragments/pullResubmit.html
+1
-1
appview/pages/templates/fragments/pullResubmit.html
+22
-192
appview/pages/templates/repo/pulls/pull.html
+22
-192
appview/pages/templates/repo/pulls/pull.html
···
77
{{ $oneIndexedRound := add .RoundNumber 1 }}
78
<details {{ if eq $idx $lastIdx }}open{{ end }}>
79
<summary id="round-#{{ $oneIndexedRound }}" class="list-none cursor-pointer">
80
-
<div class="flex gap-2 items-center">
81
-
<div class="rounded bg-white drop-shadow-sm p-3">
82
#{{ $oneIndexedRound }}
83
</div>
84
-
<div class="rounded drop-shadow-sm bg-white p-3 text-gray-500">
85
<span>
86
{{ $owner := index $.DidHandleMap $.Pull.OwnerDid }}
87
-
submitted by <a href="/{{ $owner }}">{{ $owner }}</a>
88
<span class="select-none before:content-['\00B7']"></span>
89
-
<a class="text-gray-500 hover:text-gray-500" href="#round-#{{ $oneIndexedRound }}"><time>{{ .Created | timeFmt }}</time></a>
90
<span class="select-none before:content-['·']"></span>
91
{{ $s := "s" }}
92
{{ if eq (len .Comments) 1 }}
93
{{ $s = "" }}
94
{{ end }}
95
{{ len .Comments }} comment{{$s}}
96
-
<span class="before:content-['·']"></span>
97
-
<a href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{.RoundNumber}}">view patch</a>
98
</span>
99
</div>
100
</div>
101
</summary>
102
-
<div class="pl-12 flex flex-col gap-2 mt-2 relative">
103
{{ range .Comments }}
104
<div id="comment-{{.ID}}" class="bg-white rounded drop-shadow-sm py-2 px-4 relative w-fit">
105
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
···
107
{{ $owner := index $.DidHandleMap .OwnerDid }}
108
<a href="/{{$owner}}">{{$owner}}</a>
109
<span class="before:content-['·']"></span>
110
-
<a href="#comment-{{.ID}}"><time>{{ .Created | timeFmt }}</time></a>
111
</div>
112
<div class="prose">
113
-
{{ .Body }}
114
</div>
115
</div>
116
{{ end }}
···
129
{{ end }}
130
</div>
131
</details>
132
{{ end }}
133
{{ end }}
134
{{ end }}
···
188
</div>
189
{{ end }}
190
{{ end }}
191
-
192
-
{{ define "newComment" }}
193
-
{{ $rootObj := index . 0 }}
194
-
{{ $submissionId := index . 1 }}
195
-
196
-
{{ with $rootObj }}
197
-
{{ if .LoggedInUser }}
198
-
<div class="bg-white rounded drop-shadow-sm py-2 px-4 relative w-full md:w-96">
199
-
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
200
-
<div class="text-sm text-gray-500">
201
-
{{ index .DidHandleMap .LoggedInUser.Did }}
202
-
</div>
203
-
<form
204
-
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/comment"
205
-
hx-swap="none">
206
-
<input type="hidden" name="submissionId" value="{{ $submissionId }}">
207
-
<textarea
208
-
name="body"
209
-
class="w-full border-0 h-8 focus:outline-none focus:ring-0 px-0 py-1"
210
-
placeholder="Add to the discussion..." /></textarea>
211
-
<div class="flex justify-end">
212
-
<button type="submit" class="btn text-sm mt-2">comment</button>
213
-
</div>
214
-
<div id="pull-comment"></div>
215
-
</form>
216
-
</div>
217
-
{{ else }}
218
-
<div class="bg-white rounded drop-shadow-sm px-6 py-4 text-sm w-fit">
219
-
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
220
-
<a href="/login" class="underline">login</a> to join the discussion
221
-
</div>
222
-
{{ end }}
223
-
{{ end }}
224
-
{{ end }}
225
-
226
-
{{ define "alreadyMergedCard" }}
227
-
<div
228
-
id="merge-status-card"
229
-
class="rounded relative bg-purple-50 border border-purple-200 p-4">
230
-
231
-
<div class="flex items-center gap-2 text-purple-500">
232
-
{{ i "git-merge" "w-4 h-4" }}
233
-
<span class="font-medium"
234
-
>pull request successfully merged</span
235
-
>
236
-
</div>
237
-
238
-
<div class="mt-2 text-sm text-gray-700">
239
-
<p>This pull request has been merged into the base branch.</p>
240
-
</div>
241
-
</div>
242
-
{{ end }}
243
-
244
-
{{ define "isConflictedCard" }}
245
-
<div
246
-
id="merge-status-card"
247
-
class="rounded relative border bg-red-50 border-red-200 p-4">
248
-
249
-
<div class="flex items-center gap-2 text-red-500">
250
-
<i data-lucide="alert-triangle" class="w-4 h-4"></i>
251
-
<span class="font-medium">merge conflicts detected</span>
252
-
</div>
253
-
254
-
<div class="mt-2">
255
-
<ul class="text-sm space-y-1">
256
-
{{ range .MergeCheck.Conflicts }}
257
-
<li class="flex items-center">
258
-
<i
259
-
data-lucide="file-warning"
260
-
class="w-3 h-3 mr-1.5 text-red-500"
261
-
></i>
262
-
<span class="font-mono"
263
-
>{{ slice .Filename 0 (sub (len .Filename) 2) }}</span
264
-
>
265
-
</li>
266
-
{{ end }}
267
-
</ul>
268
-
</div>
269
-
<div class="mt-3 text-sm text-gray-700">
270
-
<p>
271
-
Please resolve these conflicts locally and update
272
-
the patch to continue with the merge.
273
-
</p>
274
-
</div>
275
-
</div>
276
-
{{ end }}
277
-
278
-
279
-
{{ define "noConflictsCard" }}
280
-
{{ $isPushAllowed := .RepoInfo.Roles.IsPushAllowed }}
281
-
{{ $isPullAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Pull.OwnerDid) }}
282
-
<div
283
-
id="merge-status-card"
284
-
class="rounded relative border bg-green-50 border-green-200 p-4">
285
-
286
-
<div class="flex items-center gap-2 text-green-500">
287
-
<i data-lucide="check-circle" class="w-4 h-4"></i>
288
-
<span class="font-medium">ready to merge</span>
289
-
</div>
290
-
291
-
<div class="mt-2 text-sm text-gray-700">
292
-
No conflicts detected with the base branch. This
293
-
pull request can be merged safely.
294
-
</div>
295
-
296
-
<div class="flex items-center gap-2">
297
-
{{ if $isPushAllowed }}
298
-
<button
299
-
class="btn mt-4 flex items-center gap-2"
300
-
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
301
-
hx-swap="none"
302
-
{{ if or .Pull.State.IsClosed .MergeCheck.IsConflicted }}
303
-
disabled
304
-
{{ end }}>
305
-
<i data-lucide="git-merge" class="w-4 h-4"></i>
306
-
<span>merge</span>
307
-
</button>
308
-
{{ end }}
309
-
310
-
{{ if and (or $isPullAuthor $isPushAllowed) (not .Pull.State.IsMerged) }}
311
-
{{ $action := "close" }}
312
-
{{ $icon := "circle-x" }}
313
-
{{ $hoverColor := "red" }}
314
-
{{ if .Pull.State.IsClosed }}
315
-
{{ $action = "reopen" }}
316
-
{{ $icon = "circle-dot" }}
317
-
{{ $hoverColor = "green" }}
318
-
{{ end }}
319
-
<button
320
-
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/{{ $action }}"
321
-
hx-swap="none"
322
-
class="btn mt-4 flex items-center gap-2">
323
-
<i data-lucide="{{ $icon }}" class="w-4 h-4 text-{{ $hoverColor }}-400"></i>
324
-
<span class="text-black">{{ $action }}</span>
325
-
</button>
326
-
{{ end }}
327
-
328
-
<div id="pull-merge-error" class="error"></div>
329
-
<div id="pull-merge-success" class="success"></div>
330
-
</div>
331
-
</div>
332
-
{{ end }}
333
-
334
-
{{ define "resubmitCard" }}
335
-
<div
336
-
id="resubmit-pull-card"
337
-
class="rounded relative border bg-amber-50 border-amber-200 p-4">
338
-
339
-
<div class="flex items-center gap-2 text-amber-500">
340
-
<i data-lucide="edit" class="w-4 h-4"></i>
341
-
<span class="font-medium">resubmit your patch</span>
342
-
</div>
343
-
344
-
<div class="mt-2 text-sm text-gray-700">
345
-
You can update this patch to address any reviews.
346
-
This will begin a new round of reviews,
347
-
but you'll still be able to view your previous submissions and feedback.
348
-
</div>
349
-
350
-
<div class="mt-4 flex flex-col">
351
-
<form hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/resubmit" class="w-full" hx-swap="none">
352
-
<textarea
353
-
name="patch"
354
-
class="w-full p-2 mb-2 rounded border border-gray-200"
355
-
placeholder="Paste your updated patch here."
356
-
></textarea>
357
-
<button
358
-
type="submit"
359
-
class="btn flex items-center gap-2"
360
-
{{ if or .Pull.State.IsClosed }}
361
-
disabled
362
-
{{ end }}>
363
-
<i data-lucide="refresh-ccw" class="w-4 h-4"></i>
364
-
<span>resubmit</span>
365
-
</button>
366
-
</form>
367
-
368
-
<div id="resubmit-error" class="error"></div>
369
-
<div id="resubmit-success" class="success"></div>
370
-
</div>
371
-
</div>
372
-
{{ end }}
···
77
{{ $oneIndexedRound := add .RoundNumber 1 }}
78
<details {{ if eq $idx $lastIdx }}open{{ end }}>
79
<summary id="round-#{{ $oneIndexedRound }}" class="list-none cursor-pointer">
80
+
<div class="flex flex-wrap gap-2 items-center">
81
+
<!-- round number -->
82
+
<div class="rounded bg-white drop-shadow-sm px-3 py-2">
83
#{{ $oneIndexedRound }}
84
</div>
85
+
<!-- round summary -->
86
+
<div class="rounded drop-shadow-sm bg-white p-2 text-gray-500">
87
<span>
88
{{ $owner := index $.DidHandleMap $.Pull.OwnerDid }}
89
+
{{ $re := "re" }}
90
+
{{ if eq .RoundNumber 0 }}
91
+
{{ $re = "" }}
92
+
{{ end }}
93
+
<span class="hidden md:inline">{{$re}}submitted</span>
94
+
by <a href="/{{ $owner }}">{{ $owner }}</a>
95
<span class="select-none before:content-['\00B7']"></span>
96
+
<a class="text-gray-500 hover:text-gray-500" href="#round-#{{ $oneIndexedRound }}"><time>{{ .Created | shortTimeFmt }}</time></a>
97
<span class="select-none before:content-['·']"></span>
98
{{ $s := "s" }}
99
{{ if eq (len .Comments) 1 }}
100
{{ $s = "" }}
101
{{ end }}
102
{{ len .Comments }} comment{{$s}}
103
</span>
104
</div>
105
+
<!-- view patch -->
106
+
<a class="btn flex items-center gap-2 no-underline hover:no-underline p-2"
107
+
hx-boost="true"
108
+
href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/round/{{.RoundNumber}}">
109
+
{{ i "file-diff" "w-4 h-4" }} <span class="hidden md:inline">view patch</span>
110
+
</a>
111
</div>
112
</summary>
113
+
<div class="md:pl-12 flex flex-col gap-2 mt-2 relative">
114
{{ range .Comments }}
115
<div id="comment-{{.ID}}" class="bg-white rounded drop-shadow-sm py-2 px-4 relative w-fit">
116
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
···
118
{{ $owner := index $.DidHandleMap .OwnerDid }}
119
<a href="/{{$owner}}">{{$owner}}</a>
120
<span class="before:content-['·']"></span>
121
+
<a class="text-gray-500 hover:text-gray-500" href="#comment-{{.ID}}"><time>{{ .Created | shortTimeFmt }}</time></a>
122
</div>
123
<div class="prose">
124
+
{{ .Body | markdown }}
125
</div>
126
</div>
127
{{ end }}
···
140
{{ end }}
141
</div>
142
</details>
143
+
<hr class="md:hidden"/>
144
{{ end }}
145
{{ end }}
146
{{ end }}
···
200
</div>
201
{{ end }}
202
{{ end }}
+1
-1
input.css
+1
-1
input.css
···
132
@apply relative z-10 inline-flex min-h-[30px] cursor-pointer items-center
133
justify-center bg-transparent px-2 pb-[0.2rem] text-base
134
text-gray-900 before:absolute before:inset-0 before:-z-10
135
-
before:block before:rounded-sm before:border before:border-gray-200
136
before:bg-white before:drop-shadow-sm
137
before:content-[''] hover:before:border-gray-300
138
hover:before:bg-gray-50
···
132
@apply relative z-10 inline-flex min-h-[30px] cursor-pointer items-center
133
justify-center bg-transparent px-2 pb-[0.2rem] text-base
134
text-gray-900 before:absolute before:inset-0 before:-z-10
135
+
before:block before:rounded before:border before:border-gray-200
136
before:bg-white before:drop-shadow-sm
137
before:content-[''] hover:before:border-gray-300
138
hover:before:bg-gray-50