Skip to content

Commit

Permalink
Support displaying images data from tui i (#55)
Browse files Browse the repository at this point in the history
* Add lipgloss table

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Add lipgloss table part 2

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Add stub for  model

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Make fmt

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Add debug model stub

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Rename welcome model -> home

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Do not print to the console when in tui mode

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Support tui -> i

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Rm dead code

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Reenable debug and dry up code

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Run Fmt

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Use a bubble tea specific name

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Use bubble tea specific naming for image model

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Delete duplicate images TUI model

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Swap in bubble tea specific names for images model

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Swap in bubble tea specific names for home model struct

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Swap out Models for TUIs to improve naming for manging multiple tui models

Signed-off-by: Evan Harris <echarris@smcm.edu>

* Swap in bubble tea specific names for debug tui

Signed-off-by: Evan Harris <echarris@smcm.edu>

---------

Signed-off-by: Evan Harris <echarris@smcm.edu>
  • Loading branch information
eharris128 committed Sep 18, 2024
1 parent d44918c commit 89f9cf2
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 89 deletions.
22 changes: 13 additions & 9 deletions pkg/app/master/command/images/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ const (
)

type CommandParams struct {
Runtime string `json:"runtime,omitempty"`
Filter string `json:"filter,omitempty"`
TUI bool `json:"tui"`
Runtime string `json:"runtime,omitempty"`
Filter string `json:"filter,omitempty"`
TUI bool `json:"tui,omitempty"`
GlobalTUI bool `json:"globalTui,omitempty"`
}

var ImagesFlags = []cli.Flag{
Expand All @@ -40,17 +41,20 @@ var CLI = &cli.Command{
return command.ErrNoGlobalParams
}

xc := app.NewExecutionContext(
Name,
gcvalues.QuietCLIMode,
gcvalues.OutputFormat)

tuiMode := ctx.Bool(FlagTUI)
cparams := &CommandParams{
Runtime: ctx.String(command.FlagRuntime),
Filter: ctx.String(FlagFilter),
TUI: ctx.Bool(FlagTUI),
TUI: tuiMode,
}

quietLogs := tuiMode || gcvalues.QuietCLIMode

xc := app.NewExecutionContext(
Name,
quietLogs,
gcvalues.OutputFormat)

OnCommand(xc, gcvalues, cparams)
return nil
},
Expand Down
25 changes: 13 additions & 12 deletions pkg/app/master/command/images/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/mintoolkit/mint/pkg/app"
"github.com/mintoolkit/mint/pkg/app/master/command"
"github.com/mintoolkit/mint/pkg/app/master/tui"
imagesModel "github.com/mintoolkit/mint/pkg/app/master/tui/images"
"github.com/mintoolkit/mint/pkg/app/master/version"
cmd "github.com/mintoolkit/mint/pkg/command"
"github.com/mintoolkit/mint/pkg/crt"
Expand All @@ -34,13 +33,14 @@ type ovars = app.OutVars
func OnCommand(
xc *app.ExecutionContext,
gparams *command.GenericParams,
cparams *CommandParams) {
cparams *CommandParams) map[string]crt.BasicImageInfo {
const cmdName = Name
logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})

logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)

cmdReport := report.NewImagesCommand(gparams.ReportLocation, gparams.InContainer)

cmdReport.State = cmd.StateStarted

