From 6ea25d1b67ac67f9f337b9adc224da7d2ef4b21c Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Sun, 20 Jul 2025 19:23:06 +0100 Subject: [PATCH] appview: add language, open issues and open PR stats to repo cards Signed-off-by: oppiliappan --- appview/db/repos.go | 112 +++++++++++------- appview/pages/funcmap.go | 2 + .../templates/user/fragments/repoCard.html | 57 +++++++++ appview/pages/templates/user/profile.html | 46 +------ appview/pages/templates/user/repos.html | 23 +--- appview/repo/repo.go | 16 ++- appview/state/knotstream.go | 2 +- appview/state/profile.go | 11 +- 8 files changed, 153 insertions(+), 116 deletions(-) create mode 100644 appview/pages/templates/user/fragments/repoCard.html diff --git a/appview/db/repos.go b/appview/db/repos.go index c28f206..5b7826f 100644 --- a/appview/db/repos.go +++ b/appview/db/repos.go @@ -3,6 +3,8 @@ package db import ( "database/sql" "fmt" + "log" + "slices" "strings" "time" @@ -72,7 +74,7 @@ func GetAllRepos(e Execer, limit int) ([]Repo, error) { } func GetRepos(e Execer, filters ...filter) ([]Repo, error) { - repoMap := make(map[syntax.ATURI]Repo) + repoMap := make(map[syntax.ATURI]*Repo) var conditions []string var args []any @@ -139,7 +141,8 @@ func GetRepos(e Execer, filters ...filter) ([]Repo, error) { repo.Spindle = spindle.String } - repoMap[repo.RepoAt()] = repo + repo.RepoStats = &RepoStats{} + repoMap[repo.RepoAt()] = &repo } if err = rows.Err(); err != nil { @@ -148,8 +151,49 @@ func GetRepos(e Execer, filters ...filter) ([]Repo, error) { inClause := strings.TrimSuffix(strings.Repeat("?, ", len(repoMap)), ", ") args = make([]any, len(repoMap)) + + i := 0 for _, r := range repoMap { - args = append(args, r.RepoAt()) + args[i] = r.RepoAt() + i++ + } + + languageQuery := fmt.Sprintf( + ` + select + repo_at, language + from + repo_languages r1 + where + repo_at IN (%s) + and is_default_ref = 1 + and id = ( + select id + from repo_languages r2 + where r2.repo_at = r1.repo_at + and r2.is_default_ref = 1 + order by bytes desc + limit 1 + ); + `, + inClause, + ) + rows, err = e.Query(languageQuery, args...) + if err != nil { + return nil, fmt.Errorf("failed to execute lang query: %w ", err) + } + for rows.Next() { + var repoat, lang string + if err := rows.Scan(&repoat, &lang); err != nil { + log.Println("err", "err", err) + continue + } + if r, ok := repoMap[syntax.ATURI(repoat)]; ok { + r.RepoStats.Language = lang + } + } + if err = rows.Err(); err != nil { + return nil, fmt.Errorf("failed to execute lang query: %w ", err) } starCountQuery := fmt.Sprintf( @@ -168,6 +212,7 @@ func GetRepos(e Execer, filters ...filter) ([]Repo, error) { var repoat string var count int if err := rows.Scan(&repoat, &count); err != nil { + log.Println("err", "err", err) continue } if r, ok := repoMap[syntax.ATURI(repoat)]; ok { @@ -196,6 +241,7 @@ func GetRepos(e Execer, filters ...filter) ([]Repo, error) { var repoat string var open, closed int if err := rows.Scan(&repoat, &open, &closed); err != nil { + log.Println("err", "err", err) continue } if r, ok := repoMap[syntax.ATURI(repoat)]; ok { @@ -236,6 +282,7 @@ func GetRepos(e Execer, filters ...filter) ([]Repo, error) { var repoat string var open, merged, closed, deleted int if err := rows.Scan(&repoat, &open, &merged, &closed, &deleted); err != nil { + log.Println("err", "err", err) continue } if r, ok := repoMap[syntax.ATURI(repoat)]; ok { @@ -251,9 +298,16 @@ func GetRepos(e Execer, filters ...filter) ([]Repo, error) { var repos []Repo for _, r := range repoMap { - repos = append(repos, r) + repos = append(repos, *r) } + slices.SortFunc(repos, func(a, b Repo) int { + if a.Created.After(b.Created) { + return 1 + } + return -1 + }) + return repos, nil } @@ -509,63 +563,33 @@ func UpdateSpindle(e Execer, repoAt, spindle string) error { } func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) { - var repos []Repo - - rows, err := e.Query( - `select - r.did, r.name, r.knot, r.rkey, r.description, r.created, count(s.id) as star_count - from - repos r - join - collaborators c on r.id = c.repo - left join - stars s on r.at_uri = s.repo_at - where - c.did = ? - group by - r.id;`, collaborator) + rows, err := e.Query(`select repo from collaborators where did = ?`, collaborator) if err != nil { return nil, err } defer rows.Close() + var repoIds []int for rows.Next() { - var repo Repo - var repoStats RepoStats - var createdAt string - var nullableDescription sql.NullString - - err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repoStats.StarCount) + var id int + err := rows.Scan(&id) if err != nil { return nil, err } - - if nullableDescription.Valid { - repo.Description = nullableDescription.String - } else { - repo.Description = "" - } - - createdAtTime, err := time.Parse(time.RFC3339, createdAt) - if err != nil { - repo.Created = time.Now() - } else { - repo.Created = createdAtTime - } - - repo.RepoStats = &repoStats - - repos = append(repos, repo) + repoIds = append(repoIds, id) } - if err := rows.Err(); err != nil { return nil, err } + if repoIds == nil { + return nil, nil + } - return repos, nil + return GetRepos(e, FilterIn("id", repoIds)) } type RepoStats struct { + Language string StarCount int IssueCount IssueCount PullCount PullCount diff --git a/appview/pages/funcmap.go b/appview/pages/funcmap.go index 1dccb18..b061b92 100644 --- a/appview/pages/funcmap.go +++ b/appview/pages/funcmap.go @@ -17,6 +17,7 @@ import ( "time" "github.com/dustin/go-humanize" + "github.com/go-enry/go-enry/v2" "github.com/microcosm-cc/bluemonday" "tangled.sh/tangled.sh/core/appview/filetree" "tangled.sh/tangled.sh/core/appview/pages/markup" @@ -241,6 +242,7 @@ func (p *Pages) funcMap() template.FuncMap { }, "tinyAvatar": p.tinyAvatar, + "langColor": enry.GetColor, } } diff --git a/appview/pages/templates/user/fragments/repoCard.html b/appview/pages/templates/user/fragments/repoCard.html new file mode 100644 index 0000000..d64c00f --- /dev/null +++ b/appview/pages/templates/user/fragments/repoCard.html @@ -0,0 +1,57 @@ +{{ define "user/fragments/repoCard" }} + {{ $root := index . 0 }} + {{ $repo := index . 1 }} + {{ $fullName := index . 2 }} + + {{ with $repo }} +
+
+ {{- if $fullName -}} + {{ index $root.DidHandleMap .Did }}/{{ .Name }} + {{- else -}} + {{ .Name }} + {{- end -}} +
+ {{ with .Description }} +
+ {{ . }} +
+ {{ end }} + + {{ if .RepoStats }} + {{ block "repoStats" .RepoStats }} {{ end }} + {{ end }} +
+ {{ end }} +{{ end }} + +{{ define "repoStats" }} +
+ {{ with .Language }} +
+
+ {{ . }} +
+ {{ end }} + {{ with .StarCount }} +
+ {{ i "star" "w-3 h-3 fill-current" }} + {{ . }} +
+ {{ end }} + {{ with .IssueCount.Open }} +
+ {{ i "circle-dot" "w-3 h-3" }} + {{ . }} +
+ {{ end }} + {{ with .PullCount.Open }} +
+ {{ i "git-pull-request-arrow" "w-3 h-3" }} + {{ . }} +
+ {{ end }} +
+{{ end }} + + diff --git a/appview/pages/templates/user/profile.html b/appview/pages/templates/user/profile.html index bb4a70f..fdf470c 100644 --- a/appview/pages/templates/user/profile.html +++ b/appview/pages/templates/user/profile.html @@ -260,28 +260,7 @@
{{ range .Repos }} -
- - {{ if .Description }} -
- {{ .Description }} -
- {{ end }} -
- {{ if .RepoStats.StarCount }} -
- {{ i "star" "w-3 h-3 fill-current" }} - {{ .RepoStats.StarCount }} -
- {{ end }} -
-
+ {{ template "user/fragments/repoCard" (list $ . false) }} {{ else }}

This user does not have any repos yet.

{{ end }} @@ -295,28 +274,7 @@

COLLABORATING ON

{{ range .CollaboratingRepos }} -
- - {{ if .Description }} -
- {{ .Description }} -
- {{ end }} -
- {{ if .RepoStats.StarCount }} -
- {{ i "star" "w-3 h-3 fill-current" }} - {{ .RepoStats.StarCount }} -
- {{ end }} -
-
+ {{ template "user/fragments/repoCard" (list $ . true) }} {{ else }}

This user is not collaborating.

{{ end }} diff --git a/appview/pages/templates/user/repos.html b/appview/pages/templates/user/repos.html index 494799f..789d6ad 100644 --- a/appview/pages/templates/user/repos.html +++ b/appview/pages/templates/user/repos.html @@ -22,28 +22,7 @@

ALL REPOSITORIES

{{ range .Repos }} -
- - {{ if .Description }} -
- {{ .Description }} -
- {{ end }} -
- {{ if .RepoStats.StarCount }} -
- {{ i "star" "w-3 h-3 fill-current" }} - {{ .RepoStats.StarCount }} -
- {{ end }} -
-
+ {{ template "user/fragments/repoCard" (list $ . false) }} {{ else }}

This user does not have any repos yet.

{{ end }} diff --git a/appview/repo/repo.go b/appview/repo/repo.go index 86067e5..31436b2 100644 --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -106,14 +106,14 @@ func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) { return } - result, err := us.Tags(f.OwnerDid(), f.RepoName) + tagResult, err := us.Tags(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) return } tagMap := make(map[string][]string) - for _, tag := range result.Tags { + for _, tag := range tagResult.Tags { hash := tag.Hash if tag.Tag != nil { hash = tag.Tag.Target.String() @@ -121,6 +121,17 @@ func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) { tagMap[hash] = append(tagMap[hash], tag.Name) } + branchResult, err := us.Branches(f.OwnerDid(), f.RepoName) + if err != nil { + log.Println("failed to reach knotserver", err) + return + } + + for _, branch := range branchResult.Branches { + hash := branch.Hash + tagMap[hash] = append(tagMap[hash], branch.Name) + } + user := rp.oauth.GetUser(r) emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(repolog.Commits), true) @@ -154,7 +165,6 @@ func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) { VerifiedCommits: vc, Pipelines: pipelines, }) - return } func (rp *Repo) RepoDescriptionEdit(w http.ResponseWriter, r *http.Request) { diff --git a/appview/state/knotstream.go b/appview/state/knotstream.go index 4c7255d..536ccb9 100644 --- a/appview/state/knotstream.go +++ b/appview/state/knotstream.go @@ -130,7 +130,7 @@ func populatePunchcard(d *db.DB, record tangled.GitRefUpdate) error { } func updateRepoLanguages(d *db.DB, record tangled.GitRefUpdate) error { - if record.Meta == nil && record.Meta.LangBreakdown == nil { + if record.Meta == nil || record.Meta.LangBreakdown == nil || record.Meta.LangBreakdown.Inputs == nil { return fmt.Errorf("empty language data for repo: %s/%s", record.RepoDid, record.RepoName) } diff --git a/appview/state/profile.go b/appview/state/profile.go index e4731c7..66f28b1 100644 --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -50,7 +50,10 @@ func (s *State) profilePage(w http.ResponseWriter, r *http.Request) { log.Printf("getting profile data for %s: %s", ident.DID.String(), err) } - repos, err := db.GetAllReposByDid(s.db, ident.DID.String()) + repos, err := db.GetRepos( + s.db, + db.FilterEq("did", ident.DID.String()), + ) if err != nil { log.Printf("getting repos for %s: %s", ident.DID.String(), err) } @@ -171,7 +174,10 @@ func (s *State) reposPage(w http.ResponseWriter, r *http.Request) { log.Printf("getting profile data for %s: %s", ident.DID.String(), err) } - repos, err := db.GetAllReposByDid(s.db, ident.DID.String()) + repos, err := db.GetRepos( + s.db, + db.FilterEq("did", ident.DID.String()), + ) if err != nil { log.Printf("getting repos for %s: %s", ident.DID.String(), err) } @@ -192,6 +198,7 @@ func (s *State) reposPage(w http.ResponseWriter, r *http.Request) { s.pages.ReposPage(w, pages.ReposPageParams{ LoggedInUser: loggedInUser, Repos: repos, + DidHandleMap: map[string]string{ident.DID.String(): ident.Handle.String()}, Card: pages.ProfileCard{ UserDid: ident.DID.String(), UserHandle: ident.Handle.String(), -- knotmirror 0.0.1