forked from clan/clan-core
Merge pull request 'vm-manager: More error handling' (#675) from Qubasa-main into main
This commit is contained in:
commit
3914d61008
@ -9,6 +9,7 @@ from clan_cli.flakes.inspect import FlakeConfig, inspect_flake
|
||||
|
||||
from ..clan_uri import ClanURI
|
||||
from ..dirs import user_history_file
|
||||
from ..errors import ClanError
|
||||
from ..locked_open import read_history_file, write_history_file
|
||||
|
||||
|
||||
@ -53,11 +54,11 @@ def list_history() -> list[HistoryEntry]:
|
||||
try:
|
||||
parsed = read_history_file()
|
||||
for i, p in enumerate(parsed.copy()):
|
||||
parsed[i] = merge_dicts(p, p["settings"])
|
||||
# Everything from the settings dict is merged into the flake dict, and can override existing values
|
||||
parsed[i] = merge_dicts(p, p.get("settings", {}))
|
||||
logs = [HistoryEntry(**p) for p in parsed]
|
||||
except (json.JSONDecodeError, TypeError) as ex:
|
||||
print("Failed to load history. Invalid JSON.")
|
||||
print(f"{user_history_file()}: {ex}")
|
||||
raise ClanError(f"History file at {user_history_file()} is corrupted") from ex
|
||||
|
||||
return logs
|
||||
|
||||
|
@ -4,10 +4,13 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import gi
|
||||
from clan_cli import history
|
||||
from clan_cli.history.list import list_history
|
||||
|
||||
from .errors.show_error import show_error_dialog
|
||||
|
||||
gi.require_version("GdkPixbuf", "2.0")
|
||||
|
||||
from clan_cli.errors import ClanError
|
||||
from gi.repository import GdkPixbuf
|
||||
|
||||
from clan_vm_manager import assets
|
||||
@ -58,30 +61,34 @@ class VM:
|
||||
description: str | None = None
|
||||
|
||||
|
||||
# TODO: How to handle incompatible / corrupted history file. Delete it?
|
||||
# start/end indexes can be used optionally for pagination
|
||||
def get_initial_vms(
|
||||
running_vms: list[str], start: int = 0, end: int | None = None
|
||||
) -> list[VM]:
|
||||
vm_list = []
|
||||
|
||||
# Execute `clan flakes add <path>` to democlan for this to work
|
||||
for entry in history.list.list_history():
|
||||
icon = assets.loc / "placeholder.jpeg"
|
||||
if entry.flake.icon is not None:
|
||||
icon = entry.flake.icon
|
||||
try:
|
||||
# Execute `clan flakes add <path>` to democlan for this to work
|
||||
for entry in list_history():
|
||||
icon = assets.loc / "placeholder.jpeg"
|
||||
if entry.flake.icon is not None:
|
||||
icon = entry.flake.icon
|
||||
|
||||
status = False
|
||||
if entry.flake.flake_url in running_vms:
|
||||
status = True
|
||||
status = False
|
||||
if entry.flake.flake_url in running_vms:
|
||||
status = True
|
||||
|
||||
base = VMBase(
|
||||
icon=icon,
|
||||
name=entry.flake.clan_name,
|
||||
url=entry.flake.flake_url,
|
||||
status=status,
|
||||
_flake_attr=entry.flake.flake_attr,
|
||||
)
|
||||
vm_list.append(VM(base=base))
|
||||
base = VMBase(
|
||||
icon=icon,
|
||||
name=entry.flake.clan_name,
|
||||
url=entry.flake.flake_url,
|
||||
status=status,
|
||||
_flake_attr=entry.flake.flake_attr,
|
||||
)
|
||||
vm_list.append(VM(base=base))
|
||||
except ClanError as e:
|
||||
show_error_dialog(e)
|
||||
|
||||
# start/end slices can be used for pagination
|
||||
return vm_list[start:end]
|
||||
|
@ -1,9 +1,10 @@
|
||||
from collections.abc import Callable
|
||||
|
||||
from gi.repository import GdkPixbuf, Gtk
|
||||
from gi.repository import Gdk, GdkPixbuf, Gtk
|
||||
|
||||
from ..interfaces import Callbacks
|
||||
from ..models import VMBase
|
||||
from .context_menu import VmMenu
|
||||
|
||||
|
||||
class ClanEditForm(Gtk.ListBox):
|
||||
@ -97,7 +98,6 @@ class ClanList(Gtk.Box):
|
||||
self.set_selected = set_selected
|
||||
self.show_toolbar = show_toolbar
|
||||
self.cbs = cbs
|
||||
|
||||
self.show_join = cbs.show_join
|
||||
|
||||
self.selected_vm: VMBase | None = selected_vm
|
||||
@ -228,6 +228,8 @@ class ClanListView(Gtk.Box):
|
||||
self.vms: list[VMBase] = vms
|
||||
self.on_select_row = on_select_row
|
||||
self.on_double_click = on_double_click
|
||||
self.context_menu: VmMenu | None = None
|
||||
|
||||
store_types = VMBase.name_to_type_map().values()
|
||||
|
||||
self.list_store = Gtk.ListStore(*store_types)
|
||||
@ -241,6 +243,7 @@ class ClanListView(Gtk.Box):
|
||||
selection = self.tree_view.get_selection()
|
||||
selection.connect("changed", self._on_select_row)
|
||||
self.tree_view.connect("row-activated", self._on_double_click)
|
||||
self.tree_view.connect("button-press-event", self._on_button_pressed)
|
||||
|
||||
self.set_border_width(10)
|
||||
self.add(self.tree_view)
|
||||
@ -272,12 +275,29 @@ class ClanListView(Gtk.Box):
|
||||
vm = VMBase(*model[row])
|
||||
self.on_select_row(vm)
|
||||
|
||||
def _on_button_pressed(
|
||||
self, tree_view: Gtk.TreeView, event: Gdk.EventButton
|
||||
) -> None:
|
||||
if self.context_menu:
|
||||
self.context_menu.destroy()
|
||||
self.context_menu = None
|
||||
|
||||
if event.button == 3:
|
||||
path, column, x, y = tree_view.get_path_at_pos(event.x, event.y)
|
||||
if path is not None:
|
||||
vm = VMBase(*self.list_store[path[0]])
|
||||
print(event)
|
||||
print(f"Right click on {vm.url}")
|
||||
self.context_menu = VmMenu(vm)
|
||||
self.context_menu.popup_at_pointer(event)
|
||||
|
||||
def _on_double_click(
|
||||
self, tree_view: Gtk.TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn
|
||||
) -> None:
|
||||
# Get the selection object of the tree view
|
||||
selection = tree_view.get_selection()
|
||||
model, row = selection.get_selected()
|
||||
|
||||
if row is not None:
|
||||
vm = VMBase(*model[row])
|
||||
self.on_double_click(vm)
|
||||
|
39
pkgs/clan-vm-manager/clan_vm_manager/ui/context_menu.py
Normal file
39
pkgs/clan-vm-manager/clan_vm_manager/ui/context_menu.py
Normal file
@ -0,0 +1,39 @@
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
from ..models import VMBase
|
||||
|
||||
|
||||
class VmMenu(Gtk.Menu):
|
||||
def __init__(self, vm: VMBase) -> None:
|
||||
super().__init__()
|
||||
self.vm = vm
|
||||
self.menu_items = [
|
||||
("Start", self.start_vm),
|
||||
("Stop", self.stop_vm),
|
||||
("Edit", self.edit_vm),
|
||||
("Remove", self.remove_vm),
|
||||
("Write to USB", self.write_to_usb),
|
||||
]
|
||||
for item in self.menu_items:
|
||||
menu_item = Gtk.MenuItem(label=item[0])
|
||||
menu_item.connect("activate", item[1])
|
||||
self.append(menu_item)
|
||||
self.show_all()
|
||||
|
||||
def start_vm(self, widget: Gtk.Widget) -> None:
|
||||
print("start_vm")
|
||||
|
||||
def stop_vm(self, widget: Gtk.Widget) -> None:
|
||||
print("stop_vm")
|
||||
|
||||
def edit_vm(self, widget: Gtk.Widget) -> None:
|
||||
print("edit_vm")
|
||||
|
||||
def remove_vm(self, widget: Gtk.Widget) -> None:
|
||||
print("remove_vm")
|
||||
|
||||
def write_to_usb(self, widget: Gtk.Widget) -> None:
|
||||
print("write_to_usb")
|
@ -33,6 +33,7 @@ class OverviewWindow(Gtk.ApplicationWindow):
|
||||
set_selected=self.set_selected,
|
||||
selected_vm=None,
|
||||
)
|
||||
|
||||
# Add named stacks
|
||||
self.stack.add_titled(clan_list, "list", "List")
|
||||
self.stack.add_titled(
|
||||
|
Loading…
Reference in New Issue
Block a user