Skip to content

Commit a26e740

Browse files
committed
Add main application file for GitLab Runner TUI and update .gitignore to specify binary file.
1 parent e18f90b commit a26e740

File tree

2 files changed

+182
-2
lines changed

2 files changed

+182
-2
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
# Go workspace file
1818
go.work
1919

20-
# Binary
20+
# Binary (only the executable file, not directories)
2121
/gitlab-runner-tui
22-
gitlab-runner-tui
2322

2423
# Build directories
2524
/build/

cmd/gitlab-runner-tui/main.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"log"
7+
"os"
8+
9+
tea "github.com/charmbracelet/bubbletea"
10+
"github.com/charmbracelet/lipgloss"
11+
"github.com/larkin/gitlab-runner-tui/pkg/runner"
12+
"github.com/larkin/gitlab-runner-tui/pkg/ui"
13+
)
14+
15+
type model struct {
16+
tabs []string
17+
activeTab int
18+
runnersView *ui.RunnersView
19+
logsView *ui.LogsView
20+
configView *ui.ConfigView
21+
systemView *ui.SystemView
22+
width int
23+
height int
24+
quitting bool
25+
}
26+
27+
func initialModel(configPath string) model {
28+
service := runner.NewService(configPath)
29+
30+
return model{
31+
tabs: []string{"Runners", "Logs", "Config", "System"},
32+
activeTab: 0,
33+
runnersView: ui.NewRunnersView(service),
34+
logsView: ui.NewLogsView(service),
35+
configView: ui.NewConfigView(configPath),
36+
systemView: ui.NewSystemView(service),
37+
}
38+
}
39+
40+
func (m model) Init() tea.Cmd {
41+
return tea.Batch(
42+
m.runnersView.Init(),
43+
m.logsView.Init(),
44+
m.configView.Init(),
45+
m.systemView.Init(),
46+
)
47+
}
48+
49+
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
50+
var cmds []tea.Cmd
51+
52+
switch msg := msg.(type) {
53+
case tea.WindowSizeMsg:
54+
m.width = msg.Width
55+
m.height = msg.Height
56+
57+
m.runnersView.Update(msg)
58+
m.logsView.Update(msg)
59+
m.configView.Update(msg)
60+
m.systemView.Update(msg)
61+
62+
return m, nil
63+
64+
case tea.KeyMsg:
65+
switch msg.String() {
66+
case "ctrl+c", "q":
67+
if m.activeTab == 1 {
68+
m.activeTab = 0
69+
return m, nil
70+
}
71+
m.quitting = true
72+
return m, tea.Quit
73+
74+
case "tab":
75+
m.activeTab = (m.activeTab + 1) % len(m.tabs)
76+
return m, nil
77+
78+
case "shift+tab":
79+
m.activeTab = (m.activeTab - 1 + len(m.tabs)) % len(m.tabs)
80+
return m, nil
81+
82+
case "1", "2", "3", "4":
83+
if idx := int(msg.String()[0] - '1'); idx < len(m.tabs) {
84+
m.activeTab = idx
85+
}
86+
return m, nil
87+
88+
case "enter":
89+
if m.activeTab == 0 {
90+
if runner := m.runnersView.GetSelectedRunner(); runner != nil {
91+
m.logsView.SetRunner(runner.Name)
92+
m.activeTab = 1
93+
}
94+
}
95+
}
96+
}
97+
98+
switch m.activeTab {
99+
case 0:
100+
updatedView, cmd := m.runnersView.Update(msg)
101+
m.runnersView = updatedView.(*ui.RunnersView)
102+
cmds = append(cmds, cmd)
103+
case 1:
104+
updatedView, cmd := m.logsView.Update(msg)
105+
m.logsView = updatedView.(*ui.LogsView)
106+
cmds = append(cmds, cmd)
107+
case 2:
108+
updatedView, cmd := m.configView.Update(msg)
109+
m.configView = updatedView.(*ui.ConfigView)
110+
cmds = append(cmds, cmd)
111+
case 3:
112+
updatedView, cmd := m.systemView.Update(msg)
113+
m.systemView = updatedView.(*ui.SystemView)
114+
cmds = append(cmds, cmd)
115+
}
116+
117+
return m, tea.Batch(cmds...)
118+
}
119+
120+
func (m model) View() string {
121+
if m.quitting {
122+
return ""
123+
}
124+
125+
tabBar := m.renderTabBar()
126+
127+
var content string
128+
switch m.activeTab {
129+
case 0:
130+
content = m.runnersView.View()
131+
case 1:
132+
content = m.logsView.View()
133+
case 2:
134+
content = m.configView.View()
135+
case 3:
136+
content = m.systemView.View()
137+
}
138+
139+
return lipgloss.JoinVertical(
140+
lipgloss.Left,
141+
tabBar,
142+
content,
143+
)
144+
}
145+
146+
func (m model) renderTabBar() string {
147+
var tabs []string
148+
149+
for i, tab := range m.tabs {
150+
style := ui.TabStyle
151+
if i == m.activeTab {
152+
style = ui.ActiveTabStyle
153+
}
154+
tabs = append(tabs, style.Render(fmt.Sprintf("%d. %s", i+1, tab)))
155+
}
156+
157+
return lipgloss.JoinHorizontal(lipgloss.Top, tabs...)
158+
}
159+
160+
func main() {
161+
var configPath string
162+
flag.StringVar(&configPath, "config", "/etc/gitlab-runner/config.toml", "Path to GitLab Runner config file")
163+
flag.Parse()
164+
165+
if _, err := os.Stat(configPath); os.IsNotExist(err) {
166+
altPath := os.ExpandEnv("$HOME/.gitlab-runner/config.toml")
167+
if _, err := os.Stat(altPath); err == nil {
168+
configPath = altPath
169+
}
170+
}
171+
172+
p := tea.NewProgram(
173+
initialModel(configPath),
174+
tea.WithAltScreen(),
175+
tea.WithMouseCellMotion(),
176+
)
177+
178+
if _, err := p.Run(); err != nil {
179+
log.Fatal(err)
180+
}
181+
}

0 commit comments

Comments
 (0)