server groups: grouped sidebar, GroupDialog, context menus, i18n + cleanup old releases
- Groups CRUD in sidebar (create, rename, change color, reorder, delete) - Collapsible group headers with color dots and server count - "Move to Group" context menu on servers - Group dropdown in ServerDialog (add/edit) - 17 i18n keys (EN/RU/ZH) - Search auto-expands groups - Cleaned up old release binaries Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,33 @@ class ServerDialog(ctk.CTkToplevel):
|
||||
self.port_entry = ctk.CTkEntry(port_frame, placeholder_text=t("placeholder_port"))
|
||||
self.port_entry.pack(fill="x")
|
||||
|
||||
# ── Group selector (only when groups exist) ──
|
||||
self._group_id_map: dict[str, str | None] = {}
|
||||
self._group_var = ctk.StringVar(value=t("no_group"))
|
||||
groups = self.store.get_groups()
|
||||
if groups:
|
||||
group_frame = ctk.CTkFrame(self, fg_color="transparent")
|
||||
group_frame.pack(fill="x", padx=20, pady=(5, 5))
|
||||
ctk.CTkLabel(group_frame, text=t("group"), anchor="w").pack(fill="x")
|
||||
|
||||
no_group_label = t("no_group")
|
||||
group_values = [no_group_label]
|
||||
self._group_id_map[no_group_label] = None
|
||||
for g in groups:
|
||||
display = f"\u25cf {g['name']}"
|
||||
group_values.append(display)
|
||||
self._group_id_map[display] = g["id"]
|
||||
|
||||
ctk.CTkOptionMenu(group_frame, values=group_values,
|
||||
variable=self._group_var).pack(fill="x")
|
||||
|
||||
# Pre-select if editing
|
||||
if server and server.get("group"):
|
||||
for display, gid in self._group_id_map.items():
|
||||
if gid == server.get("group"):
|
||||
self._group_var.set(display)
|
||||
break
|
||||
|
||||
# ── Conditional fields container — all packed here, shown/hidden dynamically ──
|
||||
# We use self as parent but wrap each field group in a frame for easy show/hide.
|
||||
|
||||
@@ -347,6 +374,12 @@ class ServerDialog(ctk.CTkToplevel):
|
||||
}
|
||||
if totp_secret:
|
||||
server_data["totp_secret"] = totp_secret
|
||||
|
||||
# Group assignment
|
||||
if self._group_id_map:
|
||||
selected_group = self._group_id_map.get(self._group_var.get())
|
||||
if selected_group:
|
||||
server_data["group"] = selected_group
|
||||
if self.skip_check_var.get():
|
||||
server_data["skip_check"] = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user