Initial commit: ServerManager GUI application
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>
This commit is contained in:
107
gui/app.py
Normal file
107
gui/app.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user