refactor: mover apps TUI de fn_operations/ a apps/

Separa aplicaciones ejecutables (docker_tui, pipeline_launcher) de la
librería fn_operations. La carpeta apps/ contiene módulos Go independientes,
fn_operations/ queda como librería pura de models/store/operations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-28 17:14:22 +01:00
parent edfff680b3
commit 5d3b56fe8e
21 changed files with 3 additions and 3 deletions
+128
View File
@@ -0,0 +1,128 @@
package views
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/lucasdataproyects/devfactory/tui"
)
type networksState int
const (
networksLoading networksState = iota
networksList
networksAction
)
type networksLoadedMsg []DockerNetwork
type networksActionMsg struct{ output string; err error }
type NetworksModel struct {
state networksState
list tui.ListModel
spinner tui.SpinnerModel
styles tui.Styles
networks []DockerNetwork
err error
}
func NewNetworksModel(styles tui.Styles) NetworksModel {
return NetworksModel{
state: networksLoading,
list: tui.NewList(nil),
spinner: tui.NewSpinner("Loading networks..."),
styles: styles,
}
}
func (m NetworksModel) Init() tea.Cmd {
return tea.Batch(m.spinner.Init(), loadNetworks)
}
func loadNetworks() tea.Msg {
networks, err := ListNetworks()
if err != nil {
return networksLoadedMsg(nil)
}
return networksLoadedMsg(networks)
}
func (m NetworksModel) Update(msg tea.Msg) (NetworksModel, tea.Cmd) {
switch msg := msg.(type) {
case networksLoadedMsg:
m.networks = []DockerNetwork(msg)
items := make([]tui.ListItem, len(m.networks))
for i, n := range m.networks {
items[i] = tui.ListItem{
Title: n.Name,
Description: fmt.Sprintf("Driver: %s — Scope: %s", n.Driver, n.Scope),
Value: n,
}
}
m.list.SetItems(items)
m.state = networksList
return m, nil
case networksActionMsg:
if msg.err != nil {
m.err = msg.err
}
m.state = networksList
return m, loadNetworks
case tea.KeyMsg:
if m.state == networksList {
switch msg.String() {
case "r":
m.state = networksLoading
return m, tea.Batch(m.spinner.Init(), loadNetworks)
case "d", "delete":
if item := m.list.SelectedItem(); item != nil {
net := item.Value.(DockerNetwork)
m.state = networksAction
return m, func() tea.Msg {
err := RemoveNetwork(net.Name)
return networksActionMsg{output: "Removed", err: err}
}
}
}
}
}
var cmd tea.Cmd
switch m.state {
case networksLoading, networksAction:
var model tea.Model
model, cmd = m.spinner.Update(msg)
m.spinner = model.(tui.SpinnerModel)
case networksList:
var model tea.Model
model, cmd = m.list.Update(msg)
m.list = model.(tui.ListModel)
}
return m, cmd
}
// HandleBack retrocede un nivel. Retorna true si ya estaba en estado base.
func (m *NetworksModel) HandleBack() bool {
return true
}
func (m NetworksModel) View() string {
switch m.state {
case networksLoading, networksAction:
return m.spinner.View()
case networksList:
if len(m.networks) == 0 {
return m.styles.Muted.Render("No networks found. Press 'r' to refresh.")
}
help := m.styles.Muted.Render(" d: remove │ r: refresh")
view := m.list.View() + "\n" + help
if m.err != nil {
view += "\n" + m.styles.Error.Render(fmt.Sprintf(" Error: %v", m.err))
}
return view
}
return ""
}