forked from tangled.org/core
this repo has no description

group timeline events in profile

timeline events in profiles are grouped by month (each month is a card) and by type (repos, issues and pulls).

Changed files
+422 -162
appview
+48 -18
appview/db/issues.go
···
OwnerDid string
IssueId int
IssueAt string
-
Created *time.Time
+
Created time.Time
Title string
Body string
Open bool
+
+
// optionally, populate this when querying for reverse mappings
+
// like comment counts, parent repo etc.
Metadata *IssueMetadata
}
type IssueMetadata struct {
CommentCount int
+
Repo *Repo
// labels, assignee etc.
}
···
if err != nil {
return nil, err
}
-
issue.Created = &createdTime
+
issue.Created = createdTime
issue.Metadata = &metadata
issues = append(issues, issue)
···
return issues, nil
}
-
func GetIssuesByOwnerDid(e Execer, ownerDid string) ([]Issue, error) {
+
// timeframe here is directly passed into the sql query filter, and any
+
// timeframe in the past should be negative; e.g.: "-3 months"
+
func GetIssuesByOwnerDid(e Execer, ownerDid string, timeframe string) ([]Issue, error) {
var issues []Issue
rows, err := e.Query(
···
i.title,
i.body,
i.open,
-
count(c.id)
+
r.did,
+
r.name,
+
r.knot,
+
r.rkey,
+
r.created
from
issues i
-
left join
-
comments c on i.repo_at = c.repo_at and i.issue_id = c.issue_id
+
join
+
repos r on i.repo_at = r.at_uri
where
-
i.owner_did = ?
-
group by
-
i.id, i.owner_did, i.repo_at, i.issue_id, i.created, i.title, i.body, i.open
+
i.owner_did = ? and i.created >= date ('now', ?)
order by
i.created desc`,
-
ownerDid)
+
ownerDid, timeframe)
if err != nil {
return nil, err
}
···
for rows.Next() {
var issue Issue
-
var createdAt string
-
var metadata IssueMetadata
-
err := rows.Scan(&issue.OwnerDid, &issue.RepoAt, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open, &metadata.CommentCount)
+
var issueCreatedAt, repoCreatedAt string
+
var repo Repo
+
err := rows.Scan(
+
&issue.OwnerDid,
+
&issue.RepoAt,
+
&issue.IssueId,
+
&issueCreatedAt,
+
&issue.Title,
+
&issue.Body,
+
&issue.Open,
+
&repo.Did,
+
&repo.Name,
+
&repo.Knot,
+
&repo.Rkey,
+
&repoCreatedAt,
+
)
if err != nil {
return nil, err
}
-
createdTime, err := time.Parse(time.RFC3339, createdAt)
+
issueCreatedTime, err := time.Parse(time.RFC3339, issueCreatedAt)
+
if err != nil {
+
return nil, err
+
}
+
issue.Created = issueCreatedTime
+
+
repoCreatedTime, err := time.Parse(time.RFC3339, repoCreatedAt)
if err != nil {
return nil, err
}
-
issue.Created = &createdTime
-
issue.Metadata = &metadata
+
repo.Created = repoCreatedTime
+
+
issue.Metadata = &IssueMetadata{
+
Repo: &repo,
+
}
issues = append(issues, issue)
}
···
if err != nil {
return nil, err
}
-
issue.Created = &createdTime
+
issue.Created = createdTime
return &issue, nil
}
···
if err != nil {
return nil, nil, err
}
-
issue.Created = &createdTime
+
issue.Created = createdTime
comments, err := GetComments(e, repoAt, issueId)
if err != nil {
+119 -48
appview/db/profile.go
···
import (
"fmt"
-
"sort"
"time"
)
-
type ProfileTimelineEvent struct {
-
EventAt time.Time
-
Type string
-
*Issue
-
*Pull
-
*Repo
+
type RepoEvent struct {
+
Repo *Repo
+
Source *Repo
+
}
+
+
type ProfileTimeline struct {
+
ByMonth []ByMonth
+
}
-
// optional: populate only if Repo is a fork
-
Source *Repo
+
type ByMonth struct {
+
RepoEvents []RepoEvent
+
IssueEvents IssueEvents
+
PullEvents PullEvents
}
-
func MakeProfileTimeline(e Execer, forDid string) ([]ProfileTimelineEvent, error) {
-
timeline := []ProfileTimelineEvent{}
-
limit := 30
+
func (b ByMonth) IsEmpty() bool {
+
return len(b.RepoEvents) == 0 &&
+
len(b.IssueEvents.Items) == 0 &&
+
len(b.PullEvents.Items) == 0
+
}
+
+
type IssueEvents struct {
+
Items []*Issue
+
}
+
+
type IssueEventStats struct {
+
Open int
+
Closed int
+
}
+
+
func (i IssueEvents) Stats() IssueEventStats {
+
var open, closed int
+
for _, issue := range i.Items {
+
if issue.Open {
+
open += 1
+
} else {
+
closed += 1
+
}
+
}
+
+
return IssueEventStats{
+
Open: open,
+
Closed: closed,
+
}
+
}
+
+
type PullEvents struct {
+
Items []*Pull
+
}
+
+
func (p PullEvents) Stats() PullEventStats {
+
var open, merged, closed int
+
for _, pull := range p.Items {
+
switch pull.State {
+
case PullOpen:
+
open += 1
+
case PullMerged:
+
merged += 1
+
case PullClosed:
+
closed += 1
+
}
+
}
+
+
return PullEventStats{
+
Open: open,
+
Merged: merged,
+
Closed: closed,
+
}
+
}
+
+
type PullEventStats struct {
+
Closed int
+
Open int
+
Merged int
+
}
+
+
const TimeframeMonths = 3
+
+
func MakeProfileTimeline(e Execer, forDid string) (*ProfileTimeline, error) {
+
timeline := ProfileTimeline{
+
ByMonth: make([]ByMonth, TimeframeMonths),
+
}
+
currentMonth := time.Now().Month()
+
timeframe := fmt.Sprintf("-%d months", TimeframeMonths)
-
pulls, err := GetPullsByOwnerDid(e, forDid)
+
pulls, err := GetPullsByOwnerDid(e, forDid, timeframe)
if err != nil {
-
return timeline, fmt.Errorf("error getting pulls by owner did: %w", err)
+
return nil, fmt.Errorf("error getting pulls by owner did: %w", err)
}
+
// group pulls by month
for _, pull := range pulls {
-
repo, err := GetRepoByAtUri(e, string(pull.RepoAt))
-
if err != nil {
-
return timeline, fmt.Errorf("error getting repo by at uri: %w", err)
+
pullMonth := pull.Created.Month()
+
+
if currentMonth-pullMonth > TimeframeMonths {
+
// shouldn't happen; but times are weird
+
continue
}
-
timeline = append(timeline, ProfileTimelineEvent{
-
EventAt: pull.Created,
-
Type: "pull",
-
Pull: &pull,
-
Repo: repo,
-
})
+
idx := currentMonth - pullMonth
+
items := &timeline.ByMonth[idx].PullEvents.Items
+
+
*items = append(*items, &pull)
}
-
issues, err := GetIssuesByOwnerDid(e, forDid)
+
issues, err := GetIssuesByOwnerDid(e, forDid, timeframe)
if err != nil {
-
return timeline, fmt.Errorf("error getting issues by owner did: %w", err)
+
return nil, fmt.Errorf("error getting issues by owner did: %w", err)
}
for _, issue := range issues {
-
repo, err := GetRepoByAtUri(e, string(issue.RepoAt))
-
if err != nil {
-
return timeline, fmt.Errorf("error getting repo by at uri: %w", err)
+
issueMonth := issue.Created.Month()
+
+
if currentMonth-issueMonth > TimeframeMonths {
+
// shouldn't happen; but times are weird
+
continue
}
-
timeline = append(timeline, ProfileTimelineEvent{
-
EventAt: *issue.Created,
-
Type: "issue",
-
Issue: &issue,
-
Repo: repo,
-
})
+
idx := currentMonth - issueMonth
+
items := &timeline.ByMonth[idx].IssueEvents.Items
+
+
*items = append(*items, &issue)
}
repos, err := GetAllReposByDid(e, forDid)
if err != nil {
-
return timeline, fmt.Errorf("error getting all repos by did: %w", err)
+
return nil, fmt.Errorf("error getting all repos by did: %w", err)
}
for _, repo := range repos {
+
// TODO: get this in the original query; requires COALESCE because nullable
var sourceRepo *Repo
if repo.Source != "" {
sourceRepo, err = GetRepoByAtUri(e, repo.Source)
···
}
}
-
timeline = append(timeline, ProfileTimelineEvent{
-
EventAt: repo.Created,
-
Type: "repo",
-
Repo: &repo,
-
Source: sourceRepo,
-
})
-
}
+
repoMonth := repo.Created.Month()
+
+
if currentMonth-repoMonth > TimeframeMonths {
+
// shouldn't happen; but times are weird
+
continue
+
}
-
sort.Slice(timeline, func(i, j int) bool {
-
return timeline[i].EventAt.After(timeline[j].EventAt)
-
})
+
idx := currentMonth - repoMonth
-
if len(timeline) > limit {
-
timeline = timeline[:limit]
+
items := &timeline.ByMonth[idx].RepoEvents
+
*items = append(*items, RepoEvent{
+
Repo: &repo,
+
Source: sourceRepo,
+
})
}
-
return timeline, nil
+
return &timeline, nil
}
+40 -14
appview/db/pulls.go
···
// meta
Created time.Time
PullSource *PullSource
+
+
// optionally, populate this when querying for reverse mappings
+
Repo *Repo
}
type PullSource struct {
···
return &pull, nil
}
-
func GetPullsByOwnerDid(e Execer, did string) ([]Pull, error) {
+
// timeframe here is directly passed into the sql query filter, and any
+
// timeframe in the past should be negative; e.g.: "-3 months"
+
func GetPullsByOwnerDid(e Execer, did, timeframe string) ([]Pull, error) {
var pulls []Pull
rows, err := e.Query(`
select
-
owner_did,
-
repo_at,
-
pull_id,
-
created,
-
title,
-
state
+
p.owner_did,
+
p.repo_at,
+
p.pull_id,
+
p.created,
+
p.title,
+
p.state,
+
r.did,
+
r.name,
+
r.knot,
+
r.rkey,
+
r.created
from
-
pulls
+
pulls p
+
join
+
repos r on p.repo_at = r.at_uri
where
-
owner_did = ?
+
p.owner_did = ? and p.created >= date ('now', ?)
order by
-
created desc`, did)
+
p.created desc`, did, timeframe)
if err != nil {
return nil, err
}
···
for rows.Next() {
var pull Pull
-
var createdAt string
+
var repo Repo
+
var pullCreatedAt, repoCreatedAt string
err := rows.Scan(
&pull.OwnerDid,
&pull.RepoAt,
&pull.PullId,
-
&createdAt,
+
&pullCreatedAt,
&pull.Title,
&pull.State,
+
&repo.Did,
+
&repo.Name,
+
&repo.Knot,
+
&repo.Rkey,
+
&repoCreatedAt,
)
if err != nil {
return nil, err
}
-
createdTime, err := time.Parse(time.RFC3339, createdAt)
+
pullCreatedTime, err := time.Parse(time.RFC3339, pullCreatedAt)
if err != nil {
return nil, err
}
-
pull.Created = createdTime
+
pull.Created = pullCreatedTime
+
+
repoCreatedTime, err := time.Parse(time.RFC3339, repoCreatedAt)
+
if err != nil {
+
return nil, err
+
}
+
repo.Created = repoCreatedTime
+
+
pull.Repo = &repo
pulls = append(pulls, pull)
}
+3 -1
appview/db/repos.go
···
where
r.did = ?
group by
-
r.at_uri`, did)
+
r.at_uri
+
order by r.created desc`,
+
did)
if err != nil {
return nil, err
}
+3 -2
appview/pages/pages.go
···
CollaboratingRepos []db.Repo
ProfileStats ProfileStats
FollowStatus db.FollowStatus
-
DidHandleMap map[string]string
AvatarUri string
-
ProfileTimeline []db.ProfileTimelineEvent
+
ProfileTimeline *db.ProfileTimeline
+
+
DidHandleMap map[string]string
}
type ProfileStats struct {
+1 -1
appview/pages/templates/repo/blob.html
···
>
/
{{ else }}
-
<span class="text-bold text-gray-600 dark:text-gray-300"
+
<span class="text-bold text-black dark:text-white"
>{{ index . 0 }}</span
>
{{ end }}
+3 -3
appview/pages/templates/repo/tree.html
···
{{ $containerstyle := "py-1" }}
{{ $linkstyle := "no-underline hover:underline" }}
-
<div class="pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-500">
+
<div class="pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-700">
<div class="flex flex-col md:flex-row md:justify-between gap-2">
-
<div id="breadcrumbs" class="overflow-x-auto whitespace-nowrap">
+
<div id="breadcrumbs" class="overflow-x-auto whitespace-nowrap text-gray-400 dark:text-gray-500">
{{ range .BreadCrumbs }}
-
<a href="{{ index . 1}}" class="text-bold text-gray-500 dark:text-gray-400 {{ $linkstyle }}">{{ index . 0 }}</a> /
+
<a href="{{ index . 1}}" class="text-bold text-gray-500 dark:text-gray-400 {{ $linkstyle }}">{{ index . 0 }}</a> /
{{ end }}
</div>
<div id="dir-info" class="text-gray-500 dark:text-gray-400 text-xs md:text-sm flex flex-wrap items-center gap-1 md:gap-0">
+193 -69
appview/pages/templates/user/profile.html
···
{{ block "ownRepos" . }}{{ end }}
{{ block "collaboratingRepos" . }}{{ end }}
</div>
-
<div class="md:col-span-2 order-3 md:order-3">
{{ block "profileTimeline" . }}{{ end }}
</div>
</div>
{{ end }}
+
{{ define "profileTimeline" }}
+
<p class="text-sm font-bold py-2 dark:text-white px-6">ACTIVITY</p>
+
<div class="flex flex-col gap-6 relative">
+
{{ with .ProfileTimeline }}
+
{{ range $idx, $byMonth := .ByMonth }}
+
{{ with $byMonth }}
+
<div class="bg-white dark:bg-gray-800 px-6 py-4 rounded drop-shadow-sm">
+
{{ if eq $idx 0 }}
+
+
{{ else }}
+
{{ $s := "s" }}
+
{{ if eq $idx 1 }}
+
{{ $s = "" }}
+
{{ end }}
+
<p class="text-sm font-bold dark:text-white mb-2">{{$idx}} month{{$s}} ago</p>
+
{{ end }}
-
{{ define "profileTimeline" }}
-
<div class="flex flex-col gap-3 relative">
-
<p class="px-6 text-sm font-bold py-2 dark:text-white">ACTIVITY</p>
-
{{ range .ProfileTimeline }}
-
{{ if eq .Type "issue" }}
-
<div class="px-6 py-2 bg-white dark:bg-gray-800 rounded drop-shadow-sm w-fit max-w-full flex items-center gap-2">
-
{{ $textColor := "text-gray-800 dark:text-gray-400" }}
-
{{ $icon := "ban" }}
-
{{ if .Issue.Open }}
-
{{ $textColor = "text-green-600 dark:text-green-500" }}
-
{{ $icon = "circle-dot" }}
-
{{ end }}
-
<div class="p-1 {{ $textColor }}">
-
{{ i $icon "w-5 h-5" }}
+
{{ if .IsEmpty }}
+
<div class="text-gray-500 dark:text-gray-400">
+
No activity for this month
</div>
-
<div>
-
<p class="text-gray-600 dark:text-gray-300">
-
<a href="/{{ index $.DidHandleMap .Repo.Did }}/{{ .Repo.Name }}/issues/{{ .Issue.IssueId }}" class="no-underline hover:underline">{{ .Issue.Title }} <span class="text-gray-500 dark:text-gray-400">#{{ .Issue.IssueId }}</span></a>
-
on
-
<a href="/{{ index $.DidHandleMap .Repo.Did }}/{{ .Repo.Name }}" class="no-underline hover:underline">{{ index $.DidHandleMap .Repo.Did }}<span class="select-none">/</span>{{ .Repo.Name }}</a>
-
<time class="text-gray-700 dark:text-gray-400 text-xs ml-2">{{ .Issue.Created | shortTimeFmt }}</time>
-
</p>
+
{{ else }}
+
<div class="flex flex-col gap-1">
+
{{ block "repoEvents" (list .RepoEvents $.DidHandleMap) }} {{ end }}
+
{{ block "issueEvents" (list .IssueEvents $.DidHandleMap) }} {{ end }}
+
{{ block "pullEvents" (list .PullEvents $.DidHandleMap) }} {{ end }}
</div>
+
{{ end }}
+
</div>
+
+
{{ end }}
+
{{ else }}
+
<p class="dark:text-white">This user does not have any activity yet.</p>
+
{{ end }}
+
{{ end }}
+
</div>
+
{{ end }}
+
+
{{ define "repoEvents" }}
+
{{ $items := index . 0 }}
+
{{ $handleMap := index . 1 }}
+
+
{{ if gt (len $items) 0 }}
+
<details>
+
<summary class="list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400">
+
<div class="flex flex-wrap items-center gap-2">
+
{{ i "book-plus" "w-4 h-4" }}
+
created {{ len $items }} {{if eq (len $items) 1 }}repository{{else}}repositories{{end}}
+
</div>
+
</summary>
+
<div class="py-2 text-sm flex flex-col gap-3 mb-2">
+
{{ range $items }}
+
<div class="flex flex-wrap items-center gap-2">
+
<span class="text-gray-500 dark:text-gray-400">
+
{{ if .Source }}
+
{{ i "git-fork" "w-4 h-4" }}
+
{{ else }}
+
{{ i "book-plus" "w-4 h-4" }}
+
{{ end }}
+
</span>
+
<a href="/{{ index $handleMap .Repo.Did }}/{{ .Repo.Name }}" class="no-underline hover:underline">
+
{{- .Repo.Name -}}
+
</a>
</div>
-
{{ else if eq .Type "pull" }}
-
<div class="px-6 py-2 bg-white dark:bg-gray-800 rounded drop-shadow-sm w-fit flex items-center gap-3">
-
{{ $textColor := "text-gray-800 dark:text-gray-400" }}
-
{{ $icon := "git-pull-request-closed" }}
-
{{ if .Pull.State.IsOpen }}
-
{{ $textColor = "text-green-600 dark:text-green-500" }}
-
{{ $icon = "git-pull-request" }}
-
{{ else if .Pull.State.IsMerged }}
-
{{ $textColor = "text-purple-600 dark:text-purple-500" }}
-
{{ $icon = "git-merge" }}
+
{{ end }}
+
</div>
+
</details>
+
{{ end }}
+
{{ end }}
+
+
{{ define "issueEvents" }}
+
{{ $i := index . 0 }}
+
{{ $items := $i.Items }}
+
{{ $stats := $i.Stats }}
+
{{ $handleMap := index . 1 }}
+
+
{{ if gt (len $items) 0 }}
+
<details>
+
<summary class="list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400">
+
<div class="flex flex-wrap items-center gap-2">
+
{{ i "circle-dot" "w-4 h-4" }}
+
+
<div>
+
created {{ len $items }} {{if eq (len $items) 1 }}issue{{else}}issues{{end}}
+
</div>
+
+
{{ if gt $stats.Open 0 }}
+
<span class="px-2 py-1/2 text-sm rounded text-white bg-green-600 dark:bg-green-700">
+
{{$stats.Open}} open
+
</span>
+
{{ end }}
+
+
{{ if gt $stats.Closed 0 }}
+
<span class="px-2 py-1/2 text-sm rounded text-white bg-gray-800 dark:bg-gray-700">
+
{{$stats.Closed}} closed
+
</span>
+
{{ end }}
+
+
</div>
+
</summary>
+
<div class="py-2 text-sm flex flex-col gap-3 mb-2">
+
{{ range $items }}
+
{{ $repoOwner := index $handleMap .Metadata.Repo.Did }}
+
{{ $repoName := .Metadata.Repo.Name }}
+
{{ $repoUrl := printf "%s/%s" $repoOwner $repoName }}
+
+
<div class="flex gap-2 text-gray-600 dark:text-gray-300">
+
{{ if .Open }}
+
<span class="text-green-600 dark:text-green-500">
+
{{ i "circle-dot" "w-4 h-4" }}
+
</span>
+
{{ else }}
+
<span class="text-gray-500 dark:text-gray-400">
+
{{ i "ban" "w-4 h-4" }}
+
</span>
{{ end }}
-
<div class="{{ $textColor }} p-1">
-
{{ i $icon "w-5 h-5" }}
+
<div class="flex-none min-w-8 text-right">
+
<span class="text-gray-500 dark:text-gray-400">#{{ .IssueId }}</span>
</div>
-
<div>
-
<p class="text-gray-600 dark:text-gray-300">
-
<a href="/{{ index $.DidHandleMap .Repo.Did }}/{{ .Repo.Name }}/pulls/{{ .Pull.PullId }}" class="no-underline hover:underline">{{ .Pull.Title }} <span class="text-gray-500 dark:text-gray-400">#{{ .Pull.PullId }}</span></a>
+
<div class="break-words max-w-full">
+
<a href="/{{$repoUrl}}/issues/{{ .IssueId }}" class="no-underline hover:underline">
+
{{ .Title -}}
+
</a>
on
-
<a href="/{{ index $.DidHandleMap .Repo.Did }}/{{ .Repo.Name }}" class="no-underline hover:underline">
-
{{ index $.DidHandleMap .Repo.Did }}<span class="select-none">/</span>{{ .Repo.Name }}</a>
-
<time class="text-gray-700 dark:text-gray-400 text-xs ml-2">{{ .Pull.Created | shortTimeFmt }}</time>
-
</p>
+
<a href="/{{$repoUrl}}" class="no-underline hover:underline whitespace-nowrap">
+
{{$repoUrl}}
+
</a>
</div>
</div>
-
{{ else if eq .Type "repo" }}
-
<div class="px-6 py-2 bg-white dark:bg-gray-800 rounded drop-shadow-sm w-fit flex items-center gap-3">
-
{{ if .Source }}
-
<div class="text-gray-800 dark:text-gray-400 p-1">
-
{{ i "git-fork" "w-5 h-5" }}
-
</div>
+
{{ end }}
+
</div>
+
</details>
+
{{ end }}
+
{{ end }}
+
+
{{ define "pullEvents" }}
+
{{ $i := index . 0 }}
+
{{ $items := $i.Items }}
+
{{ $stats := $i.Stats }}
+
{{ $handleMap := index . 1 }}
+
{{ if gt (len $items) 0 }}
+
<details>
+
<summary class="list-none cursor-pointer hover:text-gray-500 hover:dark:text-gray-400">
+
<div class="flex flex-wrap items-center gap-2">
+
{{ i "git-pull-request" "w-4 h-4" }}
+
+
<div>
+
created {{ len $items }} {{if eq (len $items) 1 }}pull request{{else}}pull requests{{end}}
+
</div>
+
+
{{ if gt $stats.Open 0 }}
+
<span class="px-2 py-1/2 text-sm rounded text-white bg-green-600 dark:bg-green-700">
+
{{$stats.Open}} open
+
</span>
+
{{ end }}
+
+
{{ if gt $stats.Merged 0 }}
+
<span class="px-2 py-1/2 text-sm rounded text-white bg-purple-600 dark:bg-purple-700">
+
{{$stats.Merged}} merged
+
</span>
+
{{ end }}
+
+
+
{{ if gt $stats.Closed 0 }}
+
<span class="px-2 py-1/2 text-sm rounded text-black dark:text-white bg-gray-50 dark:bg-gray-700 ">
+
{{$stats.Closed}} closed
+
</span>
+
{{ end }}
+
+
</div>
+
</summary>
+
<div class="py-2 text-sm flex flex-col gap-3 mb-2">
+
{{ range $items }}
+
{{ $repoOwner := index $handleMap .Repo.Did }}
+
{{ $repoName := .Repo.Name }}
+
{{ $repoUrl := printf "%s/%s" $repoOwner $repoName }}
+
+
<div class="flex gap-2 text-gray-600 dark:text-gray-300">
+
{{ if .State.IsOpen }}
+
<span class="text-green-600 dark:text-green-500">
+
{{ i "git-pull-request" "w-4 h-4" }}
+
</span>
+
{{ else if .State.IsMerged }}
+
<span class="text-purple-600 dark:text-purple-500">
+
{{ i "git-merge" "w-4 h-4" }}
+
</span>
{{ else }}
-
<div class="text-gray-800 dark:text-gray-400 p-1">
-
{{ i "book-plus" "w-5 h-5" }}
+
<span class="text-gray-600 dark:text-gray-300">
+
{{ i "git-pull-request-closed" "w-4 h-4" }}
+
</span>
+
{{ end }}
+
<div class="flex-none min-w-8 text-right">
+
<span class="text-gray-500 dark:text-gray-400">#{{ .PullId }}</span>
</div>
-
{{ end }}
-
<div>
-
<p class="text-gray-600 dark:text-gray-300">
-
-
{{ if .Source }}
-
forked
-
<a href="/{{ index $.DidHandleMap .Source.Did }}/{{ .Source.Name }}" class="no-underline hover:underline">
-
{{ index $.DidHandleMap .Source.Did }}/{{ .Source.Name }}
-
</a>
-
to
-
<a href="/{{ didOrHandle $.UserHandle $.UserDid }}/{{ .Repo.Name }}" class="no-underline hover:underline">{{ .Repo.Name }}</a>
-
{{ else }}
-
created
-
<a href="/{{ index $.DidHandleMap .Repo.Did }}/{{ .Repo.Name }}" class="no-underline hover:underline">{{ .Repo.Name }}</a>
-
{{ end }}
-
<time class="text-gray-700 dark:text-gray-400 text-xs ml-2">{{ .Repo.Created | shortTimeFmt }}</time>
-
</p>
+
<div class="break-words max-w-full">
+
<a href="/{{$repoUrl}}/pulls/{{ .PullId }}" class="no-underline hover:underline">
+
{{ .Title -}}
+
</a>
+
on
+
<a href="/{{$repoUrl}}" class="no-underline hover:underline whitespace-nowrap">
+
{{$repoUrl}}
+
</a>
</div>
</div>
-
{{ end }}
-
{{ else }}
-
<p class="px-6 dark:text-white">This user does not have any activity yet.</p>
{{ end }}
</div>
+
</details>
+
{{ end }}
{{ end }}
{{ define "profileCard" }}
+11 -5
appview/state/profile.go
···
for _, r := range collaboratingRepos {
didsToResolve = append(didsToResolve, r.Did)
}
-
for _, evt := range timeline {
-
if evt.Repo != nil {
-
if evt.Repo.Source != "" {
-
didsToResolve = append(didsToResolve, evt.Source.Did)
+
for _, byMonth := range timeline.ByMonth {
+
for _, pe := range byMonth.PullEvents.Items {
+
didsToResolve = append(didsToResolve, pe.Repo.Did)
+
}
+
for _, ie := range byMonth.IssueEvents.Items {
+
didsToResolve = append(didsToResolve, ie.Metadata.Repo.Did)
+
}
+
for _, re := range byMonth.RepoEvents {
+
didsToResolve = append(didsToResolve, re.Repo.Did)
+
if re.Source != nil {
+
didsToResolve = append(didsToResolve, re.Source.Did)
}
}
-
didsToResolve = append(didsToResolve, evt.Repo.Did)
}
resolvedIds := s.resolver.ResolveIdents(r.Context(), didsToResolve)
+1 -1
go.mod
···
github.com/sethvargo/go-envconfig v1.1.0
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e
github.com/yuin/goldmark v1.4.13
-
golang.org/x/crypto v0.36.0
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
)
···
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
+
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/time v0.5.0 // indirect