CustomTkinter desktop app for managing remote servers. Features: SSH terminal, SFTP file transfer, key management, background status monitoring, server CRUD with dark theme. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
108 lines
3.3 KiB
Python
108 lines
3.3 KiB
Python
"""
|
|
Main application window — sidebar + tabview layout.
|
|
"""
|
|
|
|
import customtkinter as ctk
|
|
from tkinter import messagebox
|
|
|
|
from core.server_store import ServerStore
|
|
from core.status_checker import StatusChecker
|
|
from gui.sidebar import Sidebar
|
|
from gui.server_dialog import ServerDialog
|
|
from gui.tabs.terminal_tab import TerminalTab
|
|
from gui.tabs.files_tab import FilesTab
|
|
from gui.tabs.info_tab import InfoTab
|
|
from gui.tabs.keys_tab import KeysTab
|
|
|
|
|
|
class App(ctk.CTk):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
# Window config
|
|
self.title("ServerManager")
|
|
self.geometry("1100x700")
|
|
self.minsize(900, 500)
|
|
|
|
ctk.set_appearance_mode("dark")
|
|
ctk.set_default_color_theme("blue")
|
|
|
|
# Core
|
|
self.store = ServerStore()
|
|
self.checker = StatusChecker(self.store, interval=60)
|
|
|
|
# Layout
|
|
self._build_layout()
|
|
|
|
# Status checker
|
|
self.checker.set_gui_callback(lambda: self.after(0, self._on_status_update))
|
|
self.checker.start()
|
|
self.checker.check_all_now()
|
|
|
|
# Cleanup on close
|
|
self.protocol("WM_DELETE_WINDOW", self._on_close)
|
|
|
|
def _build_layout(self):
|
|
# Sidebar
|
|
self.sidebar = Sidebar(self, self.store, on_select=self._on_server_select)
|
|
self.sidebar.pack(side="left", fill="y")
|
|
self.sidebar.add_callback = self._add_server
|
|
self.sidebar.edit_callback = self._edit_server
|
|
self.sidebar.delete_callback = self._delete_server
|
|
|
|
# Main area
|
|
main = ctk.CTkFrame(self, fg_color="transparent")
|
|
main.pack(side="right", fill="both", expand=True)
|
|
|
|
# Tabview
|
|
self.tabview = ctk.CTkTabview(main)
|
|
self.tabview.pack(fill="both", expand=True, padx=10, pady=10)
|
|
|
|
# Tabs
|
|
self.tabview.add("Terminal")
|
|
self.tabview.add("Files")
|
|
self.tabview.add("Info")
|
|
self.tabview.add("Keys")
|
|
|
|
self.terminal_tab = TerminalTab(self.tabview.tab("Terminal"), self.store)
|
|
self.terminal_tab.pack(fill="both", expand=True)
|
|
|
|
self.files_tab = FilesTab(self.tabview.tab("Files"), self.store)
|
|
self.files_tab.pack(fill="both", expand=True)
|
|
|
|
self.info_tab = InfoTab(self.tabview.tab("Info"), self.store, edit_callback=self._edit_server)
|
|
self.info_tab.pack(fill="both", expand=True)
|
|
|
|
self.keys_tab = KeysTab(self.tabview.tab("Keys"), self.store)
|
|
self.keys_tab.pack(fill="both", expand=True)
|
|
|
|
def _on_server_select(self, alias: str):
|
|
self.terminal_tab.set_server(alias)
|
|
self.files_tab.set_server(alias)
|
|
self.info_tab.set_server(alias)
|
|
self.keys_tab.set_server(alias)
|
|
|
|
def _add_server(self):
|
|
dialog = ServerDialog(self, self.store)
|
|
self.wait_window(dialog)
|
|
|
|
def _edit_server(self, alias: str):
|
|
server = self.store.get_server(alias)
|
|
if server:
|
|
dialog = ServerDialog(self, self.store, server=server)
|
|
self.wait_window(dialog)
|
|
self.info_tab.refresh()
|
|
|
|
def _delete_server(self, alias: str):
|
|
if messagebox.askyesno("Delete Server", f"Remove '{alias}'?"):
|
|
self.store.remove_server(alias)
|
|
self._on_server_select(None)
|
|
|
|
def _on_status_update(self):
|
|
self.sidebar.update_statuses()
|
|
self.info_tab.refresh()
|
|
|
|
def _on_close(self):
|
|
self.checker.stop()
|
|
self.destroy()
|