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:
chrome-storm-c442
2026-02-24 09:35:24 -05:00
parent 2d1d942ddc
commit eede67e6a9
26 changed files with 3990 additions and 168 deletions

View File

@@ -8,17 +8,25 @@ from core.i18n import t
class InfoTab(ctk.CTkFrame):
# Map field keys to i18n keys
_FIELD_KEYS = ["alias", "ip", "port", "user", "type", "notes", "status"]
_FIELD_KEYS = ["alias", "ip", "port", "user", "type", "database", "db_index", "ssl", "notes", "status"]
_FIELD_I18N = {
"alias": "info_alias",
"ip": "info_ip",
"port": "info_port",
"user": "info_user",
"type": "info_type",
"database": "info_database",
"db_index": "info_db_index",
"ssl": "info_ssl",
"notes": "info_notes",
"status": "info_status",
}
# Which fields are relevant per server type
_SQL_TYPES = {"mariadb", "mssql", "postgresql"}
_SSL_TYPES = {"grafana", "prometheus", "winrm"}
_NO_USER_TYPES = {"redis", "grafana", "prometheus"}
def __init__(self, master, store, edit_callback=None):
super().__init__(master, fg_color="transparent")
self.store = store
@@ -65,12 +73,39 @@ class InfoTab(ctk.CTkFrame):
if not server:
return
stype = server.get("type", "ssh").lower()
self.header.configure(text=server["alias"])
self._fields["alias"].configure(text=server.get("alias", "-"))
self._fields["ip"].configure(text=server.get("ip", "-"))
self._fields["port"].configure(text=str(server.get("port", 22)))
self._fields["user"].configure(text=server.get("user", "root"))
self._fields["type"].configure(text=server.get("type", "ssh").upper())
# Hide user for types that don't use it
if stype in self._NO_USER_TYPES:
self._fields["user"].configure(text="-")
else:
self._fields["user"].configure(text=server.get("user", "root"))
self._fields["type"].configure(text=stype.upper())
# Database field — relevant for SQL types
if stype in self._SQL_TYPES:
self._fields["database"].configure(text=server.get("database", "-"))
else:
self._fields["database"].configure(text="-")
# DB index — relevant for redis
if stype == "redis":
self._fields["db_index"].configure(text=str(server.get("db_index", 0)))
else:
self._fields["db_index"].configure(text="-")
# SSL — relevant for grafana, prometheus, winrm
if stype in self._SSL_TYPES:
self._fields["ssl"].configure(text="Yes" if server.get("use_ssl") else "No")
else:
self._fields["ssl"].configure(text="-")
self._fields["notes"].configure(text=server.get("notes", "-") or "-")
status = self.store.get_status(self._current_alias)