Files
tui/widget/pipelineView.go

264 lines
7.4 KiB
Go

package widget
import (
"context"
"fmt"
"io"
"git.ohea.xyz/cursorius/tui/queries"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
)
type pipelineWidgetViewPage int
const (
topLevel pipelineWidgetViewPage = 0
viewRun = 1
viewRunBuildOutput = 2
viewRunStdout = 3
viewRunStderr = 4
)
type pipelineWidgetView struct {
client graphql.Client
page pipelineWidgetViewPage
pipeline queries.GetPipelinePipeline
runsList list.Model
viewRunSelector list.Model
viewRunBuildOutputPager viewport.Model
viewRunStdoutPager viewport.Model
viewRunStderrPager viewport.Model
}
func (m pipelineWidgetView) Init() tea.Cmd {
return nil
}
func (m pipelineWidgetView) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.runsList.SetWidth(msg.Width - 20)
m.runsList.SetHeight(msg.Height - 20)
case tea.KeyMsg:
switch msg.String() {
case "r":
return m, func() tea.Msg {
view, err := createPipelineWidgetView(m.client, m.pipeline.Id)
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
case "backspace":
switch m.page {
case topLevel:
return m, func() tea.Msg {
view, err := createPipelineWidgetList(m.client)
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
case viewRun:
m.page = topLevel
case viewRunBuildOutput:
m.page = viewRun
case viewRunStderr:
m.page = viewRun
case viewRunStdout:
m.page = viewRun
}
case "enter":
switch m.page {
case topLevel:
run := m.pipeline.Runs[m.runsList.Index()]
content := []list.Item{
pipelineWidgetViewRunsSelectorItem(fmt.Sprintf("ID: %v", run.Id)),
}
if run.InProgress != nil {
content = append(content, pipelineWidgetViewRunsSelectorItem(fmt.Sprintf("In Progress: %v", *run.InProgress)))
} else {
content = append(content, pipelineWidgetViewRunsSelectorItem("In Progress: null"))
}
if run.Result != nil {
content = append(content, pipelineWidgetViewRunsSelectorItem(fmt.Sprintf("Result: %v", *run.Result)))
} else {
content = append(content, pipelineWidgetViewRunsSelectorItem("Result: null"))
}
content = append(content, pipelineWidgetViewRunsSelectorItem("View Build Output"))
content = append(content, pipelineWidgetViewRunsSelectorItem("View Stdout"))
content = append(content, pipelineWidgetViewRunsSelectorItem("View Stderr"))
runOutputList := list.New(content, pipelineWigetViewRunsSelectorItemDelegate{}, m.runsList.Width(), m.runsList.Height())
runOutputList.SetShowStatusBar(false)
runOutputList.Title = "View Run"
runOutputList.DisableQuitKeybindings()
m.viewRunSelector = runOutputList
m.page = viewRun
case viewRun:
run := m.pipeline.Runs[m.runsList.Index()]
switch m.viewRunSelector.Index() {
case 3:
if run.BuildOutput == nil {
break
}
m.viewRunBuildOutputPager = viewport.New(m.runsList.Width(), m.runsList.Height())
m.viewRunBuildOutputPager.SetContent(*run.BuildOutput)
m.page = viewRunBuildOutput
case 4:
if run.Stdout == nil {
break
}
m.viewRunStdoutPager = viewport.New(m.runsList.Width(), m.runsList.Height())
m.viewRunStdoutPager.SetContent(*run.Stdout)
m.page = viewRunStdout
case 5:
if run.Stderr == nil {
break
}
m.viewRunStderrPager = viewport.New(m.runsList.Width(), m.runsList.Height())
m.viewRunStderrPager.SetContent(*run.Stderr)
m.page = viewRunStderr
}
}
}
}
var cmd tea.Cmd
switch m.page {
case topLevel:
m.runsList, cmd = m.runsList.Update(msg)
case viewRun:
m.viewRunSelector, cmd = m.viewRunSelector.Update(msg)
case viewRunBuildOutput:
m.viewRunBuildOutputPager, cmd = m.viewRunBuildOutputPager.Update(msg)
case viewRunStdout:
m.viewRunStdoutPager, cmd = m.viewRunStdoutPager.Update(msg)
case viewRunStderr:
m.viewRunStderrPager, cmd = m.viewRunStderrPager.Update(msg)
}
return m, cmd
}
func (m pipelineWidgetView) View() string {
s := ""
switch m.page {
case topLevel:
s += fmt.Sprintf("Pipeline: %v\n\n", m.pipeline.Name)
s += fmt.Sprintf("Id: %v\n", m.pipeline.Id)
s += fmt.Sprintf("Url: %v\n", m.pipeline.Url)
s += fmt.Sprintf("Poll Interval: %v\n", m.pipeline.PollInterval)
if m.pipeline.CloneCredential != nil {
s += fmt.Sprintf("Clone Credential: %v (%v)\n\n", m.pipeline.CloneCredential.Name, m.pipeline.CloneCredential.Type)
} else {
s += fmt.Sprintf("Clone Credential: None\n\n")
}
s += m.runsList.View()
case viewRun:
s += m.viewRunSelector.View()
case viewRunBuildOutput:
s += m.viewRunBuildOutputPager.View()
case viewRunStdout:
s += m.viewRunStdoutPager.View()
case viewRunStderr:
s += m.viewRunStderrPager.View()
}
return s
}
func createPipelineWidgetView(client graphql.Client, id string) (tea.Model, error) {
getPipelineResp, err := queries.GetPipeline(context.Background(), client, id)
if err != nil {
return nil, err
}
if getPipelineResp.Pipeline == nil {
return nil, fmt.Errorf("Server did not give us a pipeline")
}
var content []list.Item
for _, run := range getPipelineResp.Pipeline.Runs {
content = append(content, pipelineWidgetViewRunsItem{
id: run.Id,
})
}
runsList := list.New(content, pipelineWigetViewRunsItemDelegate{}, 0, 0)
runsList.SetShowStatusBar(false)
runsList.Title = "Runs"
return pipelineWidgetView{
client: client,
page: topLevel,
pipeline: *getPipelineResp.Pipeline,
runsList: runsList,
}, nil
}
type pipelineWidgetViewRunsItem struct {
id string
}
func (i pipelineWidgetViewRunsItem) FilterValue() string { return "" }
type pipelineWigetViewRunsItemDelegate struct{}
func (d pipelineWigetViewRunsItemDelegate) Height() int { return 1 }
func (d pipelineWigetViewRunsItemDelegate) Spacing() int { return 0 }
func (d pipelineWigetViewRunsItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d pipelineWigetViewRunsItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case pipelineWidgetViewRunsItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := fn(i.id)
fmt.Fprint(w, str)
}
}
type pipelineWidgetViewRunsSelectorItem string
func (i pipelineWidgetViewRunsSelectorItem) FilterValue() string { return "" }
type pipelineWigetViewRunsSelectorItemDelegate struct{}
func (d pipelineWigetViewRunsSelectorItemDelegate) Height() int { return 1 }
func (d pipelineWigetViewRunsSelectorItemDelegate) Spacing() int { return 0 }
func (d pipelineWigetViewRunsSelectorItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
return nil
}
func (d pipelineWigetViewRunsSelectorItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case pipelineWidgetViewRunsSelectorItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := fn(string(i))
fmt.Fprint(w, str)
}
}