dtop 1.0.0__tar.gz
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.
- dtop-1.0.0/LICENSE +21 -0
- dtop-1.0.0/MANIFEST.in +4 -0
- dtop-1.0.0/PKG-INFO +170 -0
- dtop-1.0.0/README.md +136 -0
- dtop-1.0.0/dtop/__init__.py +12 -0
- dtop-1.0.0/dtop/actions/__init__.py +1 -0
- dtop-1.0.0/dtop/actions/container_actions.py +185 -0
- dtop-1.0.0/dtop/core/__init__.py +1 -0
- dtop-1.0.0/dtop/core/docker_tui.py +845 -0
- dtop-1.0.0/dtop/core/stats.py +511 -0
- dtop-1.0.0/dtop/main.py +48 -0
- dtop-1.0.0/dtop/utils/__init__.py +1 -0
- dtop-1.0.0/dtop/utils/config.py +69 -0
- dtop-1.0.0/dtop/utils/normalize_logs.py +233 -0
- dtop-1.0.0/dtop/utils/utils.py +72 -0
- dtop-1.0.0/dtop/views/__init__.py +1 -0
- dtop-1.0.0/dtop/views/inspect_view.py +702 -0
- dtop-1.0.0/dtop/views/log_view.py +2317 -0
- dtop-1.0.0/dtop.egg-info/PKG-INFO +170 -0
- dtop-1.0.0/dtop.egg-info/SOURCES.txt +27 -0
- dtop-1.0.0/dtop.egg-info/dependency_links.txt +1 -0
- dtop-1.0.0/dtop.egg-info/entry_points.txt +2 -0
- dtop-1.0.0/dtop.egg-info/requires.txt +4 -0
- dtop-1.0.0/dtop.egg-info/top_level.txt +1 -0
- dtop-1.0.0/pyproject.toml +55 -0
- dtop-1.0.0/scripts/install.sh +144 -0
- dtop-1.0.0/scripts/uninstall.sh +66 -0
- dtop-1.0.0/setup.cfg +4 -0
- dtop-1.0.0/tests/test.py +129 -0
dtop-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 StakeSquid
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
dtop-1.0.0/MANIFEST.in
ADDED
dtop-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dtop
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A high-performance terminal UI for Docker container management
|
|
5
|
+
Author: StakeSquid
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/StakeSquid/dtop
|
|
8
|
+
Project-URL: Repository, https://github.com/StakeSquid/dtop
|
|
9
|
+
Project-URL: Issues, https://github.com/StakeSquid/dtop/issues
|
|
10
|
+
Keywords: docker,tui,terminal,containers,monitoring
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Console :: Curses
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Operating System :: Unix
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Topic :: System :: Monitoring
|
|
25
|
+
Classifier: Topic :: System :: Systems Administration
|
|
26
|
+
Classifier: Topic :: Utilities
|
|
27
|
+
Requires-Python: >=3.8
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: docker>=6.0.0
|
|
31
|
+
Provides-Extra: full
|
|
32
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "full"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# dtop - Docker Terminal UI
|
|
36
|
+
|
|
37
|
+
A high-performance terminal UI for Docker container management with real-time monitoring and advanced log viewing.
|
|
38
|
+
|
|
39
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 39 12 PM" src="https://github.com/user-attachments/assets/e5697f99-fdd4-4d41-bd69-02072db5385c" />
|
|
40
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 39 21 PM" src="https://github.com/user-attachments/assets/0694304e-f256-47b5-923b-5c05ed0035b7" />
|
|
41
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 39 48 PM" src="https://github.com/user-attachments/assets/df379064-9f33-48f7-9e8b-635723df6572" />
|
|
42
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 40 01 PM" src="https://github.com/user-attachments/assets/aeb20e8e-202c-49f8-bd09-7b563964bb9e" />
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
- **Real-time Stats**: Live CPU, memory, and network monitoring with parallel stats collection
|
|
49
|
+
- **Log Management**:
|
|
50
|
+
- Advanced normalization for consistent log formatting
|
|
51
|
+
- Text search with highlighted results
|
|
52
|
+
- Powerful filtering with inclusion/exclusion support
|
|
53
|
+
- Follow mode for real-time updates
|
|
54
|
+
- **Container Controls**: Start/stop, pause/unpause, restart, exec shell, force recreate
|
|
55
|
+
- **Mouse Support**: Click navigation, scrolling, and menu interaction
|
|
56
|
+
- **Customizable Interface**: Resizable columns with persistent configuration
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
### One-Line Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Install directly from GitHub
|
|
64
|
+
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/StakeSquid/dtop/main/install.sh)"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Manual Install
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# 1. Clone repository
|
|
71
|
+
git clone https://github.com/StakeSquid/dtop
|
|
72
|
+
cd dtop
|
|
73
|
+
|
|
74
|
+
# 2. Install dependency
|
|
75
|
+
pip install docker
|
|
76
|
+
|
|
77
|
+
# 3. Run directly
|
|
78
|
+
chmod +x main.py
|
|
79
|
+
./main.py
|
|
80
|
+
|
|
81
|
+
# 4. Or install system-wide
|
|
82
|
+
sudo mkdir -p /usr/local/bin/docker-tui
|
|
83
|
+
sudo cp *.py /usr/local/bin/docker-tui/
|
|
84
|
+
sudo chmod +x /usr/local/bin/docker-tui/*.py
|
|
85
|
+
sudo tee /usr/local/bin/dtop > /dev/null << 'EOF'
|
|
86
|
+
#!/bin/bash
|
|
87
|
+
exec python3 /usr/local/bin/docker-tui/main.py "$@"
|
|
88
|
+
EOF
|
|
89
|
+
sudo chmod +x /usr/local/bin/dtop
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Uninstall
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
sudo rm -rf /usr/local/bin/docker-tui /usr/local/bin/dtop
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Quick Reference
|
|
99
|
+
|
|
100
|
+
### Controls
|
|
101
|
+
|
|
102
|
+
| View | Key | Action |
|
|
103
|
+
|------|-----|--------|
|
|
104
|
+
| **Main** | ↑/↓, Click | Navigate containers |
|
|
105
|
+
| | Enter/Click | Show container menu |
|
|
106
|
+
| | L | View container logs |
|
|
107
|
+
| | Q | Quit |
|
|
108
|
+
| **Logs** | ↑/↓, PgUp/PgDn | Scroll logs |
|
|
109
|
+
| | / | Search in logs |
|
|
110
|
+
| | \\ | Filter logs (grep) |
|
|
111
|
+
| | F | Toggle follow mode |
|
|
112
|
+
| | N | Toggle log normalization |
|
|
113
|
+
| | W | Toggle line wrapping |
|
|
114
|
+
| | n/N | Next/previous search hit |
|
|
115
|
+
| | ESC | Clear filter or return to container list |
|
|
116
|
+
|
|
117
|
+
### Container Actions
|
|
118
|
+
|
|
119
|
+
- **Logs**: View detailed container logs
|
|
120
|
+
- **Start/Stop**: Toggle container running state
|
|
121
|
+
- **Pause/Unpause**: Temporarily pause execution
|
|
122
|
+
- **Restart**: Restart the container
|
|
123
|
+
- **Recreate**: Recreate container from image
|
|
124
|
+
- **Exec Shell**: Open interactive shell in container
|
|
125
|
+
|
|
126
|
+
## Advanced Log Filtering
|
|
127
|
+
|
|
128
|
+
The log viewer supports powerful filtering with both inclusion and exclusion patterns:
|
|
129
|
+
|
|
130
|
+
### Filter Syntax
|
|
131
|
+
|
|
132
|
+
- **Include**: `word` or `+word` - Show only lines containing "word"
|
|
133
|
+
- **Exclude**: `-word` or `!word` - Hide lines containing "word"
|
|
134
|
+
- **Multiple filters**: Space-separated, all conditions must match
|
|
135
|
+
- **Multi-word**: Use quotes for phrases: `"error message" -"debug"`
|
|
136
|
+
|
|
137
|
+
### Examples
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
error # Show only lines with "error"
|
|
141
|
+
+error -debug # Show lines with "error" but not "debug"
|
|
142
|
+
error warning -verbose # Show lines with "error" OR "warning", but not "verbose"
|
|
143
|
+
"connection failed" # Show lines with exact phrase
|
|
144
|
+
+ERROR -"DEBUG:" -INFO # Case-sensitive: ERROR lines without DEBUG: or INFO
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Filter Behavior
|
|
148
|
+
|
|
149
|
+
- Multiple inclusion filters work as OR (any match includes the line)
|
|
150
|
+
- Exclusion filters always take precedence (any match excludes the line)
|
|
151
|
+
- Press Tab to toggle case sensitivity
|
|
152
|
+
- Press ESC to clear active filter
|
|
153
|
+
- Press \\ to modify current filter
|
|
154
|
+
|
|
155
|
+
## Configuration
|
|
156
|
+
|
|
157
|
+
- Settings automatically saved to `~/.docker_tui.json`
|
|
158
|
+
- Columns auto-adjust to terminal width
|
|
159
|
+
- Resizable columns (drag separators with mouse)
|
|
160
|
+
|
|
161
|
+
## Requirements
|
|
162
|
+
|
|
163
|
+
- Python 3.8+
|
|
164
|
+
- Docker daemon
|
|
165
|
+
- `docker` Python package
|
|
166
|
+
- Terminal with mouse support and colors
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT License - See LICENSE file for details.
|
dtop-1.0.0/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# dtop - Docker Terminal UI
|
|
2
|
+
|
|
3
|
+
A high-performance terminal UI for Docker container management with real-time monitoring and advanced log viewing.
|
|
4
|
+
|
|
5
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 39 12 PM" src="https://github.com/user-attachments/assets/e5697f99-fdd4-4d41-bd69-02072db5385c" />
|
|
6
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 39 21 PM" src="https://github.com/user-attachments/assets/0694304e-f256-47b5-923b-5c05ed0035b7" />
|
|
7
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 39 48 PM" src="https://github.com/user-attachments/assets/df379064-9f33-48f7-9e8b-635723df6572" />
|
|
8
|
+
<img width="1611" alt="Screenshot 2025-05-24 at 6 40 01 PM" src="https://github.com/user-attachments/assets/aeb20e8e-202c-49f8-bd09-7b563964bb9e" />
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Real-time Stats**: Live CPU, memory, and network monitoring with parallel stats collection
|
|
15
|
+
- **Log Management**:
|
|
16
|
+
- Advanced normalization for consistent log formatting
|
|
17
|
+
- Text search with highlighted results
|
|
18
|
+
- Powerful filtering with inclusion/exclusion support
|
|
19
|
+
- Follow mode for real-time updates
|
|
20
|
+
- **Container Controls**: Start/stop, pause/unpause, restart, exec shell, force recreate
|
|
21
|
+
- **Mouse Support**: Click navigation, scrolling, and menu interaction
|
|
22
|
+
- **Customizable Interface**: Resizable columns with persistent configuration
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### One-Line Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Install directly from GitHub
|
|
30
|
+
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/StakeSquid/dtop/main/install.sh)"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Manual Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# 1. Clone repository
|
|
37
|
+
git clone https://github.com/StakeSquid/dtop
|
|
38
|
+
cd dtop
|
|
39
|
+
|
|
40
|
+
# 2. Install dependency
|
|
41
|
+
pip install docker
|
|
42
|
+
|
|
43
|
+
# 3. Run directly
|
|
44
|
+
chmod +x main.py
|
|
45
|
+
./main.py
|
|
46
|
+
|
|
47
|
+
# 4. Or install system-wide
|
|
48
|
+
sudo mkdir -p /usr/local/bin/docker-tui
|
|
49
|
+
sudo cp *.py /usr/local/bin/docker-tui/
|
|
50
|
+
sudo chmod +x /usr/local/bin/docker-tui/*.py
|
|
51
|
+
sudo tee /usr/local/bin/dtop > /dev/null << 'EOF'
|
|
52
|
+
#!/bin/bash
|
|
53
|
+
exec python3 /usr/local/bin/docker-tui/main.py "$@"
|
|
54
|
+
EOF
|
|
55
|
+
sudo chmod +x /usr/local/bin/dtop
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Uninstall
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
sudo rm -rf /usr/local/bin/docker-tui /usr/local/bin/dtop
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick Reference
|
|
65
|
+
|
|
66
|
+
### Controls
|
|
67
|
+
|
|
68
|
+
| View | Key | Action |
|
|
69
|
+
|------|-----|--------|
|
|
70
|
+
| **Main** | ↑/↓, Click | Navigate containers |
|
|
71
|
+
| | Enter/Click | Show container menu |
|
|
72
|
+
| | L | View container logs |
|
|
73
|
+
| | Q | Quit |
|
|
74
|
+
| **Logs** | ↑/↓, PgUp/PgDn | Scroll logs |
|
|
75
|
+
| | / | Search in logs |
|
|
76
|
+
| | \\ | Filter logs (grep) |
|
|
77
|
+
| | F | Toggle follow mode |
|
|
78
|
+
| | N | Toggle log normalization |
|
|
79
|
+
| | W | Toggle line wrapping |
|
|
80
|
+
| | n/N | Next/previous search hit |
|
|
81
|
+
| | ESC | Clear filter or return to container list |
|
|
82
|
+
|
|
83
|
+
### Container Actions
|
|
84
|
+
|
|
85
|
+
- **Logs**: View detailed container logs
|
|
86
|
+
- **Start/Stop**: Toggle container running state
|
|
87
|
+
- **Pause/Unpause**: Temporarily pause execution
|
|
88
|
+
- **Restart**: Restart the container
|
|
89
|
+
- **Recreate**: Recreate container from image
|
|
90
|
+
- **Exec Shell**: Open interactive shell in container
|
|
91
|
+
|
|
92
|
+
## Advanced Log Filtering
|
|
93
|
+
|
|
94
|
+
The log viewer supports powerful filtering with both inclusion and exclusion patterns:
|
|
95
|
+
|
|
96
|
+
### Filter Syntax
|
|
97
|
+
|
|
98
|
+
- **Include**: `word` or `+word` - Show only lines containing "word"
|
|
99
|
+
- **Exclude**: `-word` or `!word` - Hide lines containing "word"
|
|
100
|
+
- **Multiple filters**: Space-separated, all conditions must match
|
|
101
|
+
- **Multi-word**: Use quotes for phrases: `"error message" -"debug"`
|
|
102
|
+
|
|
103
|
+
### Examples
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
error # Show only lines with "error"
|
|
107
|
+
+error -debug # Show lines with "error" but not "debug"
|
|
108
|
+
error warning -verbose # Show lines with "error" OR "warning", but not "verbose"
|
|
109
|
+
"connection failed" # Show lines with exact phrase
|
|
110
|
+
+ERROR -"DEBUG:" -INFO # Case-sensitive: ERROR lines without DEBUG: or INFO
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Filter Behavior
|
|
114
|
+
|
|
115
|
+
- Multiple inclusion filters work as OR (any match includes the line)
|
|
116
|
+
- Exclusion filters always take precedence (any match excludes the line)
|
|
117
|
+
- Press Tab to toggle case sensitivity
|
|
118
|
+
- Press ESC to clear active filter
|
|
119
|
+
- Press \\ to modify current filter
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
- Settings automatically saved to `~/.docker_tui.json`
|
|
124
|
+
- Columns auto-adjust to terminal width
|
|
125
|
+
- Resizable columns (drag separators with mouse)
|
|
126
|
+
|
|
127
|
+
## Requirements
|
|
128
|
+
|
|
129
|
+
- Python 3.8+
|
|
130
|
+
- Docker daemon
|
|
131
|
+
- `docker` Python package
|
|
132
|
+
- Terminal with mouse support and colors
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT License - See LICENSE file for details.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
dtop - Docker Terminal UI
|
|
3
|
+
A high-performance terminal UI for Docker container management.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__version__ = "1.0.0"
|
|
7
|
+
__author__ = "StakeSquid"
|
|
8
|
+
__description__ = "A high-performance terminal UI for Docker container management"
|
|
9
|
+
|
|
10
|
+
from .core.docker_tui import DockerTUI
|
|
11
|
+
|
|
12
|
+
__all__ = ["DockerTUI"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Container action modules for dtop"""
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Docker TUI - Container Actions Module
|
|
4
|
+
-----------
|
|
5
|
+
Handles container actions menu and operations.
|
|
6
|
+
"""
|
|
7
|
+
import curses
|
|
8
|
+
import subprocess
|
|
9
|
+
import time
|
|
10
|
+
from ..utils.utils import safe_addstr
|
|
11
|
+
|
|
12
|
+
def show_menu(tui, stdscr, container):
|
|
13
|
+
"""Show action menu for container with arrow key navigation"""
|
|
14
|
+
try:
|
|
15
|
+
# Determine available actions based on container state
|
|
16
|
+
is_running = container.status == "running"
|
|
17
|
+
is_paused = container.status == "paused"
|
|
18
|
+
|
|
19
|
+
# Build menu options with keys, labels, and availability
|
|
20
|
+
opts = []
|
|
21
|
+
opts.append(("L", "Logs", True))
|
|
22
|
+
opts.append(("I", "Inspect", True)) # Always available
|
|
23
|
+
opts.append(("S", "Stop" if is_running else "Start", True))
|
|
24
|
+
opts.append(("P", "Unpause" if is_paused else "Pause", is_running and not is_paused))
|
|
25
|
+
opts.append(("R", "Restart", is_running))
|
|
26
|
+
opts.append(("F", "Recreate", True))
|
|
27
|
+
opts.append(("E", "Exec Shell", is_running))
|
|
28
|
+
opts.append(("C", "Cancel", True))
|
|
29
|
+
|
|
30
|
+
# Calculate dimensions
|
|
31
|
+
h, w = stdscr.getmaxyx()
|
|
32
|
+
menu_width = 30
|
|
33
|
+
menu_height = len(opts) + 4
|
|
34
|
+
|
|
35
|
+
# Create menu in top-left corner with border
|
|
36
|
+
menu = curses.newwin(menu_height, menu_width, 1, 0)
|
|
37
|
+
menu.keypad(True) # Enable keypad for arrow keys
|
|
38
|
+
menu.border()
|
|
39
|
+
|
|
40
|
+
# Draw title
|
|
41
|
+
title = f" Container: {container.name[:20]} "
|
|
42
|
+
safe_addstr(menu, 0, (menu_width - len(title))//2, title)
|
|
43
|
+
|
|
44
|
+
# Current selection
|
|
45
|
+
current = 0
|
|
46
|
+
|
|
47
|
+
# Menu loop
|
|
48
|
+
while True:
|
|
49
|
+
# Draw all options
|
|
50
|
+
for i, (key, label, enabled) in enumerate(opts):
|
|
51
|
+
# Format option text
|
|
52
|
+
text = f"{key}: {label}"
|
|
53
|
+
|
|
54
|
+
# Determine attributes
|
|
55
|
+
if i == current and enabled:
|
|
56
|
+
attr = curses.color_pair(7) | curses.A_BOLD
|
|
57
|
+
elif i == current:
|
|
58
|
+
attr = curses.color_pair(6) | curses.A_DIM
|
|
59
|
+
elif enabled:
|
|
60
|
+
attr = curses.A_NORMAL
|
|
61
|
+
else:
|
|
62
|
+
attr = curses.A_DIM
|
|
63
|
+
|
|
64
|
+
# Draw option
|
|
65
|
+
safe_addstr(menu, i + 2, 2, " " * (menu_width - 4), curses.A_NORMAL)
|
|
66
|
+
safe_addstr(menu, i + 2, 2, text, attr)
|
|
67
|
+
|
|
68
|
+
# Draw help
|
|
69
|
+
help_text = "↑/↓:Navigate | Enter/Click:Select | ESC:Cancel"
|
|
70
|
+
safe_addstr(menu, menu_height - 1, (menu_width - len(help_text))//2, help_text, curses.A_DIM)
|
|
71
|
+
|
|
72
|
+
menu.refresh()
|
|
73
|
+
|
|
74
|
+
# Handle input
|
|
75
|
+
c = menu.getch()
|
|
76
|
+
|
|
77
|
+
if c == curses.KEY_UP and current > 0:
|
|
78
|
+
current = (current - 1) % len(opts)
|
|
79
|
+
# Skip disabled options
|
|
80
|
+
while not opts[current][2] and current > 0:
|
|
81
|
+
current = (current - 1) % len(opts)
|
|
82
|
+
|
|
83
|
+
elif c == curses.KEY_DOWN and current < len(opts) - 1:
|
|
84
|
+
current = (current + 1) % len(opts)
|
|
85
|
+
# Skip disabled options
|
|
86
|
+
while not opts[current][2] and current < len(opts) - 1:
|
|
87
|
+
current = (current + 1) % len(opts)
|
|
88
|
+
|
|
89
|
+
elif c in (10, curses.KEY_ENTER) and opts[current][2]:
|
|
90
|
+
# Selected an enabled option
|
|
91
|
+
action_key = opts[current][0].lower()
|
|
92
|
+
break
|
|
93
|
+
|
|
94
|
+
elif c == curses.KEY_MOUSE:
|
|
95
|
+
try:
|
|
96
|
+
_, mx, my, _, button_state = curses.getmouse()
|
|
97
|
+
if button_state & curses.BUTTON1_CLICKED:
|
|
98
|
+
# Check if click was on a menu item
|
|
99
|
+
for i, (_, _, enabled) in enumerate(opts):
|
|
100
|
+
if my == i + 2 and enabled:
|
|
101
|
+
action_key = opts[i][0].lower()
|
|
102
|
+
break
|
|
103
|
+
else:
|
|
104
|
+
# Click not on menu item, continue loop
|
|
105
|
+
continue
|
|
106
|
+
break
|
|
107
|
+
except curses.error:
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
elif c == 27: # ESC
|
|
111
|
+
action_key = 'c' # Cancel
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
elif c in range(97, 123): # a-z
|
|
115
|
+
action_key = chr(c)
|
|
116
|
+
# Check if this key is a valid shortcut
|
|
117
|
+
for key, _, enabled in opts:
|
|
118
|
+
if key.lower() == action_key and enabled:
|
|
119
|
+
break
|
|
120
|
+
else:
|
|
121
|
+
# Not a valid shortcut, continue loop
|
|
122
|
+
continue
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
elif c in range(65, 91): # A-Z
|
|
126
|
+
action_key = chr(c).lower()
|
|
127
|
+
# Check if this key is a valid shortcut
|
|
128
|
+
for key, _, enabled in opts:
|
|
129
|
+
if key.lower() == action_key and enabled:
|
|
130
|
+
break
|
|
131
|
+
else:
|
|
132
|
+
# Not a valid shortcut, continue loop
|
|
133
|
+
continue
|
|
134
|
+
break
|
|
135
|
+
|
|
136
|
+
# Clean up
|
|
137
|
+
del menu
|
|
138
|
+
stdscr.touchwin()
|
|
139
|
+
stdscr.refresh()
|
|
140
|
+
|
|
141
|
+
# Return selected action
|
|
142
|
+
return action_key
|
|
143
|
+
|
|
144
|
+
except Exception as e:
|
|
145
|
+
# Show error and wait for key
|
|
146
|
+
h, w = stdscr.getmaxyx()
|
|
147
|
+
stdscr.clear()
|
|
148
|
+
safe_addstr(stdscr, h//2, (w-len(str(e))-10)//2, f"Error: {e}", curses.A_BOLD)
|
|
149
|
+
safe_addstr(stdscr, h//2+1, (w-25)//2, "Press any key to continue...", curses.A_DIM)
|
|
150
|
+
stdscr.refresh()
|
|
151
|
+
stdscr.getch()
|
|
152
|
+
return 'c' # Return cancel on error
|
|
153
|
+
|
|
154
|
+
def execute_action(tui, stdscr, container, action_key):
|
|
155
|
+
"""Execute the selected container action"""
|
|
156
|
+
# Import here to avoid circular imports
|
|
157
|
+
from ..views import log_view
|
|
158
|
+
from ..views import inspect_view
|
|
159
|
+
|
|
160
|
+
if action_key == 'l':
|
|
161
|
+
log_view.show_logs(tui, stdscr, container)
|
|
162
|
+
elif action_key == 'i': # Use the new inspect_view module
|
|
163
|
+
inspect_view.show_inspect(tui, stdscr, container)
|
|
164
|
+
elif action_key == 's':
|
|
165
|
+
if container.status == "running":
|
|
166
|
+
container.stop()
|
|
167
|
+
else:
|
|
168
|
+
container.start()
|
|
169
|
+
elif action_key == 'p':
|
|
170
|
+
if container.status == "paused":
|
|
171
|
+
container.unpause()
|
|
172
|
+
elif container.status == "running":
|
|
173
|
+
container.pause()
|
|
174
|
+
elif action_key == 'r' and container.status == "running":
|
|
175
|
+
container.restart()
|
|
176
|
+
elif action_key == 'f':
|
|
177
|
+
img = container.image.tags[0] if container.image.tags else container.image.short_id
|
|
178
|
+
container.remove(force=True)
|
|
179
|
+
tui.client.containers.run(img, detach=True)
|
|
180
|
+
elif action_key == 'e' and container.status == "running":
|
|
181
|
+
curses.endwin()
|
|
182
|
+
subprocess.call(["docker","exec","-it",container.id,"/bin/bash"])
|
|
183
|
+
stdscr.clear()
|
|
184
|
+
curses.doupdate()
|
|
185
|
+
# 'c' (cancel) does nothing
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core modules for dtop Docker TUI"""
|