stuff
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
from models import VPNType
|
||||
from .host_item import HostItem
|
||||
from gi.repository import Gtk
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from .host_item import HostItem
|
||||
from models import VPNType
|
||||
|
||||
|
||||
def escape_markup(text: str) -> str:
|
||||
"""Escape special characters for Pango markup."""
|
||||
return text.replace('&', '&').replace('<', '<').replace('>', '>')
|
||||
|
||||
|
||||
class ActiveLocationCard:
|
||||
@@ -11,49 +16,78 @@ class ActiveLocationCard:
|
||||
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_vbox = Gtk.Box(
|
||||
orientation=Gtk.Orientation.VERTICAL, spacing=8)
|
||||
|
||||
# Location header with controls
|
||||
header_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
|
||||
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"<b>📍 {self.location.name}</b>")
|
||||
escaped_location_name = escape_markup(self.location.name)
|
||||
location_label.set_markup(f"<b>📍 {escaped_location_name}</b>")
|
||||
location_label.set_halign(Gtk.Align.START)
|
||||
info_vbox.pack_start(location_label, False, False, 0)
|
||||
|
||||
# VPN type
|
||||
|
||||
# VPN type and external address
|
||||
vpn_icons = {
|
||||
VPNType.OPENVPN: "🔒",
|
||||
VPNType.WIREGUARD: "⚡",
|
||||
VPNType.IPSEC: "🛡️"
|
||||
}
|
||||
vpn_icon = vpn_icons.get(self.location.vpn_type, "🔑")
|
||||
|
||||
|
||||
type_text = f"{vpn_icon} {self.location.vpn_type.value} VPN"
|
||||
if self.location.external_addresses:
|
||||
if len(self.location.external_addresses) == 1:
|
||||
type_text += f" • 🌐 {self.location.external_addresses[0]}"
|
||||
else:
|
||||
type_text += f" • 🌐 {len(self.location.external_addresses)} endpoints"
|
||||
|
||||
type_label = Gtk.Label()
|
||||
type_label.set_markup(f"<small>{vpn_icon} {self.location.vpn_type.value} VPN</small>")
|
||||
type_label.set_markup(f"<small>{type_text}</small>")
|
||||
type_label.set_halign(Gtk.Align.START)
|
||||
info_vbox.pack_start(type_label, False, False, 0)
|
||||
|
||||
|
||||
# External addresses and networks if available
|
||||
if self.location.external_addresses and len(self.location.external_addresses) > 1:
|
||||
# Show full list if more than one
|
||||
addresses_text = "🌐 External: " + \
|
||||
", ".join(self.location.external_addresses)
|
||||
addresses_label = Gtk.Label()
|
||||
addresses_label.set_markup(f"<small>{addresses_text}</small>")
|
||||
addresses_label.set_halign(Gtk.Align.START)
|
||||
info_vbox.pack_start(addresses_label, False, False, 0)
|
||||
|
||||
if self.location.networks:
|
||||
networks_text = "📡 Networks: " + ", ".join(self.location.networks)
|
||||
networks_label = Gtk.Label()
|
||||
networks_label.set_markup(f"<small>{networks_text}</small>")
|
||||
networks_label.set_halign(Gtk.Align.START)
|
||||
info_vbox.pack_start(networks_label, False, False, 0)
|
||||
|
||||
# Status and controls
|
||||
controls_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
|
||||
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"<small><span color='{status_color}'>{status_text}</span></small>")
|
||||
status_label.set_markup(
|
||||
f"<small><span color='{status_color}'>{status_text}</span></small>")
|
||||
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)
|
||||
@@ -63,14 +97,14 @@ class ActiveLocationCard:
|
||||
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()
|
||||
@@ -78,23 +112,26 @@ class ActiveLocationCard:
|
||||
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 = 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'])
|
||||
host_item = HostItem(host, self.location,
|
||||
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)
|
||||
self.callbacks['deactivate_location'](
|
||||
self.location, self.customer_name)
|
||||
|
||||
|
||||
class InactiveLocationCard:
|
||||
@@ -103,54 +140,68 @@ class InactiveLocationCard:
|
||||
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_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"<b>📍 {self.location.name}</b>")
|
||||
escaped_location_name = escape_markup(self.location.name)
|
||||
location_label.set_markup(f"<b>📍 {escaped_location_name}</b>")
|
||||
location_label.set_halign(Gtk.Align.START)
|
||||
info_vbox.pack_start(location_label, False, False, 0)
|
||||
|
||||
# VPN type and host count
|
||||
|
||||
# VPN type, external address and host count
|
||||
vpn_icons = {
|
||||
VPNType.OPENVPN: "🔒",
|
||||
VPNType.WIREGUARD: "⚡",
|
||||
VPNType.WIREGUARD: "⚡",
|
||||
VPNType.IPSEC: "🛡️"
|
||||
}
|
||||
vpn_icon = vpn_icons.get(self.location.vpn_type, "🔑")
|
||||
host_count = len(self.location.hosts)
|
||||
|
||||
|
||||
details_text = f"{vpn_icon} {self.location.vpn_type.value} VPN • {host_count} hosts"
|
||||
if self.location.external_addresses:
|
||||
if len(self.location.external_addresses) == 1:
|
||||
details_text += f" • 🌐 {self.location.external_addresses[0]}"
|
||||
else:
|
||||
details_text += f" • 🌐 {len(self.location.external_addresses)} endpoints"
|
||||
if self.location.networks:
|
||||
network_count = len(self.location.networks)
|
||||
details_text += f" • {network_count} network{'s' if network_count > 1 else ''}"
|
||||
|
||||
details_label = Gtk.Label()
|
||||
details_label.set_markup(f"<small>{vpn_icon} {self.location.vpn_type.value} VPN • {host_count} hosts</small>")
|
||||
details_label.set_markup(f"<small>{details_text}</small>")
|
||||
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)
|
||||
|
||||
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)
|
||||
self.callbacks['set_current_location'](
|
||||
self.location, self.customer_name)
|
||||
|
||||
Reference in New Issue
Block a user