cdd-cli 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.atl/skill-registry.md +30 -0
- package/.editorconfig +12 -0
- package/.eslintrc.json +1 -1
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/.~lock.ROADMAP.md# +1 -0
- package/CHANGELOG.md +80 -0
- package/README.es.md +198 -0
- package/README.md +81 -23
- package/ROADMAP.md +647 -0
- package/SECURITY.md +5 -0
- package/__mocks__/ink.cjs +17 -0
- package/coverage/clover.xml +471 -500
- package/coverage/coverage-final.json +16 -16
- package/coverage/lcov-report/ContainerCreationPrompt.jsx.html +400 -0
- package/coverage/lcov-report/ControlsHUD.jsx.html +256 -0
- package/coverage/lcov-report/components/ContainerCreationPrompt.jsx.html +394 -0
- package/coverage/lcov-report/components/PromptField.jsx.html +229 -0
- package/coverage/lcov-report/components/SuggestionPanel.jsx.html +268 -0
- package/coverage/lcov-report/components/index.html +146 -0
- package/coverage/lcov-report/helpers/constants.js.html +139 -22
- package/coverage/lcov-report/helpers/containerOptionsBuilder.js.html +75 -42
- package/coverage/lcov-report/helpers/dockerHubService.js.html +310 -0
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerActions.js.html +162 -84
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/containerList.js.html +50 -32
- package/coverage/lcov-report/helpers/dockerService/serviceComponents/index.html +21 -21
- package/coverage/lcov-report/helpers/imageNameUtils.js.html +181 -0
- package/coverage/lcov-report/helpers/index.html +84 -54
- package/coverage/lcov-report/helpers/logger.js.html +68 -68
- package/coverage/lcov-report/helpers/safeCall.js.html +15 -15
- package/coverage/lcov-report/helpers/validationHelpers.js.html +66 -114
- package/coverage/lcov-report/hooks/creation/index.html +20 -20
- package/coverage/lcov-report/hooks/creation/useContainerActions.js.html +38 -17
- package/coverage/lcov-report/hooks/creation/useContainerCreation.js.html +593 -89
- package/coverage/lcov-report/hooks/creation/useLogsViewer.js.html +7 -7
- package/coverage/lcov-report/hooks/debug/index.html +5 -5
- package/coverage/lcov-report/hooks/debug/useDebugLogs.js.html +35 -20
- package/coverage/lcov-report/hooks/index.html +40 -40
- package/coverage/lcov-report/hooks/navigation/index.html +19 -19
- package/coverage/lcov-report/hooks/navigation/useContainerSelection.js.html +38 -29
- package/coverage/lcov-report/hooks/useContainerCommandRouter.js.html +119 -80
- package/coverage/lcov-report/hooks/useControls.js.html +306 -123
- package/coverage/lcov-report/hooks/useEraseConfirmation.js.html +8 -8
- package/coverage/lcov-report/hooks/useExitHandler.js.html +50 -41
- package/coverage/lcov-report/index.html +52 -67
- package/coverage/lcov.info +899 -952
- package/dist/App.js +18 -12
- package/dist/components/ContainerCreationPrompt.js +50 -13
- package/dist/components/ContainerList.js +3 -3
- package/dist/components/ContainerRow.js +20 -20
- package/dist/components/ContainerSection.js +3 -3
- package/dist/components/ControlsHUD.js +106 -0
- package/dist/components/Footer.js +2 -2
- package/dist/components/Header.js +7 -7
- package/dist/components/LogViewer.js +3 -3
- package/dist/components/MessageFeedback.js +2 -2
- package/dist/components/PromptField.js +4 -4
- package/dist/components/StatsBar.js +5 -5
- package/dist/components/SuggestionPanel.js +53 -0
- package/dist/components/UsageMenu.js +3 -3
- package/dist/helpers/appInfo.js +7 -7
- package/dist/helpers/constants.js +154 -1
- package/dist/helpers/containerOptionsBuilder.js +3 -3
- package/dist/helpers/dockerHubService.js +111 -0
- package/dist/helpers/dockerService/dockerService.js +1 -1
- package/dist/helpers/dockerService/serviceComponents/containerActions.js +99 -40
- package/dist/helpers/dockerService/serviceComponents/containerList.js +11 -11
- package/dist/helpers/dockerService/serviceComponents/containerLogs.js +9 -9
- package/dist/helpers/dockerService/serviceComponents/containerStats.js +5 -5
- package/dist/helpers/dockerService/serviceComponents/imageUtils.js +1 -1
- package/dist/helpers/exitWithMessage.js +10 -10
- package/dist/helpers/imageNameUtils.js +32 -0
- package/dist/helpers/logger.js +13 -13
- package/dist/helpers/safeCall.js +2 -2
- package/dist/helpers/validationHelpers.js +76 -21
- package/dist/hooks/creation/useContainerActions.js +28 -11
- package/dist/hooks/creation/useContainerCreation.js +452 -62
- package/dist/hooks/creation/useLogsViewer.js +2 -2
- package/dist/hooks/debug/useDebugLogs.js +4 -4
- package/dist/hooks/useContainerCommandRouter.js +14 -14
- package/dist/hooks/useContainers.js +3 -3
- package/dist/hooks/useControls.js +85 -38
- package/dist/hooks/useEraseConfirmation.js +3 -3
- package/dist/index.js +9 -2
- package/jest.config.cjs +7 -0
- package/package.json +7 -3
- package/src/App.jsx +39 -16
- package/src/components/ContainerCreationPrompt.jsx +54 -10
- package/src/components/ContainerList.jsx +3 -3
- package/src/components/ContainerRow.jsx +19 -16
- package/src/components/ContainerSection.jsx +3 -3
- package/src/components/ControlsHUD.jsx +66 -0
- package/src/components/Footer.jsx +2 -2
- package/src/components/Header.jsx +7 -7
- package/src/components/LogViewer.jsx +5 -3
- package/src/components/MessageFeedback.jsx +2 -2
- package/src/components/PromptField.jsx +4 -4
- package/src/components/StatsBar.jsx +11 -7
- package/src/components/SuggestionPanel.jsx +61 -0
- package/src/components/UsageMenu.jsx +18 -13
- package/src/helpers/appInfo.js +7 -7
- package/src/helpers/constants.js +48 -9
- package/src/helpers/containerOptionsBuilder.js +16 -5
- package/src/helpers/dockerHubService.js +75 -0
- package/src/helpers/dockerService/dockerService.js +1 -1
- package/src/helpers/dockerService/serviceComponents/containerActions.js +87 -61
- package/src/helpers/dockerService/serviceComponents/containerList.js +31 -25
- package/src/helpers/dockerService/serviceComponents/containerLogs.js +41 -26
- package/src/helpers/dockerService/serviceComponents/containerStats.js +13 -11
- package/src/helpers/dockerService/serviceComponents/imageUtils.js +5 -4
- package/src/helpers/exitWithMessage.js +13 -7
- package/src/helpers/imageNameUtils.js +32 -0
- package/src/helpers/logger.js +15 -16
- package/src/helpers/safeCall.js +2 -2
- package/src/helpers/validationHelpers.js +13 -29
- package/src/hooks/creation/useContainerActions.js +32 -12
- package/src/hooks/creation/useContainerCreation.js +293 -47
- package/src/hooks/creation/useLogsViewer.js +2 -2
- package/src/hooks/debug/useDebugLogs.js +15 -10
- package/src/hooks/navigation/useContainerSelection.js +17 -14
- package/src/hooks/useContainerCommandRouter.js +71 -58
- package/src/hooks/useContainers.js +4 -4
- package/src/hooks/useControls.js +135 -72
- package/src/hooks/useEraseConfirmation.js +3 -3
- package/src/hooks/useExitHandler.js +29 -26
- package/src/index.js +8 -4
- package/test/ContainerCreationPrompt.dom.test.js +313 -0
- package/test/ControlsHUD.dom.test.js +125 -0
- package/test/SuggestionPanel.dom.test.js +83 -0
- package/test/constants.test.js +41 -0
- package/test/dockerHubService.test.js +213 -0
- package/test/logger.test.js +58 -0
- package/test/resolveImageTag.test.js +26 -0
- package/test/useContainerCreation.dom.test.js +428 -2
- package/test/useContainerCreationHub.dom.test.js +184 -0
- package/test/useControls.dom.test.js +406 -4
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
# 🗺️ CDD — CLI Docker Dashboard: Roadmap de Desarrollo
|
|
2
|
+
|
|
3
|
+
> **Versión actual:** v4.0.0
|
|
4
|
+
> **Fecha:** 2026-04-28
|
|
5
|
+
> **Proyecto:** CDD es un dashboard TUI (Terminal UI) para gestionar contenedores Docker desde la línea de comandos. Construido con React/Ink, permite inspeccionar, iniciar, detener, crear y monitorear contenedores sin salir de la terminal.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📋 Resumen del Roadmap
|
|
10
|
+
|
|
11
|
+
| Fase | Versión | Foco Principal | Features incluidas |
|
|
12
|
+
|------|---------|---------------|-------------------|
|
|
13
|
+
| **Fase 0** | — | Deuda Técnica (Tests) | 8A, 8B, 8C, 8D |
|
|
14
|
+
| **Fase 1** | v4.1.0 | Navegación y UX crítica | 3A, 3B, 3D |
|
|
15
|
+
| **Fase 2** | v4.2.0 | Observabilidad y salud | 2B, 2C, 2D, 3C |
|
|
16
|
+
| **Fase 3** | v4.3.0 | Wizard de Creación mejorado | 1A, 1B, 1C |
|
|
17
|
+
| **Fase 4** | v5.0.0 | Gestión de Imágenes + Conectividad | 4A, 4B, 4C, 5B |
|
|
18
|
+
| **Backlog** | — | Ideas de baja prioridad | 2A, 5A, 6.x, 1D, 4D |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🚨 Fase 0 — Deuda Técnica (Prerrequisito bloqueante)
|
|
23
|
+
|
|
24
|
+
> **Objetivo:** Cubrir con tests los módulos críticos antes de agregar cualquier feature nueva. Sin esta base, cada iteración rompe cosas silenciosamente.
|
|
25
|
+
|
|
26
|
+
Esta fase no tiene versión de release asociada — es trabajo de infraestructura de calidad que debe completarse antes de la v4.1.0.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### 🔴 8A — Tests: `containerStats.js`
|
|
31
|
+
|
|
32
|
+
**Prioridad:** 🟠 Muy Alta
|
|
33
|
+
|
|
34
|
+
**Por qué es crítico:** Este módulo consume la API de stats de Docker en tiempo real (streaming). Sin tests, cualquier cambio en el formato de datos del daemon o en la lógica de parsing puede romper silenciosamente las métricas mostradas al usuario.
|
|
35
|
+
|
|
36
|
+
**Sub-tareas técnicas:**
|
|
37
|
+
- [ ] Identificar todas las funciones exportadas por `containerStats.js`
|
|
38
|
+
- [ ] Mockear el cliente Docker (`dockerode` o equivalente) para respuestas de stream
|
|
39
|
+
- [ ] Escribir test: parseo correcto de CPU % desde datos crudos del daemon
|
|
40
|
+
- [ ] Escribir test: parseo correcto de memoria usada / límite
|
|
41
|
+
- [ ] Escribir test: manejo de contenedor detenido (stats vacíos o null)
|
|
42
|
+
- [ ] Escribir test: manejo de error en stream (container no encontrado, daemon caído)
|
|
43
|
+
- [ ] Verificar cobertura >= 80% del módulo
|
|
44
|
+
|
|
45
|
+
**Criterio de aceptación:**
|
|
46
|
+
- Todos los tests pasan en CI
|
|
47
|
+
- Los casos de error (container inexistente, stream interrumpido) están cubiertos
|
|
48
|
+
- No hay lógica de transformación de datos sin test
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### 🔴 8B — Tests: `containerLogs.js`
|
|
53
|
+
|
|
54
|
+
**Prioridad:** 🟠 Muy Alta
|
|
55
|
+
|
|
56
|
+
**Por qué es crítico:** Los logs son uno de los flujos más usados del TUI. Este módulo maneja streaming de logs, buffering y posiblemente filtrado. Un bug aquí afecta directamente la experiencia de depuración del usuario.
|
|
57
|
+
|
|
58
|
+
**Sub-tareas técnicas:**
|
|
59
|
+
- [ ] Identificar funciones exportadas: fetch de logs, streaming, parsing de timestamps
|
|
60
|
+
- [ ] Mockear stream de logs de Docker con datos sintéticos (stdout/stderr multiplex)
|
|
61
|
+
- [ ] Escribir test: lectura de logs con formato TTY
|
|
62
|
+
- [ ] Escribir test: lectura de logs sin TTY (stream multiplexado con header)
|
|
63
|
+
- [ ] Escribir test: logs vacíos (contenedor nuevo sin salida)
|
|
64
|
+
- [ ] Escribir test: truncado/límite de líneas si existe lógica de límite
|
|
65
|
+
- [ ] Escribir test: error al acceder a logs de contenedor inexistente
|
|
66
|
+
|
|
67
|
+
**Criterio de aceptación:**
|
|
68
|
+
- Los dos modos de stream (TTY y multiplexado) están testeados
|
|
69
|
+
- El módulo se puede importar e invocar sin un daemon real corriendo
|
|
70
|
+
- Cobertura >= 80%
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### 🔴 8C — Tests: `imageUtils.js`
|
|
75
|
+
|
|
76
|
+
**Prioridad:** 🟠 Muy Alta
|
|
77
|
+
|
|
78
|
+
**Por qué es crítico:** Las utilidades de imagen son reutilizadas en múltiples vistas (lista de contenedores, wizard de creación, gestión de imágenes). Un bug en formateo o filtrado afecta múltiples partes de la UI.
|
|
79
|
+
|
|
80
|
+
**Sub-tareas técnicas:**
|
|
81
|
+
- [ ] Mapear todas las funciones utilitarias del módulo
|
|
82
|
+
- [ ] Escribir test: formateo de nombres de imagen (tag, digest, sin tag → "latest")
|
|
83
|
+
- [ ] Escribir test: cálculo/formateo de tamaño de imagen (bytes → MB/GB)
|
|
84
|
+
- [ ] Escribir test: filtrado o búsqueda de imágenes por nombre
|
|
85
|
+
- [ ] Escribir test: manejo de imágenes sin nombre (`<none>:<none>`)
|
|
86
|
+
- [ ] Escribir test: parseo de fecha de creación
|
|
87
|
+
|
|
88
|
+
**Criterio de aceptación:**
|
|
89
|
+
- Todas las funciones exportadas tienen al menos un test positivo y uno negativo
|
|
90
|
+
- Los edge cases (`<none>` tags, tamaños cero, fechas inválidas) están cubiertos
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### 🔴 8D — Tests: `ContainerRow.jsx`
|
|
95
|
+
|
|
96
|
+
**Prioridad:** 🟠 Muy Alta
|
|
97
|
+
|
|
98
|
+
**Por qué es crítico:** `ContainerRow` es el componente más renderizado del TUI — aparece por cada contenedor en la lista. Cualquier regresión visual o de estado en este componente es inmediatamente visible para el usuario.
|
|
99
|
+
|
|
100
|
+
**Sub-tareas técnicas:**
|
|
101
|
+
- [ ] Configurar testing de componentes Ink/React (ink-testing-library o equivalente)
|
|
102
|
+
- [ ] Escribir test: render de contenedor en estado `running`
|
|
103
|
+
- [ ] Escribir test: render de contenedor en estado `exited` / `stopped`
|
|
104
|
+
- [ ] Escribir test: render de contenedor seleccionado (highlight / foco activo)
|
|
105
|
+
- [ ] Escribir test: truncado de nombre largo de contenedor
|
|
106
|
+
- [ ] Escribir test: muestra correcta de imagen y puerto(s)
|
|
107
|
+
- [ ] Escribir snapshot test para detectar regresiones de layout
|
|
108
|
+
|
|
109
|
+
**Criterio de aceptación:**
|
|
110
|
+
- El componente puede renderizarse en tests sin un terminal real
|
|
111
|
+
- Los tres estados principales (running, exited, selected) tienen cobertura
|
|
112
|
+
- Snapshot actualizado y en control de versiones
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 🧭 Fase 1 — v4.1.0: Navegación y UX crítica
|
|
117
|
+
|
|
118
|
+
> **Objetivo:** Hacer que encontrar y manejar contenedores sea rápido y fluido, independientemente de cuántos haya corriendo.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### 🔴 3A — Filtro de contenedores
|
|
123
|
+
|
|
124
|
+
**Prioridad:** 🔴 Suprema
|
|
125
|
+
|
|
126
|
+
**Descripción:** El usuario debe poder filtrar la lista de contenedores en tiempo real escribiendo texto. El filtro debe aplicarse sobre nombre del contenedor, imagen y estado. Es la feature de mayor impacto en usabilidad para usuarios con muchos contenedores.
|
|
127
|
+
|
|
128
|
+
**Sub-tareas técnicas:**
|
|
129
|
+
- [ ] Agregar estado `filterQuery` en el componente de lista de contenedores
|
|
130
|
+
- [ ] Implementar keybinding para activar el modo filtro (ej. `/` o `f`)
|
|
131
|
+
- [ ] Renderizar un input de texto en el footer/header cuando el modo filtro está activo
|
|
132
|
+
- [ ] Filtrar la lista derivada en tiempo real mientras el usuario escribe (case-insensitive)
|
|
133
|
+
- [ ] Aplicar filtro sobre: nombre del contenedor, nombre de imagen, estado
|
|
134
|
+
- [ ] Permitir salir del modo filtro con `Esc` y limpiar el query
|
|
135
|
+
- [ ] Mantener la selección actual si el contenedor seleccionado sigue visible tras filtrar
|
|
136
|
+
- [ ] Mostrar contador de resultados (ej. `3 / 12 contenedores`)
|
|
137
|
+
|
|
138
|
+
**Criterio de aceptación:**
|
|
139
|
+
- Escribir `/web` en la lista muestra solo contenedores cuyo nombre o imagen contiene "web"
|
|
140
|
+
- `Esc` limpia el filtro y restaura la lista completa
|
|
141
|
+
- El contador de resultados es preciso
|
|
142
|
+
- Con lista vacía tras filtrar, se muestra mensaje "Sin resultados para '{query}'"
|
|
143
|
+
|
|
144
|
+
**Testing:**
|
|
145
|
+
- Test: filtrar por nombre exacto devuelve solo ese contenedor
|
|
146
|
+
- Test: filtrar por imagen devuelve contenedores que usan esa imagen
|
|
147
|
+
- Test: filtro vacío devuelve todos los contenedores
|
|
148
|
+
- Test: `Esc` limpia el estado de filtro
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### 🟡 3B — Scroll real en logs (todos los logs disponibles)
|
|
153
|
+
|
|
154
|
+
**Prioridad:** 🟡 Alta
|
|
155
|
+
|
|
156
|
+
**Descripción:** El panel de logs debe mostrar TODOS los logs disponibles del contenedor (no solo los últimos N), con scroll real que permita navegar hacia arriba y abajo. El usuario quiere poder ir al inicio del log de un contenedor y leer la historia completa, como hace `docker logs` sin `--tail`.
|
|
157
|
+
|
|
158
|
+
**Sub-tareas técnicas:**
|
|
159
|
+
- [ ] Cambiar la petición de logs para usar `tail: 'all'` en lugar de un límite fijo
|
|
160
|
+
- [ ] Implementar buffer de líneas en el estado del componente de logs
|
|
161
|
+
- [ ] Agregar índice de scroll (línea superior visible) en el estado
|
|
162
|
+
- [ ] Implementar scroll con teclas `↑` / `↓` (de línea en línea)
|
|
163
|
+
- [ ] Implementar scroll con `PgUp` / `PgDn` (saltos de página)
|
|
164
|
+
- [ ] Implementar `Home` / `End` para ir al inicio/fin del buffer
|
|
165
|
+
- [ ] Calcular dinámicamente cuántas líneas caben en el viewport actual
|
|
166
|
+
- [ ] Agregar indicador visual de posición (ej. `línea 120 / 3042` en el footer)
|
|
167
|
+
- [ ] Para logs en streaming (follow): auto-scroll al final a menos que el usuario haya scrolleado hacia arriba
|
|
168
|
+
|
|
169
|
+
**Criterio de aceptación:**
|
|
170
|
+
- `docker logs` de un contenedor con 5000 líneas muestra todas las 5000 líneas navegables
|
|
171
|
+
- El usuario puede llegar al inicio con `Home` y al final con `End`
|
|
172
|
+
- Al activar "follow" desde el inicio, el scroll sigue bajando automáticamente
|
|
173
|
+
- Si el usuario scrollea hacia arriba en modo follow, el auto-scroll se pausa
|
|
174
|
+
|
|
175
|
+
**Testing:**
|
|
176
|
+
- Test: buffer contiene todas las líneas recibidas del stream
|
|
177
|
+
- Test: scroll respeta los límites (no pasa de 0 ni del máximo)
|
|
178
|
+
- Test: auto-scroll se desactiva cuando el usuario scrollea manualmente
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### 🟠 3D — Ordenamiento de la lista de contenedores
|
|
183
|
+
|
|
184
|
+
**Prioridad:** 🟠 Muy Alta
|
|
185
|
+
|
|
186
|
+
**Descripción:** El usuario debe poder ordenar la lista de contenedores por diferentes criterios: nombre, estado, imagen, y tiempo de creación/uptime. El orden debe ser configurable con atajos de teclado y debe persistir durante la sesión.
|
|
187
|
+
|
|
188
|
+
**Sub-tareas técnicas:**
|
|
189
|
+
- [ ] Definir los criterios de ordenamiento soportados: `name`, `status`, `image`, `created`
|
|
190
|
+
- [ ] Agregar estado `sortBy` y `sortDirection` (asc/desc) en el componente de lista
|
|
191
|
+
- [ ] Implementar función de comparación para cada criterio
|
|
192
|
+
- [ ] Agregar keybindings para ciclar entre criterios (ej. `s` para ciclar sort)
|
|
193
|
+
- [ ] Mostrar el criterio activo y la dirección en el header de la lista (ej. `↑ nombre`)
|
|
194
|
+
- [ ] Toggle de dirección al presionar el mismo criterio dos veces
|
|
195
|
+
- [ ] El sort debe ser compatible con el filtro activo (3A): ordenar el resultado filtrado
|
|
196
|
+
|
|
197
|
+
**Criterio de aceptación:**
|
|
198
|
+
- Presionar el keybinding ordena la lista visualmente de forma inmediata
|
|
199
|
+
- Presionar el mismo criterio invierte el orden (asc → desc)
|
|
200
|
+
- El indicador de sort activo es visible en la UI
|
|
201
|
+
- Filtro y sort funcionan juntos sin conflicto
|
|
202
|
+
|
|
203
|
+
**Testing:**
|
|
204
|
+
- Test: ordenar por nombre produce lista en orden alfabético
|
|
205
|
+
- Test: ordenar por estado agrupa running antes de exited
|
|
206
|
+
- Test: toggle de dirección invierte el orden correctamente
|
|
207
|
+
- Test: sort se aplica sobre la lista ya filtrada
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### 📐 Testing — Fase 1
|
|
212
|
+
|
|
213
|
+
Todos los features de esta fase tocan lógica de estado y transformación de datos. Priorizar:
|
|
214
|
+
- Tests de la función de filtrado (pura, sin UI)
|
|
215
|
+
- Tests de la función de sort (pura, sin UI)
|
|
216
|
+
- Tests del buffer de scroll de logs
|
|
217
|
+
- Actualizar snapshots de `ContainerRow` si el indicador de sort afecta el header
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 🔬 Fase 2 — v4.2.0: Observabilidad y Salud de Contenedores
|
|
222
|
+
|
|
223
|
+
> **Objetivo:** Dar al usuario visibilidad real del estado interno de sus contenedores: métricas expandidas, health checks y alertas de cambio de estado.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### 🟡 2B — Stats expandidos (Disk I/O, memoria en MB, tasa de red)
|
|
228
|
+
|
|
229
|
+
**Prioridad:** 🟡 Alta
|
|
230
|
+
|
|
231
|
+
**Descripción:** El panel de estadísticas actual muestra métricas básicas. Debe expandirse para mostrar Disk I/O (read/write en bytes/s), uso de memoria en MB y GB (no solo porcentaje), y tasa de red (inbound/outbound en KB/s o MB/s). Los datos provienen de la misma API de stats de Docker.
|
|
232
|
+
|
|
233
|
+
**Sub-tareas técnicas:**
|
|
234
|
+
- [ ] Revisar el payload completo de `/containers/{id}/stats` y mapear campos disponibles
|
|
235
|
+
- [ ] Extraer `blkio_stats` para Disk I/O (read/write acumulados → calcular delta entre muestras)
|
|
236
|
+
- [ ] Extraer `memory_stats.usage` y `memory_stats.limit` y formatear en MB/GB
|
|
237
|
+
- [ ] Extraer `networks` para calcular rx_bytes/tx_bytes delta entre muestras
|
|
238
|
+
- [ ] Implementar función de cálculo de tasa (delta / intervalo de muestreo)
|
|
239
|
+
- [ ] Diseñar layout del panel de stats con las nuevas métricas
|
|
240
|
+
- [ ] Formatear automáticamente (KB, MB, GB según magnitud)
|
|
241
|
+
|
|
242
|
+
**Criterio de aceptación:**
|
|
243
|
+
- El panel muestra: CPU%, Memoria (usado/límite en MB), Disk Read, Disk Write, Net In, Net Out
|
|
244
|
+
- Los valores de tasa (Disk/Net) son calculados correctamente como deltas entre dos muestras
|
|
245
|
+
- El formateo cambia dinámicamente (ej. "1.2 MB/s" no "1234567 B/s")
|
|
246
|
+
|
|
247
|
+
**Testing:**
|
|
248
|
+
- Test: cálculo de delta de bytes entre dos muestras consecutivas
|
|
249
|
+
- Test: formateo de bytes a unidad legible
|
|
250
|
+
- Test: manejo de primera muestra (no hay delta previo → mostrar 0 o "—")
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### 🟡 2C — Health Check visible
|
|
255
|
+
|
|
256
|
+
**Prioridad:** 🟡 Alta
|
|
257
|
+
|
|
258
|
+
**Descripción:** Si un contenedor tiene un health check configurado, el TUI debe mostrar su estado (`healthy`, `unhealthy`, `starting`) de forma destacada. También debe mostrar el resultado del último chequeo (exit code y output). Muchos usuarios no saben que sus contenedores están `unhealthy` hasta que algo falla.
|
|
259
|
+
|
|
260
|
+
**Sub-tareas técnicas:**
|
|
261
|
+
- [ ] Leer `State.Health` del endpoint `GET /containers/{id}/json`
|
|
262
|
+
- [ ] Mostrar badge de estado de health en `ContainerRow` cuando existe health check
|
|
263
|
+
- [ ] En el panel de detalle, mostrar: estado, último chequeo (timestamp), output del último test
|
|
264
|
+
- [ ] Diferenciar visualmente: sin health check / healthy / starting / unhealthy
|
|
265
|
+
- [ ] Para `unhealthy`, mostrar el output del log del health check para diagnóstico
|
|
266
|
+
|
|
267
|
+
**Criterio de aceptación:**
|
|
268
|
+
- Un contenedor `unhealthy` muestra un indicador visual distinto en la lista
|
|
269
|
+
- El panel de detalle muestra el output del último health check fallido
|
|
270
|
+
- Un contenedor sin health check configurado no muestra el badge
|
|
271
|
+
|
|
272
|
+
**Testing:**
|
|
273
|
+
- Test: componente recibe `Health: null` → no renderiza badge
|
|
274
|
+
- Test: componente recibe `Health.Status: "unhealthy"` → renderiza badge de error
|
|
275
|
+
- Test: output del último log se muestra correctamente truncado
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### 🟡 2D — Notificaciones de estado
|
|
280
|
+
|
|
281
|
+
**Prioridad:** 🟡 Alta
|
|
282
|
+
|
|
283
|
+
**Descripción:** Cuando un contenedor cambia de estado (ej. pasa de `running` a `exited`, o un health check pasa a `unhealthy`), el TUI debe mostrar una notificación temporal no bloqueante (tipo toast) en la esquina de la pantalla. Esto permite al usuario seguir trabajando y ser alertado de cambios sin que el UI quede bloqueado.
|
|
284
|
+
|
|
285
|
+
**Sub-tareas técnicas:**
|
|
286
|
+
- [ ] Implementar sistema de polling de estados de contenedores (o usar Docker events API `GET /events`)
|
|
287
|
+
- [ ] Preferir Docker events API para reactividad real vs polling
|
|
288
|
+
- [ ] Crear componente `Notification` / `Toast` con texto, tipo (info/warn/error) y auto-dismiss
|
|
289
|
+
- [ ] Implementar cola de notificaciones con tiempo de vida configurable (ej. 5 segundos)
|
|
290
|
+
- [ ] Disparar notificación cuando: `running → exited`, `healthy → unhealthy`, contenedor creado/eliminado externamente
|
|
291
|
+
- [ ] Posicionar el toast en esquina inferior derecha sin bloquear la lista
|
|
292
|
+
|
|
293
|
+
**Criterio de aceptación:**
|
|
294
|
+
- Un contenedor que se detiene externamente (`docker stop` en otra terminal) genera un toast en el TUI en menos de 2 segundos
|
|
295
|
+
- El toast desaparece automáticamente tras 5 segundos
|
|
296
|
+
- Múltiples notificaciones simultáneas se apilan sin solaparse
|
|
297
|
+
- Las notificaciones no interrumpen el flujo de teclado del usuario
|
|
298
|
+
|
|
299
|
+
**Testing:**
|
|
300
|
+
- Test: la cola de notificaciones agrega y remueve correctamente
|
|
301
|
+
- Test: el componente Toast se renderiza con los tipos correctos (info/warn/error)
|
|
302
|
+
- Test: dos notificaciones se apilan sin reemplazarse
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### 🟢 3C — Filtro de texto en logs
|
|
307
|
+
|
|
308
|
+
**Prioridad:** 🟢 Media
|
|
309
|
+
|
|
310
|
+
**Descripción:** Dentro del panel de logs (implementado en 3B), el usuario puede activar un filtro de texto para mostrar solo las líneas que contienen el patrón buscado. Compatible con el scroll completo de 3B — filtra el buffer completo, no solo las líneas visibles.
|
|
311
|
+
|
|
312
|
+
**Sub-tareas técnicas:**
|
|
313
|
+
- [ ] Agregar keybinding para activar filtro de logs (ej. `f` dentro del panel de logs)
|
|
314
|
+
- [ ] Renderizar input de texto para el patrón de búsqueda
|
|
315
|
+
- [ ] Filtrar el buffer completo de líneas contra el patrón (case-insensitive por defecto)
|
|
316
|
+
- [ ] Resaltar en cada línea visible el texto que coincide con el patrón
|
|
317
|
+
- [ ] Mostrar contador de líneas coincidentes (ej. `47 / 3042 líneas`)
|
|
318
|
+
- [ ] `Esc` limpia el filtro y restaura el buffer completo
|
|
319
|
+
- [ ] Si el filtro está activo, el scroll opera sobre el buffer filtrado
|
|
320
|
+
|
|
321
|
+
**Criterio de aceptación:**
|
|
322
|
+
- Escribir "ERROR" muestra solo líneas con "ERROR", resaltadas
|
|
323
|
+
- El contador refleja las líneas coincidentes sobre el total
|
|
324
|
+
- `Esc` restaura todas las líneas y el scroll vuelve a la posición anterior
|
|
325
|
+
- El filtro opera sobre el buffer completo, no solo las líneas visibles
|
|
326
|
+
|
|
327
|
+
**Testing:**
|
|
328
|
+
- Test: filtro vacío devuelve el buffer completo
|
|
329
|
+
- Test: filtro "ERROR" sobre buffer con 3 líneas ERROR devuelve exactamente 3
|
|
330
|
+
- Test: el resaltado de texto funciona correctamente con el patrón
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
### 📐 Testing — Fase 2
|
|
335
|
+
|
|
336
|
+
- Tests para la lógica de cálculo de deltas de stats (2B) — puramente funcional
|
|
337
|
+
- Tests del parser de health check status (2C)
|
|
338
|
+
- Tests de la cola de notificaciones (2D) — insert, auto-dismiss, límite de cola
|
|
339
|
+
- Tests del filtro de logs sobre buffer (3C)
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 🧙 Fase 3 — v4.3.0: Wizard de Creación Mejorado
|
|
344
|
+
|
|
345
|
+
> **Objetivo:** Hacer que crear contenedores desde el TUI sea tan completo y claro como usar `docker run` con sus flags más importantes.
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
### 🟡 1A — Volúmenes en el Wizard
|
|
350
|
+
|
|
351
|
+
**Prioridad:** 🟡 Alta
|
|
352
|
+
|
|
353
|
+
**Descripción:** El wizard de creación de contenedores debe ofrecer al usuario elegir explícitamente la estrategia de persistencia de datos: volumen nombrado (datos persisten entre reinicios), bind mount (carpeta local), `tmpfs` (en memoria, datos volátiles) o ninguno. Esto evita el error común de crear contenedores sin entender qué pasa con sus datos al detenerlos.
|
|
354
|
+
|
|
355
|
+
**Sub-tareas técnicas:**
|
|
356
|
+
- [ ] Agregar paso "Almacenamiento" al wizard con selector de tipo: `none`, `named volume`, `bind mount`, `tmpfs`
|
|
357
|
+
- [ ] Para `named volume`: input para nombre del volumen (o auto-generar basado en el nombre del contenedor) y ruta del mountpoint dentro del contenedor
|
|
358
|
+
- [ ] Para `bind mount`: input para ruta local (host) y ruta destino en el contenedor; validar que la ruta local existe
|
|
359
|
+
- [ ] Para `tmpfs`: input para ruta del mountpoint en el contenedor; input opcional para tamaño máximo
|
|
360
|
+
- [ ] Traducir la selección a los flags correctos en el payload de creación (`Volumes`, `HostConfig.Binds`, `HostConfig.Mounts`)
|
|
361
|
+
- [ ] Mostrar resumen de la configuración elegida en el paso final del wizard
|
|
362
|
+
|
|
363
|
+
**Criterio de aceptación:**
|
|
364
|
+
- Crear un contenedor con volumen nombrado genera un volumen persistente verificable con `docker volume ls`
|
|
365
|
+
- Crear con `tmpfs` no genera volumen persistente
|
|
366
|
+
- El resumen final del wizard muestra la configuración de almacenamiento seleccionada
|
|
367
|
+
- Un bind mount a ruta inexistente muestra error de validación antes de continuar
|
|
368
|
+
|
|
369
|
+
**Testing:**
|
|
370
|
+
- Test: traducción de selección `named volume` al payload de API correcto
|
|
371
|
+
- Test: traducción de `tmpfs` al payload correcto
|
|
372
|
+
- Test: validación de ruta local en bind mount (path no existe → error)
|
|
373
|
+
- Test: `none` no incluye campos de volumen en el payload
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
### 🟡 1B — Redes en el Wizard
|
|
378
|
+
|
|
379
|
+
**Prioridad:** 🟡 Alta
|
|
380
|
+
|
|
381
|
+
**Descripción:** El wizard debe permitir al usuario elegir a qué red(es) conectar el contenedor al crearlo. Debe listar las redes disponibles en el daemon, permitir seleccionar una o crear una nueva red, y permitir configurar aliases dentro de la red. Esto es clave para que los contenedores se comuniquen entre sí.
|
|
382
|
+
|
|
383
|
+
**Sub-tareas técnicas:**
|
|
384
|
+
- [ ] Agregar paso "Red" al wizard
|
|
385
|
+
- [ ] Listar redes existentes con `GET /networks` y presentarlas en un selector
|
|
386
|
+
- [ ] Mostrar tipo de red junto al nombre (bridge, host, none, overlay)
|
|
387
|
+
- [ ] Opción para no conectar a ninguna red (`--network none`)
|
|
388
|
+
- [ ] Opción para crear una nueva red bridge con nombre personalizado (invocar `POST /networks/create` antes de crear el contenedor)
|
|
389
|
+
- [ ] Input opcional para alias dentro de la red
|
|
390
|
+
- [ ] Traducir selección al campo `NetworkingConfig` del payload de creación
|
|
391
|
+
|
|
392
|
+
**Criterio de aceptación:**
|
|
393
|
+
- El contenedor creado aparece en la red seleccionada (verificable con `docker network inspect`)
|
|
394
|
+
- Si se crea una red nueva, esta existe antes de que el contenedor sea creado
|
|
395
|
+
- Seleccionar `none` crea el contenedor sin interfaces de red
|
|
396
|
+
|
|
397
|
+
**Testing:**
|
|
398
|
+
- Test: el listado de redes consume correctamente el endpoint de Docker
|
|
399
|
+
- Test: traducción de selección al campo `NetworkingConfig`
|
|
400
|
+
- Test: flujo de creación de red nueva → asociación al contenedor
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
### 🟢 1C — Restart Policy en el Wizard
|
|
405
|
+
|
|
406
|
+
**Prioridad:** 🟢 Media
|
|
407
|
+
|
|
408
|
+
**Descripción:** El wizard debe incluir un selector de política de reinicio del contenedor: `no` (nunca reiniciar), `always` (siempre), `on-failure` (solo si sale con error, con límite de reintentos opcional), `unless-stopped`. Este campo es simple pero evita confusión a usuarios que esperan que sus contenedores sobrevivan a reinicios del daemon.
|
|
409
|
+
|
|
410
|
+
**Sub-tareas técnicas:**
|
|
411
|
+
- [ ] Agregar campo "Restart Policy" al wizard (selector entre las 4 opciones)
|
|
412
|
+
- [ ] Para `on-failure`: mostrar input adicional para `MaximumRetryCount` (0 = sin límite)
|
|
413
|
+
- [ ] Mostrar descripción breve de cada opción junto al nombre
|
|
414
|
+
- [ ] Traducir a `HostConfig.RestartPolicy` en el payload
|
|
415
|
+
|
|
416
|
+
**Criterio de aceptación:**
|
|
417
|
+
- Seleccionar `always` crea el contenedor con `RestartPolicy.Name: "always"`
|
|
418
|
+
- Seleccionar `on-failure` con 3 reintentos crea el contenedor con `MaximumRetryCount: 3`
|
|
419
|
+
- La descripción de cada opción es visible en el UI durante la selección
|
|
420
|
+
|
|
421
|
+
**Testing:**
|
|
422
|
+
- Test: traducción de cada opción al campo del payload correcto
|
|
423
|
+
- Test: `on-failure` incluye `MaximumRetryCount` en el payload
|
|
424
|
+
- Test: valor por defecto es `no`
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
### 📐 Testing — Fase 3
|
|
429
|
+
|
|
430
|
+
- Tests de cada paso del wizard por separado (sin necesidad de correr el wizard completo)
|
|
431
|
+
- Tests de la función que construye el payload final de creación con todas las opciones nuevas
|
|
432
|
+
- Test de integración del wizard end-to-end con un mock del cliente Docker
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## 🖼️ Fase 4 — v5.0.0: Gestión de Imágenes y Conectividad
|
|
437
|
+
|
|
438
|
+
> **Objetivo:** Dar al usuario control sobre imágenes locales y abrir el TUI a entornos Docker remotos.
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
### 🟢 4A — Vista de imágenes locales
|
|
443
|
+
|
|
444
|
+
**Prioridad:** 🟢 Media
|
|
445
|
+
|
|
446
|
+
**Descripción:** Agregar una vista dedicada que liste todas las imágenes Docker locales con su nombre, tag, tamaño y fecha de creación. Debe permitir eliminar imágenes no usadas y ver qué contenedores usan cada imagen.
|
|
447
|
+
|
|
448
|
+
**Sub-tareas técnicas:**
|
|
449
|
+
- [ ] Agregar tab / vista "Imágenes" navegable desde el menú principal (keybinding `i` o tab)
|
|
450
|
+
- [ ] Consumir `GET /images/json` para listar imágenes
|
|
451
|
+
- [ ] Renderizar tabla: nombre:tag, ID (short), tamaño, fecha
|
|
452
|
+
- [ ] Acción de eliminar imagen seleccionada (`DELETE /images/{id}`) con confirmación
|
|
453
|
+
- [ ] Manejar error de imagen en uso (Docker retorna 409 → mostrar mensaje claro)
|
|
454
|
+
- [ ] Mostrar imágenes sin tag (`<none>:<none>`) con label "dangling"
|
|
455
|
+
|
|
456
|
+
**Criterio de aceptación:**
|
|
457
|
+
- La vista lista todas las imágenes locales incluyendo las dangling
|
|
458
|
+
- Eliminar una imagen en uso muestra un mensaje de error explicativo, no un crash
|
|
459
|
+
- Eliminar una imagen no usada la remueve y refresca la lista
|
|
460
|
+
|
|
461
|
+
**Testing:**
|
|
462
|
+
- Test: render de imagen sin tag (dangling)
|
|
463
|
+
- Test: error 409 al borrar imagen en uso → mensaje claro, no excepción
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
### 🟢 4B — Pull de imagen sin crear contenedor
|
|
468
|
+
|
|
469
|
+
**Prioridad:** 🟢 Media
|
|
470
|
+
|
|
471
|
+
**Descripción:** Desde la vista de imágenes (4A), el usuario puede hacer pull de cualquier imagen de Docker Hub o registry privado sin necesidad de crear un contenedor. Debe mostrar el progreso del pull en tiempo real.
|
|
472
|
+
|
|
473
|
+
**Sub-tareas técnicas:**
|
|
474
|
+
- [ ] Agregar acción "Pull imagen" en la vista de imágenes
|
|
475
|
+
- [ ] Modal/panel con input para el nombre de la imagen (ej. `nginx:latest`)
|
|
476
|
+
- [ ] Consumir `POST /images/create` con stream de respuesta para mostrar progreso
|
|
477
|
+
- [ ] Parsear las capas del progreso del pull y mostrar barra o lista de estado por capa
|
|
478
|
+
- [ ] Al finalizar, agregar la imagen a la lista sin necesidad de refetch completo
|
|
479
|
+
- [ ] Manejar error de imagen no encontrada o autenticación fallida
|
|
480
|
+
|
|
481
|
+
**Criterio de aceptación:**
|
|
482
|
+
- El usuario puede escribir `postgres:16` y ver el pull en tiempo real
|
|
483
|
+
- Al finalizar el pull, la imagen aparece en la lista
|
|
484
|
+
- Si el nombre de imagen no existe, se muestra error "imagen no encontrada"
|
|
485
|
+
|
|
486
|
+
**Testing:**
|
|
487
|
+
- Test: parseo del stream de progreso de pull (por capas)
|
|
488
|
+
- Test: manejo de error 404 (imagen no encontrada en registry)
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
### 🟢 4C — Export `docker run` / compose
|
|
493
|
+
|
|
494
|
+
**Prioridad:** 🟢 Media
|
|
495
|
+
|
|
496
|
+
**Descripción:** Para cualquier contenedor existente, el usuario puede generar el comando `docker run` equivalente o un fragmento de `docker-compose.yml` que recree ese contenedor con la misma configuración. Útil para documentación y reproducibilidad.
|
|
497
|
+
|
|
498
|
+
**Sub-tareas técnicas:**
|
|
499
|
+
- [ ] Leer la configuración completa del contenedor con `GET /containers/{id}/json`
|
|
500
|
+
- [ ] Implementar función `toDockerRun(containerInfo)` que genere el string del comando
|
|
501
|
+
- [ ] Implementar función `toComposeService(containerInfo)` que genere el YAML del servicio
|
|
502
|
+
- [ ] Incluir: imagen, ports, volumes, env vars, network, restart policy, nombre
|
|
503
|
+
- [ ] Modal con el output generado y opción de copiar al portapapeles (si el entorno lo soporta)
|
|
504
|
+
- [ ] Advertir si algún campo no es representable en el formato exportado
|
|
505
|
+
|
|
506
|
+
**Criterio de aceptación:**
|
|
507
|
+
- El `docker run` generado, al ejecutarse, crea un contenedor funcionalmente equivalente
|
|
508
|
+
- El fragmento de compose es YAML válido
|
|
509
|
+
- Variables de entorno sensibles no son ocultadas pero sí se advierte al usuario
|
|
510
|
+
|
|
511
|
+
**Testing:**
|
|
512
|
+
- Test: `toDockerRun` con un contenedor con ports, volumes y env genera el comando correcto
|
|
513
|
+
- Test: `toComposeService` genera YAML válido y parseable
|
|
514
|
+
- Test: contenedor sin puertos no incluye flag `-p` en el output
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
### 🟢 5B — Multi-contexto Docker
|
|
519
|
+
|
|
520
|
+
**Prioridad:** 🟢 Media
|
|
521
|
+
|
|
522
|
+
**Descripción:** El TUI debe leer los contextos de Docker (`~/.docker/contexts/`) y permitir al usuario cambiar entre ellos desde una interfaz en el header. Al cambiar de contexto, todos los datos de contenedores, imágenes y redes se recargan desde el nuevo daemon.
|
|
523
|
+
|
|
524
|
+
**Sub-tareas técnicas:**
|
|
525
|
+
- [ ] Leer contextos disponibles desde `~/.docker/contexts/meta/` o via `docker context ls --format json`
|
|
526
|
+
- [ ] Mostrar el contexto activo en el header del TUI
|
|
527
|
+
- [ ] Acción para cambiar de contexto (modal con selector)
|
|
528
|
+
- [ ] Al cambiar, reinicializar el cliente Docker con el socket/host del nuevo contexto
|
|
529
|
+
- [ ] Recargar todos los datos desde el nuevo daemon
|
|
530
|
+
- [ ] Manejar error si el contexto seleccionado no está disponible (daemon apagado)
|
|
531
|
+
|
|
532
|
+
**Criterio de aceptación:**
|
|
533
|
+
- El contexto activo es visible en el header
|
|
534
|
+
- Cambiar a un contexto con un daemon remoto muestra los contenedores de ese daemon
|
|
535
|
+
- Si el daemon del contexto no responde, se muestra error sin crashear el TUI
|
|
536
|
+
|
|
537
|
+
**Testing:**
|
|
538
|
+
- Test: parsing de los archivos de contexto de Docker
|
|
539
|
+
- Test: error de conexión al cambiar a contexto no disponible → mensaje claro
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
### 📐 Testing — Fase 4
|
|
544
|
+
|
|
545
|
+
- Tests de `toDockerRun` y `toComposeService` (funciones puras, fáciles de testear)
|
|
546
|
+
- Tests del parser de contextos de Docker
|
|
547
|
+
- Tests del flujo de pull con mock del stream de progreso
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## 📦 Backlog — Features de Baja Prioridad
|
|
552
|
+
|
|
553
|
+
Estas features no tienen fase asignada. Entran en el backlog para ser consideradas en futuras iteraciones según capacidad y demanda.
|
|
554
|
+
|
|
555
|
+
| ID | Feature | Prioridad | Notas |
|
|
556
|
+
|----|---------|-----------|-------|
|
|
557
|
+
| 2A | Panel Inspect | 🔵 Baja | Vista de `docker inspect` completa formateada como JSON |
|
|
558
|
+
| 5A | Soporte `DOCKER_HOST` | 🔵 Baja | Leer variable de entorno `DOCKER_HOST` para conexiones remotas simples |
|
|
559
|
+
| 6.x | Persistencia y Configuración | 🔵 Muy Baja | Preferencias de usuario, keybindings personalizables, temas |
|
|
560
|
+
| 1D | Recetas guardables | 🔵 Baja | Ver sección de Ideas Exploratorias |
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## 🔭 Ideas Exploratorias
|
|
565
|
+
|
|
566
|
+
> Estas ideas no tienen versión asignada. Requieren investigación adicional antes de comprometerse a implementarlas.
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
### 💡 4D — Build de imagen custom desde el TUI
|
|
571
|
+
|
|
572
|
+
**Idea:** El usuario puede seleccionar un directorio con un `Dockerfile` (o incluso definir uno básico en el TUI) y hacer build de una imagen directamente desde la interfaz, sin salir a la terminal.
|
|
573
|
+
|
|
574
|
+
**Viabilidad técnica:**
|
|
575
|
+
La API de Docker soporta `POST /build` con un tar del contexto de build. La parte técnica de enviar el build es viable. El desafío real está en la UX: el usuario necesita poder seleccionar un directorio del filesystem (requiere un file picker en TUI), y el output del build (stream de texto con cada paso del Dockerfile) necesita una vista dedicada de progreso.
|
|
576
|
+
|
|
577
|
+
**Complejidad adicional:**
|
|
578
|
+
- File picker en TUI es complejo de implementar con buena UX (Ink no tiene uno nativo)
|
|
579
|
+
- Empaquetar el contexto de build como tar en memoria para mandarlo a la API
|
|
580
|
+
- El stream de build output tiene formato JSON por línea que debe parsearse y mostrarse limpiamente
|
|
581
|
+
|
|
582
|
+
**Riesgos:**
|
|
583
|
+
- Contextos de build grandes (proyectos con `node_modules` sin `.dockerignore`) pueden ser muy lentos o consumir mucha memoria
|
|
584
|
+
- La UX de file picker puede quedar inferior a simplemente usar `docker build` en terminal
|
|
585
|
+
- Requiere que el TUI tenga permisos de lectura al filesystem del usuario
|
|
586
|
+
|
|
587
|
+
**Recomendación:** Explorar primero si existe una librería de file picker para Ink. Si no hay una mantenida, esta feature tiene un costo de UX muy alto. Alternativa: el usuario provee la ruta como string (sin picker visual) — reduce la complejidad significativamente.
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
### 💡 1D — Recetas de contenedores guardables
|
|
592
|
+
|
|
593
|
+
**Idea:** El usuario puede guardar una configuración de contenedor como "receta" (nombre, imagen, volúmenes, redes, env vars) y reutilizarla con un nombre para recrear el mismo contenedor rápidamente.
|
|
594
|
+
|
|
595
|
+
**Viabilidad técnica:**
|
|
596
|
+
Las recetas serían JSON serializado en un archivo de configuración local (ej. `~/.config/cdd/recipes.json`). La lectura y escritura es trivial. El wizard de creación necesitaría un paso de "cargar receta" al inicio y un botón de "guardar como receta" al final.
|
|
597
|
+
|
|
598
|
+
**Riesgos:**
|
|
599
|
+
- Las recetas con variables de entorno pueden contener credenciales → necesidad de advertencias y posiblemente cifrado opcional
|
|
600
|
+
- La migración de recetas entre versiones del schema JSON puede romper recetas antiguas
|
|
601
|
+
- Los usuarios power users probablemente prefieren Docker Compose para esto — la propuesta de valor debe ser clara
|
|
602
|
+
|
|
603
|
+
**Recomendación:** Solo implementar si el wizard de creación (Fase 3) ha sido bien recibido y los usuarios piden explícitamente esta funcionalidad. No es prioritario ahora.
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
### 💡 7A — Docker exec interactivo
|
|
608
|
+
|
|
609
|
+
**Idea:** El usuario puede abrir una shell interactiva dentro de un contenedor corriendo, como `docker exec -it {container} sh`, directamente desde el TUI.
|
|
610
|
+
|
|
611
|
+
**Viabilidad técnica:**
|
|
612
|
+
La API de Docker soporta `POST /containers/{id}/exec` seguido de `POST /exec/{id}/start`. El problema es que esto requiere una terminal interactiva con PTY real, que debe ser manejada por el TUI. Ink/React está diseñado para UIs reactivas, no para hacer passthrough de un PTY arbitrario. Probablemente requiera spawnear un proceso hijo con `child_process.spawn` apuntando al terminal del usuario y "salir" del TUI temporalmente.
|
|
613
|
+
|
|
614
|
+
**Riesgos:**
|
|
615
|
+
- Integrar un PTY interactivo dentro de Ink puede ser estructuralmente incompatible con el modelo de renderizado de React/Ink
|
|
616
|
+
- La alternativa de suspender el TUI y lanzar el exec en el terminal nativo es viable pero requiere gestión de ciclo de vida cuidadosa (restaurar el TUI al salir)
|
|
617
|
+
- Posibles problemas con tamaños de terminal (SIGWINCH) cuando el usuario redimensiona la ventana dentro del exec
|
|
618
|
+
|
|
619
|
+
**Recomendación:** Investigar si `ink` tiene soporte para suspender el renderizado y restaurarlo. Si lo tiene, la implementación es viable. Si no, esta feature requeriría cambios arquitecturales significativos.
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
### 💡 7B — Soporte Docker Compose
|
|
624
|
+
|
|
625
|
+
**Idea:** Detectar archivos `docker-compose.yml` en el directorio actual y ofrecer acciones de compose (up, down, restart por servicio) desde el TUI.
|
|
626
|
+
|
|
627
|
+
**Viabilidad técnica:**
|
|
628
|
+
Docker Compose no tiene una API REST propia — `docker compose` es un plugin de CLI que invoca la API de Docker en secuencia. La opción más pragmática es invocar `docker compose` como proceso hijo. Alternativamente, leer el `docker-compose.yml`, parsear los servicios y orquestar las llamadas a la API de Docker manualmente — esto duplica lógica que ya tiene Compose.
|
|
629
|
+
|
|
630
|
+
**Riesgos:**
|
|
631
|
+
- Depender del CLI de `docker compose` como proceso hijo crea una dependencia externa que puede no estar instalada
|
|
632
|
+
- Parsear y ejecutar compose manualmente es una reimplementación parcial de Compose, con todos los bugs propios
|
|
633
|
+
- El scope de "soporte compose" puede expandirse indefinidamente (redes, profiles, overrides, etc.)
|
|
634
|
+
|
|
635
|
+
**Recomendación:** Si se implementa, usar el CLI de `docker compose` como proceso hijo para las acciones, y parsear el YAML solo para mostrar información (nombres de servicios, imágenes). No reimplementar la lógica de Compose.
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## 📌 Notas de Versionado
|
|
640
|
+
|
|
641
|
+
- **v4.x** — Mejoras incrementales sobre la base existente. Sin cambios de arquitectura.
|
|
642
|
+
- **v5.0.0** — Contiene cambios que afectan múltiples capas (multi-contexto, vistas nuevas). Justifica bump de versión mayor.
|
|
643
|
+
- Las ideas exploratorias (4D, 7A, 7B, 1D) no tienen versión asignada intencionalmente — su complejidad real se conoce solo después de investigación dedicada.
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
*Documento generado el 2026-04-28 — Roadmap v1.0 para CDD v4.0.0*
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const React = require('react');
|
|
2
|
+
exports.Box = ({ children, ...props }) =>
|
|
3
|
+
React.createElement('div', { ...props }, children);
|
|
4
|
+
exports.Text = ({ children, color }) =>
|
|
5
|
+
React.createElement('span', { 'data-color': color }, children);
|
|
6
|
+
|
|
7
|
+
// Capture the last registered useInput handler so tests can simulate keypresses.
|
|
8
|
+
let _inputHandler = null;
|
|
9
|
+
exports.useInput = (fn) => { _inputHandler = fn; };
|
|
10
|
+
/** Simulate a keypress through the last registered useInput handler. */
|
|
11
|
+
exports.__triggerInput = (input, key = {}) => {
|
|
12
|
+
if (_inputHandler) _inputHandler(input, key);
|
|
13
|
+
};
|
|
14
|
+
/** Reset captured handler between tests. */
|
|
15
|
+
exports.__resetInput = () => { _inputHandler = null; };
|
|
16
|
+
|
|
17
|
+
exports.useApp = () => ({ exit: () => {} });
|