Skip to content

Commit

Permalink
Convert admin task to table-based implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
robinovitch61 authored and cshintov committed Jan 28, 2024
1 parent d89de2d commit 6fdb98f
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 186 deletions.
123 changes: 61 additions & 62 deletions internal/tui/components/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package app

import (
"fmt"
"github.com/robinovitch61/wander/internal/tui/components/toast"
"os"
"os/exec"
"path"
Expand Down Expand Up @@ -63,8 +64,8 @@ type Config struct {

type Model struct {
confirmed bool
config Config
client api.Client
config Config
client api.Client

header header.Model
compact bool
Expand All @@ -91,6 +92,9 @@ type Model struct {
logsStream nomad.LogsStream
lastLogFinished bool

// adminAction is a key of TaskAdminActions (or JobAdminActions, when it exists)
adminAction nomad.AdminAction

width, height int
initialized bool
err error
Expand Down Expand Up @@ -167,6 +171,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case nomad.PageLoadedMsg:
dev.Debug(fmt.Sprintf("page loaded: %v", msg.Page))
if msg.Page == m.currentPage {
m.getCurrentPageModel().SetHeader(msg.TableHeader)
m.getCurrentPageModel().SetAllPageRows(msg.AllPageRows)
Expand Down Expand Up @@ -231,16 +236,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, nomad.ReadEventsStreamNextMessage(m.eventsStream, query))
}

case nomad.TaskRestartedMsg:
// Reset confirmation
m.confirmed = false
dev.MyDebug("🔴 reset confirmation when task restarted")
m.setPage(nomad.JobTasksPage)
cmds = append(cmds, m.getCurrentPageCmd())

case nomad.AdminMenuMsg:
m.setPage(nomad.AdminMenu)

case nomad.LogsStreamMsg:
if m.currentPage == nomad.LogsPage && m.logType == msg.Type {
logLines := strings.Split(msg.Value, "\n")
Expand Down Expand Up @@ -309,6 +304,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return nomad.ExecCompleteMsg{Output: string(stdoutProxy.SavedOutput)}
})
}

case nomad.TaskAdminActionCompleteMsg:
m.getCurrentPageModel().SetToast(
toast.New(
fmt.Sprintf("%s completed successfully", nomad.GetTaskAdminText(m.adminAction, msg.TaskName, msg.AllocName, msg.AllocID)),
),
style.SuccessToast,
)
}

currentPageModel = m.getCurrentPageModel()
Expand Down Expand Up @@ -402,6 +405,17 @@ func (m *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
m.event = selectedPageRow.Key
case nomad.LogsPage:
m.logline = selectedPageRow.Row
case nomad.TaskAdminPage:
m.adminAction = nomad.KeyToAdminAction(selectedPageRow.Key)
case nomad.TaskAdminConfirmPage:
if selectedPageRow.Key == constants.ConfirmationKey {
cmds = append(cmds, nomad.GetCmdForTaskAdminAction(m.client, m.adminAction, m.taskName, m.alloc.Name, m.alloc.ID))
} else {
backPage := m.currentPage.Backward(m.inJobsMode)
m.setPage(backPage)
cmds = append(cmds, m.getCurrentPageCmd())
return tea.Batch(cmds...)
}
default:
if m.currentPage.ShowsTasks() {
taskInfo, err := nomad.TaskInfoFromKey(selectedPageRow.Key)
Expand All @@ -413,10 +427,11 @@ func (m *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
}
}

nextPage := m.currentPage.Forward()
nextPage := m.currentPage.Forward(m.inJobsMode)
if nextPage != m.currentPage {
m.setPage(nextPage)
return m.getCurrentPageCmd()
cmds = append(cmds, m.getCurrentPageCmd())
return tea.Batch(cmds...)
}
}

Expand Down Expand Up @@ -549,16 +564,8 @@ func (m *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
return m.getCurrentPageCmd()
}

if key.Matches(msg, keymap.KeyMap.Yes) && m.currentPage == nomad.ConfirmPage {
m.confirmed = true
m.setPage(m.previousPage)
return m.getCurrentPageCmd()
}

