cdd-cli 3.0.1 → 3.1.1
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/.github/ISSUE_TEMPLATE/bug_report.md +30 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/PULL_REQUEST_TEMPLATE/pull_request.md +14 -0
- package/.github/workflows/ci.yml +29 -0
- package/CHANGELOG.md +34 -0
- package/CODE_OF_CONDUCT.md +12 -0
- package/CONTRIBUTING.md +22 -0
- package/README.md +83 -166
- package/SECURITY.md +5 -0
- package/babel.config.cjs +6 -0
- package/dist/App.js +38 -24
- package/dist/cdd.bundle.js +8 -0
- package/dist/components/ContainerCreationPrompt.js +48 -0
- package/dist/components/ContainerCreator.js +81 -0
- package/dist/components/ContainerList.js +24 -4
- package/dist/components/ContainerRow.js +66 -13
- package/dist/components/ContainerSection.js +14 -0
- package/dist/components/Footer.js +10 -0
- package/dist/components/PromptField.js +20 -0
- package/dist/components/UsageMenu.js +8 -0
- package/dist/helpers/actionHelpers.js +0 -1
- package/dist/helpers/dockerActions.js +13 -0
- package/dist/helpers/dockerService/dockerService.js +5 -0
- package/dist/helpers/dockerService/serviceComponents/containerActions.js +163 -0
- package/dist/helpers/dockerService/serviceComponents/containerList.js +57 -0
- package/dist/helpers/dockerService/serviceComponents/containerLogs.js +24 -0
- package/dist/helpers/dockerService/serviceComponents/containerStats.js +50 -0
- package/dist/helpers/dockerService/serviceComponents/imageUtils.js +52 -0
- package/dist/helpers/dockerService.js +111 -0
- package/dist/helpers/validationHelpers.js +26 -0
- package/dist/hooks/creation/useContainerActions.js +171 -0
- package/dist/hooks/creation/useContainerCreation.js +141 -0
- package/dist/hooks/creation/useLogsViewer.js +62 -0
- package/dist/hooks/useContainers.js +11 -1
- package/dist/hooks/useControls.js +298 -78
- package/dist/hooks/useLogsStream.js +1 -1
- package/dist/index.js +11 -0
- package/esbuild.config.cjs +11 -0
- package/jest.config.cjs +6 -0
- package/package.json +10 -6
- package/src/App.jsx +32 -26
- package/src/components/ContainerCreationPrompt.jsx +37 -0
- package/src/components/ContainerList.jsx +10 -6
- package/src/components/ContainerRow.jsx +36 -19
- package/src/components/ContainerSection.jsx +10 -0
- package/src/components/Footer.jsx +10 -0
- package/src/components/PromptField.jsx +18 -0
- package/src/components/UsageMenu.jsx +17 -0
- package/src/helpers/actionHelpers.js +0 -1
- package/src/helpers/dockerService/dockerService.js +3 -0
- package/src/helpers/dockerService/serviceComponents/containerActions.js +52 -0
- package/src/helpers/dockerService/serviceComponents/containerList.js +26 -0
- package/src/helpers/dockerService/serviceComponents/containerLogs.js +19 -0
- package/src/helpers/dockerService/serviceComponents/containerStats.js +34 -0
- package/src/helpers/dockerService/serviceComponents/imageUtils.js +21 -0
- package/src/helpers/validationHelpers.js +16 -0
- package/src/hooks/creation/useContainerActions.js +68 -0
- package/src/hooks/creation/useContainerCreation.js +104 -0
- package/src/hooks/creation/useLogsViewer.js +50 -0
- package/src/hooks/useContainers.js +1 -1
- package/src/hooks/useControls.js +176 -55
- package/src/hooks/useLogsStream.js +1 -1
- package/test/validationHelpers.test.js +28 -0
- package/PLAN_KEYBINDINGS_Y_REALTIME.md +0 -260
- package/docs/en/README.md +0 -167
- package/src/components/StatsViewer.jsx +0 -0
- package/src/helpers/dockerActions.js +0 -52
- package/src/helpers/dockerService.js +0 -100
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: ''
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Describe the bug**
|
|
10
|
+
A clear and concise description of what the bug is.
|
|
11
|
+
|
|
12
|
+
**To Reproduce**
|
|
13
|
+
Steps to reproduce the behavior:
|
|
14
|
+
1. Go to '...'
|
|
15
|
+
2. Run '...'
|
|
16
|
+
3. See error
|
|
17
|
+
|
|
18
|
+
**Expected behavior**
|
|
19
|
+
A clear and concise description of what you expected to happen.
|
|
20
|
+
|
|
21
|
+
**Screenshots or logs**
|
|
22
|
+
If applicable, add screenshots or logs to help explain your problem.
|
|
23
|
+
|
|
24
|
+
**Environment (please complete the following information):**
|
|
25
|
+
- OS: (e.g. Ubuntu 22.04)
|
|
26
|
+
- Node version: (e.g. 18.x)
|
|
27
|
+
- cdd-cli version: (e.g. 3.1.0)
|
|
28
|
+
|
|
29
|
+
**Additional context**
|
|
30
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
title: ''
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Is your feature request related to a problem? Please describe.**
|
|
10
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
11
|
+
|
|
12
|
+
**Describe the solution you'd like**
|
|
13
|
+
A clear and concise description of what you want to happen.
|
|
14
|
+
|
|
15
|
+
**Describe alternatives you've considered**
|
|
16
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
|
17
|
+
|
|
18
|
+
**Additional context**
|
|
19
|
+
Add any other context or screenshots about the feature request here.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!-- Please replace the placeholders and remove this comment -->
|
|
2
|
+
## Summary
|
|
3
|
+
|
|
4
|
+
What does this PR change and why?
|
|
5
|
+
|
|
6
|
+
## Checklist
|
|
7
|
+
|
|
8
|
+
- [ ] I have read the contributing guidelines
|
|
9
|
+
- [ ] Tests added / updated
|
|
10
|
+
- [ ] Documentation updated
|
|
11
|
+
|
|
12
|
+
## Related issues
|
|
13
|
+
|
|
14
|
+
Closes: # (issue)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test-and-build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout repository
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Setup Node.js
|
|
17
|
+
uses: actions/setup-node@v4
|
|
18
|
+
with:
|
|
19
|
+
node-version: '18'
|
|
20
|
+
cache: 'npm'
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: npm ci
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: npm test
|
|
27
|
+
|
|
28
|
+
- name: Build
|
|
29
|
+
run: npm run build
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
+
|
|
7
|
+
## [3.1.0] - 2025-10-16
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Modularized hooks: `useContainerCreation`, `useContainerActions`, `useLogsViewer`.
|
|
12
|
+
- Validation helpers and unit tests for port validation.
|
|
13
|
+
- CI workflow (GitHub Actions) and README improvements.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Container creation UX: English feedback messages, mandatory/validated port input, DB image warnings.
|
|
18
|
+
- Added erase action (key `E`) with confirmation to delete containers.
|
|
19
|
+
- Normalized source imports to include explicit `.js`/`.jsx` extensions for ESM compatibility.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Various runtime & build issues after modularization (import fixes, exposing container action functions, creation flow wiring).
|
|
24
|
+
|
|
25
|
+
## [Unreleased]
|
|
26
|
+
|
|
27
|
+
- Incoming fixes and smaller tests / docs updates
|
|
28
|
+
|
|
29
|
+
## [3.1.1] - 2025-10-16
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Minor docs typo fixes and README global install note added.
|
|
34
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
This project follows the Contributor Covenant Code of Conduct. By participating, you agree to abide by its terms.
|
|
4
|
+
|
|
5
|
+
Please see https://www.contributor-covenant.org/ for the full text.
|
|
6
|
+
## Code of Conduct
|
|
7
|
+
|
|
8
|
+
This project follows the [Contributor Covenant](https://www.contributor-covenant.org/).
|
|
9
|
+
|
|
10
|
+
Be respectful, inclusive, and kind. Harassment, discrimination, or abusive language will not be tolerated.
|
|
11
|
+
|
|
12
|
+
If you experience or witness unacceptable behavior, please contact the maintainers.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! Please follow these guidelines:
|
|
4
|
+
|
|
5
|
+
- Fork the repository and create a feature branch.
|
|
6
|
+
- Keep changes small and focused.
|
|
7
|
+
- Add or update tests for new behaviors.
|
|
8
|
+
- Run `npm test` and `npm run build` before opening a PR.
|
|
9
|
+
- Use conventional commits where possible.
|
|
10
|
+
|
|
11
|
+
For any design or large changes, open an issue first to discuss.
|
|
12
|
+
## Contributing to CDD-CLI
|
|
13
|
+
|
|
14
|
+
Thanks for your interest in contributing! A few guidelines to make collaboration smooth:
|
|
15
|
+
|
|
16
|
+
- Fork the repo and create a branch for your feature/fix: `git checkout -b feat/my-feature`.
|
|
17
|
+
- Write tests for any new behavior and ensure existing tests pass: `npm test`.
|
|
18
|
+
- Follow the existing code style and run `npm run build` before opening a PR.
|
|
19
|
+
- Keep PRs focused and describe motivation and changes.
|
|
20
|
+
- Tag reviewers and link related issues.
|
|
21
|
+
|
|
22
|
+
We appreciate clear, well-tested contributions.
|
package/README.md
CHANGED
|
@@ -1,205 +1,122 @@
|
|
|
1
|
-
##
|
|
1
|
+
## CDD-CLI — Docker Dashboard (Terminal)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install
|
|
12
|
-
```
|
|
13
|
-
3. Transpila el código fuente:
|
|
14
|
-
```bash
|
|
15
|
-
npm run build
|
|
16
|
-
```
|
|
17
|
-
4. Ejecuta el CLI localmente:
|
|
18
|
-
```bash
|
|
19
|
-
node dist/index.js
|
|
20
|
-
```
|
|
21
|
-
5. Prueba el comando global localmente:
|
|
22
|
-
```bash
|
|
23
|
-
npm link
|
|
24
|
-
cdd
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Testing y troubleshooting
|
|
28
|
-
- Si modificas componentes, recuerda siempre ejecutar `npm run build` antes de probar.
|
|
29
|
-
- Si tienes problemas con permisos de Docker, ejecuta la terminal como administrador o usa `sudo`.
|
|
30
|
-
- Para limpiar la instalación global:
|
|
31
|
-
```bash
|
|
32
|
-
npm uninstall -g cdd-cli
|
|
33
|
-
```
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://img.shields.io/npm/v/cdd-cli?color=blue&label=npm%20package" alt="npm version"/>
|
|
5
|
+
<img src="https://img.shields.io/npm/dt/cdd-cli?color=green&label=downloads" alt="npm downloads"/>
|
|
6
|
+
<a href="https://github.com/caertos/cdd/actions/workflows/ci.yml">
|
|
7
|
+
<img src="https://github.com/caertos/cdd/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI status" />
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
34
10
|
|
|
35
|
-
|
|
36
|
-
1. Haz un fork del repositorio y crea una rama para tu feature o fix.
|
|
37
|
-
2. Asegúrate de que tu código pase el build y funcione correctamente.
|
|
38
|
-
3. Haz un Pull Request con una descripción clara de tus cambios.
|
|
11
|
+
Short, bilingual README with quickstart, development and tests.
|
|
39
12
|
|
|
40
13
|
---
|
|
41
|
-
## Advanced instructions
|
|
42
14
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
3. Transpile the source code:
|
|
54
|
-
```bash
|
|
55
|
-
npm run build
|
|
56
|
-
```
|
|
57
|
-
4. Run the CLI locally:
|
|
58
|
-
```bash
|
|
59
|
-
node dist/index.js
|
|
60
|
-
```
|
|
61
|
-
5. Test the global command locally:
|
|
62
|
-
```bash
|
|
63
|
-
npm link
|
|
64
|
-
cdd
|
|
65
|
-
```
|
|
15
|
+
## Quick start (local)
|
|
16
|
+
|
|
17
|
+
1. Clone the repo and install dependencies:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone https://github.com/caertos/cdd.git
|
|
21
|
+
cd cdd
|
|
22
|
+
npm install
|
|
23
|
+
```
|
|
66
24
|
|
|
67
|
-
|
|
68
|
-
- If you modify components, always run `npm run build` before testing.
|
|
69
|
-
- If you have Docker permission issues, run your terminal as administrator or use `sudo`.
|
|
70
|
-
- To clean up the global install:
|
|
71
|
-
```bash
|
|
72
|
-
npm uninstall -g cdd-cli
|
|
73
|
-
```
|
|
25
|
+
2. Build and run locally:
|
|
74
26
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
27
|
+
```bash
|
|
28
|
+
npm run build
|
|
29
|
+
node dist/index.js
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
3. To test the CLI as a globally available command during development:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm link
|
|
36
|
+
cdd
|
|
37
|
+
```
|
|
79
38
|
|
|
80
39
|
---
|
|
81
40
|
|
|
41
|
+
## Usage (interactive)
|
|
82
42
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
43
|
+
- Use ↑/↓ to navigate containers.
|
|
44
|
+
- I: start selected container
|
|
45
|
+
- P: stop selected container
|
|
46
|
+
- R: restart selected container
|
|
47
|
+
- C: create container (interactive prompt)
|
|
48
|
+
- L: view logs for selected container
|
|
49
|
+
- E: erase (remove) selected container (confirmation required)
|
|
50
|
+
- Q: quit
|
|
87
51
|
|
|
88
|
-
|
|
89
|
-
[English version below]
|
|
52
|
+
The dashboard auto-refreshes container list every few seconds.
|
|
90
53
|
|
|
91
54
|
---
|
|
92
55
|
|
|
93
|
-
##
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
│ mysql-dev mysql:latest 🟢 RUNNING │
|
|
100
|
-
│ CPU: ░░░░░░░░░░ 0.1% MEM: ░░░░░░░░░░ 4.9% │
|
|
101
|
-
│ │
|
|
102
|
-
│ redis-test redis:alpine 🔴 EXITED │
|
|
103
|
-
│ │
|
|
104
|
-
│ Press Ctrl+C to exit │
|
|
105
|
-
│ Crafted by Carlos Cochero • 2025 │
|
|
106
|
-
╰────────────────────────────────────────────────────────────────────────────╯
|
|
107
|
-
```
|
|
108
|
-
# 🐳 CDD-CLI — Docker Dashboard in your Terminal
|
|
109
|
-
|
|
110
|
-
## Visual example
|
|
111
|
-
|
|
112
|
-
```text
|
|
113
|
-
╭────────────────────────────────────────────────────────────────────────────╮
|
|
114
|
-
│ 🐳 CDD — CLI Docker Dashboard 2 containers found │
|
|
115
|
-
│ │
|
|
116
|
-
│ mysql-dev mysql:latest 🟢 RUNNING │
|
|
117
|
-
│ CPU: ░░░░░░░░░░ 0.1% MEM: ░░░░░░░░░░ 4.9% │
|
|
118
|
-
│ │
|
|
119
|
-
│ redis-test redis:alpine 🔴 EXITED │
|
|
120
|
-
│ │
|
|
121
|
-
│ Press Ctrl+C to exit │
|
|
122
|
-
│ Crafted by Carlos Cochero • 2025 │
|
|
123
|
-
╰────────────────────────────────────────────────────────────────────────────╯
|
|
56
|
+
## Install globally
|
|
57
|
+
|
|
58
|
+
To install the CLI globally so you can run `cdd` from any terminal, use:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install -g cdd-cli
|
|
124
62
|
```
|
|
125
63
|
|
|
126
|
-
|
|
64
|
+
After installing globally, run the CLI with:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cdd
|
|
68
|
+
```
|
|
127
69
|
|
|
128
70
|
---
|
|
129
71
|
|
|
130
|
-
##
|
|
131
|
-
CDD-CLI es una herramienta de línea de comandos (CLI) multiplataforma que te permite monitorear y visualizar en tiempo real el estado de tus contenedores Docker directamente desde la terminal, usando una interfaz moderna y colorida basada en React e Ink.
|
|
72
|
+
## Development
|
|
132
73
|
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
- Actualización automática cada 2 segundos.
|
|
136
|
-
- Interfaz amigable, con colores y emojis.
|
|
137
|
-
- Compatible con Linux, macOS y Windows (bash, cmd, PowerShell).
|
|
74
|
+
- Node.js >= 18 is recommended.
|
|
75
|
+
- To run the app from source during development:
|
|
138
76
|
|
|
139
|
-
|
|
77
|
+
```bash
|
|
78
|
+
npm install
|
|
79
|
+
npm run build
|
|
80
|
+
node dist/index.js
|
|
81
|
+
```
|
|
140
82
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
npm install -g cdd-cli
|
|
145
|
-
```
|
|
146
|
-
3. Ejecuta el dashboard desde cualquier terminal:
|
|
147
|
-
```bash
|
|
148
|
-
cdd
|
|
149
|
-
```
|
|
83
|
+
If you change source files, re-run `npm run build` before running the CLI.
|
|
84
|
+
|
|
85
|
+
---
|
|
150
86
|
|
|
151
|
-
##
|
|
152
|
-
- Al ejecutar `cdd`, verás una tabla interactiva con todos tus contenedores Docker.
|
|
153
|
-
- Los contenedores en ejecución muestran estadísticas de CPU y memoria en tiempo real.
|
|
154
|
-
- Puedes navegar usando las flechas ↑/↓ y controlar los contenedores con atajos de teclado.
|
|
155
|
-
- Usa `Ctrl+C` o la tecla `Q` para salir.
|
|
87
|
+
## Tests
|
|
156
88
|
|
|
157
|
-
|
|
89
|
+
We use Jest for unit tests. Run:
|
|
158
90
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
- L : Ver logs en tiempo real del contenedor seleccionado
|
|
163
|
-
- Q : Salir del dashboard o de la vista de logs
|
|
91
|
+
```bash
|
|
92
|
+
npm test
|
|
93
|
+
```
|
|
164
94
|
|
|
165
|
-
|
|
166
|
-
- 🐳 Visualización clara y compacta de todos los contenedores.
|
|
167
|
-
- 🔄 Refresco automático de datos.
|
|
168
|
-
- 📊 Estadísticas de uso de recursos para contenedores activos.
|
|
169
|
-
- 🎨 Interfaz visual con colores y emojis para estados.
|
|
170
|
-
- 👤 Autor: Carlos Cochero (2025)
|
|
95
|
+
Tests are located in `test/` and cover utility helpers.
|
|
171
96
|
|
|
172
|
-
|
|
173
|
-
- Node.js >= 18
|
|
174
|
-
- Docker instalado y corriendo (el CLI se conecta al socket local de Docker)
|
|
97
|
+
---
|
|
175
98
|
|
|
176
|
-
##
|
|
177
|
-
|
|
178
|
-
|
|
99
|
+
## Contributing
|
|
100
|
+
|
|
101
|
+
1. Fork the repo and create a feature branch.
|
|
102
|
+
2. Add tests for new behavior.
|
|
103
|
+
3. Ensure `npm test` and `npm run build` pass.
|
|
104
|
+
4. Open a Pull Request with a clear description.
|
|
179
105
|
|
|
180
106
|
---
|
|
181
107
|
|
|
182
|
-
|
|
108
|
+
## Troubleshooting
|
|
183
109
|
|
|
184
|
-
|
|
185
|
-
|
|
110
|
+
- If you don't see containers, ensure Docker is running and that your user has access to the Docker socket.
|
|
111
|
+
- If Docker permissions are required, run the CLI with `sudo` (Linux/macOS) or as Administrator (Windows).
|
|
112
|
+
- The project generates `dist/` — keep it out of version control (it's in .gitignore).
|
|
186
113
|
|
|
187
|
-
|
|
188
|
-
- Shows name, image, state, ports, and CPU/MEM stats.
|
|
189
|
-
- Auto-refresh every 2 seconds.
|
|
190
|
-
- Friendly, colorful, emoji-rich UI.
|
|
191
|
-
- Works on Linux, macOS, and Windows (bash, cmd, PowerShell).
|
|
114
|
+
---
|
|
192
115
|
|
|
193
|
-
##
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
This project is MIT/ISC licensed (see `LICENSE`).
|
|
194
119
|
|
|
195
|
-
1. Make sure you have Node.js (v18+) and Docker installed and running.
|
|
196
|
-
2. Install the CLI globally from npm:
|
|
197
|
-
```bash
|
|
198
|
-
npm install -g cdd-cli
|
|
199
|
-
```
|
|
200
|
-
3. Run the dashboard from any terminal:
|
|
201
|
-
```bash
|
|
202
|
-
cdd
|
|
203
120
|
```
|
|
204
121
|
|
|
205
122
|
## Usage
|
package/SECURITY.md
ADDED
package/babel.config.cjs
ADDED
package/dist/App.js
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main React component for the CDD CLI UI.
|
|
3
|
+
* Componente principal de React para la UI del CLI CDD.
|
|
4
|
+
*
|
|
5
|
+
* @component
|
|
6
|
+
* @returns {JSX.Element} The rendered app / La app renderizada
|
|
7
|
+
* @example
|
|
8
|
+
* // EN: Render the app
|
|
9
|
+
* // ES: Renderizar la app
|
|
10
|
+
* <App />
|
|
11
|
+
*/
|
|
1
12
|
import React from "react";
|
|
2
13
|
import { Box, Text, Spacer } from "ink";
|
|
3
14
|
import { useContainers } from "./hooks/useContainers.js";
|
|
4
15
|
import { useControls } from "./hooks/useControls.js";
|
|
5
|
-
import
|
|
6
|
-
import MessageFeedback from "./components/MessageFeedback.
|
|
7
|
-
import Header from "./components/Header.
|
|
8
|
-
import LogViewer from "./components/LogViewer.
|
|
16
|
+
import ContainerSection from "./components/ContainerSection.jsx";
|
|
17
|
+
import MessageFeedback from "./components/MessageFeedback.jsx";
|
|
18
|
+
import Header from "./components/Header.jsx";
|
|
19
|
+
import LogViewer from "./components/LogViewer.jsx";
|
|
20
|
+
import ContainerCreationPrompt from "./components/ContainerCreationPrompt.jsx";
|
|
21
|
+
import UsageMenu from "./components/UsageMenu.jsx";
|
|
22
|
+
import Footer from "./components/Footer.jsx";
|
|
9
23
|
export default function App() {
|
|
10
24
|
var _useContainers = useContainers(),
|
|
11
25
|
containers = _useContainers.containers;
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
var controls = useControls(containers);
|
|
27
|
+
if (controls.creatingContainer) {
|
|
28
|
+
return /*#__PURE__*/React.createElement(ContainerCreationPrompt, {
|
|
29
|
+
step: controls.creationStep,
|
|
30
|
+
imageName: controls.imageNameInput,
|
|
31
|
+
containerName: controls.containerNameInput,
|
|
32
|
+
portInput: controls.portInput,
|
|
33
|
+
envInput: controls.envInput,
|
|
34
|
+
message: controls.message,
|
|
35
|
+
messageColor: controls.messageColor
|
|
36
|
+
});
|
|
37
|
+
}
|
|
19
38
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Box, {
|
|
20
39
|
flexDirection: "column",
|
|
21
40
|
borderStyle: "round",
|
|
@@ -23,20 +42,15 @@ export default function App() {
|
|
|
23
42
|
padding: 1
|
|
24
43
|
}, /*#__PURE__*/React.createElement(Header, {
|
|
25
44
|
count: containers.length
|
|
26
|
-
}), /*#__PURE__*/React.createElement(Text, null, " "),
|
|
45
|
+
}), /*#__PURE__*/React.createElement(Text, null, " "), /*#__PURE__*/React.createElement(ContainerSection, {
|
|
27
46
|
containers: containers,
|
|
28
|
-
selected: selected
|
|
47
|
+
selected: controls.selected
|
|
29
48
|
}), /*#__PURE__*/React.createElement(Spacer, null), /*#__PURE__*/React.createElement(MessageFeedback, {
|
|
30
|
-
message: message,
|
|
31
|
-
color: messageColor
|
|
32
|
-
}), /*#__PURE__*/React.createElement(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
dimColor: true
|
|
37
|
-
}, "Crafted by Carlos Cochero \u2022 2025"))), showLogs && /*#__PURE__*/React.createElement(LogViewer, {
|
|
38
|
-
logs: logs,
|
|
39
|
-
onExit: exitLogs,
|
|
40
|
-
container: containers[selected]
|
|
49
|
+
message: controls.message,
|
|
50
|
+
color: controls.messageColor
|
|
51
|
+
}), /*#__PURE__*/React.createElement(UsageMenu, null), /*#__PURE__*/React.createElement(Footer, null)), controls.showLogs && /*#__PURE__*/React.createElement(LogViewer, {
|
|
52
|
+
logs: controls.logs,
|
|
53
|
+
onExit: controls.exitLogs,
|
|
54
|
+
container: containers[controls.selected]
|
|
41
55
|
}));
|
|
42
56
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import Rt from"react";import{render as $t}from"ink";import x from"react";import{Box as Lt,Text as jt,Spacer as Dt}from"ink";import{useState as tt,useEffect as rt}from"react";import et from"dockerode";var f=new et({socketPath:"/var/run/docker.sock"});async function Ee(){return(await f.listContainers({all:!0})).map(e=>({id:e.Id,name:e.Names[0].replace("/",""),image:e.Image,state:e.State,status:e.Status,ports:[...new Set(e.Ports.filter(r=>r.PublicPort).map(r=>`${r.PublicPort}:${r.PrivatePort}`))]}))}function Ie(){let[t,e]=tt([]);return rt(()=>{let r=async()=>e(await Ee());r();let o=setInterval(r,3e3);return()=>clearInterval(o)},[]),{containers:t}}import{useState as T,useRef as ot}from"react";import{useInput as nt}from"ink";async function Oe(t){return(await f.listImages()).some(r=>(r.RepoTags||[]).includes(t)||(r.RepoDigests||[]).some(o=>o.includes(t)))}async function Be(t){await new Promise((e,r)=>{f.pull(t,(o,n)=>{if(o)return r(new Error("Error al hacer pull de la imagen: "+o.message));f.modem.followProgress(n,s=>{s?r(new Error("Error durante el pull: "+s.message)):e()})})})}async function ve(t,e={}){let r;try{r=await Oe(t)}catch(n){throw new Error("Error al listar im\xE1genes locales: "+n.message)}if(!r)try{await Be(t)}catch(n){throw new Error("No se pudo descargar la imagen: "+n.message)}let o={Image:t,Tty:!0,...e};try{let n=await f.createContainer(o);return n.id||n.Id}catch(n){throw new Error("Error al crear el contenedor: "+n.message)}}async function Se(t){await f.getContainer(t).start()}async function Ae(t){await f.getContainer(t).stop()}async function Ne(t){await f.getContainer(t).restart()}function Pe(t,e,r,o){f.getContainer(t).logs({follow:!0,stdout:!0,stderr:!0,tail:100},(s,i)=>{if(s){o?.(s);return}i.on("data",u=>e?.(u.toString())),i.on("end",()=>r?.()),i.on("error",u=>o?.(u))})}async function Y({containers:t,selected:e,actionFn:r,actionLabel:o,setMessage:n,setMessageColor:s,stateCheck:i}){let u=t[e];if(u){if(i&&i(u)){n(i(u)),s("red"),setTimeout(()=>n(""),2e3);return}n(`${o} container...`),s("green");try{await r(u.id),n(`${o} container...`),s("green"),setTimeout(()=>n(""),3e3)}catch{n(`Failed to ${o.toLowerCase()} container.`),s("red"),setTimeout(()=>n(""),3e3)}}}import{spawn as Fe}from"child_process";function _e({setMessage:t,setMessageColor:e,message:r="Exiting...",color:o="yellow",delay:n=1500}){t(r),e(o),setTimeout(()=>{t(""),process.platform==="win32"?Fe("cmd",["/c","cls"],{stdio:"inherit"}):Fe("clear",[],{stdio:"inherit"}),process.exit()},n)}function Me(t=[]){let[e,r]=T(0),[o,n]=T(""),[s,i]=T("yellow"),[u,w]=T(!1),[E,b]=T([]),[m,C]=T(!1),[B,F]=T(""),[z,G]=T(""),[Q,_]=T(""),[X,M]=T(""),[p,S]=T(0),J=ot(null),U=t.length,Z=()=>{w(!1),b([]),J.current&&(J.current.destroy?.(),J.current=null)};return nt(async(d,V)=>{if(u){(d==="q"||V.escape)&&Z();return}if(m){if(V.escape){C(!1),F(""),G(""),_(""),M(""),S(0),n("Creaci\xF3n cancelada"),i("yellow");return}if(d==="\r"){if(p===0){if(!B.trim()){n("El nombre de la imagen no puede estar vac\xEDo."),i("red");return}S(1),n("Opcional: Ingresa el nombre del contenedor o deja vac\xEDo y presiona Enter"),i("yellow");return}if(p===1){S(2),n("Opcional: Ingresa puertos (formato 8080:80,443:443) o deja vac\xEDo y presiona Enter"),i("yellow");return}if(p===2){S(3),n("Opcional: Ingresa variables de entorno (formato VAR1=val1,VAR2=val2) o deja vac\xEDo y presiona Enter"),i("yellow");return}if(p===3){let a={};if(z.trim()&&(a.name=z.trim()),Q.trim()){let h=Q.split(",").map(ee=>ee.trim()).filter(Boolean);a.ExposedPorts={},a.HostConfig={PortBindings:{}},h.forEach(ee=>{let[we,te]=ee.split(":");we&&te&&(a.ExposedPorts[`${te}/tcp`]={},a.HostConfig.PortBindings[`${te}/tcp`]=[{HostPort:we}])})}X.trim()&&(a.Env=X.split(",").map(h=>h.trim()).filter(Boolean)),n("Creando contenedor..."),i("yellow");try{let h=await ve(B.trim(),a);n(`Contenedor creado con ID: ${h}`),i("green")}catch(h){n(`Error: ${h.message}`),i("red")}setTimeout(()=>{C(!1),F(""),G(""),_(""),M(""),S(0)},2500);return}}else d==="\x7F"?(p===0&&F(a=>a.slice(0,-1)),p===1&&G(a=>a.slice(0,-1)),p===2&&_(a=>a.slice(0,-1)),p===3&&M(a=>a.slice(0,-1))):(p===0&&F(a=>a+d),p===1&&G(a=>a+d),p===2&&_(a=>a+d),p===3&&M(a=>a+d));return}if(V.upArrow&&U>0&&r(a=>a===0?U-1:a-1),V.downArrow&&U>0&&r(a=>a===U-1?0:a+1),d==="q"){_e({setMessage:n,setMessageColor:i});return}if(d==="i"&&Y({containers:t,selected:e,actionFn:Se,actionLabel:"Starting",setMessage:n,setMessageColor:i,stateCheck:a=>(a.state==="running"||a.status==="running")&&"Container is already running."}),d==="p"&&Y({containers:t,selected:e,actionFn:Ae,actionLabel:"Stopping",setMessage:n,setMessageColor:i,stateCheck:a=>(a.state==="exited"||a.status==="exited"||a.state==="stopped"||a.status==="stopped")&&"Container is already stopped."}),d==="r"&&Y({containers:t,selected:e,actionFn:Ne,actionLabel:"Restarting",setMessage:n,setMessageColor:i}),d==="l"&&t[e])return w(!0),b([]),Pe(t[e].id,a=>b(h=>[...h,...a.split(`
|
|
3
|
+
`).filter(Boolean)]),()=>{},a=>b(h=>[...h,`Error: ${a.message}`])),{selected:e,setSelected:r,message:o,messageColor:s,showLogs:u,logs:E,exitLogs:Z};d==="c"&&(C(!0),F(""),_(""),M(""),S(0),n("Ingresa el nombre de la imagen Docker y presiona Enter"),i("yellow"))}),{selected:e,setSelected:r,message:o,messageColor:s,showLogs:u,logs:E,exitLogs:Z,creatingContainer:m,imageNameInput:B,containerNameInput:z,portInput:Q,envInput:X,creationStep:p}}import D from"react";import{Box as It,Text as Ot}from"ink";import I,{useState as Ke,useEffect as wt}from"react";import{Box as le,Text as j}from"ink";async function ke(t){let r=await f.getContainer(t).stats({stream:!1}),o=r.cpu_stats.cpu_usage.total_usage-r.precpu_stats.cpu_usage.total_usage,n=r.cpu_stats.system_cpu_usage-r.precpu_stats.system_cpu_usage,s=n>0?o/n*100:0,i=r.memory_stats.usage||0,u=r.memory_stats.limit||1,w=i/u*100,E=r.networks?Object.values(r.networks).map(m=>m.rx_bytes).reduce((m,C)=>m+C,0):0,b=r.networks?Object.values(r.networks).map(m=>m.tx_bytes).reduce((m,C)=>m+C,0):0;return{cpuPercent:s.toFixed(1),memPercent:w.toFixed(1),netIO:{rx:E,tx:b}}}import Tt from"react";import{Text as yt}from"ink";var Le=(t=0)=>e=>`\x1B[${e+t}m`,je=(t=0)=>e=>`\x1B[${38+t};5;${e}m`,De=(t=0)=>(e,r,o)=>`\x1B[${38+t};2;${e};${r};${o}m`,l={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}},gr=Object.keys(l.modifier),it=Object.keys(l.color),st=Object.keys(l.bgColor),xr=[...it,...st];function at(){let t=new Map;for(let[e,r]of Object.entries(l)){for(let[o,n]of Object.entries(r))l[o]={open:`\x1B[${n[0]}m`,close:`\x1B[${n[1]}m`},r[o]=l[o],t.set(n[0],n[1]);Object.defineProperty(l,e,{value:r,enumerable:!1})}return Object.defineProperty(l,"codes",{value:t,enumerable:!1}),l.color.close="\x1B[39m",l.bgColor.close="\x1B[49m",l.color.ansi=Le(),l.color.ansi256=je(),l.color.ansi16m=De(),l.bgColor.ansi=Le(10),l.bgColor.ansi256=je(10),l.bgColor.ansi16m=De(10),Object.defineProperties(l,{rgbToAnsi256:{value(e,r,o){return e===r&&r===o?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(r/255*5)+Math.round(o/255*5)},enumerable:!1},hexToRgb:{value(e){let r=/[a-f\d]{6}|[a-f\d]{3}/i.exec(e.toString(16));if(!r)return[0,0,0];let[o]=r;o.length===3&&(o=[...o].map(s=>s+s).join(""));let n=Number.parseInt(o,16);return[n>>16&255,n>>8&255,n&255]},enumerable:!1},hexToAnsi256:{value:e=>l.rgbToAnsi256(...l.hexToRgb(e)),enumerable:!1},ansi256ToAnsi:{value(e){if(e<8)return 30+e;if(e<16)return 90+(e-8);let r,o,n;if(e>=232)r=((e-232)*10+8)/255,o=r,n=r;else{e-=16;let u=e%36;r=Math.floor(e/36)/5,o=Math.floor(u/6)/5,n=u%6/5}let s=Math.max(r,o,n)*2;if(s===0)return 30;let i=30+(Math.round(n)<<2|Math.round(o)<<1|Math.round(r));return s===2&&(i+=60),i},enumerable:!1},rgbToAnsi:{value:(e,r,o)=>l.ansi256ToAnsi(l.rgbToAnsi256(e,r,o)),enumerable:!1},hexToAnsi:{value:e=>l.ansi256ToAnsi(l.hexToAnsi256(e)),enumerable:!1}}),l}var lt=at(),y=lt;import re from"node:process";import ct from"node:os";import Re from"node:tty";function g(t,e=globalThis.Deno?globalThis.Deno.args:re.argv){let r=t.startsWith("-")?"":t.length===1?"-":"--",o=e.indexOf(r+t),n=e.indexOf("--");return o!==-1&&(n===-1||o<n)}var{env:c}=re,q;g("no-color")||g("no-colors")||g("color=false")||g("color=never")?q=0:(g("color")||g("colors")||g("color=true")||g("color=always"))&&(q=1);function ut(){if("FORCE_COLOR"in c)return c.FORCE_COLOR==="true"?1:c.FORCE_COLOR==="false"?0:c.FORCE_COLOR.length===0?1:Math.min(Number.parseInt(c.FORCE_COLOR,10),3)}function mt(t){return t===0?!1:{level:t,hasBasic:!0,has256:t>=2,has16m:t>=3}}function ft(t,{streamIsTTY:e,sniffFlags:r=!0}={}){let o=ut();o!==void 0&&(q=o);let n=r?q:o;if(n===0)return 0;if(r){if(g("color=16m")||g("color=full")||g("color=truecolor"))return 3;if(g("color=256"))return 2}if("TF_BUILD"in c&&"AGENT_NAME"in c)return 1;if(t&&!e&&n===void 0)return 0;let s=n||0;if(c.TERM==="dumb")return s;if(re.platform==="win32"){let i=ct.release().split(".");return Number(i[0])>=10&&Number(i[2])>=10586?Number(i[2])>=14931?3:2:1}if("CI"in c)return["GITHUB_ACTIONS","GITEA_ACTIONS","CIRCLECI"].some(i=>i in c)?3:["TRAVIS","APPVEYOR","GITLAB_CI","BUILDKITE","DRONE"].some(i=>i in c)||c.CI_NAME==="codeship"?1:s;if("TEAMCITY_VERSION"in c)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(c.TEAMCITY_VERSION)?1:0;if(c.COLORTERM==="truecolor"||c.TERM==="xterm-kitty"||c.TERM==="xterm-ghostty"||c.TERM==="wezterm")return 3;if("TERM_PROGRAM"in c){let i=Number.parseInt((c.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(c.TERM_PROGRAM){case"iTerm.app":return i>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(c.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(c.TERM)||"COLORTERM"in c?1:s}function $e(t,e={}){let r=ft(t,{streamIsTTY:t&&t.isTTY,...e});return mt(r)}var pt={stdout:$e({isTTY:Re.isatty(1)}),stderr:$e({isTTY:Re.isatty(2)})},Ge=pt;function Ue(t,e,r){let o=t.indexOf(e);if(o===-1)return t;let n=e.length,s=0,i="";do i+=t.slice(s,o)+e+r,s=o+n,o=t.indexOf(e,s);while(o!==-1);return i+=t.slice(s),i}function Ve(t,e,r,o){let n=0,s="";do{let i=t[o-1]==="\r";s+=t.slice(n,i?o-1:o)+e+(i?`\r
|
|
4
|
+
`:`
|
|
5
|
+
`)+r,n=o+1,o=t.indexOf(`
|
|
6
|
+
`,n)}while(o!==-1);return s+=t.slice(n),s}var{stdout:Ye,stderr:qe}=Ge,oe=Symbol("GENERATOR"),A=Symbol("STYLER"),k=Symbol("IS_EMPTY"),We=["ansi","ansi","ansi256","ansi16m"],N=Object.create(null),dt=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");let r=Ye?Ye.level:0;t.level=e.level===void 0?r:e.level};var gt=t=>{let e=(...r)=>r.join(" ");return dt(e,t),Object.setPrototypeOf(e,L.prototype),e};function L(t){return gt(t)}Object.setPrototypeOf(L.prototype,Function.prototype);for(let[t,e]of Object.entries(y))N[t]={get(){let r=W(this,ie(e.open,e.close,this[A]),this[k]);return Object.defineProperty(this,t,{value:r}),r}};N.visible={get(){let t=W(this,this[A],!0);return Object.defineProperty(this,"visible",{value:t}),t}};var ne=(t,e,r,...o)=>t==="rgb"?e==="ansi16m"?y[r].ansi16m(...o):e==="ansi256"?y[r].ansi256(y.rgbToAnsi256(...o)):y[r].ansi(y.rgbToAnsi(...o)):t==="hex"?ne("rgb",e,r,...y.hexToRgb(...o)):y[r][t](...o),xt=["rgb","hex","ansi256"];for(let t of xt){N[t]={get(){let{level:r}=this;return function(...o){let n=ie(ne(t,We[r],"color",...o),y.color.close,this[A]);return W(this,n,this[k])}}};let e="bg"+t[0].toUpperCase()+t.slice(1);N[e]={get(){let{level:r}=this;return function(...o){let n=ie(ne(t,We[r],"bgColor",...o),y.bgColor.close,this[A]);return W(this,n,this[k])}}}}var bt=Object.defineProperties(()=>{},{...N,level:{enumerable:!0,get(){return this[oe].level},set(t){this[oe].level=t}}}),ie=(t,e,r)=>{let o,n;return r===void 0?(o=t,n=e):(o=r.openAll+t,n=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:n,parent:r}},W=(t,e,r)=>{let o=(...n)=>Ct(o,n.length===1?""+n[0]:n.join(" "));return Object.setPrototypeOf(o,bt),o[oe]=t,o[A]=e,o[k]=r,o},Ct=(t,e)=>{if(t.level<=0||!e)return t[k]?"":e;let r=t[A];if(r===void 0)return e;let{openAll:o,closeAll:n}=r;if(e.includes("\x1B"))for(;r!==void 0;)e=Ue(e,r.close,r.open),r=r.parent;let s=e.indexOf(`
|
|
7
|
+
`);return s!==-1&&(e=Ve(e,n,o,s)),o+e+n};Object.defineProperties(L.prototype,N);var ht=L(),Br=L({level:qe?qe.level:0});var P=ht;function ae({cpu:t,mem:e}){let r=He(t),o=He(e);return Tt.createElement(yt,null,"CPU: ",r," ",se(t),"% MEM: ",o," ",se(e),"%")}function He(t){let e=Math.round(t/10),r=10-e,o="\u2593".repeat(e)+"\u2591".repeat(r);return se(t,o)}function se(t,e=t.toString()){return t<50?P.greenBright(e):t<80?P.yellowBright(e):P.redBright(e)}var Et=t=>t==="running"?{text:"\u{1F7E2} RUNNING",color:"green"}:t==="exited"?{text:"\u{1F534} EXITED",color:"red"}:t==="paused"?{text:"\u{1F7E0} PAUSED",color:"yellow"}:{text:t.toUpperCase(),color:"gray"};function ce({container:t}){let{id:e,name:r,image:o,state:n}=t,[s,i]=Ke({cpuPercent:0,memPercent:0,netIO:{rx:0,tx:0}}),u=m=>!m||m.length===0?"":Array.isArray(m)?m.map((C,B)=>`\u{1F517} ${C}`).join(" "):`\u{1F517} ${m}`,[w,E]=Ke("");wt(()=>{if(n!=="running")return;let m=async()=>{try{let B=await ke(e);i(B),E("")}catch{i({cpuPercent:0,memPercent:0,netIO:{rx:0,tx:0}}),E("No se pudo obtener stats")}};m();let C=setInterval(m,1500);return()=>clearInterval(C)},[e,n]);let b=Et(n);return I.createElement(le,{flexDirection:"column",marginBottom:1},I.createElement(le,null,I.createElement(j,{color:"cyan"},r.padEnd(20))," ",I.createElement(j,{color:"gray"},o.padEnd(20))," ",I.createElement(j,{color:b.color},b.text)," ",I.createElement(j,{color:"yellow"},u(t.ports))),n==="running"&&I.createElement(le,{marginLeft:2},I.createElement(ae,{cpu:parseFloat(s.cpuPercent),mem:parseFloat(s.memPercent)}),w&&I.createElement(j,{color:"red"},w)))}function ue({containers:t,selected:e}){return D.createElement(D.Fragment,null,t.map((r,o)=>D.createElement(It,{key:r.id,flexDirection:"row",alignItems:"center"},D.createElement(Ot,{color:o===e?"green":void 0},o===e?"\u27A4":" "),D.createElement(ce,{container:r,isSelected:o===e}))))}import ze from"react";import{Text as Bt}from"ink";function me({containers:t,selected:e}){return t.length===0?ze.createElement(Bt,null,"No containers found"):ze.createElement(ue,{containers:t,selected:e})}import Qe from"react";import{Box as vt,Text as St}from"ink";function fe({message:t,color:e}){return t?Qe.createElement(vt,{marginBottom:1},Qe.createElement(St,{color:e},t)):null}import H from"react";import{Box as At,Text as pe}from"ink";function de({count:t}){return H.createElement(At,{justifyContent:"space-between"},H.createElement(pe,{color:"cyanBright"},"\u{1F433} ",P.bold("CDD"),H.createElement(pe,{color:"gray"}," \u2014 CLI Docker Dashboard")),H.createElement(pe,{color:"gray"},t," container",t===1?"":"s"," found"))}import R from"react";import{Text as ge,useInput as Nt}from"ink";function xe({logs:t,onExit:e,container:r}){Nt((n,s)=>{s.escape&&e()});let o=t.slice(-15);return R.createElement(R.Fragment,null,R.createElement(ge,{color:"green"},r?.name||"Container"," logs, press ESC to exit"),o.length===0?R.createElement(ge,{dimColor:!0},"No logs..."):o.map((n,s)=>R.createElement(ge,{key:s},n)))}import K from"react";import{Box as Pt,Text as Ft}from"ink";import $ from"react";import{Text as be}from"ink";function Xe({label:t,value:e,required:r}){let o=r&&!e.trim();return $.createElement($.Fragment,null,$.createElement(be,null,t),$.createElement(be,{color:o?"red":"cyan"},e,"_"))}function Je({message:t,color:e}){return t?$.createElement(be,{color:e||"yellow"},t):null}function Ce(t){let{step:e,imageName:r,containerName:o,portInput:n,envInput:s,message:i,messageColor:u}=t,w=[{label:"Nombre de la imagen Docker:",value:r,required:!0},{label:"Nombre del contenedor (opcional):",value:o,required:!1},{label:"Puertos (opcional, formato 8080:80,443:443):",value:n,required:!1},{label:"Variables de entorno (opcional, formato VAR1=val1,VAR2=val2):",value:s,required:!1}],{label:E,value:b,required:m}=w[e]||{};return K.createElement(Pt,{flexDirection:"column",borderStyle:"round",borderColor:"yellow",padding:1},K.createElement(Xe,{label:E,value:b,required:m}),K.createElement(Je,{message:i,color:u}),K.createElement(Ft,{dimColor:!0},"Presiona Enter para continuar, Escape para cancelar"))}import O from"react";import{Box as _t,Text as v}from"ink";function he(){return O.createElement(_t,{flexDirection:"column",marginTop:1},O.createElement(v,null,"Use \u2191/\u2193 for navigation"),O.createElement(v,null,"\u2022I to initiate selected container"),O.createElement(v,null,"\u2022P to stop selected container"),O.createElement(v,null,"\u2022R to restart selected container"),O.createElement(v,null,"\u2022C to create a container"),O.createElement(v,null,"\u2022L to view logs of selected container"),O.createElement(v,null,"\u2022Q to quit"))}import Ze from"react";import{Box as Mt,Text as kt}from"ink";function Te(){return Ze.createElement(Mt,{justifyContent:"flex-end",width:"100%"},Ze.createElement(kt,{dimColor:!0},"Crafted by Carlos Cochero \u2022 2025"))}function ye(){let{containers:t}=Ie(),e=Me(t);return e.creatingContainer?x.createElement(Ce,{step:e.creationStep,imageName:e.imageNameInput,containerName:e.containerNameInput,portInput:e.portInput,envInput:e.envInput,message:e.message,messageColor:e.messageColor}):x.createElement(x.Fragment,null,x.createElement(Lt,{flexDirection:"column",borderStyle:"round",borderColor:"cyan",padding:1},x.createElement(de,{count:t.length}),x.createElement(jt,null," "),x.createElement(me,{containers:t,selected:e.selected}),x.createElement(Dt,null),x.createElement(fe,{message:e.message,color:e.messageColor}),x.createElement(he,null),x.createElement(Te,null)),e.showLogs&&x.createElement(xe,{logs:e.logs,onExit:e.exitLogs,container:t[e.selected]}))}$t(Rt.createElement(ye,null));
|
|
8
|
+
//# sourceMappingURL=cdd.bundle.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { PromptField, PromptMessage } from "./PromptField.jsx";
|
|
4
|
+
export default function ContainerCreationPrompt(props) {
|
|
5
|
+
var step = props.step,
|
|
6
|
+
imageName = props.imageName,
|
|
7
|
+
containerName = props.containerName,
|
|
8
|
+
portInput = props.portInput,
|
|
9
|
+
envInput = props.envInput,
|
|
10
|
+
message = props.message,
|
|
11
|
+
messageColor = props.messageColor;
|
|
12
|
+
var prompts = [{
|
|
13
|
+
label: "Name of the image to create (e.g., nginx:latest):",
|
|
14
|
+
value: imageName,
|
|
15
|
+
required: true
|
|
16
|
+
}, {
|
|
17
|
+
label: "Name of the container (optional):",
|
|
18
|
+
value: containerName,
|
|
19
|
+
required: false
|
|
20
|
+
}, {
|
|
21
|
+
label: "Ports (optional, format 8080:80,443:443):",
|
|
22
|
+
value: portInput,
|
|
23
|
+
required: false
|
|
24
|
+
}, {
|
|
25
|
+
label: "Environment variables (optional, format VAR1=val1,VAR2=val2):",
|
|
26
|
+
value: envInput,
|
|
27
|
+
required: false
|
|
28
|
+
}];
|
|
29
|
+
var _ref = prompts[step] || {},
|
|
30
|
+
label = _ref.label,
|
|
31
|
+
value = _ref.value,
|
|
32
|
+
required = _ref.required;
|
|
33
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
34
|
+
flexDirection: "column",
|
|
35
|
+
borderStyle: "round",
|
|
36
|
+
borderColor: "yellow",
|
|
37
|
+
padding: 1
|
|
38
|
+
}, /*#__PURE__*/React.createElement(PromptField, {
|
|
39
|
+
label: label,
|
|
40
|
+
value: value,
|
|
41
|
+
required: required
|
|
42
|
+
}), /*#__PURE__*/React.createElement(PromptMessage, {
|
|
43
|
+
message: message,
|
|
44
|
+
color: messageColor
|
|
45
|
+
}), /*#__PURE__*/React.createElement(Text, {
|
|
46
|
+
dimColor: true
|
|
47
|
+
}, "Press Enter to continue, Escape to cancel"));
|
|
48
|
+
}
|