forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

appview/{db,pages,models}: show tooltips for user handles when hovering on reactions

Signed-off-by: Cameron Smith <cam@camsmith.dev>

authored by Cameron Smith and committed by Tangled 56721612 4a1653c5

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