// Open Admin Menu
if key.Matches(msg, keymap.KeyMap.AdminMenu) && m.currentPage.ShowsTasks() {
if key.Matches(msg, keymap.KeyMap.AdminMenu) && m.currentPage.HasAdminMenu() {
if selectedPageRow, err := m.getCurrentPageModel().GetSelectedPageRow(); err == nil {

// Get task info from the currently selected row
taskInfo, err := nomad.TaskInfoFromKey(selectedPageRow.Key)
if err != nil {
Expand All @@ -567,39 +574,12 @@ func (m *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
}
if taskInfo.Running {
m.alloc, m.taskName = taskInfo.Alloc, taskInfo.TaskName
m.setPage(nomad.AdminMenu)
m.setPage(nomad.TaskAdminPage)
return m.getCurrentPageCmd()
}
}
}

// Restart a task
if key.Matches(msg, keymap.KeyMap.RestartTask) && m.currentPage.IsAdmin() {
// Get the currently selected row
if selectedPageRow, err := m.pageModels[nomad.JobTasksPage].GetSelectedPageRow(); err == nil {
// Get task info from the currently selected row
taskInfo, err := nomad.TaskInfoFromKey(selectedPageRow.Key)
if err != nil {
m.err = err
return nil
}

if taskInfo.Running {
m.alloc, m.taskName = taskInfo.Alloc, taskInfo.TaskName
if m.confirmed {
m.setPage(nomad.RestartTaskPage)
return m.getCurrentPageCmd()
} else {
m.previousPage = nomad.RestartTaskPage
m.setPage(nomad.ConfirmPage)
return nil
}
}
} else {
dev.Debug("🔴 error getting selected page row")
}
}

if m.currentPage == nomad.LogsPage {
switch {
case key.Matches(msg, keymap.KeyMap.StdOut):
Expand Down Expand Up @@ -717,26 +697,45 @@ func (m Model) getCurrentPageCmd() tea.Cmd {
AllPageRows: allPageRows,
}
}

case nomad.AllocSpecPage:
return nomad.FetchAllocSpec(m.client, m.alloc.ID)

case nomad.RestartTaskPage:
return nomad.RestartTask(m.client, m.alloc.ID, m.taskName)

case nomad.AdminMenu:
return nomad.ShowAdminMenu(m.client, m.alloc.ID, m.taskName)

case nomad.LogsPage:
return nomad.FetchLogs(
m.client, m.alloc, m.taskName, m.logType, m.config.Log.Offset, m.config.Log.Tail)

case nomad.LoglinePage:
return nomad.PrettifyLine(m.logline, nomad.LoglinePage)

case nomad.StatsPage:
return nomad.FetchStats(m.client, m.alloc.ID, m.alloc.Name)

case nomad.TaskAdminPage:
return func() tea.Msg {
// this does no async work, just constructs the task admin menu
var rows []page.Row
for action := range nomad.TaskAdminActions {
rows = append(rows, page.Row{
Key: nomad.AdminActionToKey(action),
Row: nomad.GetTaskAdminText(action, m.taskName, m.alloc.Name, m.alloc.ID),
})
}
return nomad.PageLoadedMsg{
Page: nomad.TaskAdminPage,
TableHeader: []string{"Available Admin Actions"},
AllPageRows: rows,
}
}
case nomad.TaskAdminConfirmPage:
return func() tea.Msg {
// this does no async work, just constructs the confirmation page
confirmationText := nomad.GetTaskAdminText(m.adminAction, m.taskName, m.alloc.Name, m.alloc.ID)
confirmationText = strings.ToLower(confirmationText[:1]) + confirmationText[1:]
return nomad.PageLoadedMsg{
Page: nomad.TaskAdminConfirmPage,
TableHeader: []string{"Are you sure?"},
AllPageRows: []page.Row{
{Key: "Cancel", Row: "Cancel"},
{Key: constants.ConfirmationKey, Row: fmt.Sprintf("Yes, %s", confirmationText)},
},
}
}
default:
panic(fmt.Sprintf("Load command for page:%s not found", m.currentPage))
}
Expand Down
4 changes: 4 additions & 0 deletions internal/tui/components/page/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ func (m *Model) SetViewportXOffset(n int) {
m.viewport.SetXOffset(n)
}

func (m *Model) SetToast(toast toast.Model, style lipgloss.Style) {
m.viewport.SetToast(toast, style)
}

func (m *Model) HideToast() {
m.viewport.HideToast()
}
Expand Down
5 changes: 5 additions & 0 deletions internal/tui/components/viewport/viewport.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,11 @@ func (m *Model) ToggleWrapText() {
m.updateForWrapText()
}

func (m *Model) SetToast(toast toast.Model, style lipgloss.Style) {
m.toast = toast
m.toast.MessageStyle = style.Copy().Width(m.width)
}

func (m *Model) HideToast() {
m.toast.Visible = false
}
Expand Down
2 changes: 2 additions & 0 deletions internal/tui/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ const DefaultEventJQQuery = `.Events[] | {"1:Index": .Index, "2:Topic": .Topic,

// DefaultAllocEventJQQuery is a single line as this shows up verbatim in `wander --help`
const DefaultAllocEventJQQuery = `.Index as $index | .Events[] | .Type as $type | .Payload.Allocation | .DeploymentStatus.Healthy as $healthy | .ClientStatus as $clientStatus | .Name as $allocName | (.TaskStates // {"":{"Events": [{}]}}) | to_entries[] | .key as $k | .value.Events[] | {"0:Index": $index, "1:AllocName": $allocName, "2:TaskName": $k, "3:Type": $type, "4:Time": ((.Time // 0) / 1000000000 | todate), "5:Msg": .DisplayMessage, "6:Healthy": $healthy, "7:ClientStatus": $clientStatus}`

const ConfirmationKey = "Yes"
11 changes: 1 addition & 10 deletions internal/tui/keymap/keymap.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
)

type keyMap struct {
Yes key.Binding
Back key.Binding
Exec key.Binding
Exit key.Binding
Expand All @@ -26,14 +25,10 @@ type keyMap struct {
StdErr key.Binding
Spec key.Binding
Wrap key.Binding
RestartTask key.Binding
AdminMenu key.Binding
}

var KeyMap = keyMap{
Yes: key.NewBinding(
key.WithKeys("y"),
),
Back: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "back"),
Expand Down Expand Up @@ -114,12 +109,8 @@ var KeyMap = keyMap{
key.WithKeys("ctrl+w"),
key.WithHelp("ctrl+w", "toggle wrap"),
),
RestartTask: key.NewBinding(
key.WithKeys("t"),
key.WithHelp("t", "Restart task"),
),
AdminMenu: key.NewBinding(
key.WithKeys("X"),
key.WithHelp("X", "Open Admin Menu"),
key.WithHelp("X", "admin"),
),
}
32 changes: 0 additions & 32 deletions internal/tui/nomad/jobtasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,35 +109,3 @@ func jobTasksAsTable(jobTaskRowEntries []taskRowEntry, columns []string) ([]stri

return table.HeaderRows, rows
}

type TaskRestartedMsg struct {
AllocID string
TaskName string
}

/*
Restarts a task given an allocation ID and task name
*/
func RestartTask(client api.Client, allocID, taskName string) tea.Cmd {
return func() tea.Msg {
// Get the allocation
alloc, _, err := client.Allocations().Info(allocID, nil)
if err != nil {
return message.ErrMsg{Err: err}
}

// Restart the task
err = client.Allocations().Restart(alloc, taskName, nil)
if err != nil {
return message.ErrMsg{Err: err}
}

return TaskRestartedMsg{AllocID: allocID, TaskName: taskName}
}
}

func ShowAdminMenu(client api.Client, allocID, taskName string) tea.Cmd {
return func() tea.Msg {
return AdminMenuMsg{AllocID: allocID, TaskName: taskName}
}
}
Loading

0 comments on commit 6fdb98f

Please sign in to comment.