feat: multi-type server support — SQL, Redis, Grafana, Prometheus, Telnet, WinRM, RDP/VNC
Full implementation of multi-type server management across GUI and CLI: New clients: SQLClient (MariaDB/MSSQL/PostgreSQL), RedisClient, GrafanaClient, PrometheusClient, TelnetSession, WinRMClient, RemoteDesktopLauncher. New GUI tabs: QueryTab (SQL editor + Treeview), RedisTab (console + history), GrafanaTab (dashboards + alerts), PrometheusTab (PromQL + targets), PowershellTab (PS/CMD), LaunchTab (RDP/VNC external client). Infrastructure: TAB_REGISTRY for conditional tabs per server type, adaptive server_dialog fields, colored type badges in sidebar, status checker for all types (SSH/TCP/SQL/Redis/HTTP), 100+ i18n keys. CLI: ssh.py extended with --sql, --redis, --grafana-*, --prom-*, --ps, --cmd. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
110
gui/tabs/launch_tab.py
Normal file
110
gui/tabs/launch_tab.py
Normal file
@@ -0,0 +1,110 @@
|
||||
"""
|
||||
Launch tab — connect button for RDP/VNC remote desktop sessions.
|
||||
"""
|
||||
|
||||
import threading
|
||||
import customtkinter as ctk
|
||||
from core.remote_desktop import RemoteDesktopLauncher
|
||||
from core.i18n import t
|
||||
|
||||
|
||||
class LaunchTab(ctk.CTkFrame):
|
||||
"""Minimal tab: server info + big Connect button for RDP/VNC."""
|
||||
|
||||
def __init__(self, master, store):
|
||||
super().__init__(master, fg_color="transparent")
|
||||
self.store = store
|
||||
self._current_alias: str | None = None
|
||||
self._server_type: str | None = None # "rdp" or "vnc"
|
||||
|
||||
self._build_ui()
|
||||
|
||||
def _build_ui(self):
|
||||
# Server info label
|
||||
self._info_label = ctk.CTkLabel(
|
||||
self, text=t("no_server_selected_info"),
|
||||
font=ctk.CTkFont(size=16), wraplength=400,
|
||||
)
|
||||
self._info_label.pack(padx=20, pady=(40, 20))
|
||||
|
||||
# Big connect button
|
||||
self._connect_btn = ctk.CTkButton(
|
||||
self, text=t("launch_connect"),
|
||||
font=ctk.CTkFont(size=18, weight="bold"),
|
||||
width=220, height=50,
|
||||
command=self._on_connect,
|
||||
)
|
||||
self._connect_btn.pack(pady=20)
|
||||
self._connect_btn.configure(state="disabled")
|
||||
|
||||
# Status / result label
|
||||
self._status_label = ctk.CTkLabel(
|
||||
self, text="", font=ctk.CTkFont(size=13),
|
||||
text_color="#888888", wraplength=400,
|
||||
)
|
||||
self._status_label.pack(padx=20, pady=(10, 0))
|
||||
|
||||
def set_server(self, alias: str | None):
|
||||
self._current_alias = alias
|
||||
self._status_label.configure(text="", text_color="#888888")
|
||||
|
||||
if alias is None:
|
||||
self._info_label.configure(text=t("no_server_selected_info"))
|
||||
self._connect_btn.configure(state="disabled")
|
||||
self._server_type = None
|
||||
return
|
||||
|
||||
server = self.store.get_server(alias)
|
||||
if not server:
|
||||
self._info_label.configure(text=t("server_not_found").format(alias=alias))
|
||||
self._connect_btn.configure(state="disabled")
|
||||
self._server_type = None
|
||||
return
|
||||
|
||||
stype = server.get("type", "").lower()
|
||||
self._server_type = stype
|
||||
|
||||
if stype == "rdp":
|
||||
info_text = t("launch_rdp_info").format(alias=alias)
|
||||
elif stype == "vnc":
|
||||
info_text = t("launch_vnc_info").format(alias=alias)
|
||||
else:
|
||||
info_text = f"{alias} ({stype.upper()})"
|
||||
|
||||
self._info_label.configure(text=info_text)
|
||||
self._connect_btn.configure(state="normal")
|
||||
|
||||
def _on_connect(self):
|
||||
if not self._current_alias or not self._server_type:
|
||||
return
|
||||
|
||||
server = self.store.get_server(self._current_alias)
|
||||
if not server:
|
||||
return
|
||||
|
||||
self._connect_btn.configure(state="disabled")
|
||||
self._status_label.configure(
|
||||
text=t("launch_starting"), text_color="#ccaa00",
|
||||
)
|
||||
|
||||
stype = self._server_type
|
||||
|
||||
def _do():
|
||||
try:
|
||||
if stype == "rdp":
|
||||
RemoteDesktopLauncher.launch_rdp(server)
|
||||
elif stype == "vnc":
|
||||
RemoteDesktopLauncher.launch_vnc(server)
|
||||
|
||||
self.after(0, lambda: self._status_label.configure(
|
||||
text=t("launch_started"), text_color="#44cc44",
|
||||
))
|
||||
except Exception as exc:
|
||||
self.after(0, lambda: self._status_label.configure(
|
||||
text=t("launch_error").format(error=str(exc)),
|
||||
text_color="#ff4444",
|
||||
))
|
||||
finally:
|
||||
self.after(0, lambda: self._connect_btn.configure(state="normal"))
|
||||
|
||||
threading.Thread(target=_do, daemon=True).start()
|
||||
Reference in New Issue
Block a user