diff --git a/fn_operations/docker_tui/app/model.go b/fn_operations/docker_tui/app/model.go index c0d83f08..eeb6c71e 100644 --- a/fn_operations/docker_tui/app/model.go +++ b/fn_operations/docker_tui/app/model.go @@ -53,6 +53,12 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { 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() @@ -129,6 +135,29 @@ func (m Model) renderTabs() string { 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: diff --git a/fn_operations/docker_tui/views/compose.go b/fn_operations/docker_tui/views/compose.go index 18d1f588..ca35838e 100644 --- a/fn_operations/docker_tui/views/compose.go +++ b/fn_operations/docker_tui/views/compose.go @@ -134,9 +134,6 @@ func (m ComposeModel) Update(msg tea.Msg) (ComposeModel, tea.Cmd) { if m.scrollOff > 0 { m.scrollOff-- } - case "esc", "q", "0": - m.state = composeList - return m, nil } return m, nil } @@ -156,6 +153,17 @@ func (m ComposeModel) Update(msg tea.Msg) (ComposeModel, tea.Cmd) { return m, cmd } +// HandleBack retrocede un nivel. Retorna true si ya estaba en estado base. +func (m *ComposeModel) HandleBack() bool { + switch m.state { + case composeLogs: + m.state = composeList + return false + default: + return true + } +} + func (m ComposeModel) View() string { switch m.state { case composeLoading, composeAction: diff --git a/fn_operations/docker_tui/views/containers.go b/fn_operations/docker_tui/views/containers.go index 1dcf803c..40aa2d48 100644 --- a/fn_operations/docker_tui/views/containers.go +++ b/fn_operations/docker_tui/views/containers.go @@ -132,9 +132,6 @@ func (m ContainersModel) Update(msg tea.Msg) (ContainersModel, tea.Cmd) { if m.scrollOff > 0 { m.scrollOff-- } - case "esc", "q", "0": - m.state = containersList - return m, nil } return m, nil } @@ -155,6 +152,17 @@ func (m ContainersModel) Update(msg tea.Msg) (ContainersModel, tea.Cmd) { return m, cmd } +// HandleBack retrocede un nivel. Retorna true si ya estaba en estado base (el caller debe salir). +func (m *ContainersModel) HandleBack() bool { + switch m.state { + case containersLogs: + m.state = containersList + return false + default: + return true + } +} + func (m ContainersModel) View() string { switch m.state { case containersLoading: diff --git a/fn_operations/docker_tui/views/images.go b/fn_operations/docker_tui/views/images.go index ec989592..478a756b 100644 --- a/fn_operations/docker_tui/views/images.go +++ b/fn_operations/docker_tui/views/images.go @@ -108,6 +108,11 @@ func (m ImagesModel) Update(msg tea.Msg) (ImagesModel, tea.Cmd) { return m, cmd } +// HandleBack retrocede un nivel. Retorna true si ya estaba en estado base. +func (m *ImagesModel) HandleBack() bool { + return true +} + func (m ImagesModel) View() string { switch m.state { case imagesLoading, imagesAction: diff --git a/fn_operations/docker_tui/views/networks.go b/fn_operations/docker_tui/views/networks.go index 5c3aefac..076603b7 100644 --- a/fn_operations/docker_tui/views/networks.go +++ b/fn_operations/docker_tui/views/networks.go @@ -104,6 +104,11 @@ func (m NetworksModel) Update(msg tea.Msg) (NetworksModel, tea.Cmd) { 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: diff --git a/fn_operations/docker_tui/views/volumes.go b/fn_operations/docker_tui/views/volumes.go index b55d4ec7..67999d8b 100644 --- a/fn_operations/docker_tui/views/volumes.go +++ b/fn_operations/docker_tui/views/volumes.go @@ -104,6 +104,11 @@ func (m VolumesModel) Update(msg tea.Msg) (VolumesModel, tea.Cmd) { return m, cmd } +// HandleBack retrocede un nivel. Retorna true si ya estaba en estado base. +func (m *VolumesModel) HandleBack() bool { + return true +} + func (m VolumesModel) View() string { switch m.state { case volumesLoading, volumesAction: diff --git a/functions/pipelines/docker_tui.go b/functions/pipelines/docker_tui.go new file mode 100644 index 00000000..8eb5d6a8 --- /dev/null +++ b/functions/pipelines/docker_tui.go @@ -0,0 +1,9 @@ +package pipelines + +// DockerTUI es el pipeline principal que compone componentes TUI de DevFactory +// con comandos Docker para crear una aplicacion de terminal interactiva. +// +// Vistas: Containers, Images, Volumes, Networks, Compose. +// Arquitectura: Elm (Model-Update-View) con tabs y state machines. +// +// Implementation: fn_operations/docker_tui/main.go diff --git a/functions/pipelines/docker_tui.md b/functions/pipelines/docker_tui.md new file mode 100644 index 00000000..04af1bba --- /dev/null +++ b/functions/pipelines/docker_tui.md @@ -0,0 +1,61 @@ +--- +name: docker_tui +kind: pipeline +lang: go +domain: infra +version: "1.0.0" +purity: impure +signature: "func main() — TUI fullscreen para gestionar Docker" +description: "Pipeline que compone componentes TUI de DevFactory con comandos Docker para crear una aplicacion de terminal interactiva. Gestiona containers, images, volumes, networks y compose." +tags: [docker, tui, pipeline, infra, bubbletea, devfactory] +uses_functions: + - new_filtered_list_go_tui + - new_list_go_tui + - new_spinner_go_tui + - new_base_model_go_tui + - default_styles_go_tui + - run_fullscreen_go_tui + - run_cmd_timeout_go_shell + - docker_list_containers_go_infra + - docker_start_container_go_infra + - docker_stop_container_go_infra + - docker_container_logs_go_infra + - docker_list_images_go_infra + - docker_remove_image_go_infra +uses_types: + - container_go_docker + - image_go_docker + - volume_go_docker + - network_go_docker + - compose_project_go_docker + - list_model_go_tui + - filtered_list_model_go_tui + - spinner_model_go_tui + - styles_go_tui + - base_model_go_tui + - cmd_result_go_shell +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: + - github.com/charmbracelet/bubbletea + - github.com/lucasdataproyects/devfactory +tested: false +tests: [] +test_file_path: "" +file_path: "fn_operations/docker_tui/main.go" +--- + +## Ejemplo + +```bash +cd fn_operations/docker_tui && go run . +``` + +## Notas + +Pipeline principal del proyecto Docker TUI. Compone funciones de los dominios tui, shell e infra +para crear una aplicacion de terminal con 5 vistas: Containers (start/stop/restart/logs), +Images (list/remove), Volumes (list/remove), Networks (list/remove), Compose (up/down/logs). + +Arquitectura Elm (Model-Update-View) con navegacion por tabs y state machines por vista.