Skip to content

Commit 16cf7c8

Browse files
committed
feat(dashboards): multiple dashboards initial support
1 parent d340b2d commit 16cf7c8

File tree

4 files changed

+136
-81
lines changed

4 files changed

+136
-81
lines changed

config/utils.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ func (cfg IssuesSectionConfig) ToSectionConfig() SectionConfig {
4343
}
4444
}
4545

46+
func (cfg DashboardsConfig) ToSectionConfig() SectionConfig {
47+
return SectionConfig{
48+
Title: cfg.Title,
49+
}
50+
}
51+
4652
func MergeColumnConfigs(defaultCfg, sectionCfg ColumnConfig) ColumnConfig {
4753
colCfg := defaultCfg
4854
if sectionCfg.Width != nil {

ui/components/dashboard/dashboard.go

Lines changed: 102 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ import (
77
"github.com/charmbracelet/bubbles/key"
88
tea "github.com/charmbracelet/bubbletea"
99
"github.com/charmbracelet/lipgloss"
10-
"github.com/charmbracelet/log"
1110

1211
"github.com/dlvhdr/gh-dash/config"
1312
"github.com/dlvhdr/gh-dash/ui/common"
14-
"github.com/dlvhdr/gh-dash/ui/components/container"
13+
"github.com/dlvhdr/gh-dash/ui/components"
1514
"github.com/dlvhdr/gh-dash/ui/components/prssection"
1615
"github.com/dlvhdr/gh-dash/ui/components/section"
1716
"github.com/dlvhdr/gh-dash/ui/components/sectioncard"
@@ -21,25 +20,27 @@ import (
2120
)
2221

2322
type Model struct {
24-
ctx *context.ProgramContext
25-
containers []container.Model
26-
cards []*sectioncard.Model
27-
focusedCardId int
23+
ctx *context.ProgramContext
24+
boards []board
25+
focusedCardId int
26+
focusedBoardId int
27+
}
28+
29+
type board struct {
30+
cards []*sectioncard.Model
2831
}
2932

3033
func NewModel(ctx context.ProgramContext) Model {
31-
return Model{ctx: &ctx, cards: []*sectioncard.Model{}}
34+
return Model{ctx: &ctx, boards: []board{}}
3235
}
3336

3437
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
3538
var cmd tea.Cmd
3639
switch msg := msg.(type) {
3740
case tea.KeyMsg:
38-
if len(m.cards) == 0 {
39-
break
40-
}
4141

42-
currCard := m.cards[m.focusedCardId]
42+
board := m.boards[m.focusedBoardId]
43+
currCard := board.cards[m.focusedCardId]
4344

4445
switch {
4546

@@ -61,43 +62,23 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
6162

6263
case key.Matches(msg, keys.Keys.PrevCard):
6364
m.GoToPrevCard()
64-
}
65-
66-
case common.ConfigReadMsg:
67-
sections, fetchSectionsCmds := m.fetchAllDashboards()
68-
for i := 0; i < len(sections); i++ {
69-
section := sections[i]
70-
prsSection := prssection.NewModel(section.Id, m.ctx, config.PrsSectionConfig{
71-
Title: section.Config.Title,
72-
Filters: section.Config.Filters,
73-
Layout: config.PrsLayoutConfig{},
74-
}, time.Now(), true)
75-
prsSection.Table.SetHeaderHidden(true)
76-
prsSection.Table.SetFooterHidden(true)
77-
prsSection.Table.EmptyState = nil
78-
prsSection.Table.SetSeparatorHidden(true)
79-
prsSection.Table.IsActive = i == 0
80-
sectionStyle := lipgloss.NewStyle().Padding(0)
81-
prsSection.Style = &sectionStyle
82-
cellStyle := m.ctx.Styles.Table.CellStyle.Copy().Background(m.ctx.Styles.Card.Content.GetBackground())
83-
prsSection.Table.CellStyle = &cellStyle
8465

85-
card := sectioncard.NewModel(m.ctx)
86-
card.Title = section.Config.Title
87-
card.Subtitle = "(loading...)"
88-
card.Section = &prsSection
66+
case key.Matches(msg, keys.Keys.PrevSection):
67+
m.previousBoard()
8968

90-
card.UpdateProgramContext(m.ctx)
91-
m.cards = append(m.cards, &card)
92-
log.Debug("SectionDataFetchedMsg fetching", "title", section.Config.Title)
69+
case key.Matches(msg, keys.Keys.NextSection):
70+
m.nextBoard()
9371
}
9472

73+
case common.ConfigReadMsg:
74+
fetchSectionsCmds := m.fetchAllDashboards()
9575
cmd = fetchSectionsCmds
9676

9777
case section.SectionDataFetchedMsg:
98-
log.Debug("SectionDataFetchedMsg fetched", "title", m.cards[msg.Id].Title, "prs", len(msg.Prs))
78+
boardId := 0
79+
cards := m.boards[boardId].cards
9980
if msg.Type == string(config.PRsView) {
100-
m.cards[msg.Id].SetPrs(prssection.SectionPullRequestsFetchedMsg{
81+
cards[msg.Id].SetPrs(prssection.SectionPullRequestsFetchedMsg{
10182
Prs: msg.Prs,
10283
TotalCount: msg.TotalCount,
10384
PageInfo: msg.PageInfo,
@@ -108,16 +89,10 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
10889
}
10990

11091
func (m Model) View() string {
111-
elements := make([]string, len(m.cards))
112-
for i := 0; i < len(m.cards); i++ {
113-
log.Debug(
114-
"view",
115-
"getItem",
116-
m.cards[i].Section.Table.GetCurrItem(),
117-
"isActive",
118-
m.cards[i].Section.Table.IsActive,
119-
)
120-
elements[i] = m.cards[i].View()
92+
cards := m.boards[m.focusedBoardId].cards
93+
elements := make([]string, len(cards))
94+
for i := 0; i < len(cards); i++ {
95+
elements[i] = cards[i].View()
12196
}
12297
content := lipgloss.JoinVertical(lipgloss.Left, elements...)
12398
return lipgloss.PlaceVertical(
@@ -130,51 +105,103 @@ func (m Model) View() string {
130105
func (m *Model) UpdateProgramContext(ctx *context.ProgramContext) {
131106
m.ctx = ctx
132107

133-
for i := 0; i < len(m.cards); i++ {
134-
m.cards[i].UpdateProgramContext(ctx)
108+
for i := 0; i < len(m.boards); i++ {
109+
for j := 0; j < len(m.boards[i].cards); j++ {
110+
m.boards[i].cards[j].UpdateProgramContext(ctx)
111+
}
135112
}
136113
}
137114

138-
func (m *Model) fetchAllDashboards() ([]section.Model, tea.Cmd) {
115+
func (m *Model) fetchAllDashboards() tea.Cmd {
139116
var cmds []tea.Cmd
140-
var sections []section.Model
141-
142-
for i := 0; i < len(m.ctx.Config.Dashboards[0].Sections); i++ {
143-
log.Debug("[Dashboard] Creating task with id", "i")
144-
config := m.ctx.Config.Dashboards[0].Sections[i]
145-
sectionModel := section.Model{
146-
BaseModel: section.BaseModel{
147-
Id: i,
148-
Ctx: m.ctx,
149-
Type: "prs",
150-
Config: config,
151-
},
152-
}
153-
sections = append(sections, sectionModel)
154-
if strings.Contains(sectionModel.Config.Filters, "is:pr") {
155-
cmds = append(cmds, sectionModel.FetchSectionRows(nil)...)
117+
118+
for i := 0; i < len(m.ctx.Config.Dashboards); i++ {
119+
var cards []*sectioncard.Model
120+
for j := 0; j < len(m.ctx.Config.Dashboards[i].Sections); j++ {
121+
sectionConfig := m.ctx.Config.Dashboards[i].Sections[j]
122+
sectionModel := section.Model{
123+
BaseModel: section.BaseModel{
124+
Id: j,
125+
Ctx: m.ctx,
126+
Type: "prs",
127+
Config: sectionConfig,
128+
},
129+
}
130+
if strings.Contains(sectionModel.Config.Filters, "is:pr") {
131+
cmds = append(cmds, sectionModel.FetchSectionRows(nil)...)
132+
}
133+
134+
prsSection := prssection.NewModel(
135+
sectionModel.Id,
136+
m.ctx,
137+
config.PrsSectionConfig{
138+
Title: sectionModel.Config.Title,
139+
Filters: sectionModel.Config.Filters,
140+
Layout: config.PrsLayoutConfig{},
141+
},
142+
time.Now(),
143+
true,
144+
)
145+
prsSection.Table.SetHeaderHidden(true)
146+
prsSection.Table.SetFooterHidden(true)
147+
prsSection.Table.EmptyState = nil
148+
prsSection.Table.SetSeparatorHidden(true)
149+
prsSection.Table.IsActive = j == 0
150+
sectionStyle := lipgloss.NewStyle().Padding(0)
151+
prsSection.Style = &sectionStyle
152+
cellStyle := m.ctx.Styles.Table.CellStyle.Copy().
153+
Background(m.ctx.Styles.Card.Content.GetBackground())
154+
prsSection.Table.CellStyle = &cellStyle
155+
156+
card := sectioncard.NewModel(m.ctx)
157+
card.Title = sectionModel.Config.Title
158+
card.Subtitle = "(loading...)"
159+
card.Section = &prsSection
160+
161+
card.UpdateProgramContext(m.ctx)
162+
163+
cards = append(cards, &card)
156164
}
165+
m.boards = append(m.boards, board{
166+
cards: cards,
167+
})
157168
}
158169

159-
return sections, tea.Batch(cmds...)
170+
return tea.Batch(cmds...)
160171
}
161172

162173
func (m *Model) GoToNextCard() {
163-
currCard := m.cards[m.focusedCardId]
174+
cards := m.boards[m.focusedBoardId].cards
175+
currCard := cards[m.focusedCardId]
164176
currCard.Section.Unfocus()
165177

166-
m.focusedCardId = utils.Min(len(m.cards)-1, m.focusedCardId+1)
167-
nextCard := m.cards[m.focusedCardId]
178+
m.focusedCardId = utils.Min(len(cards)-1, m.focusedCardId+1)
179+
nextCard := cards[m.focusedCardId]
168180
nextCard.Section.Focus()
169181
nextCard.Section.FirstItem()
170182
}
171183

172184
func (m *Model) GoToPrevCard() {
173-
currCard := m.cards[m.focusedCardId]
185+
cards := m.boards[m.focusedBoardId].cards
186+
currCard := cards[m.focusedCardId]
174187
currCard.Section.Unfocus()
175188

176189
m.focusedCardId = utils.Max(0, m.focusedCardId-1)
177-
nextCard := m.cards[m.focusedCardId]
190+
nextCard := cards[m.focusedCardId]
178191
nextCard.Section.FirstItem()
179192
nextCard.Section.Focus()
180193
}
194+
195+
func (m *Model) previousBoard() {
196+
m.focusedBoardId = components.GetPrevCyclicItem(
197+
m.focusedBoardId,
198+
len(m.boards),
199+
)
200+
}
201+
202+
func (m *Model) nextBoard() {
203+
m.focusedBoardId = components.GetNextCyclicItem(
204+
m.focusedBoardId,
205+
len(m.boards),
206+
)
207+
}

ui/components/utils.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,26 @@ import (
55
"strings"
66

77
"github.com/charmbracelet/lipgloss"
8+
89
"github.com/dlvhdr/gh-dash/ui/context"
910
)
1011

11-
func GetIssueTextStyle(ctx *context.ProgramContext, state string) lipgloss.Style {
12+
func GetIssueTextStyle(
13+
ctx *context.ProgramContext,
14+
state string,
15+
) lipgloss.Style {
1216
if state == "OPEN" {
1317
return lipgloss.NewStyle().Foreground(ctx.Theme.PrimaryText)
1418
}
1519
return lipgloss.NewStyle().Foreground(ctx.Theme.FaintText)
1620
}
1721

18-
func RenderIssueTitle(ctx *context.ProgramContext, state string, title string, number int) string {
22+
func RenderIssueTitle(
23+
ctx *context.ProgramContext,
24+
state string,
25+
title string,
26+
number int,
27+
) string {
1928
prNumber := fmt.Sprintf("#%d", number)
2029
var prNumberFg lipgloss.AdaptiveColor
2130
if state != "OPEN" {
@@ -34,3 +43,16 @@ func RenderIssueTitle(ctx *context.ProgramContext, state string, title string, n
3443
res := fmt.Sprintf("%s %s", prNumber, rTitle)
3544
return res
3645
}
46+
47+
func GetPrevCyclicItem(currItem, totalItems int) int {
48+
prevItem := (currItem - 1) % totalItems
49+
if prevItem < 0 {
50+
prevItem += totalItems
51+
}
52+
53+
return prevItem
54+
}
55+
56+
func GetNextCyclicItem(currItem, totalItems int) int {
57+
return (currItem + 1) % totalItems
58+
}

ui/context/context.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"time"
55

66
tea "github.com/charmbracelet/bubbletea"
7+
78
"github.com/dlvhdr/gh-dash/config"
89
"github.com/dlvhdr/gh-dash/ui/theme"
910
)
@@ -45,10 +46,9 @@ type ProgramContext struct {
4546
func (ctx *ProgramContext) GetViewSectionsConfig() []config.SectionConfig {
4647
var configs []config.SectionConfig
4748
if ctx.View == config.DashboardsView {
48-
configs = append([]config.SectionConfig{{
49-
Title: "Dashboard",
50-
Filters: "",
51-
}})
49+
for _, cfg := range ctx.Config.Dashboards {
50+
configs = append(configs, cfg.ToSectionConfig())
51+
}
5252
} else if ctx.View == config.PRsView {
5353
for _, cfg := range ctx.Config.PRSections {
5454
configs = append(configs, cfg.ToSectionConfig())

0 commit comments

Comments
 (0)