Files
fn_registry/fn_operations/docker_tui/app/model.go
T
egutierrez 1e6751d6c0 refactor: navegacion consistente con HandleBack en todas las vistas
Cada vista expone HandleBack() bool que retrocede un nivel interno (logs ->
lista) o indica que esta en estado base. El model principal intercepta q/0/esc
y delega a HandleBack: si retorna true, sale de la TUI; si false, la vista
retrocedio internamente. Elimina manejo duplicado de esc/q/0 en sub-estados.
2026-03-28 04:52:21 +01:00

176 lines
3.8 KiB
Go

package app
import (
"docker-tui/views"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/lucasdataproyects/devfactory/tui"
)
type View int
const (
ViewContainers View = iota
ViewImages
ViewVolumes
ViewNetworks
ViewCompose
)
var tabNames = []string{"Containers", "Images", "Volumes", "Networks", "Compose"}
type Model struct {
tui.BaseModel
activeTab int
containers views.ContainersModel
images views.ImagesModel
volumes views.VolumesModel
networks views.NetworksModel
compose views.ComposeModel
ready bool
}
func New() Model {
styles := tui.DefaultStyles()
return Model{
BaseModel: tui.NewBaseModel().WithStyles(styles),
containers: views.NewContainersModel(styles),
images: views.NewImagesModel(styles),
volumes: views.NewVolumesModel(styles),
networks: views.NewNetworksModel(styles),
compose: views.NewComposeModel(styles),
}
}
func (m Model) Init() tea.Cmd {
return m.containers.Init()
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case views.KeyQuit:
return m, tea.Quit
case "q", "0", "esc":
updated, atBase := m.handleBack()
if atBase {
return updated, tea.Quit
}
return updated, nil
case views.KeyTab:
m.activeTab = (m.activeTab + 1) % len(tabNames)
return m, m.initActiveView()
case "shift+tab":
m.activeTab = (m.activeTab - 1 + len(tabNames)) % len(tabNames)
return m, m.initActiveView()
}
case tea.WindowSizeMsg:
m.HandleWindowSize(msg)
m.ready = true
}
var cmd tea.Cmd
switch View(m.activeTab) {
case ViewContainers:
m.containers, cmd = m.containers.Update(msg)
case ViewImages:
m.images, cmd = m.images.Update(msg)
case ViewVolumes:
m.volumes, cmd = m.volumes.Update(msg)
case ViewNetworks:
m.networks, cmd = m.networks.Update(msg)
case ViewCompose:
m.compose, cmd = m.compose.Update(msg)
}
return m, cmd
}
func (m Model) View() string {
if !m.ready {
return "Loading..."
}
// Tab bar
tabs := m.renderTabs()
// Active view content
var content string
switch View(m.activeTab) {
case ViewContainers:
content = m.containers.View()
case ViewImages:
content = m.images.View()
case ViewVolumes:
content = m.volumes.View()
case ViewNetworks:
content = m.networks.View()
case ViewCompose:
content = m.compose.View()
}
// Status bar
status := m.Styles.StatusBar.Render(" Tab: switch view │ Ctrl+C: quit │ Enter: action │ r: refresh")
return lipgloss.JoinVertical(lipgloss.Left,
tabs,
"",
content,
"",
status,
)
}
func (m Model) renderTabs() string {
var tabs []string
for i, name := range tabNames {
if i == m.activeTab {
tabs = append(tabs, m.Styles.Selected.Render(" "+name+" "))
} else {
tabs = append(tabs, m.Styles.Muted.Render(" "+name+" "))
}
}
row := lipgloss.JoinHorizontal(lipgloss.Top, tabs...)
return m.Styles.Header.Render("Docker TUI") + " " + row
}
// handleBack asks the active view to go back one level.
// Returns the updated model and true if the view was already at base level (app should quit).
func (m Model) handleBack() (Model, bool) {
switch View(m.activeTab) {
case ViewContainers:
atBase := m.containers.HandleBack()
return m, atBase
case ViewImages:
atBase := m.images.HandleBack()
return m, atBase
case ViewVolumes:
atBase := m.volumes.HandleBack()
return m, atBase
case ViewNetworks:
atBase := m.networks.HandleBack()
return m, atBase
case ViewCompose:
atBase := m.compose.HandleBack()
return m, atBase
}
return m, true
}
func (m Model) initActiveView() tea.Cmd {
switch View(m.activeTab) {
case ViewContainers:
return m.containers.Init()
case ViewImages:
return m.images.Init()
case ViewVolumes:
return m.volumes.Init()
case ViewNetworks:
return m.networks.Init()
case ViewCompose:
return m.compose.Init()
}
return nil
}