-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from ewilliams0305/service-view
Service view
- Loading branch information
Showing
6 changed files
with
325 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package tui | ||
|
||
import ( | ||
"os/exec" | ||
"time" | ||
|
||
"github.com/charmbracelet/bubbles/list" | ||
"github.com/charmbracelet/bubbles/progress" | ||
tea "github.com/charmbracelet/bubbletea" | ||
"github.com/charmbracelet/lipgloss" | ||
) | ||
|
||
type VirtualControlServiceModel struct { | ||
altscreenActive bool | ||
err error | ||
help SystemsHelpModel | ||
list list.Model | ||
progress progress.Model | ||
} | ||
|
||
type serviceOption struct { | ||
title, desc string | ||
} | ||
|
||
type journalClosedMessage struct{ err error } | ||
|
||
type serviceClosedMessage struct{ err error } | ||
|
||
var docStyle = lipgloss.NewStyle().Margin(1, 2) | ||
|
||
func (i serviceOption) Title() string { return i.title } | ||
func (i serviceOption) Description() string { return i.desc } | ||
func (i serviceOption) FilterValue() string { return i.title } | ||
|
||
func InitialSystemModel() VirtualControlServiceModel { | ||
|
||
items := []list.Item{ | ||
serviceOption{title: "Stop", desc: "stops the virtual control systemd service"}, | ||
serviceOption{title: "Start", desc: "starts the virtual control systemd service"}, | ||
serviceOption{title: "Restart", desc: "restarts the virtual control systemd service"}, | ||
serviceOption{title: "Logs", desc: "views the virtual control service journal"}, | ||
} | ||
|
||
prog := progress.New(progress.WithDefaultGradient()) | ||
prog.Width = app.width | ||
|
||
m := VirtualControlServiceModel{ | ||
help: NewSystensHelpModel(), | ||
altscreenActive: true, | ||
list: list.New(items, list.NewDefaultDelegate(), 100, 20), | ||
progress: prog, | ||
} | ||
|
||
m.list.Title = "Virtual Control Service Actions" | ||
return m | ||
} | ||
|
||
func (m VirtualControlServiceModel) Init() tea.Cmd { | ||
return nil | ||
} | ||
|
||
func (m VirtualControlServiceModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { | ||
switch msg := msg.(type) { | ||
case tea.KeyMsg: | ||
switch msg.String() { | ||
|
||
case "s", "ctrl+s": | ||
if m.list.FilterState() != list.Filtering { | ||
return m, tea.Batch(stopService(), systemTickCmd()) | ||
} | ||
case "n", "ctrl+n": | ||
if m.list.FilterState() != list.Filtering { | ||
return m, tea.Batch(startService(), systemTickCmd()) | ||
} | ||
case "r", "ctrl+r": | ||
if m.list.FilterState() != list.Filtering { | ||
return m, tea.Batch(restartService(), systemTickCmd()) | ||
} | ||
case "l", "ctrl+l": | ||
if m.list.FilterState() != list.Filtering { | ||
return m, tea.Batch(openJournal(), tea.EnterAltScreen) | ||
} | ||
case "esc", "ctrl+q", "q": | ||
if m.list.FilterState() != list.Filtering { | ||
return ReturnToHomeModel(systemd), DeviceInfoCommand | ||
} | ||
|
||
case "enter": | ||
|
||
switch m.list.Cursor() { | ||
case 0: | ||
return m, tea.Batch(stopService(), systemTickCmd()) | ||
case 1: | ||
return m, tea.Batch(startService(), systemTickCmd()) | ||
case 2: | ||
return m, tea.Batch(restartService(), systemTickCmd()) | ||
case 3: | ||
return m, tea.Batch(openJournal(), tea.EnterAltScreen) | ||
|
||
} | ||
} | ||
|
||
case error: | ||
m.err = msg | ||
return m, nil | ||
|
||
case journalClosedMessage: | ||
if msg.err != nil { | ||
m.err = msg.err | ||
return m, nil | ||
} | ||
case serviceClosedMessage: | ||
if msg.err != nil { | ||
m.err = msg.err | ||
return m, nil | ||
} | ||
|
||
case progress.FrameMsg: | ||
progressModel, cmd := m.progress.Update(msg) | ||
m.progress = progressModel.(progress.Model) | ||
return m, cmd | ||
|
||
case progressTick: | ||
if m.progress.Percent() == 1.0 { | ||
prog := progress.New(progress.WithDefaultGradient()) | ||
prog.Width = app.width | ||
m.progress = prog | ||
return m, tea.Batch(openJournal(), tea.EnterAltScreen) | ||
} | ||
return m, tea.Batch(systemTickCmd(), m.progress.IncrPercent(0.20)) | ||
} | ||
|
||
var cmd tea.Cmd | ||
m.list, cmd = m.list.Update(msg) | ||
return m, cmd | ||
} | ||
|
||
func (m VirtualControlServiceModel) View() string { | ||
s := "\n" | ||
s += docStyle.Render(m.list.View()) | ||
s += "\n\n\n" | ||
|
||
if m.err != nil { | ||
s += RenderErrorBox("Failed interacting with the virtual control service", m.err) | ||
} | ||
|
||
if m.progress.Percent() != 0.0 { | ||
s += "\n" + m.progress.View() + "\n" | ||
} else { | ||
s += "\n\n\n" | ||
} | ||
|
||
s += m.help.renderHelpInfo() | ||
return s | ||
} | ||
|
||
func systemTickCmd() tea.Cmd { | ||
return tea.Tick(time.Millisecond*300, func(t time.Time) tea.Msg { | ||
return progressTick(t) | ||
}) | ||
} | ||
|
||
func openJournal() tea.Cmd { | ||
|
||
c := exec.Command("journalctl", "-u", "virtualcontrol.service", "-f") | ||
return tea.ExecProcess(c, func(err error) tea.Msg { | ||
return journalClosedMessage{err} | ||
}) | ||
} | ||
func stopService() tea.Cmd { | ||
|
||
c := exec.Command("systemctl", "stop", "virtualcontrol.service") | ||
return tea.ExecProcess(c, func(err error) tea.Msg { | ||
return serviceClosedMessage{err} | ||
}) | ||
} | ||
func startService() tea.Cmd { | ||
|
||
c := exec.Command("systemctl", "start", "virtualcontrol.service") | ||
return tea.ExecProcess(c, func(err error) tea.Msg { | ||
return serviceClosedMessage{err} | ||
}) | ||
} | ||
func restartService() tea.Cmd { | ||
|
||
c := exec.Command("systemctl", "restart", "virtualcontrol.service") | ||
return tea.ExecProcess(c, func(err error) tea.Msg { | ||
return serviceClosedMessage{err} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package tui | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/charmbracelet/bubbles/help" | ||
"github.com/charmbracelet/bubbles/key" | ||
tea "github.com/charmbracelet/bubbletea" | ||
"github.com/charmbracelet/lipgloss" | ||
) | ||
|
||
// 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 serviceKeyMap struct { | ||
Up key.Binding | ||
Down key.Binding | ||
Help key.Binding | ||
Quit key.Binding | ||
Start key.Binding | ||
Stop key.Binding | ||
Restart key.Binding | ||
Logs key.Binding | ||
} | ||
|
||
// ShortHelp returns keybindings to be shown in the mini help view. It's part | ||
// of the key.Map interface. | ||
func (k serviceKeyMap) ShortHelp() []key.Binding { | ||
return []key.Binding{k.Quit, k.Up, k.Down, k.Start, k.Stop, k.Restart, k.Logs} | ||
} | ||
|
||
// FullHelp returns keybindings for the expanded help view. It's part of the | ||
// key.Map interface. | ||
func (k serviceKeyMap) FullHelp() [][]key.Binding { | ||
return [][]key.Binding{ | ||
{k.Help, k.Up, k.Down}, // first column | ||
{k.Start, k.Stop, k.Logs}, // second column | ||
} | ||
} | ||
|
||
var serviceKeys = serviceKeyMap{ | ||
Up: key.NewBinding( | ||
key.WithKeys("up", "k"), | ||
key.WithHelp("↑/k", "move up"), | ||
), | ||
Down: key.NewBinding( | ||
key.WithKeys("down", "j"), | ||
key.WithHelp("↓/j", "move down"), | ||
), | ||
Help: key.NewBinding( | ||
key.WithKeys("?", "h"), | ||
key.WithHelp("?", "toggle help"), | ||
), | ||
Quit: key.NewBinding( | ||
key.WithKeys("q", "esc", "ctrl+c"), | ||
key.WithHelp("q", "quit"), | ||
), | ||
Stop: key.NewBinding( | ||
key.WithKeys("ctrl+s"), | ||
key.WithHelp("ctrl+s", "stop service"), | ||
), | ||
Start: key.NewBinding( | ||
key.WithKeys("ctrl+n"), | ||
key.WithHelp("ctrl+n", "start service"), | ||
), | ||
Restart: key.NewBinding( | ||
key.WithKeys("ctrl+r"), | ||
key.WithHelp("ctrl+r", "restart room"), | ||
), | ||
Logs: key.NewBinding( | ||
key.WithKeys("ctrl+l"), | ||
key.WithHelp("ctrl+l", "display logs"), | ||
), | ||
} | ||
|
||
type SystemsHelpModel struct { | ||
keys serviceKeyMap | ||
help help.Model | ||
inputStyle lipgloss.Style | ||
} | ||
|
||
func NewSystensHelpModel() SystemsHelpModel { | ||
return SystemsHelpModel{ | ||
keys: serviceKeys, | ||
help: help.New(), | ||
inputStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("#FF75B7")), | ||
} | ||
} | ||
|
||
func (m SystemsHelpModel) Init() tea.Cmd { | ||
return nil | ||
} | ||
|
||
func (m SystemsHelpModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { | ||
switch msg := msg.(type) { | ||
case tea.WindowSizeMsg: | ||
m.help.Width = msg.Width | ||
|
||
case tea.KeyMsg: | ||
switch { | ||
|
||
case key.Matches(msg, m.keys.Help): | ||
m.help.ShowAll = !m.help.ShowAll | ||
case key.Matches(msg, m.keys.Quit): | ||
return VirtualControlServiceModel{}, nil | ||
} | ||
} | ||
return m, nil | ||
} | ||
|
||
func (m SystemsHelpModel) View() string { | ||
var status string | ||
|
||
helpView := m.help.View(m.keys) | ||
height := 8 - strings.Count(status, "\n") - strings.Count(helpView, "\n") | ||
|
||
return "\n" + status + strings.Repeat("\n", height) + helpView | ||
} | ||
|
||
func (m SystemsHelpModel) renderHelpInfo() string { | ||
helpView := m.help.View(m.keys) | ||
return "\n" + helpView | ||
} |