diff --git a/internal/tui/components/app/app.go b/internal/tui/components/app/app.go index 35dfef8f..9449bbe8 100644 --- a/internal/tui/components/app/app.go +++ b/internal/tui/components/app/app.go @@ -15,17 +15,11 @@ import ( "github.com/robinovitch61/wander/internal/tui/message" "github.com/robinovitch61/wander/internal/tui/nomad" "github.com/robinovitch61/wander/internal/tui/style" - "os" "os/exec" "strings" "time" ) -// TODO: move and rename -type TmpMsg struct { - Output string -} - type TLSConfig struct { CACert, CAPath, ClientCert, ClientKey, ServerName string SkipVerify bool @@ -82,6 +76,8 @@ type Model struct { updateID int + lastExecContent string + eventsStream nomad.EventsStream event string meta map[string]string @@ -109,7 +105,7 @@ func InitialModel(c Config) Model { c.LogoColor, c.URL, c.Version, - nomad.GetPageKeyHelp(firstPage, false, false, false, false, nomad.StdOut, false, !c.StartAllTasksView), + nomad.GetPageKeyHelp(firstPage, false, false, false, nomad.StdOut, false, !c.StartAllTasksView), ) return Model{ config: c, @@ -260,18 +256,22 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.updateID = nextUpdateID() } - case TmpMsg: - dev.Debug("LEOO") - dev.Debug(msg.Output) + case nomad.ExecCompleteMsg: + if m.currentPage == nomad.ExecPage { + m.getCurrentPageModel().SetDoesNeedNewInput() + m.lastExecContent = strings.TrimSpace(msg.Output) + m.setPage(nomad.ExecCompletePage) + cmds = append(cmds, m.getCurrentPageCmd()) + } case message.PageInputReceivedMsg: if m.currentPage == nomad.ExecPage { c := exec.Command("wander", "exec", m.alloc.ID, m.taskName, msg.Input) - save := &saveOutput{} - c.Stdout = save + stdoutProxy := &nomad.StdoutProxy{} + c.Stdout = stdoutProxy m.getCurrentPageModel().SetDoesNeedNewInput() return m, tea.ExecProcess(c, func(err error) tea.Msg { - return TmpMsg{Output: string(save.savedOutput)} + return nomad.ExecCompleteMsg{Output: string(stdoutProxy.SavedOutput)} }) } } @@ -286,15 +286,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Batch(cmds...) } -type saveOutput struct { - savedOutput []byte -} - -func (so *saveOutput) Write(p []byte) (n int, err error) { - so.savedOutput = append(so.savedOutput, p...) - return os.Stdout.Write(p) -} - func (m Model) View() string { if m.err != nil { return fmt.Sprintf("Error: %v", m.err) + "\n\nif this seems wrong, consider opening an issue here: https://github.com/robinovitch61/wander/issues/new/choose" + "\n\nq/ctrl+c to quit" @@ -577,7 +568,7 @@ func (m *Model) appendToViewport(content string, startOnNewLine bool) { } func (m *Model) updateKeyHelp() { - newKeyHelp := nomad.GetPageKeyHelp(m.currentPage, m.currentPageFilterFocused(), m.currentPageFilterApplied(), m.currentPageViewportSaving(), m.getCurrentPageModel().EnteringInput(), m.logType, m.compact, m.inJobsMode) + newKeyHelp := nomad.GetPageKeyHelp(m.currentPage, m.currentPageFilterFocused(), m.currentPageFilterApplied(), m.currentPageViewportSaving(), m.logType, m.compact, m.inJobsMode) m.header.SetKeyHelp(newKeyHelp) } @@ -620,6 +611,15 @@ func (m Model) getCurrentPageCmd() tea.Cmd { // this does no real work, just moves to request the command input return nomad.PageLoadedMsg{Page: nomad.ExecPage, TableHeader: []string{}, AllPageRows: []page.Row{}} } + case nomad.ExecCompletePage: + return func() tea.Msg { + // this does no real work, just shows the output of the prior exec session + var allPageRows []page.Row + for _, row := range strings.Split(m.lastExecContent, "\r\n") { + allPageRows = append(allPageRows, page.Row{Row: row}) + } + return nomad.PageLoadedMsg{Page: nomad.ExecCompletePage, TableHeader: []string{"Output"}, AllPageRows: allPageRows} + } case nomad.AllocSpecPage: return nomad.FetchAllocSpec(m.client, m.alloc.ID) case nomad.LogsPage: diff --git a/internal/tui/components/page/page.go b/internal/tui/components/page/page.go index 24f565de..acc49192 100644 --- a/internal/tui/components/page/page.go +++ b/internal/tui/components/page/page.go @@ -40,7 +40,6 @@ type Model struct { doesRequestInput bool textinput textinput.Model - needsNewInput bool inputPrefix string initialized bool @@ -59,14 +58,12 @@ func New(c Config, copySavePath, startFiltering, filterWithContext bool) Model { pageViewport.SetWrapText(c.WrapText) pageViewport.ConditionalStyle = c.ViewportConditionalStyle - needsNewInput := false var pageTextInput textinput.Model if c.RequestInput { pageTextInput = textinput.New() pageTextInput.Focus() pageTextInput.Prompt = "" pageTextInput.SetValue(constants.DefaultPageInput) - needsNewInput = true } model := Model{ @@ -79,7 +76,6 @@ func New(c Config, copySavePath, startFiltering, filterWithContext bool) Model { copySavePath: copySavePath, doesRequestInput: c.RequestInput, textinput: pageTextInput, - needsNewInput: needsNewInput, FilterWithContext: filterWithContext, } return model @@ -100,7 +96,6 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: if msg.String() == "enter" && len(m.textinput.Value()) > 0 { - m.needsNewInput = false return m, func() tea.Msg { return message.PageInputReceivedMsg{Input: m.textinput.Value()} } } } @@ -279,7 +274,6 @@ func (m *Model) SetDoesNeedNewInput() { return } m.initialized = false - m.needsNewInput = true } func (m *Model) SetViewportPromptVisible(v bool) { @@ -336,7 +330,7 @@ func (m Model) ViewportSelectionAtBottom() bool { } func (m Model) EnteringInput() bool { - return m.doesRequestInput && m.needsNewInput + return m.doesRequestInput } func (m Model) FilterFocused() bool { diff --git a/internal/tui/nomad/execapp.go b/internal/tui/nomad/exec.go similarity index 97% rename from internal/tui/nomad/execapp.go rename to internal/tui/nomad/exec.go index ed1d22e5..13baebda 100644 --- a/internal/tui/nomad/execapp.go +++ b/internal/tui/nomad/exec.go @@ -13,6 +13,19 @@ import ( "syscall" ) +type ExecCompleteMsg struct { + Output string +} + +type StdoutProxy struct { + SavedOutput []byte +} + +func (so *StdoutProxy) Write(p []byte) (n int, err error) { + so.SavedOutput = append(so.SavedOutput, p...) + return os.Stdout.Write(p) +} + func AllocExec(client *api.Client, allocID, task string, args []string) (int, error) { alloc, _, err := client.Allocations().Info(allocID, nil) if err != nil { diff --git a/internal/tui/nomad/pages.go b/internal/tui/nomad/pages.go index 6d6c594d..af11a162 100644 --- a/internal/tui/nomad/pages.go +++ b/internal/tui/nomad/pages.go @@ -31,6 +31,7 @@ const ( AllEventPage JobTasksPage ExecPage + ExecCompletePage AllocSpecPage LogsPage LoglinePage @@ -106,6 +107,11 @@ func GetAllPageConfigs(width, height int, compactTables bool) map[Page]page.Conf LoadingString: ExecPage.LoadingString(), SelectionEnabled: false, WrapText: true, RequestInput: true, }, + ExecCompletePage: { + Width: width, Height: height, + LoadingString: ExecCompletePage.LoadingString(), + SelectionEnabled: false, WrapText: false, RequestInput: false, + }, AllocSpecPage: { Width: width, Height: height, LoadingString: AllocSpecPage.LoadingString(), @@ -140,7 +146,7 @@ func (p Page) DoesLoad() bool { } func (p Page) DoesReload() bool { - noReloadPages := []Page{LoglinePage, JobEventsPage, JobEventPage, AllocEventsPage, AllocEventPage, AllEventsPage, AllEventPage, ExecPage} + noReloadPages := []Page{LoglinePage, JobEventsPage, JobEventPage, AllocEventsPage, AllocEventPage, AllEventsPage, AllEventPage, ExecPage, ExecCompletePage} for _, noReloadPage := range noReloadPages { if noReloadPage == p { return false @@ -165,17 +171,18 @@ func (p Page) CanBeFirstPage() bool { func (p Page) doesUpdate() bool { noUpdatePages := []Page{ - LoglinePage, // doesn't load - ExecPage, // doesn't reload - LogsPage, // currently makes scrolling impossible - solve in https://github.com/robinovitch61/wander/issues/1 - JobSpecPage, // would require changes to make scrolling possible - AllocSpecPage, // would require changes to make scrolling possible - JobEventsPage, // constant connection, streams data - JobEventPage, // doesn't load - AllocEventsPage, // constant connection, streams data - AllocEventPage, // doesn't load - AllEventsPage, // constant connection, streams data - AllEventPage, // doesn't load + LoglinePage, // doesn't load + ExecPage, // doesn't reload + ExecCompletePage, // doesn't reload + LogsPage, // currently makes scrolling impossible - solve in https://github.com/robinovitch61/wander/issues/1 + JobSpecPage, // would require changes to make scrolling possible + AllocSpecPage, // would require changes to make scrolling possible + JobEventsPage, // constant connection, streams data + JobEventPage, // doesn't load + AllocEventsPage, // constant connection, streams data + AllocEventPage, // doesn't load + AllEventsPage, // constant connection, streams data + AllEventPage, // doesn't load } for _, noUpdatePage := range noUpdatePages { if noUpdatePage == p { @@ -209,6 +216,8 @@ func (p Page) String() string { return "tasks" case ExecPage: return "exec" + case ExecCompletePage: + return "exec complete" case AllocSpecPage: return "allocation spec" case LogsPage: @@ -274,6 +283,8 @@ func (p Page) Backward(inJobsMode bool) Page { return JobsPage case ExecPage: return returnToTasksPage(inJobsMode) + case ExecCompletePage: + return returnToTasksPage(inJobsMode) case AllocSpecPage: return returnToTasksPage(inJobsMode) case LogsPage: @@ -327,6 +338,8 @@ func (p Page) GetFilterPrefix(namespace, jobID, taskName, allocName, allocID str return fmt.Sprintf("Tasks for Job %s", style.Bold.Render(jobID)) case ExecPage: return fmt.Sprintf("Exec for Task %s", taskFilterPrefix(taskName, allocName)) + case ExecCompletePage: + return fmt.Sprintf("Exec Complete for Task %s", taskFilterPrefix(taskName, allocName)) case AllocSpecPage: return fmt.Sprintf("Spec for Allocation %s %s", style.Bold.Render(allocName), formatter.ShortAllocID(allocID)) case LogsPage: @@ -386,7 +399,7 @@ func changeKeyHelp(k *key.Binding, h string) { func GetPageKeyHelp( currentPage Page, - filterFocused, filterApplied, saving, enteringInput bool, + filterFocused, filterApplied, saving bool, logType LogType, compact, inJobsMode bool, ) string { @@ -397,7 +410,7 @@ func GetPageKeyHelp( changeKeyHelp(&keymap.KeyMap.Compact, "compact") } - if filterFocused || enteringInput { + if filterFocused { keymap.KeyMap.Exit.SetHelp("ctrl+c", "exit") } else { keymap.KeyMap.Exit.SetHelp("q/ctrl+c", "exit") @@ -458,12 +471,9 @@ func GetPageKeyHelp( } if currentPage == ExecPage { - // TODO: could probs remove the entering input status as it always is now - if enteringInput { - changeKeyHelp(&keymap.KeyMap.Forward, "run command") - secondRow = append(fourthRow, keymap.KeyMap.Forward) - return getShortHelp(firstRow) + "\n" + getShortHelp(secondRow) - } + changeKeyHelp(&keymap.KeyMap.Forward, "run command") + secondRow = append(fourthRow, keymap.KeyMap.Forward) + return getShortHelp(firstRow) + "\n" + getShortHelp(secondRow) } if saving { diff --git a/test b/test new file mode 100644 index 00000000..4c94882c --- /dev/null +++ b/test @@ -0,0 +1,9 @@ +Using config file: /Users/leo/.wander.yaml +allocID: e48de9e2-7195-5c02-130b-808aed4c77b4, task: redis +/ # ls +alloc home opt secrets var +bin lib proc srv +dev local root sys +entrypoint.sh media run tmp +etc mnt sbin usr +/ #  diff --git a/test2 b/test2 new file mode 100644 index 00000000..e5a6484f --- /dev/null +++ b/test2 @@ -0,0 +1,15 @@ +Using config file: /Users/leo/.wander.yaml +allocID: e48de9e2-7195-5c02-130b-808aed4c77b4, task: redis +/ # ls +alloc home opt secrets var +bin lib proc srv +dev local root sys +entrypoint.sh media run tmp +etc mnt sbin usr +/ # ls +alloc home opt secrets var +bin lib proc srv +dev local root sys +entrypoint.sh media run tmp +etc mnt sbin usr +/ #