Skip to content

Commit

Permalink
improving pull request list display
Browse files Browse the repository at this point in the history
  • Loading branch information
k1nho committed Sep 22, 2023
1 parent 8a5bde6 commit c6d334a
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 56 deletions.
25 changes: 23 additions & 2 deletions cmd/show/styles.go → cmd/show/constants.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package show

import (
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)

// WindowSize stores the size of the terminal
var WindowSize tea.WindowSizeMsg

// STYLES
// Keymaps
var OpenPR = key.NewBinding(key.WithKeys("O"), key.WithHelp("O", "open pr"))
var BackToDashboard = key.NewBinding(key.WithKeys("B"), key.WithHelp("B", "back"))
var ToggleHelpMenu = key.NewBinding(key.WithKeys("H"), key.WithHelp("H", "toggle help"))

// Viewport: The viewport of the tui (my:2, mx:40)
// STYLES
// Viewport: The viewport of the tui (my:2, mx:2)
var Viewport = lipgloss.NewStyle().Margin(1, 2)

// Container: container styling (width: 80, py: 0, px: 5)
Expand Down Expand Up @@ -40,3 +46,18 @@ var ActiveStyle = lipgloss.NewStyle().
var InactiveStyle = lipgloss.NewStyle().
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("#FFFFFF"))

// ItemStyle: style applied to items in a list.Model
var ItemStyle = lipgloss.NewStyle().PaddingLeft(4)

// SelectedItemStyle: style applied when the item is selected in a list.Model
var SelectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(Color)

// ListItemTitle: style for the list.Model title
var ListItemTitleStyle = lipgloss.NewStyle().MarginLeft(2)

// PaginationStyle: style for pagination of list.Model
var PaginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)

// HelpStyle: style for help menu
var HelpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
154 changes: 107 additions & 47 deletions cmd/show/contributors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,62 @@ import (
"context"
"errors"
"fmt"
"io"
"strings"
"sync"

"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/cli/browser"
client "github.com/open-sauced/go-api/client"
)

// prItem: type for pull request to satisfy the list.Item interface
type prItem client.DbPullRequest

func (i prItem) FilterValue() string { return i.Title }
func (i prItem) GetRepoName() string {
if i.FullName != nil {
return *i.FullName
}
return ""
}

type itemDelegate struct{}

func (d itemDelegate) Height() int { return 1 }
func (d itemDelegate) Spacing() int { return 1 }
func (d itemDelegate) Update(_ tea.Msg, _ *list.Model) tea.Cmd { return nil }
func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
i, ok := listItem.(prItem)
if !ok {
return
}

prTitle := i.Title
if len(prTitle) >= 60 {
prTitle = fmt.Sprintf("%s...", prTitle[:60])
}

str := fmt.Sprintf("#%d %s\n%s\n(%s)", i.Number, i.GetRepoName(), prTitle, i.State)

fn := ItemStyle.Render
if index == m.Index() {
fn = func(s ...string) string {
return SelectedItemStyle.Render("🍕 " + strings.Join(s, " "))
}
}

fmt.Fprint(w, fn(str))
}

// ContributorModel holds all the information related to a contributor
type ContributorModel struct {
username string
userInfo *client.DbUser
userPrs []client.DbPullRequest
prList list.Model
APIClient *client.APIClient
serverContext context.Context
}
Expand Down Expand Up @@ -45,6 +89,8 @@ func (m ContributorModel) Init() tea.Cmd { return nil }
func (m ContributorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
WindowSize = msg
case SelectMsg:
m.username = msg.contributorName
model, err := m.fetchUser()
Expand All @@ -54,12 +100,25 @@ func (m ContributorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return model, func() tea.Msg { return SuccessMsg{} }
case tea.KeyMsg:
switch msg.String() {
case "backspace":
case "B":
return m, func() tea.Msg { return BackMsg{} }
case "q", "esc", "ctrl+c", "ctrl+d":
case "H":
m.prList.SetShowHelp(!m.prList.ShowHelp())
return m, nil
case "O":
pr, ok := m.prList.SelectedItem().(prItem)
if ok {
err := browser.OpenURL(fmt.Sprintf("https://github.com/%s/pull/%d", pr.GetRepoName(), pr.Number))
if err != nil {
fmt.Println("could not open pull request in browser")
}
}
case "q", "ctrl+c", "ctrl+d":
return m, tea.Quit

}
}
m.prList, cmd = m.prList.Update(msg)
return m, cmd
}

