susops 3.0.0rc3.dev1__py3-none-any.whl
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.
- susops/__init__.py +4 -0
- susops/client.py +230 -0
- susops/core/__init__.py +0 -0
- susops/core/browsers.py +330 -0
- susops/core/config.py +253 -0
- susops/core/log_style.py +92 -0
- susops/core/pac.py +185 -0
- susops/core/ports.py +57 -0
- susops/core/process.py +167 -0
- susops/core/rpc_protocol.py +186 -0
- susops/core/rpc_server.py +131 -0
- susops/core/services_daemon.py +312 -0
- susops/core/share.py +323 -0
- susops/core/socat.py +200 -0
- susops/core/ssh.py +330 -0
- susops/core/ssh_config.py +40 -0
- susops/core/status.py +245 -0
- susops/core/types.py +171 -0
- susops/facade.py +2237 -0
- susops/tray/__init__.py +20 -0
- susops/tray/base.py +650 -0
- susops/tray/linux.py +1623 -0
- susops/tray/mac.py +3105 -0
- susops/tui/__init__.py +0 -0
- susops/tui/__main__.py +44 -0
- susops/tui/app.py +191 -0
- susops/tui/cli.py +665 -0
- susops/tui/screens/__init__.py +114 -0
- susops/tui/screens/connections.py +871 -0
- susops/tui/screens/dashboard.py +935 -0
- susops/tui/screens/shares.py +357 -0
- susops/tui/widgets/__init__.py +0 -0
- susops/tui/widgets/connection_card.py +137 -0
- susops/version.py +12 -0
- susops-3.0.0rc3.dev1.dist-info/METADATA +977 -0
- susops-3.0.0rc3.dev1.dist-info/RECORD +40 -0
- susops-3.0.0rc3.dev1.dist-info/WHEEL +5 -0
- susops-3.0.0rc3.dev1.dist-info/entry_points.txt +7 -0
- susops-3.0.0rc3.dev1.dist-info/licenses/LICENSE +674 -0
- susops-3.0.0rc3.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Shared helpers for TUI screens."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from textual.app import ComposeResult
|
|
9
|
+
from textual.containers import Horizontal
|
|
10
|
+
from textual.widgets import Footer, Label, Static
|
|
11
|
+
|
|
12
|
+
import susops
|
|
13
|
+
from susops.core.config import PortForward as _PortForward
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class _CollapsingLabel(Label):
|
|
17
|
+
"""Label that is display:none with zero margin/padding when empty, visible when it has content."""
|
|
18
|
+
|
|
19
|
+
def on_mount(self) -> None:
|
|
20
|
+
self.styles.margin = 0
|
|
21
|
+
self.styles.padding = 0
|
|
22
|
+
self.display = False
|
|
23
|
+
|
|
24
|
+
def update(self, renderable="") -> None:
|
|
25
|
+
super().update(renderable)
|
|
26
|
+
self.display = bool(str(renderable).strip())
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def open_path(path: str) -> None:
|
|
30
|
+
"""Open a file or directory with the system default handler."""
|
|
31
|
+
if sys.platform == "darwin":
|
|
32
|
+
subprocess.Popen(["open", path])
|
|
33
|
+
else:
|
|
34
|
+
subprocess.Popen(["xdg-open", path])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def open_in_explorer(file_path: str) -> None:
|
|
38
|
+
"""Open the parent directory of file_path in the system file manager."""
|
|
39
|
+
if sys.platform == "darwin":
|
|
40
|
+
subprocess.Popen(["open", "-R", file_path])
|
|
41
|
+
else:
|
|
42
|
+
subprocess.Popen(["xdg-open", str(Path(file_path).parent)])
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def share_name_markup(file_path: str, name: str) -> str:
|
|
46
|
+
"""Return Rich action-link markup for a share filename, or plain name if path contains a single quote."""
|
|
47
|
+
if "'" not in file_path:
|
|
48
|
+
return f"[@click=screen.open_share('{file_path}')]{name}[/]"
|
|
49
|
+
return name
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def compose_footer() -> ComposeResult:
|
|
53
|
+
"""Yield a footer row with key bindings and the app version on the right."""
|
|
54
|
+
with Horizontal(classes="footer-row"):
|
|
55
|
+
yield Footer()
|
|
56
|
+
yield Static(f"[@click=app.open_github()]v{susops.__version__}[/]", classes="footer-version", markup=True)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def proto_label(fw: _PortForward) -> str:
|
|
60
|
+
"""Return display string for a forward's protocol(s): TCP, UDP, or TCP+UDP."""
|
|
61
|
+
if fw.tcp and fw.udp:
|
|
62
|
+
return "TCP+UDP"
|
|
63
|
+
if fw.udp:
|
|
64
|
+
return "UDP"
|
|
65
|
+
return "TCP"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def status_dot(running: bool, enabled: bool = True, partial: bool = False) -> str:
|
|
69
|
+
"""Return Rich markup for the status indicator dot.
|
|
70
|
+
|
|
71
|
+
partial=True (TCP+UDP where one protocol is down) → yellow ●
|
|
72
|
+
running=True → green ●
|
|
73
|
+
enabled=True, not running → red ○
|
|
74
|
+
enabled=False → ─ (disabled)
|
|
75
|
+
"""
|
|
76
|
+
if not enabled:
|
|
77
|
+
return "─"
|
|
78
|
+
if partial:
|
|
79
|
+
return "[yellow]●[/yellow]"
|
|
80
|
+
if running:
|
|
81
|
+
return "[green]●[/green]"
|
|
82
|
+
return "[red]○[/red]"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def share_status_dot(running: bool, stopped: bool) -> str:
|
|
86
|
+
"""Return Rich markup for a share status dot.
|
|
87
|
+
|
|
88
|
+
running=True → green ●
|
|
89
|
+
stopped=True (manually stopped) → ─
|
|
90
|
+
otherwise (connection down) → red ○
|
|
91
|
+
"""
|
|
92
|
+
if running:
|
|
93
|
+
return "[green]●[/green]"
|
|
94
|
+
if stopped:
|
|
95
|
+
return "─"
|
|
96
|
+
return "[red]○[/red]"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def fmt_bps(bps: float) -> str:
|
|
100
|
+
if bps >= 1_048_576:
|
|
101
|
+
return f"{bps / 1_048_576:.1f}MB/s"
|
|
102
|
+
if bps >= 1024:
|
|
103
|
+
return f"{bps / 1024:.0f}kB/s"
|
|
104
|
+
return f"{bps:.0f}B/s"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def fmt_bytes(b: float) -> str:
|
|
108
|
+
if b >= 1_073_741_824:
|
|
109
|
+
return f"{b / 1_073_741_824:.1f}GB"
|
|
110
|
+
if b >= 1_048_576:
|
|
111
|
+
return f"{b / 1_048_576:.1f}MB"
|
|
112
|
+
if b >= 1024:
|
|
113
|
+
return f"{b / 1024:.0f}kB"
|
|
114
|
+
return f"{b:.0f}B"
|