mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-23 15:53:36 +05:00
Compare commits
4 Commits
0d7074f86f
...
a5eaed4f26
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5eaed4f26 | ||
|
|
1484ebf445 | ||
|
|
4547ac571a | ||
|
|
b2dd5d8ed7 |
@@ -7,7 +7,7 @@
|
|||||||
# This file may be distributed under the terms of the GNU GPLv3 license #
|
# This file may be distributed under the terms of the GNU GPLv3 license #
|
||||||
# ======================================================================= #
|
# ======================================================================= #
|
||||||
|
|
||||||
from dataclasses import field, dataclass
|
from dataclasses import field
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Union, List
|
from typing import Union, List
|
||||||
|
|
||||||
@@ -28,15 +28,14 @@ class ConnectionType(Enum):
|
|||||||
UART = "UART"
|
UART = "UART"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class FlashOptions:
|
class FlashOptions:
|
||||||
_instance = None
|
_instance = None
|
||||||
flash_method: Union[FlashMethod, None] = None
|
_flash_method: Union[FlashMethod, None] = None
|
||||||
flash_command: Union[FlashCommand, None] = None
|
_flash_command: Union[FlashCommand, None] = None
|
||||||
connection_type: Union[ConnectionType, None] = None
|
_connection_type: Union[ConnectionType, None] = None
|
||||||
mcu_list: List[str] = field(default_factory=list)
|
_mcu_list: List[str] = field(default_factory=list)
|
||||||
selected_mcu: str = ""
|
_selected_mcu: str = ""
|
||||||
selected_board: str = ""
|
_selected_board: str = ""
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
if not cls._instance:
|
if not cls._instance:
|
||||||
@@ -46,3 +45,51 @@ class FlashOptions:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def destroy(cls):
|
def destroy(cls):
|
||||||
cls._instance = None
|
cls._instance = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def flash_method(self) -> Union[FlashMethod, None]:
|
||||||
|
return self._flash_method
|
||||||
|
|
||||||
|
@flash_method.setter
|
||||||
|
def flash_method(self, value: Union[FlashMethod, None]):
|
||||||
|
self._flash_method = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def flash_command(self) -> Union[FlashCommand, None]:
|
||||||
|
return self._flash_command
|
||||||
|
|
||||||
|
@flash_command.setter
|
||||||
|
def flash_command(self, value: Union[FlashCommand, None]):
|
||||||
|
self._flash_command = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def connection_type(self) -> Union[ConnectionType, None]:
|
||||||
|
return self._connection_type
|
||||||
|
|
||||||
|
@connection_type.setter
|
||||||
|
def connection_type(self, value: Union[ConnectionType, None]):
|
||||||
|
self._connection_type = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mcu_list(self) -> List[str]:
|
||||||
|
return self._mcu_list
|
||||||
|
|
||||||
|
@mcu_list.setter
|
||||||
|
def mcu_list(self, value: List[str]) -> None:
|
||||||
|
self._mcu_list = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def selected_mcu(self) -> str:
|
||||||
|
return self._selected_mcu
|
||||||
|
|
||||||
|
@selected_mcu.setter
|
||||||
|
def selected_mcu(self, value: str) -> None:
|
||||||
|
self._selected_mcu = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def selected_board(self) -> str:
|
||||||
|
return self._selected_board
|
||||||
|
|
||||||
|
@selected_board.setter
|
||||||
|
def selected_board(self, value: str) -> None:
|
||||||
|
self._selected_board = value
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class KlipperFlashMethodMenu(BaseMenu):
|
|||||||
self.options = {
|
self.options = {
|
||||||
"1": self.select_regular,
|
"1": self.select_regular,
|
||||||
"2": self.select_sdcard,
|
"2": self.select_sdcard,
|
||||||
"h": lambda: KlipperFlashMethodHelpMenu(self).run(),
|
"h": self.help_menu,
|
||||||
}
|
}
|
||||||
self.input_label_txt = "Select flash method"
|
self.input_label_txt = "Select flash method"
|
||||||
self.footer_type = FooterType.BACK_HELP
|
self.footer_type = FooterType.BACK_HELP
|
||||||
@@ -78,6 +78,9 @@ class KlipperFlashMethodMenu(BaseMenu):
|
|||||||
def goto_next_menu(self, **kwargs):
|
def goto_next_menu(self, **kwargs):
|
||||||
KlipperFlashCommandMenu(previous_menu=self).run()
|
KlipperFlashCommandMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def help_menu(self, **kwargs):
|
||||||
|
KlipperFlashMethodHelpMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -89,7 +92,7 @@ class KlipperFlashCommandMenu(BaseMenu):
|
|||||||
self.options = {
|
self.options = {
|
||||||
"1": self.select_flash,
|
"1": self.select_flash,
|
||||||
"2": self.select_serialflash,
|
"2": self.select_serialflash,
|
||||||
"h": lambda: KlipperFlashCommandHelpMenu(previous_menu=self).run(),
|
"h": self.help_menu,
|
||||||
}
|
}
|
||||||
self.default_option = self.select_flash
|
self.default_option = self.select_flash
|
||||||
self.input_label_txt = "Select flash command"
|
self.input_label_txt = "Select flash command"
|
||||||
@@ -121,6 +124,9 @@ class KlipperFlashCommandMenu(BaseMenu):
|
|||||||
def goto_next_menu(self, **kwargs):
|
def goto_next_menu(self, **kwargs):
|
||||||
KlipperSelectMcuConnectionMenu(previous_menu=self).run()
|
KlipperSelectMcuConnectionMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def help_menu(self, **kwargs):
|
||||||
|
KlipperFlashCommandHelpMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -133,7 +139,7 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
|||||||
"1": self.select_usb,
|
"1": self.select_usb,
|
||||||
"2": self.select_dfu,
|
"2": self.select_dfu,
|
||||||
"3": self.select_usb_dfu,
|
"3": self.select_usb_dfu,
|
||||||
"h": lambda: KlipperMcuConnectionHelpMenu(previous_menu=self).run(),
|
"h": self.help_menu,
|
||||||
}
|
}
|
||||||
self.input_label_txt = "Select connection type"
|
self.input_label_txt = "Select connection type"
|
||||||
self.footer_type = FooterType.BACK_HELP
|
self.footer_type = FooterType.BACK_HELP
|
||||||
@@ -184,8 +190,6 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
|||||||
Logger.print_status("Identifying MCU connected via USB in DFU mode ...")
|
Logger.print_status("Identifying MCU connected via USB in DFU mode ...")
|
||||||
self.flash_options.mcu_list = find_usb_dfu_device()
|
self.flash_options.mcu_list = find_usb_dfu_device()
|
||||||
|
|
||||||
print(self.flash_options.mcu_list)
|
|
||||||
|
|
||||||
if len(self.flash_options.mcu_list) < 1:
|
if len(self.flash_options.mcu_list) < 1:
|
||||||
Logger.print_warn("No MCUs found!")
|
Logger.print_warn("No MCUs found!")
|
||||||
Logger.print_warn("Make sure they are connected and repeat this step.")
|
Logger.print_warn("Make sure they are connected and repeat this step.")
|
||||||
@@ -195,6 +199,9 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
|||||||
def goto_next_menu(self, **kwargs):
|
def goto_next_menu(self, **kwargs):
|
||||||
KlipperSelectMcuIdMenu(previous_menu=self).run()
|
KlipperSelectMcuIdMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def help_menu(self, **kwargs):
|
||||||
|
KlipperMcuConnectionHelpMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -205,7 +212,6 @@ class KlipperSelectMcuIdMenu(BaseMenu):
|
|||||||
self.previous_menu: BaseMenu = previous_menu
|
self.previous_menu: BaseMenu = previous_menu
|
||||||
self.flash_options = FlashOptions()
|
self.flash_options = FlashOptions()
|
||||||
self.mcu_list = self.flash_options.mcu_list
|
self.mcu_list = self.flash_options.mcu_list
|
||||||
print(self.mcu_list)
|
|
||||||
options = {f"{index}": self.flash_mcu for index in range(len(self.mcu_list))}
|
options = {f"{index}": self.flash_mcu for index in range(len(self.mcu_list))}
|
||||||
self.options = options
|
self.options = options
|
||||||
self.input_label_txt = "Select MCU to flash"
|
self.input_label_txt = "Select MCU to flash"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from core.menus.base_menu import BaseMenu
|
|||||||
from utils.constants import COLOR_YELLOW, RESET_FORMAT
|
from utils.constants import COLOR_YELLOW, RESET_FORMAT
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
class AdvancedMenu(BaseMenu):
|
class AdvancedMenu(BaseMenu):
|
||||||
def __init__(self, previous_menu: BaseMenu):
|
def __init__(self, previous_menu: BaseMenu):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -26,9 +27,9 @@ class AdvancedMenu(BaseMenu):
|
|||||||
"1": None,
|
"1": None,
|
||||||
"2": None,
|
"2": None,
|
||||||
"3": None,
|
"3": None,
|
||||||
"4": lambda: KlipperFlashMethodMenu(previous_menu=self).run(),
|
"4": self.flash,
|
||||||
"5": None,
|
"5": None,
|
||||||
"6": lambda: KlipperSelectMcuConnectionMenu(previous_menu=self).run(),
|
"6": self.get_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
def print_menu(self):
|
def print_menu(self):
|
||||||
@@ -52,3 +53,9 @@ class AdvancedMenu(BaseMenu):
|
|||||||
"""
|
"""
|
||||||
)[1:]
|
)[1:]
|
||||||
print(menu, end="")
|
print(menu, end="")
|
||||||
|
|
||||||
|
def flash(self, **kwargs):
|
||||||
|
KlipperFlashMethodMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def get_id(self, **kwargs):
|
||||||
|
KlipperSelectMcuConnectionMenu(previous_menu=self).run()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
from abc import abstractmethod, ABC
|
from abc import abstractmethod, ABC
|
||||||
from typing import Dict, Union, Callable, Type
|
from typing import Dict, Union, Callable, Type, Tuple
|
||||||
|
|
||||||
from core.menus import FooterType, NAVI_OPTIONS, ExitAppException, GoBackException
|
from core.menus import FooterType, NAVI_OPTIONS, ExitAppException, GoBackException
|
||||||
from utils.constants import (
|
from utils.constants import (
|
||||||
@@ -129,7 +129,7 @@ class BaseMenu(ABC):
|
|||||||
self.print_menu()
|
self.print_menu()
|
||||||
self.print_footer()
|
self.print_footer()
|
||||||
|
|
||||||
def validate_user_input(self, usr_input: str) -> Callable:
|
def validate_user_input(self, usr_input: str) -> Tuple[Callable, str]:
|
||||||
"""
|
"""
|
||||||
Validate the user input and either return an Option, a string or None
|
Validate the user input and either return an Option, a string or None
|
||||||
:param usr_input: The user input in form of a string
|
:param usr_input: The user input in form of a string
|
||||||
@@ -148,16 +148,16 @@ class BaseMenu(ABC):
|
|||||||
elif usr_input == "b":
|
elif usr_input == "b":
|
||||||
raise GoBackException()
|
raise GoBackException()
|
||||||
elif usr_input == "h":
|
elif usr_input == "h":
|
||||||
return option
|
return option, usr_input
|
||||||
|
|
||||||
# if usr_input is None or an empty string, we execute the menues default option if specified
|
# if usr_input is None or an empty string, we execute the menues default option if specified
|
||||||
if usr_input == "" and self.default_option is not None:
|
if usr_input == "" and self.default_option is not None:
|
||||||
return self.default_option
|
return self.default_option, usr_input
|
||||||
|
|
||||||
# user selected a regular option
|
# user selected a regular option
|
||||||
return option
|
return option, usr_input
|
||||||
|
|
||||||
def handle_user_input(self) -> Callable:
|
def handle_user_input(self) -> Tuple[Callable, str]:
|
||||||
"""Handle the user input, return the validated input or print an error."""
|
"""Handle the user input, return the validated input or print an error."""
|
||||||
while True:
|
while True:
|
||||||
print(f"{COLOR_CYAN}###### {self.input_label_txt}: {RESET_FORMAT}", end="")
|
print(f"{COLOR_CYAN}###### {self.input_label_txt}: {RESET_FORMAT}", end="")
|
||||||
@@ -173,7 +173,8 @@ class BaseMenu(ABC):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
self.display_menu()
|
self.display_menu()
|
||||||
self.handle_user_input()()
|
option = self.handle_user_input()
|
||||||
|
option[0](opt_index=option[1])
|
||||||
except GoBackException:
|
except GoBackException:
|
||||||
return
|
return
|
||||||
except ExitAppException:
|
except ExitAppException:
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import inspect
|
|||||||
import json
|
import json
|
||||||
import textwrap
|
import textwrap
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import Type, Dict
|
||||||
|
|
||||||
from core.base_extension import BaseExtension
|
from core.base_extension import BaseExtension
|
||||||
from core.menus.base_menu import BaseMenu, Options
|
from core.menus.base_menu import BaseMenu
|
||||||
from utils.constants import RESET_FORMAT, COLOR_CYAN, COLOR_YELLOW
|
from utils.constants import RESET_FORMAT, COLOR_CYAN, COLOR_YELLOW
|
||||||
|
|
||||||
|
|
||||||
@@ -27,42 +27,44 @@ class ExtensionsMenu(BaseMenu):
|
|||||||
|
|
||||||
self.previous_menu: BaseMenu = previous_menu
|
self.previous_menu: BaseMenu = previous_menu
|
||||||
self.extensions = self.discover_extensions()
|
self.extensions = self.discover_extensions()
|
||||||
self.options: Options = self.get_options(self.extensions)
|
self.options = {ext: self.extension_submenu for ext in self.extensions}
|
||||||
|
|
||||||
def discover_extensions(self) -> List[BaseExtension]:
|
def discover_extensions(self) -> Dict[str, BaseExtension]:
|
||||||
extensions = []
|
ext_dict = {}
|
||||||
extensions_dir = Path(__file__).resolve().parents[2].joinpath("extensions")
|
extensions_dir = Path(__file__).resolve().parents[2].joinpath("extensions")
|
||||||
|
|
||||||
for extension in extensions_dir.iterdir():
|
for ext in extensions_dir.iterdir():
|
||||||
metadata_json = Path(extension).joinpath("metadata.json")
|
metadata_json = Path(ext).joinpath("metadata.json")
|
||||||
if not metadata_json.exists():
|
if not metadata_json.exists():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(metadata_json, "r") as m:
|
with open(metadata_json, "r") as m:
|
||||||
|
# read extension metadata from json
|
||||||
metadata = json.load(m).get("metadata")
|
metadata = json.load(m).get("metadata")
|
||||||
module_name = (
|
module_name = metadata.get("module")
|
||||||
f"kiauh.extensions.{extension.name}.{metadata.get('module')}"
|
module_path = f"kiauh.extensions.{ext.name}.{module_name}"
|
||||||
)
|
|
||||||
name, extension = inspect.getmembers(
|
# get the class name of the extension
|
||||||
importlib.import_module(module_name),
|
ext_class: Type[BaseExtension] = inspect.getmembers(
|
||||||
|
importlib.import_module(module_path),
|
||||||
predicate=lambda o: inspect.isclass(o)
|
predicate=lambda o: inspect.isclass(o)
|
||||||
and issubclass(o, BaseExtension)
|
and issubclass(o, BaseExtension)
|
||||||
and o != BaseExtension,
|
and o != BaseExtension,
|
||||||
)[0]
|
)[0][1]
|
||||||
extensions.append(extension(metadata))
|
|
||||||
|
# instantiate the extension with its metadata and add to dict
|
||||||
|
ext_instance: BaseExtension = ext_class(metadata)
|
||||||
|
ext_dict[f"{metadata.get('index')}"] = ext_instance
|
||||||
|
|
||||||
except (IOError, json.JSONDecodeError, ImportError) as e:
|
except (IOError, json.JSONDecodeError, ImportError) as e:
|
||||||
print(f"Failed loading extension {extension}: {e}")
|
print(f"Failed loading extension {ext}: {e}")
|
||||||
|
|
||||||
return sorted(extensions, key=lambda ex: ex.metadata.get("index"))
|
return ext_dict
|
||||||
|
|
||||||
def get_options(self, extensions: List[BaseExtension]) -> Options:
|
def extension_submenu(self, **kwargs):
|
||||||
options: Options = {}
|
extension = self.extensions.get(kwargs.get("opt_index"))
|
||||||
for extension in extensions:
|
ExtensionSubmenu(self, extension).run()
|
||||||
index = extension.metadata.get("index")
|
|
||||||
options[f"{index}"] = lambda: ExtensionSubmenu(self, extension).run()
|
|
||||||
|
|
||||||
return options
|
|
||||||
|
|
||||||
def print_menu(self):
|
def print_menu(self):
|
||||||
header = " [ Extensions Menu ] "
|
header = " [ Extensions Menu ] "
|
||||||
@@ -80,7 +82,7 @@ class ExtensionsMenu(BaseMenu):
|
|||||||
)[1:]
|
)[1:]
|
||||||
print(menu, end="")
|
print(menu, end="")
|
||||||
|
|
||||||
for extension in self.extensions:
|
for extension in self.extensions.values():
|
||||||
index = extension.metadata.get("index")
|
index = extension.metadata.get("index")
|
||||||
name = extension.metadata.get("display_name")
|
name = extension.metadata.get("display_name")
|
||||||
row = f"{index}) {name}"
|
row = f"{index}) {name}"
|
||||||
|
|||||||
@@ -36,21 +36,21 @@ from utils.constants import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
class MainMenu(BaseMenu):
|
class MainMenu(BaseMenu):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.options = {
|
self.options = {
|
||||||
"0": lambda: LogUploadMenu(previous_menu=self).run(),
|
"0": self.log_upload_menu,
|
||||||
"1": lambda: InstallMenu(previous_menu=self).run(),
|
"1": self.install_menu,
|
||||||
"2": lambda: UpdateMenu(previous_menu=self).run(),
|
"2": self.update_menu,
|
||||||
"3": lambda: RemoveMenu(previous_menu=self).run(),
|
"3": self.remove_menu,
|
||||||
"4": lambda: AdvancedMenu(previous_menu=self).run(),
|
"4": self.advanced_menu,
|
||||||
"5": lambda: BackupMenu(previous_menu=self).run(),
|
"5": self.backup_menu,
|
||||||
"6": None,
|
"e": self.extension_menu,
|
||||||
"e": lambda: ExtensionsMenu(previous_menu=self).run(),
|
"s": self.settings_menu,
|
||||||
"s": lambda: SettingsMenu(previous_menu=self).run(),
|
|
||||||
}
|
}
|
||||||
self.header = True
|
self.header = True
|
||||||
self.footer_type = FooterType.QUIT
|
self.footer_type = FooterType.QUIT
|
||||||
@@ -141,3 +141,27 @@ class MainMenu(BaseMenu):
|
|||||||
"""
|
"""
|
||||||
)[1:]
|
)[1:]
|
||||||
print(menu, end="")
|
print(menu, end="")
|
||||||
|
|
||||||
|
def log_upload_menu(self, **kwargs):
|
||||||
|
LogUploadMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def install_menu(self, **kwargs):
|
||||||
|
InstallMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def update_menu(self, **kwargs):
|
||||||
|
UpdateMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def remove_menu(self, **kwargs):
|
||||||
|
RemoveMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def advanced_menu(self, **kwargs):
|
||||||
|
AdvancedMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def backup_menu(self, **kwargs):
|
||||||
|
BackupMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def settings_menu(self, **kwargs):
|
||||||
|
SettingsMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def extension_menu(self, **kwargs):
|
||||||
|
ExtensionsMenu(previous_menu=self).run()
|
||||||
|
|||||||
@@ -27,14 +27,10 @@ class RemoveMenu(BaseMenu):
|
|||||||
|
|
||||||
self.previous_menu: BaseMenu = previous_menu
|
self.previous_menu: BaseMenu = previous_menu
|
||||||
self.options = {
|
self.options = {
|
||||||
"1": lambda: KlipperRemoveMenu(previous_menu=self).run(),
|
"1": self.remove_klipper,
|
||||||
"2": lambda: MoonrakerRemoveMenu(previous_menu=self).run(),
|
"2": self.remove_moonraker,
|
||||||
"3": lambda: ClientRemoveMenu(
|
"3": self.remove_mainsail,
|
||||||
previous_menu=self, client=load_client_data("mainsail")
|
"4": self.remove_fluidd,
|
||||||
).run(),
|
|
||||||
"4": lambda: ClientRemoveMenu(
|
|
||||||
previous_menu=self, client=load_client_data("fluidd")
|
|
||||||
).run(),
|
|
||||||
"5": None,
|
"5": None,
|
||||||
"6": None,
|
"6": None,
|
||||||
"7": None,
|
"7": None,
|
||||||
@@ -72,3 +68,15 @@ class RemoveMenu(BaseMenu):
|
|||||||
"""
|
"""
|
||||||
)[1:]
|
)[1:]
|
||||||
print(menu, end="")
|
print(menu, end="")
|
||||||
|
|
||||||
|
def remove_klipper(self, **kwargs):
|
||||||
|
KlipperRemoveMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def remove_moonraker(self, **kwargs):
|
||||||
|
MoonrakerRemoveMenu(previous_menu=self).run()
|
||||||
|
|
||||||
|
def remove_mainsail(self, **kwargs):
|
||||||
|
ClientRemoveMenu(previous_menu=self, client=load_client_data("mainsail")).run()
|
||||||
|
|
||||||
|
def remove_fluidd(self, **kwargs):
|
||||||
|
ClientRemoveMenu(previous_menu=self, client=load_client_data("fluidd")).run()
|
||||||
|
|||||||
Reference in New Issue
Block a user