v1.8.96: persist sidebar width across restarts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-03-02 05:47:08 -05:00
parent 08307fbe9b
commit 7af788b72e
4 changed files with 96 additions and 3 deletions

View File

@@ -58,6 +58,7 @@ class ServerStore:
self._last_backup_hash: str = ""
self._terminal_font_size: int = 11
self._window_geometry: str = ""
self._sidebar_width: int = 250
self._servers_file: str = DEFAULT_SERVERS_FILE
# Update settings
self._update_mode: str = "auto-download" # "notify-only" | "auto-download" | "full-auto"
@@ -83,6 +84,7 @@ class ServerStore:
self._check_interval = settings.get("check_interval", 60)
self._terminal_font_size = settings.get("terminal_font_size", 11)
self._window_geometry = settings.get("window_geometry", "")
self._sidebar_width = settings.get("sidebar_width", 250)
self._update_mode = settings.get("update_mode", "auto-download")
self._last_update_check = settings.get("last_update_check", 0)
self._skip_version = settings.get("skip_version", "")
@@ -100,6 +102,7 @@ class ServerStore:
"check_interval": self._check_interval,
"terminal_font_size": self._terminal_font_size,
"window_geometry": self._window_geometry,
"sidebar_width": self._sidebar_width,
"update_mode": self._update_mode,
"last_update_check": self._last_update_check,
"skip_version": self._skip_version,
@@ -394,6 +397,89 @@ class ServerStore:
self._save()
self._notify()
# ── Groups CRUD ─────────────────────────────────
def get_groups(self) -> list[dict]:
"""Return all groups sorted by order."""
groups = list(self._data.get("groups", []))
groups.sort(key=lambda g: g.get("order", 0))
return groups
def get_group(self, group_id: str) -> Optional[dict]:
for g in self._data.get("groups", []):
if g["id"] == group_id:
return dict(g)
return None
def add_group(self, name: str, color: str = "#6b7280") -> dict:
"""Create a new group, return the created dict."""
import uuid
groups = self._data.setdefault("groups", [])
max_order = max((g.get("order", 0) for g in groups), default=-1)
group = {
"id": uuid.uuid4().hex[:8],
"name": name,
"color": color,
"collapsed": False,
"order": max_order + 1,
}
groups.append(group)
self._save()
self._notify()
return group
def update_group(self, group_id: str, **kwargs):
"""Update group fields (name, color, collapsed, order)."""
for g in self._data.get("groups", []):
if g["id"] == group_id:
for k, v in kwargs.items():
if k in ("name", "color", "collapsed", "order"):
g[k] = v
self._save()
self._notify()
return
raise ValueError(f"Group '{group_id}' not found")
def remove_group(self, group_id: str):
"""Delete group. Servers in it become ungrouped."""
self._data["groups"] = [g for g in self._data.get("groups", []) if g["id"] != group_id]
for s in self._data.get("servers", []):
if s.get("group") == group_id:
s.pop("group", None)
self._save()
self._notify()
def reorder_groups(self, ordered_ids: list[str]):
"""Set group order based on list of IDs."""
id_to_order = {gid: i for i, gid in enumerate(ordered_ids)}
for g in self._data.get("groups", []):
if g["id"] in id_to_order:
g["order"] = id_to_order[g["id"]]
self._save()
self._notify()
def set_server_group(self, alias: str, group_id: Optional[str]):
"""Move a server to a group (or None to ungroup)."""
for s in self._data.get("servers", []):
if s["alias"] == alias:
if group_id:
s["group"] = group_id
else:
s.pop("group", None)
self._save()
self._notify()
return
raise ValueError(f"Server '{alias}' not found")
def get_servers_in_group(self, group_id: Optional[str]) -> list[dict]:
"""Return servers in a group. None = ungrouped."""
all_servers = self._data.get("servers", [])
group_ids = {g["id"] for g in self._data.get("groups", [])}
if group_id is None:
return [s for s in all_servers
if not s.get("group") or s.get("group") not in group_ids]
return [s for s in all_servers if s.get("group") == group_id]
def get_ssh_key_path(self) -> str:
path = self._data.get("ssh_key", {}).get("path", "~/.ssh/id_ed25519")
return os.path.expanduser(path)

View File

@@ -125,7 +125,7 @@ class App(ctk.CTk):
# Sidebar
self.sidebar = Sidebar(self._paned, self.store, on_select=self._on_server_select, session_pool=self.session_pool)
self._paned.add(self.sidebar, minsize=180, width=250)
self._paned.add(self.sidebar, minsize=180, width=self.store._sidebar_width)
self.sidebar.add_callback = self._add_server
self.sidebar.edit_callback = self._edit_server
self.sidebar.delete_callback = self._delete_server
@@ -647,9 +647,16 @@ class App(ctk.CTk):
pass
def _on_close(self):
# Save window geometry (size + position)
# Save window geometry (size + position) and sidebar width
try:
self.store._window_geometry = self.geometry()
# Save sidebar width from PanedWindow sash position
try:
sash_pos = self._paned.sash_coord(0)
if sash_pos:
self.store._sidebar_width = sash_pos[0]
except Exception:
pass
self.store._save_settings()
except Exception:
pass

Binary file not shown.

View File

@@ -1,6 +1,6 @@
"""Version info for ServerManager."""
__version__ = "1.8.95"
__version__ = "1.8.96"
__app_name__ = "ServerManager"
__author__ = "aibot777"
__description__ = "Desktop GUI for managing remote servers"