xc.Out.State(cmd.StateStarted)
Expand Down Expand Up @@ -128,20 +128,20 @@ func OnCommand(
images, err := crtClient.ListImages(cparams.Filter)
xc.FailOn(err)

if cparams.TUI {
standalone := true
model := imagesModel.InitialModel(images, standalone)
tui.RunTUI(model, standalone)
}

if xc.Out.Quiet {
if cparams.TUI { // `images --tui`
initialTUI := InitialTUI(images, true)
tui.RunTUI(initialTUI, true)
return nil
} else if cparams.GlobalTUI { // `tui` -> `i`
return images
} else if xc.Out.Quiet {
if xc.Out.OutputFormat == command.OutputFormatJSON {
fmt.Printf("%s\n", jsonutil.ToPretty(images))
return
return nil
}

printImagesTable(images)
return
return nil
} else {
xc.Out.Info("image.list", ovars{"count": len(images)})
for name, info := range images {
Expand Down Expand Up @@ -170,6 +170,7 @@ func OnCommand(
"file": cmdReport.ReportLocation(),
})
}
return nil
}

func printImagesTable(images map[string]crt.BasicImageInfo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,24 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/dustin/go-humanize"
"github.com/mintoolkit/mint/pkg/app"

"github.com/mintoolkit/mint/pkg/app/master/command"
"github.com/mintoolkit/mint/pkg/app/master/tui/common"
"github.com/mintoolkit/mint/pkg/app/master/tui/home"
"github.com/mintoolkit/mint/pkg/app/master/tui/keys"
"github.com/mintoolkit/mint/pkg/crt"
"github.com/mintoolkit/mint/pkg/crt/docker/dockerutil"

tea "github.com/charmbracelet/bubbletea"
)

// Model represents the state of the TUI.
type Model struct {
// TUI represents the internal state of the terminal user interface.
type TUI struct {
table table.Table
width int
height int
standalone bool
loading bool
}

// Styles - move to `common`
Expand All @@ -46,13 +49,16 @@ var (

// End styles

// InitialModel returns the initial state of the model.
func InitialModel(images map[string]crt.BasicImageInfo, standalone bool) *Model {
m := &Model{
width: 20,
height: 15,
standalone: standalone,
func LoadTUI() *TUI {
m := &TUI{
width: 20,
height: 15,
loading: true,
}
return m
}

func generateTable(images map[string]crt.BasicImageInfo) table.Table {
var rows [][]string
for k, v := range images {
imageRow := []string{k, dockerutil.CleanImageID(v.ID)[:12], humanize.Time(time.Unix(v.Created, 0)), humanize.Bytes(uint64(v.Size))}
Expand All @@ -79,18 +85,49 @@ func InitialModel(images map[string]crt.BasicImageInfo, standalone bool) *Model
Headers("Name", "ID", "Created", "Size").
Rows(rows...)

m.table = *t
return *t
}

// InitialTUI returns the initial state of the TUI.
func InitialTUI(images map[string]crt.BasicImageInfo, standalone bool) *TUI {
m := &TUI{
width: 20,
height: 15,
standalone: standalone,
}
m.table = generateTable(images)
return m
}

func (m Model) Init() tea.Cmd {
func (m TUI) Init() tea.Cmd {
// Just return `nil`, which means "no I/O right now, please."
return nil
}

// Update is called to handle user input and update the model's state.
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Update is called to handle user input and update the TUI's state.
func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

switch msg := msg.(type) {
case common.Event:
xc := app.NewExecutionContext(
"tui",
true,
"json",
)

cparams := &CommandParams{
Runtime: crt.AutoRuntime,
GlobalTUI: true,
}

gcValue, ok := msg.Data.(*command.GenericParams)
if !ok || gcValue == nil {
return nil, nil
}

images := OnCommand(xc, gcValue, cparams)
m.table = generateTable(images)
return m, nil
case tea.WindowSizeMsg:
m.table.Width(msg.Width)
m.table.Height(msg.Height)
Expand All @@ -100,14 +137,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, keys.Global.Quit):
return m, tea.Quit
case key.Matches(msg, keys.Global.Back):
return home.InitialModel()
return common.TUIsInstance.Home, nil
}
}
return m, nil
}

// View returns the view that should be displayed.
func (m Model) View() string {
func (m TUI) View() string {
var components []string

content := m.table.String()
Expand All @@ -121,7 +158,7 @@ func (m Model) View() string {
)
}

func (m Model) help() string {
func (m TUI) help() string {
if m.standalone {
return common.HelpStyle("• q: quit")
}
Expand Down
10 changes: 8 additions & 2 deletions pkg/app/master/command/tui/cli.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tui

import (
"github.com/mintoolkit/mint/pkg/app/master/command"
tui "github.com/mintoolkit/mint/pkg/app/master/tui"
"github.com/mintoolkit/mint/pkg/app/master/tui/home"
cmd "github.com/mintoolkit/mint/pkg/command"
Expand All @@ -18,8 +19,13 @@ var CLI = &cli.Command{
Aliases: []string{Alias},
Usage: Usage,
Action: func(ctx *cli.Context) error {
m, _ := home.InitialModel()
tui.RunTUI(m, false)
gcvalues, ok := command.CLIContextGet(ctx.Context, command.GlobalParams).(*command.GenericParams)
if !ok || gcvalues == nil {
return command.ErrNoGlobalParams
}

initialTUI, _ := home.InitialTUI(gcvalues)
tui.RunTUI(initialTUI, false)
return nil
},
}
10 changes: 8 additions & 2 deletions pkg/app/master/tui/common/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import (

var (
// P the current tea program
P *tea.Program
Models []tea.Model
P *tea.Program
TUIsInstance TUIs
)

type TUIs struct {
Home tea.Model
Images tea.Model
Debug tea.Model
}
15 changes: 15 additions & 0 deletions pkg/app/master/tui/common/event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package common

const (
GetImagesEvent EventType = "getImages"
)

type (
// EventType identifies the type of event
EventType string
// Event represents an event in the lifecycle of a resource
Event struct {
Type EventType
Data interface{}
}
)
67 changes: 67 additions & 0 deletions pkg/app/master/tui/debug/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package debug

import (
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/lipgloss"
"github.com/mintoolkit/mint/pkg/app/master/tui/common"
"github.com/mintoolkit/mint/pkg/app/master/tui/keys"

tea "github.com/charmbracelet/bubbletea"
)

// TUI represents the state of the TUI.
type TUI struct {
standalone bool
}

// InitialTUI returns the initial state of the model.
func InitialTUI(standalone bool) *TUI {
m := &TUI{
standalone: standalone,
}

return m
}

func (m TUI) Init() tea.Cmd {
// Just return `nil`, which means "no I/O right now, please."
return nil
}

// Update is called to handle user input and update the model's state.
func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch {
case key.Matches(msg, keys.Global.Quit):
return m, tea.Quit
// NOTE -> We should only support this back navigation,
// if the images tui is not standalone
case key.Matches(msg, keys.Global.Back):
return common.TUIsInstance.Home, nil
}
}
return m, nil
}

// View returns the view that should be displayed.
func (m TUI) View() string {
var components []string

content := "Debug support coming soon"

components = append(components, content)

components = append(components, m.help())

return lipgloss.JoinVertical(lipgloss.Left,
components...,
)
}

func (m TUI) help() string {
if m.standalone {
return common.HelpStyle("• q: quit")
}
return common.HelpStyle("• esc: back • q: quit")
}
Loading

0 comments on commit 89f9cf2

Please sign in to comment.