1
0
forked from clan/clan-core

Merge pull request 'vm-manager: More error handling' (#675) from Qubasa-main into main

This commit is contained in:
clan-bot 2024-01-02 06:27:30 +00:00
commit 3914d61008
5 changed files with 90 additions and 22 deletions

View File

@ -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

View File

@ -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]

View File

@ -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)

View 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")

View File

@ -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(