Signed-off-by: oppiliappan me@oppi.li
+143
-83
Diff
round #1
+8
-6
appview/pages/pages.go
+8
-6
appview/pages/pages.go
···
712
712
}
713
713
714
714
type ProfileVouchesParams struct {
715
-
LoggedInUser *oauth.MultiAccountUser
716
-
Vouches []models.Vouch
717
-
Suggestions []models.VouchSuggestion
718
-
Card *ProfileCard
719
-
Page pagination.Page
720
-
Active string
715
+
LoggedInUser *oauth.MultiAccountUser
716
+
Vouches []models.Vouch
717
+
Suggestions []models.VouchSuggestion
718
+
Card *ProfileCard
719
+
Page pagination.Page
720
+
Active string
721
+
EvidencePulls map[syntax.ATURI]*models.Pull
722
+
EvidenceIssues map[syntax.ATURI]*models.Issue
721
723
}
722
724
723
725
func (p *Pages) ProfileVouches(w io.Writer, params ProfileVouchesParams) error {
+21
appview/pages/templates/user/fragments/issueEvent.html
+21
appview/pages/templates/user/fragments/issueEvent.html
···
1
+
{{ define "user/fragments/issueEvent" }}
2
+
{{ $repoOwner := resolve .Repo.Did }}
3
+
{{ $repoUrl := printf "%s/%s" $repoOwner .Repo.Name }}
4
+
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300 overflow-hidden">
5
+
{{ if .Open }}
6
+
<span class="text-green-600 dark:text-green-500 shrink-0">
7
+
{{ i "circle-dot" "w-4 h-4" }}
8
+
</span>
9
+
{{ else }}
10
+
<span class="text-gray-500 dark:text-gray-400 shrink-0">
11
+
{{ i "ban" "w-4 h-4" }}
12
+
</span>
13
+
{{ end }}
14
+
<span class="shrink-0 text-gray-500 dark:text-gray-400">#{{ .IssueId }}</span>
15
+
<span class="truncate">
16
+
<a href="/{{ $repoUrl }}/issues/{{ .IssueId }}" class="no-underline hover:underline">{{- .Title -}}</a>
17
+
on
18
+
<a href="/{{ $repoUrl }}" class="no-underline hover:underline">{{ $repoUrl }}</a>
19
+
</span>
20
+
</div>
21
+
{{ end }}
+8
-2
appview/pages/templates/user/fragments/picLink.html
+8
-2
appview/pages/templates/user/fragments/picLink.html
···
7
7
{{ $vr = index . 2 }}
8
8
{{ end }}
9
9
<div class="relative inline-block"
10
+
{{ if $vr }}
10
11
onmouseenter="(function(el){
11
12
clearTimeout(el._pht);
12
13
el._pht = setTimeout(function(){
···
21
22
var modal=document.getElementById('vouch-modal-'+p.dataset.vouchModalId);
22
23
if(modal&&modal.matches(':popover-open'))return;
23
24
p.classList.add('hidden');
24
-
})(this)">
25
+
})(this)"
26
+
{{ end }}>
25
27
<a href="/{{ $handle }}" title="{{ $handle }}"
28
+
{{ if $vr }}
26
29
hx-get="/profile/popover?did={{ $did }}"
27
30
hx-trigger="mouseenter once"
28
31
hx-target="next [data-profile-popover-content]"
29
-
hx-swap="innerHTML">
32
+
hx-swap="innerHTML"
33
+
{{ end }}>
30
34
<img
31
35
src="{{ tinyAvatar $did }}"
32
36
alt=""
···
55
59
</button>
56
60
{{ end }}
57
61
{{ end }}
62
+
{{ if $vr }}
58
63
<div data-profile-popover
59
64
data-vouch-modal-id="{{ normalizeForHtmlId $did }}"
60
65
class="hidden z-[9999] pt-1 w-80"
···
66
71
</div>
67
72
</div>
68
73
</div>
74
+
{{ end }}
69
75
</div>
70
76
{{ if $vr }}
71
77
{{ if ne $did $vr.ViewerDid }}
+25
appview/pages/templates/user/fragments/pullEvent.html
+25
appview/pages/templates/user/fragments/pullEvent.html
···
1
+
{{ define "user/fragments/pullEvent" }}
2
+
{{ $repoOwner := resolve .Repo.Did }}
3
+
{{ $repoUrl := printf "%s/%s" $repoOwner .Repo.Name }}
4
+
<div class="flex items-center gap-2 text-gray-600 dark:text-gray-300 overflow-hidden">
5
+
{{ if .State.IsOpen }}
6
+
<span class="text-green-600 dark:text-green-500 shrink-0">
7
+
{{ i "git-pull-request" "w-4 h-4" }}
8
+
</span>
9
+
{{ else if .State.IsMerged }}
10
+
<span class="text-purple-600 dark:text-purple-500 shrink-0">
11
+
{{ i "git-merge" "w-4 h-4" }}
12
+
</span>
13
+
{{ else }}
14
+
<span class="text-gray-600 dark:text-gray-300 shrink-0">
15
+
{{ i "git-pull-request-closed" "w-4 h-4" }}
16
+
</span>
17
+
{{ end }}
18
+
<span class="shrink-0 text-gray-500 dark:text-gray-400">#{{ .PullId }}</span>
19
+
<span class="truncate">
20
+
<a href="/{{ $repoUrl }}/pulls/{{ .PullId }}" class="no-underline hover:underline">{{- .Title -}}</a>
21
+
on
22
+
<a href="/{{ $repoUrl }}" class="no-underline hover:underline">{{ $repoUrl }}</a>
23
+
</span>
24
+
</div>
25
+
{{ end }}
+2
-58
appview/pages/templates/user/overview.html
+2
-58
appview/pages/templates/user/overview.html
···
129
129
</summary>
130
130
<div class="py-2 text-sm flex flex-col gap-3 mb-2">
131
131
{{ range $items }}
132
-
{{ $repoOwner := resolve .Repo.Did }}
133
-
{{ $repoName := .Repo.Name }}
134
-
{{ $repoUrl := printf "%s/%s" $repoOwner $repoName }}
135
-
136
-
<div class="flex gap-2 text-gray-600 dark:text-gray-300">
137
-
{{ if .Open }}
138
-
<span class="text-green-600 dark:text-green-500">
139
-
{{ i "circle-dot" "w-4 h-4" }}
140
-
</span>
141
-
{{ else }}
142
-
<span class="text-gray-500 dark:text-gray-400">
143
-
{{ i "ban" "w-4 h-4" }}
144
-
</span>
145
-
{{ end }}
146
-
<div class="flex-none min-w-8 text-right">
147
-
<span class="text-gray-500 dark:text-gray-400">#{{ .IssueId }}</span>
148
-
</div>
149
-
<div class="break-words max-w-full">
150
-
<a href="/{{$repoUrl}}/issues/{{ .IssueId }}" class="no-underline hover:underline">
151
-
{{ .Title -}}
152
-
</a>
153
-
on
154
-
<a href="/{{$repoUrl}}" class="no-underline hover:underline whitespace-nowrap">
155
-
{{$repoUrl}}
156
-
</a>
157
-
</div>
158
-
</div>
132
+
{{ template "user/fragments/issueEvent" . }}
159
133
{{ end }}
160
134
</div>
161
135
</details>
···
198
172
</summary>
199
173
<div class="py-2 text-sm flex flex-col gap-3 mb-2">
200
174
{{ range $items }}
201
-
{{ $repoOwner := resolve .Repo.Did }}
202
-
{{ $repoName := .Repo.Name }}
203
-
{{ $repoUrl := printf "%s/%s" $repoOwner $repoName }}
204
-
205
-
<div class="flex gap-2 text-gray-600 dark:text-gray-300">
206
-
{{ if .State.IsOpen }}
207
-
<span class="text-green-600 dark:text-green-500">
208
-
{{ i "git-pull-request" "w-4 h-4" }}
209
-
</span>
210
-
{{ else if .State.IsMerged }}
211
-
<span class="text-purple-600 dark:text-purple-500">
212
-
{{ i "git-merge" "w-4 h-4" }}
213
-
</span>
214
-
{{ else }}
215
-
<span class="text-gray-600 dark:text-gray-300">
216
-
{{ i "git-pull-request-closed" "w-4 h-4" }}
217
-
</span>
218
-
{{ end }}
219
-
<div class="flex-none min-w-8 text-right">
220
-
<span class="text-gray-500 dark:text-gray-400">#{{ .PullId }}</span>
221
-
</div>
222
-
<div class="break-words max-w-full">
223
-
<a href="/{{$repoUrl}}/pulls/{{ .PullId }}" class="no-underline hover:underline">
224
-
{{ .Title -}}
225
-
</a>
226
-
on
227
-
<a href="/{{$repoUrl}}" class="no-underline hover:underline whitespace-nowrap">
228
-
{{$repoUrl}}
229
-
</a>
230
-
</div>
231
-
</div>
175
+
{{ template "user/fragments/pullEvent" . }}
232
176
{{ end }}
233
177
</div>
234
178
</details>
+25
-8
appview/pages/templates/user/vouches.html
+25
-8
appview/pages/templates/user/vouches.html
···
33
33
<div class="relative flex flex-col gap-6 ml-5 px-4 border border-transparent">
34
34
<div class="absolute top-8 bottom-8 w-0.5 bg-gray-200 dark:bg-gray-700 z-0"></div>
35
35
{{ range .Vouches }}
36
-
{{ template "vouchTimelineItem" (list $.Card.UserDid $.LoggedInUser.Did .) }}
36
+
{{ template "vouchTimelineItem" (list $.Card.UserDid $.LoggedInUser.Did . $.EvidencePulls $.EvidenceIssues) }}
37
37
{{ end }}
38
38
</div>
39
39
{{ end }}
···
72
72
{{ $profileDid := index . 0 }}
73
73
{{ $viewerDid := index . 1 }}
74
74
{{ $v := index . 2 }}
75
+
{{ $evidencePulls := index . 3 }}
76
+
{{ $evidenceIssues := index . 4 }}
75
77
{{ $isOutgoing := eq $v.Did $profileDid }}
76
78
{{ $isVouch := $v.IsVouch }}
77
79
{{ $isSelf := eq $profileDid $viewerDid }}
78
80
79
-
<div class="-ml-5 flex items-center gap-3 relative z-10">
80
-
<div class="flex-shrink-0 flex items-center justify-center size-10 rounded-full
81
-
{{ if $isVouch }}bg-green-200 dark:bg-green-800{{ else }}bg-red-200 dark:bg-red-800{{ end }}">
81
+
<div class="-ml-4 flex items-start gap-3 relative z-10">
82
+
<div class="flex-shrink-0 flex items-center justify-center size-8 rounded-full
83
+
{{ if $isVouch }}bg-green-200 dark:bg-green-800{{ else }}bg-red-200 dark:bg-red-800{{ end }}
84
+
border border-gray-300 dark:border-gray-700
85
+
">
82
86
{{ if $isVouch }}
83
87
{{ if $isOutgoing }}
84
88
{{ i "arrow-up-right" "size-5 text-green-500 dark:text-green-400" }}
···
94
98
{{ end }}
95
99
</div>
96
100
97
-
<div class="flex flex-col gap-1">
98
-
<div class="flex flex-wrap items-center gap-1 text-sm dark:text-white">
101
+
<div class="flex flex-col gap-1 mt-1">
102
+
<div class="flex flex-wrap items-center gap-1 dark:text-white">
99
103
{{ if and $isSelf $isOutgoing }}
100
104
<span class="font-medium text-gray-700 dark:text-gray-300">you</span>
101
105
{{ else }}
···
109
113
{{ else }}
110
114
<a href="/{{ resolve $v.SubjectDid.String }}" class="font-medium hover:underline">{{ resolve $v.SubjectDid.String }}</a>
111
115
{{ end }}
112
-
<span class="text-gray-400 dark:text-gray-500 text-xs">{{ relTimeFmt $v.CreatedAt }}</span>
116
+
<span class="text-gray-400 dark:text-gray-500 text-sm">{{ relTimeFmt $v.CreatedAt }}</span>
113
117
</div>
114
118
{{ with $v.Reason }}
115
-
<p class="text-gray-500 dark:text-gray-400">{{ . }}</p>
119
+
<p class="text-gray-500 dark:text-gray-400 text-sm">{{ . }}</p>
120
+
{{ end }}
121
+
{{ if $v.Evidences }}
122
+
<div class="flex flex-col gap-2 mt-1 text-sm">
123
+
{{ range $v.Evidences }}
124
+
{{ $pull := index $evidencePulls . }}
125
+
{{ $issue := index $evidenceIssues . }}
126
+
{{ if $pull }}
127
+
{{ template "user/fragments/pullEvent" $pull }}
128
+
{{ else if $issue }}
129
+
{{ template "user/fragments/issueEvent" $issue }}
130
+
{{ end }}
131
+
{{ end }}
132
+
</div>
116
133
{{ end }}
117
134
</div>
118
135
</div>
+43
-5
appview/state/profile.go
+43
-5
appview/state/profile.go
···
438
438
}
439
439
}
440
440
441
+
var pullAts, issueAts []syntax.ATURI
442
+
for _, v := range vouches {
443
+
for _, ev := range v.Evidences {
444
+
switch ev.Collection().String() {
445
+
case tangled.RepoPullNSID:
446
+
pullAts = append(pullAts, ev)
447
+
case tangled.RepoIssueNSID:
448
+
issueAts = append(issueAts, ev)
449
+
}
450
+
}
451
+
}
452
+
453
+
evidencePulls := make(map[syntax.ATURI]*models.Pull)
454
+
if len(pullAts) > 0 {
455
+
pulls, err := db.GetPulls(s.db, orm.FilterIn("at_uri", pullAts))
456
+
if err != nil {
457
+
l.Error("failed to get evidence pulls", "err", err)
458
+
} else {
459
+
for _, p := range pulls {
460
+
evidencePulls[p.AtUri()] = p
461
+
}
462
+
}
463
+
}
464
+
465
+
evidenceIssues := make(map[syntax.ATURI]*models.Issue)
466
+
if len(issueAts) > 0 {
467
+
issues, err := db.GetIssues(s.db, orm.FilterIn("at_uri", issueAts))
468
+
if err != nil {
469
+
l.Error("failed to get evidence issues", "err", err)
470
+
} else {
471
+
for i := range issues {
472
+
evidenceIssues[issues[i].AtUri()] = &issues[i]
473
+
}
474
+
}
475
+
}
476
+
441
477
err = s.pages.ProfileVouches(w, pages.ProfileVouchesParams{
442
-
LoggedInUser: loggedInUser,
443
-
Vouches: vouches,
444
-
Suggestions: suggestions,
445
-
Card: profile,
446
-
Page: page,
478
+
LoggedInUser: loggedInUser,
479
+
Vouches: vouches,
480
+
Suggestions: suggestions,
481
+
Card: profile,
482
+
Page: page,
483
+
EvidencePulls: evidencePulls,
484
+
EvidenceIssues: evidenceIssues,
447
485
})
448
486
if err != nil {
449
487
l.Error("failed to render page", "err", err)
+11
-4
appview/state/vouch.go
+11
-4
appview/state/vouch.go
···
136
136
reasonPtr = &reason
137
137
}
138
138
139
-
var evidences []string
139
+
var evidences []syntax.ATURI
140
140
for _, raw := range r.Form["evidences"] {
141
-
if _, err := syntax.ParseATURI(raw); err != nil {
141
+
uri, err := syntax.ParseATURI(raw)
142
+
if err != nil {
142
143
l.Warn("invalid evidence AT-URI, skipping", "uri", raw, "err", err)
143
144
continue
144
145
}
145
-
evidences = append(evidences, raw)
146
+
evidences = append(evidences, uri)
146
147
}
147
148
148
149
var swapCid *string
···
162
163
Kind: string(kind),
163
164
Reason: reasonPtr,
164
165
CreatedAt: createdAt,
165
-
Evidences: evidences,
166
+
Evidences: func() []string {
167
+
ss := make([]string, len(evidences))
168
+
for i, e := range evidences {
169
+
ss[i] = e.String()
170
+
}
171
+
return ss
172
+
}(),
166
173
}},
167
174
})
168
175
if err != nil {