+34
-7
appview/db/reaction.go
+34
-7
appview/db/reaction.go
···
62
62
return count, nil
63
63
}
64
64
65
-
func GetReactionCountMap(e Execer, threadAt syntax.ATURI) (map[models.ReactionKind]int, error) {
66
-
countMap := map[models.ReactionKind]int{}
65
+
func GetReactionMap(e Execer, userLimit int, threadAt syntax.ATURI) (map[models.ReactionKind]models.ReactionDisplayData, error) {
66
+
query := `
67
+
select kind, reacted_by_did,
68
+
row_number() over (partition by kind order by created asc) as rn,
69
+
count(*) over (partition by kind) as total
70
+
from reactions
71
+
where thread_at = ?
72
+
order by kind, created asc`
73
+
74
+
rows, err := e.Query(query, threadAt)
75
+
if err != nil {
76
+
return nil, err
77
+
}
78
+
defer rows.Close()
79
+
80
+
reactionMap := map[models.ReactionKind]models.ReactionDisplayData{}
67
81
for _, kind := range models.OrderedReactionKinds {
68
-
count, err := GetReactionCount(e, threadAt, kind)
69
-
if err != nil {
70
-
return map[models.ReactionKind]int{}, nil
82
+
reactionMap[kind] = models.ReactionDisplayData{Count: 0, Users: []string{}}
83
+
}
84
+
85
+
for rows.Next() {
86
+
var kind models.ReactionKind
87
+
var did string
88
+
var rn, total int
89
+
if err := rows.Scan(&kind, &did, &rn, &total); err != nil {
90
+
return nil, err
71
91
}
72
-
countMap[kind] = count
92
+
93
+
data := reactionMap[kind]
94
+
data.Count = total
95
+
if userLimit > 0 && rn <= userLimit {
96
+
data.Users = append(data.Users, did)
97
+
}
98
+
reactionMap[kind] = data
73
99
}
74
-
return countMap, nil
100
+
101
+
return reactionMap, rows.Err()
75
102
}
76
103
77
104
func GetReactionStatus(e Execer, userDid string, threadAt syntax.ATURI, kind models.ReactionKind) bool {
+2
-2
appview/issues/issues.go
+2
-2
appview/issues/issues.go
···
83
83
return
84
84
}
85
85
86
-
reactionCountMap, err := db.GetReactionCountMap(rp.db, issue.AtUri())
86
+
reactionMap, err := db.GetReactionMap(rp.db, 20, issue.AtUri())
87
87
if err != nil {
88
88
l.Error("failed to get issue reactions", "err", err)
89
89
}
···
115
115
Issue: issue,
116
116
CommentList: issue.CommentList(),
117
117
OrderedReactionKinds: models.OrderedReactionKinds,
118
-
Reactions: reactionCountMap,
118
+
Reactions: reactionMap,
119
119
UserReacted: userReactions,
120
120
LabelDefs: defs,
121
121
})
+5
appview/models/reaction.go
+5
appview/models/reaction.go
+3
-2
appview/pages/pages.go
+3
-2
appview/pages/pages.go
···
985
985
LabelDefs map[string]*models.LabelDefinition
986
986
987
987
OrderedReactionKinds []models.ReactionKind
988
-
Reactions map[models.ReactionKind]int
988
+
Reactions map[models.ReactionKind]models.ReactionDisplayData
989
989
UserReacted map[models.ReactionKind]bool
990
990
}
991
991
···
1010
1010
ThreadAt syntax.ATURI
1011
1011
Kind models.ReactionKind
1012
1012
Count int
1013
+
Users []string
1013
1014
IsReacted bool
1014
1015
}
1015
1016
···
1138
1139
Pipelines map[string]models.Pipeline
1139
1140
1140
1141
OrderedReactionKinds []models.ReactionKind
1141
-
Reactions map[models.ReactionKind]int
1142
+
Reactions map[models.ReactionKind]models.ReactionDisplayData
1142
1143
UserReacted map[models.ReactionKind]bool
1143
1144
1144
1145
LabelDefs map[string]*models.LabelDefinition
+6
-1
appview/pages/templates/repo/fragments/reaction.html
+6
-1
appview/pages/templates/repo/fragments/reaction.html
···
2
2
<button
3
3
id="reactIndi-{{ .Kind }}"
4
4
class="flex justify-center items-center min-w-8 min-h-8 rounded border
5
-
leading-4 px-3 gap-1
5
+
leading-4 px-3 gap-1 relative group
6
6
{{ if eq .Count 0 }}
7
7
hidden
8
8
{{ end }}
···
20
20
dark:hover:border-gray-600
21
21
{{ end }}
22
22
"
23
+
{{ if gt (length .Users) 0 }}
24
+
title="{{ range $i, $did := .Users }}{{ if ne $i 0 }}, {{ end }}{{ resolve $did }}{{ end }}{{ if gt .Count (length .Users) }}, and {{ sub .Count (length .Users) }} more{{ end }}"
25
+
{{ else }}
26
+
title="{{ .Kind }}"
27
+
{{ end }}
23
28
{{ if .IsReacted }}
24
29
hx-delete="/react?subject={{ .ThreadAt }}&kind={{ .Kind }}"
25
30
{{ else }}
+4
-2
appview/pages/templates/repo/issues/issue.html
+4
-2
appview/pages/templates/repo/issues/issue.html
···
110
110
<div class="flex items-center gap-2">
111
111
{{ template "repo/fragments/reactionsPopUp" .OrderedReactionKinds }}
112
112
{{ range $kind := .OrderedReactionKinds }}
113
+
{{ $reactionData := index $.Reactions $kind }}
113
114
{{
114
115
template "repo/fragments/reaction"
115
116
(dict
116
117
"Kind" $kind
117
-
"Count" (index $.Reactions $kind)
118
+
"Count" $reactionData.Count
118
119
"IsReacted" (index $.UserReacted $kind)
119
-
"ThreadAt" $.Issue.AtUri)
120
+
"ThreadAt" $.Issue.AtUri
121
+
"Users" $reactionData.Users)
120
122
}}
121
123
{{ end }}
122
124
</div>
+4
-2
appview/pages/templates/repo/pulls/fragments/pullHeader.html
+4
-2
appview/pages/templates/repo/pulls/fragments/pullHeader.html
···
66
66
<div class="flex items-center gap-2 mt-2">
67
67
{{ template "repo/fragments/reactionsPopUp" . }}
68
68
{{ range $kind := . }}
69
+
{{ $reactionData := index $.Reactions $kind }}
69
70
{{
70
71
template "repo/fragments/reaction"
71
72
(dict
72
73
"Kind" $kind
73
-
"Count" (index $.Reactions $kind)
74
+
"Count" $reactionData.Count
74
75
"IsReacted" (index $.UserReacted $kind)
75
-
"ThreadAt" $.Pull.PullAt)
76
+
"ThreadAt" $.Pull.PullAt
77
+
"Users" $reactionData.Users)
76
78
}}
77
79
{{ end }}
78
80
</div>
+2
-2
appview/pulls/pulls.go
+2
-2
appview/pulls/pulls.go
···
189
189
m[p.Sha] = p
190
190
}
191
191
192
-
reactionCountMap, err := db.GetReactionCountMap(s.db, pull.PullAt())
192
+
reactionMap, err := db.GetReactionMap(s.db, 20, pull.PullAt())
193
193
if err != nil {
194
194
log.Println("failed to get pull reactions")
195
195
s.pages.Notice(w, "pulls", "Failed to load pull. Try again later.")
···
227
227
Pipelines: m,
228
228
229
229
OrderedReactionKinds: models.OrderedReactionKinds,
230
-
Reactions: reactionCountMap,
230
+
Reactions: reactionMap,
231
231
UserReacted: userReactions,
232
232
233
233
LabelDefs: defs,
+8
-6
appview/state/reaction.go
+8
-6
appview/state/reaction.go
···
70
70
return
71
71
}
72
72
73
-
count, err := db.GetReactionCount(s.db, subjectUri, reactionKind)
73
+
reactionMap, err := db.GetReactionMap(s.db, 20, subjectUri)
74
74
if err != nil {
75
-
log.Println("failed to get reaction count for ", subjectUri)
75
+
log.Println("failed to get reactions for ", subjectUri)
76
76
}
77
77
78
78
log.Println("created atproto record: ", resp.Uri)
···
80
80
s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{
81
81
ThreadAt: subjectUri,
82
82
Kind: reactionKind,
83
-
Count: count,
83
+
Count: reactionMap[reactionKind].Count,
84
+
Users: reactionMap[reactionKind].Users,
84
85
IsReacted: true,
85
86
})
86
87
···
109
110
// this is not an issue, the firehose event might have already done this
110
111
}
111
112
112
-
count, err := db.GetReactionCount(s.db, subjectUri, reactionKind)
113
+
reactionMap, err := db.GetReactionMap(s.db, 20, subjectUri)
113
114
if err != nil {
114
-
log.Println("failed to get reaction count for ", subjectUri)
115
+
log.Println("failed to get reactions for ", subjectUri)
115
116
return
116
117
}
117
118
118
119
s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{
119
120
ThreadAt: subjectUri,
120
121
Kind: reactionKind,
121
-
Count: count,
122
+
Count: reactionMap[reactionKind].Count,
123
+
Users: reactionMap[reactionKind].Users,
122
124
IsReacted: false,
123
125
})
124
126