Skip to content

Commit

Permalink
Help (#31)
Browse files Browse the repository at this point in the history
* Add helps
  • Loading branch information
adam7 authored Mar 21, 2023
1 parent 4e51308 commit 8c74d73
Show file tree
Hide file tree
Showing 13 changed files with 438 additions and 171 deletions.
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import (
"os"

"hub-bub/models"

tea "github.com/charmbracelet/bubbletea"
)

func main() {
models.MainModel = []tea.Model{&models.UserModel{}, &models.OrganisationModel{}}
models.MainModel = []tea.Model{&models.UserModel{}, &models.OrgModel{}}

p := tea.NewProgram(models.MainModel[models.UserModelName])
if _, err := p.Run(); err != nil {
Expand Down
69 changes: 69 additions & 0 deletions models/orgKeyMap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package models

import "github.com/charmbracelet/bubbles/key"

// keyMap defines a set of keybindings. To work for help it must satisfy
// key.Map. It could also very easily be a map[string]key.Binding.
type orgKeyMap struct {
Up key.Binding
Down key.Binding
Left key.Binding
Right key.Binding
Enter key.Binding
Esc key.Binding
Help key.Binding
Quit key.Binding
}

// ShortHelp returns keybindings to be shown in the mini help view. It's part
// of the key.Map interface.
func (k orgKeyMap) ShortHelp() []key.Binding {
k.Help.SetEnabled(true)
return []key.Binding{k.Up, k.Down, k.Enter, k.Esc, k.Quit}
}

// FullHelp returns keybindings for the expanded help view. It's part of the
// key.Map interface.
func (k orgKeyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{k.Up, k.Down, k.Left, k.Right}, // first column
{k.Enter, k.Esc, k.Help, k.Quit}, // second column
}
}

func NewKeyMap() orgKeyMap {
return orgKeyMap{
Up: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("↑/k", "up"),
),
Down: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("↓/j", "down"),
),
Left: key.NewBinding(
key.WithKeys("left", "h"),
key.WithHelp("←/h", "move left"),
),
Right: key.NewBinding(
key.WithKeys("right", "l"),
key.WithHelp("→/l", "move right"),
),
Enter: key.NewBinding(
key.WithKeys("enter"),
key.WithHelp("enter", "select"),
),
Esc: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "back"),
),
Help: key.NewBinding(
key.WithKeys("?"),
key.WithHelp("?", "toggle help"),
),
Quit: key.NewBinding(
key.WithKeys("q"),
key.WithHelp("q", "quit"),
),
}
}
69 changes: 38 additions & 31 deletions models/organisationModel.go → models/orgModel.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,63 @@ import (

"hub-bub/messages"
"hub-bub/structs"

"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/cli/go-gh"
graphql "github.com/cli/shurcooL-graphql"
)

