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