import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from .host_item import HostItem from models import VPNType class ActiveLocationCard: def __init__(self, location, customer_name, callbacks): self.location = location self.customer_name = customer_name self.callbacks = callbacks self.widget = self._create_widget() def _create_widget(self): # Clean card layout - just a box with proper spacing location_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8) # Location header with controls header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12) location_vbox.pack_start(header_box, False, False, 0) # Location info info_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) header_box.pack_start(info_vbox, True, True, 0) # Location name with VPN type location_label = Gtk.Label() location_label.set_markup(f"📍 {self.location.name}") location_label.set_halign(Gtk.Align.START) info_vbox.pack_start(location_label, False, False, 0) # VPN type vpn_icons = { VPNType.OPENVPN: "🔒", VPNType.WIREGUARD: "⚡", VPNType.IPSEC: "🛡️" } vpn_icon = vpn_icons.get(self.location.vpn_type, "🔑") type_label = Gtk.Label() type_label.set_markup(f"{vpn_icon} {self.location.vpn_type.value} VPN") type_label.set_halign(Gtk.Align.START) info_vbox.pack_start(type_label, False, False, 0) # Status and controls controls_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8) header_box.pack_end(controls_box, False, False, 0) # Status status_text = "● Connected" if self.location.connected else "○ Disconnected" status_color = "#4caf50" if self.location.connected else "#999" status_label = Gtk.Label() status_label.set_markup(f"{status_text}") controls_box.pack_start(status_label, False, False, 0) # Connect/Disconnect button btn_text = "Disconnect" if self.location.connected else "Connect" connect_btn = Gtk.Button(label=btn_text) if self.location.connected: connect_btn.get_style_context().add_class("destructive-action") else: connect_btn.get_style_context().add_class("suggested-action") connect_btn.connect("clicked", self._on_connect_clicked) controls_box.pack_start(connect_btn, False, False, 0) # X button to deactivate (close button style) close_btn = Gtk.Button(label="✕") close_btn.set_tooltip_text("Deactivate location") close_btn.get_style_context().add_class("circular") close_btn.connect("clicked", self._on_deactivate_clicked) controls_box.pack_start(close_btn, False, False, 0) # Hosts section if available if self.location.hosts: hosts_label = Gtk.Label() hosts_label.set_markup("Infrastructure") hosts_label.set_halign(Gtk.Align.START) hosts_label.set_margin_top(8) location_vbox.pack_start(hosts_label, False, False, 0) # Hosts box with indent hosts_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8) hosts_box.set_margin_start(16) location_vbox.pack_start(hosts_box, False, False, 0) for host in self.location.hosts: host_item = HostItem(host, self.callbacks['open_service']) hosts_box.pack_start(host_item.widget, False, False, 0) return location_vbox def _on_connect_clicked(self, button): self.callbacks['toggle_connection'](self.location) def _on_deactivate_clicked(self, button): self.callbacks['deactivate_location'](self.location, self.customer_name) class InactiveLocationCard: def __init__(self, location, customer_name, callbacks): self.location = location self.customer_name = customer_name self.callbacks = callbacks self.widget = self._create_widget() def _create_widget(self): # Clean horizontal layout location_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12) # Location info info_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) location_hbox.pack_start(info_vbox, True, True, 0) # Location name location_label = Gtk.Label() location_label.set_markup(f"📍 {self.location.name}") location_label.set_halign(Gtk.Align.START) info_vbox.pack_start(location_label, False, False, 0) # VPN type and host count vpn_icons = { VPNType.OPENVPN: "🔒", VPNType.WIREGUARD: "⚡", VPNType.IPSEC: "🛡️" } vpn_icon = vpn_icons.get(self.location.vpn_type, "🔑") host_count = len(self.location.hosts) details_label = Gtk.Label() details_label.set_markup(f"{vpn_icon} {self.location.vpn_type.value} VPN • {host_count} hosts") details_label.set_halign(Gtk.Align.START) info_vbox.pack_start(details_label, False, False, 0) # Button box for multiple buttons button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4) location_hbox.pack_end(button_box, False, False, 0) # Set as Current button current_btn = Gtk.Button(label="Set as Current") current_btn.connect("clicked", self._on_set_current_clicked) button_box.pack_start(current_btn, False, False, 0) # Activate button activate_btn = Gtk.Button(label="Set Active") activate_btn.get_style_context().add_class("suggested-action") activate_btn.connect("clicked", self._on_activate_clicked) button_box.pack_start(activate_btn, False, False, 0) return location_hbox def _on_activate_clicked(self, button): self.callbacks['set_location_active'](self.location, self.customer_name) def _on_set_current_clicked(self, button): self.callbacks['set_current_location'](self.location, self.customer_name)