type OrganisationModel struct {
type OrgModel struct {
Title string
Url string
RepoQuery structs.OrganizationQuery

repoList list.Model
repoModel RepositoryModel
repoModel RepoModel
help help.Model
keys orgKeyMap

loaded bool
width int
height int
tabsHaveFocus bool
}

func (m *OrganisationModel) panelWidth() int {
return m.width / 2
func NewOrgModel(title string, width, height int) OrgModel {
return OrgModel{
Title: title,
width: width,
height: height,
help: help.New(),
keys: NewKeyMap(),
repoModel: NewRepoModel(width/2, height),
repoList: list.New([]list.Item{}, list.NewDefaultDelegate(), width/2, height),
}
}

func (m *OrgModel) helpView() string {
if m.tabsHaveFocus {
return m.repoModel.help.View(m.repoModel.keys)
}

return m.help.View(m.keys)
}

func (m *OrganisationModel) getSelectedRepo() structs.RepositoryQuery {
func (m *OrgModel) getSelectedRepo() structs.RepositoryQuery {
return m.RepoQuery.Organization.Repositories.Edges[m.repoList.Index()].Node
}

func (m *OrganisationModel) init(width, height int) {
m.width = width
m.height = height
m.repoModel.width = m.panelWidth()
m.repoModel.height = m.height
func (m *OrgModel) init(width, height int) {
m.loaded = true

m.repoList = list.New(
[]list.Item{},
list.NewDefaultDelegate(),
m.panelWidth(),
m.height,
)

m.repoModel = NewRepositoryModel(m.panelWidth(), m.height)
}

func (m OrganisationModel) Init() tea.Cmd {
func (m OrgModel) Init() tea.Cmd {
return nil
}

func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m OrgModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
// var cmds []tea.Cmd

Expand All @@ -70,12 +76,11 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case messages.RepoListMsg:
m.repoList = buildRepoListModel(msg.OrganizationQuery, m.width, m.height)
m.RepoQuery = msg.OrganizationQuery
m.repoModel.SelectRepo(m.getSelectedRepo(), m.panelWidth(), m.height)
m.repoModel.SelectRepo(m.getSelectedRepo(), half(m.width), m.height)
return m, nil

case tea.KeyMsg:
if m.tabsHaveFocus {
// Pass messages to repository model
switch msg.Type {
case tea.KeyEsc:
m.tabsHaveFocus = false
Expand All @@ -91,10 +96,10 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.Type {
case tea.KeyDown, tea.KeyUp:
m.repoList, cmd = m.repoList.Update(msg)
m.repoModel.SelectRepo(m.getSelectedRepo(), m.panelWidth(), m.height)
m.repoModel.SelectRepo(m.getSelectedRepo(), half(m.width), m.height)
case tea.KeyEnter:
m.tabsHaveFocus = true
m.repoModel.SelectRepo(m.getSelectedRepo(), m.panelWidth(), m.height)
m.repoModel.SelectRepo(m.getSelectedRepo(), half(m.width), m.height)
case tea.KeyEsc:
return MainModel[UserModelName], nil
}
Expand All @@ -108,16 +113,18 @@ func (m OrganisationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, cmd
}

func (m OrganisationModel) View() string {
var repoList = appStyle.Width(m.panelWidth() - 4).Render(m.repoList.View())
var settings = appStyle.Width(m.panelWidth()).Render(m.repoModel.View())
func (m OrgModel) View() string {
var repoList = appStyle.Width(half(m.width)).Render(m.repoList.View())
var settings = appStyle.Width(half(m.width)).Render(m.repoModel.View())
help := m.helpView()
var rightPanel = lipgloss.JoinVertical(lipgloss.Center, settings, help)

var views = []string{repoList, settings}
var views = []string{repoList, rightPanel}

return lipgloss.JoinHorizontal(lipgloss.Top, views...)
}

func (m OrganisationModel) GetRepositories() tea.Msg {
func (m OrgModel) GetRepositories() tea.Msg {
client, err := gh.GQLClient(nil)
if err != nil {
return messages.AuthenticationErrorMsg{Err: err}
Expand Down
66 changes: 66 additions & 0 deletions models/orgModel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package models

import (
"reflect"
"testing"

tea "github.com/charmbracelet/bubbletea"
)

func TestOrgModel_Update(t *testing.T) {
type args struct {
msg tea.Msg
}
tests := []struct {
name string
m OrgModel
args args
wantModel tea.Model
wantCmd tea.Cmd
}{
// TODO: Add more test cases.
{"Quit KeyMsg", OrgModel{}, args{tea.KeyMsg{Type: tea.KeyCtrlC}}, OrgModel{}, tea.Quit},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotModel, gotCmd := tt.m.Update(tt.args.msg)
if !reflect.DeepEqual(gotModel, tt.wantModel) {
t.Errorf("OrganisationModel.Update() gotModel = %v, want %v", gotModel, tt.wantModel)
}
if reflect.ValueOf(gotCmd) != reflect.ValueOf(tt.wantCmd) {
t.Errorf("OrganisationModel.Update() gotCmd = %v, want %v", gotCmd, tt.wantCmd)
}
})
}
}

func TestOrgModel_NewOrgModel(t *testing.T) {
type args struct {
title string
width int
height int
}
tests := []struct {
name string
args args
}{
{name: "Test NewOrgModel", args: args{title: "hub-bub", width: 1024, height: 768}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NewOrgModel(tt.args.title, tt.args.width, tt.args.height)
if got.Title != tt.args.title {
t.Errorf("NewOrgModel title got = %v, want %v", got.Title, tt.args.title)
}
if got.width != tt.args.width {
t.Errorf("NewOrgModel width got = %v, want %v", got.width, tt.args.width)
}
if got.height != tt.args.height {
t.Errorf("NewOrgModel height got = %v, want %v", got.height, tt.args.height)
}
if got.keys.Enter.Enabled() != true {
t.Errorf("NewOrgModel keys.Enter got = %v, want %v", got.keys.Enter.Enabled(), true)
}
})
}
}
35 changes: 0 additions & 35 deletions models/organisationModel_test.go

This file was deleted.

63 changes: 63 additions & 0 deletions models/repoKeyMap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package models

import "github.com/charmbracelet/bubbles/key"

// keyMap defines a set of keybindings. To work for help it must satisfy
// key.Map. It could also very easily be a map[string]key.Binding.
type repoKeyMap struct {
Up key.Binding
Down key.Binding
Left key.Binding
Right key.Binding
Filter key.Binding
Esc key.Binding
Quit key.Binding
}

// ShortHelp returns keybindings to be shown in the mini help view. It's part
// of the key.Map interface.
func (k repoKeyMap) ShortHelp() []key.Binding {
return []key.Binding{k.Left, k.Right, k.Esc, k.Quit}
}

// FullHelp returns keybindings for the expanded help view. It's part of the
// key.Map interface.
func (k repoKeyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{k.Up, k.Down, k.Left, k.Right}, // first column
{k.Filter, k.Esc, k.Quit}, // second column
}
}

func NewRepoKeyMap() repoKeyMap {
return repoKeyMap{
Up: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("↑/k", "up"),
),
Down: key.NewBinding(
key.WithKeys("down", "j"),
key.WithHelp("↓/j", "down"),
),
Left: key.NewBinding(
key.WithKeys("left", "h"),
key.WithHelp("←/h", "prev tab"),
),
Right: key.NewBinding(
key.WithKeys("right", "l"),
key.WithHelp("→/l", "next tab"),
),
Filter: key.NewBinding(
key.WithKeys("/"),
key.WithHelp("/", "filter"),
),
Esc: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "back"),
),
Quit: key.NewBinding(
key.WithKeys("q"),
key.WithHelp("q", "quit"),
),
}
}
Loading

0 comments on commit 8c74d73

Please sign in to comment.