Files
GitManager/internal/repos/detail.go
T
TBNilles a192a05aaa Add repo-detail panel and /api/repo endpoint
New <repo-detail> component listens for repo:select and shows a repo's remotes, local branches (current + upstream), and recent commits. Backed by GET /api/repo (restricted to indexed repos) and read-only git readers LocalBranches/RecentCommits/RemoteDetails via repos.BuildDetail. <repo-list> highlights the selection; page docks the two panels left/right.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 16:43:01 -04:00

57 lines
1.5 KiB
Go

package repos
import (
"context"
"time"
"gitmanager/internal/git"
)
// Detail is the enriched view of a single repository shown in the detail panel.
// It embeds the cached State and adds data fetched on demand via the git
// boundary (all read-only — AGENT.md §1.3).
type Detail struct {
State
Branches []git.Branch `json:"branches"`
Commits []git.Commit `json:"commits"`
RemoteDetails []git.Remote `json:"remoteDetails"`
}
// Get returns the cached State for a repo path, or false if it is not indexed.
func (i *Index) Get(path string) (State, bool) {
i.mu.RLock()
defer i.mu.RUnlock()
s, ok := i.byKey[path]
return s, ok
}
// BuildDetail enriches a cached State with branches, recent commits, and remote
// URLs. Errors on the enriching calls are non-fatal: whatever succeeds is
// returned, and the partial failure is recorded on Detail.Error.
func BuildDetail(ctx context.Context, g *git.CLI, base State) Detail {
ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
defer cancel()
d := Detail{State: base}
if branches, err := g.LocalBranches(ctx, base.Path); err == nil {
d.Branches = branches
} else {
d.Error = err.Error()
}
if commits, err := g.RecentCommits(ctx, base.Path, 20); err == nil {
d.Commits = commits
} else if d.Error == "" {
d.Error = err.Error()
}
if remotes, err := g.RemoteDetails(ctx, base.Path); err == nil {
d.RemoteDetails = remotes
} else if d.Error == "" {
d.Error = err.Error()
}
return d
}