Expand All @@ -77,24 +136,21 @@ func (m *ContributorModel) fetchUser() (tea.Model, error) {
wg.Add(1)
go func() {
defer wg.Done()
userInfo, err := m.fetchContributorInfo(m.username)
err := m.fetchContributorInfo(m.username)
if err != nil {
errChan <- err
return
}
m.userInfo = userInfo

}()

wg.Add(1)
go func() {
defer wg.Done()
userPRs, err := m.fetchContributorPRs(m.username)
err := m.fetchContributorPRs(m.username)
if err != nil {
errChan <- err
return
}
m.userPrs = userPRs
}()

wg.Wait()
Expand All @@ -111,36 +167,68 @@ func (m *ContributorModel) fetchUser() (tea.Model, error) {
}

// fetchContributorInfo: fetches the contributor info
func (m *ContributorModel) fetchContributorInfo(name string) (*client.DbUser, error) {
func (m *ContributorModel) fetchContributorInfo(name string) error {
resp, r, err := m.APIClient.UserServiceAPI.FindOneUserByUserame(m.serverContext, name).Execute()
if err != nil {
return nil, err
return err
}

if r.StatusCode != 200 {
return nil, fmt.Errorf("HTTP failed: %d", r.StatusCode)
return fmt.Errorf("HTTP failed: %d", r.StatusCode)
}

return resp, nil
m.userInfo = resp
return nil
}

// fetchContributorPRs: fetches the contributor pull requests
func (m *ContributorModel) fetchContributorPRs(name string) ([]client.DbPullRequest, error) {
resp, r, err := m.APIClient.UserServiceAPI.FindContributorPullRequests(m.serverContext, name).Execute()
// fetchContributorPRs: fetches the contributor pull requests and creates pull request list
func (m *ContributorModel) fetchContributorPRs(name string) error {
resp, r, err := m.APIClient.UserServiceAPI.FindContributorPullRequests(m.serverContext, name).Limit(10).Execute()
if err != nil {
return nil, err
return err
}

if r.StatusCode != 200 {
return nil, fmt.Errorf("HTTP failed: %d", r.StatusCode)
return fmt.Errorf("HTTP failed: %d", r.StatusCode)
}

// create contributor pull request list
var items []list.Item
for _, pr := range resp.Data {
items = append(items, prItem(pr))
}

return resp.Data, nil
l := list.New(items, itemDelegate{}, WindowSize.Width, 14)
l.Title = "✨ Latest Pull Requests"
l.Styles.Title = ListItemTitleStyle
l.Styles.HelpStyle = HelpStyle
l.SetShowStatusBar(false)
l.SetStatusBarItemName("pull request", "pull requests")
l.AdditionalShortHelpKeys = func() []key.Binding {
return []key.Binding{
OpenPR,
BackToDashboard,
ToggleHelpMenu,
}
}

m.prList = l
return nil
}

// drawContributorView: view of the contributor model
func (m *ContributorModel) drawContributorView() string {
return Viewport.Copy().Render(lipgloss.JoinVertical(lipgloss.Center, m.drawContributorInfo(), m.drawPullRequests()))
contributorInfo := m.drawContributorInfo()

contributorView := lipgloss.JoinVertical(lipgloss.Left, lipgloss.NewStyle().PaddingLeft(2).Render(contributorInfo),
WidgetContainer.Render(m.prList.View()))

_, h := lipgloss.Size(contributorView)
if WindowSize.Height < h {
contributorView = lipgloss.JoinHorizontal(lipgloss.Center, contributorInfo, m.prList.View())
}

return contributorView
}

// drawContributorInfo: view of the contributor info (open issues, pr velocity, pr count, maintainer)
Expand All @@ -158,31 +246,3 @@ func (m *ContributorModel) drawContributorInfo() string {

return SquareBorder.Render(contributorView)
}

// drawPullRequests: view of the contributor pull requests (draws the last 5 pull requests)
func (m *ContributorModel) drawPullRequests() string {
if len(m.userPrs) == 0 {
return ""
}

pullRequests := []string{}
var numberOfPrs int

if len(m.userPrs) > 5 {
numberOfPrs = 5
} else {
numberOfPrs = len(m.userPrs)
}

for i := 0; i < numberOfPrs; i++ {
prContainer := TextContainer.Render(fmt.Sprintf("#%d %s\n%s\n(%s)", m.userPrs[i].Number, m.userPrs[i].GetFullName(),
m.userPrs[i].Title, m.userPrs[i].State))
pullRequests = append(pullRequests, prContainer)
}

formattedPrs := lipgloss.JoinVertical(lipgloss.Left, pullRequests...)
title := lipgloss.NewStyle().AlignHorizontal(lipgloss.Center).Render("✨ Latest Pull Requests")

pullRequestView := lipgloss.JoinVertical(lipgloss.Center, title, formattedPrs)
return WidgetContainer.Render(pullRequestView)
}
3 changes: 2 additions & 1 deletion cmd/show/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ func (m *DashboardModel) drawDashboardView() string {
_, h := lipgloss.Size(mainView)
if WindowSize.Height < h {
contentLeft := lipgloss.JoinVertical(lipgloss.Center, titleView, repoInfoView)
mainView = lipgloss.JoinHorizontal(lipgloss.Center, contentLeft, metricsView)
contentRight := lipgloss.JoinVertical(lipgloss.Center, metricsView, m.contributorErr)
mainView = lipgloss.JoinHorizontal(lipgloss.Center, contentLeft, contentRight)
}
frame := Viewport.Render(mainView)
return frame
Expand Down
10 changes: 4 additions & 6 deletions cmd/show/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,14 @@ func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
var cmds []tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
WindowSize.Width = msg.Width
WindowSize.Height = msg.Height
case BackMsg:
m.state = dashboardView
case SuccessMsg:
m.state = contributorView
case SelectMsg:
newContributor, newCmd := m.contributor.Update(msg)
m.contributor = newContributor
cmds = append(cmds, newCmd)
case SuccessMsg:
m.state = contributorView
}

switch m.state {
Expand All @@ -70,7 +67,8 @@ func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.dashboard = newDashboard
cmd = newCmd
case contributorView:
_, newCmd := m.contributor.Update(msg)
newContributor, newCmd := m.contributor.Update(msg)
m.contributor = newContributor
cmd = newCmd
}
cmds = append(cmds, cmd)
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
)

require (
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/google/uuid v1.3.0 // indirect
Expand All @@ -29,6 +30,7 @@ require (
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.3.8 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
Expand All @@ -17,6 +19,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
Expand Down Expand Up @@ -44,6 +47,8 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
Expand Down

0 comments on commit c6d334a

Please sign in to comment.