diff --git a/pyproject.toml b/pyproject.toml index e4454d5..27840b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ mkdocs-material = "^9.4.8" [tool.poetry.group.gui.dependencies] flet = "^0.11.0" +psutil = "^5.9.6" diff --git a/src/node_deployer_gui/__main__.py b/src/node_deployer_gui/__main__.py new file mode 100644 index 0000000..d929178 --- /dev/null +++ b/src/node_deployer_gui/__main__.py @@ -0,0 +1,11 @@ +import flet as ft + +from . import gui + + +def main(): + ft.app(target=gui.main) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/node_deployer_gui/disk_dropdown.py b/src/node_deployer_gui/disk_dropdown.py new file mode 100644 index 0000000..cfac6bc --- /dev/null +++ b/src/node_deployer_gui/disk_dropdown.py @@ -0,0 +1,37 @@ +import flet as ft +import psutil +from typing import Tuple + + +def get_disk_options() -> list[ft.dropdown.Option]: + physical_disks = list(filter(lambda x: "loop" not in x.device, psutil.disk_partitions())) + disks = [ + ft.dropdown.Option( + key=disk.device, + text=f"{disk.device} ({disk.mountpoint})", + ) + for disk in physical_disks + ] + return disks + + +def disk_dropdown(**kwargs) -> Tuple[ft.Dropdown, ft.Row]: + dropdown = ft.Dropdown( + options=get_disk_options(), + **kwargs, + ) + + def refresh_dropdown(_): + dropdown.options = get_disk_options() + dropdown.update() + + refresh_button = ft.IconButton( + icon="refresh", + tooltip="Refresh disk list", + on_click=refresh_dropdown, + ) + element = ft.Row( + controls=[dropdown, refresh_button], + alignment=ft.MainAxisAlignment.CENTER, + ) + return dropdown, element \ No newline at end of file diff --git a/src/node_deployer_gui/gui.py b/src/node_deployer_gui/gui.py index d40c22b..2afc56a 100644 --- a/src/node_deployer_gui/gui.py +++ b/src/node_deployer_gui/gui.py @@ -1,17 +1,89 @@ +from telnetlib import IP import flet as ft +from httpx import get +from node_deployer.create_disk import IPAddress, create_ignition_disk +import ipaddress + +from .disk_dropdown import disk_dropdown def main(page: ft.Page) -> None: page.title = "I-Form Server Node Deployer" + page.vertical_alignment = ft.MainAxisAlignment.CENTER - #TODO: change this test code to the actual gui - # Should basically be a simple wrapper around the node_deployer.py CLI - # Should have a file browser for selecting files - # Should have a selector for choosing the disk to write to - # Should have checks to ensure valid input - # Should have a progress bar or similar to show progress - # Intended to be idiot-proof, so anyone can use it - # Needs solid error handling and bulletproof documentation/testing + #TODO: Add a confirmation before actually writing to the disk + #TODO: Add a private password field + #TODO: Add a guard against invalid values + #TODO: Guard should trigger highlighting of the invalid fields + #TODO: Add a progress bar + #TODO: Finalise arrangement of fields + + disk, dd_element = disk_dropdown(tooltip="Select the disk to write to", label="Disk") + hostname = ft.TextField(value="host", label="Hostname", text_align=ft.TextAlign.LEFT) + password = ft.TextField(label="Password", text_align=ft.TextAlign.LEFT) + switch_ip = ft.TextField(label="Switch IP", text_align=ft.TextAlign.LEFT) + switch_port = ft.TextField(label="Switch Port", value="4789", text_align=ft.TextAlign.LEFT) + swarm_token = ft.TextField(label="Swarm Token", text_align=ft.TextAlign.LEFT) + + def get_disk() -> str: + return disk.value if disk.value is not None else "" + def get_hostname() -> str: + return hostname.value if hostname.value is not None else "" + + def get_password() -> str: + return password.value if password.value is not None else "" + + def get_switch_ip() -> IPAddress: + return ipaddress.ip_address(switch_ip.value if switch_ip.value is not None else "0.0.0.0") + + def get_switch_port() -> int: + return int(switch_port.value if switch_port.value is not None else "0") + + def get_swarm_token() -> str: + return swarm_token.value if swarm_token.value is not None else "" + + def trigger_disk_creation(_): + raise NotImplementedError + create_ignition_disk( + disk=get_disk(), + hostname=get_hostname(), + password=get_password(), + switch_ip=get_switch_ip(), + switch_port=get_switch_port(), + swarm_token=get_swarm_token(), + ) -ft.app(target=main) \ No newline at end of file + disk_row = ft.Row( + controls=[ + dd_element, + ft.FilledButton( + text="Create Ignition Disk", + on_click=trigger_disk_creation, + ), + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + + node_row = ft.Row( + controls=[ + hostname, + password, + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + + switch_row = ft.Row( + controls=[ + switch_ip, + switch_port, + ], + alignment=ft.MainAxisAlignment.CENTER + ) + + page.add( + ft.Column( + [disk_row, node_row, switch_row, swarm_token], + alignment=ft.MainAxisAlignment.CENTER, + ) + ) \ No newline at end of file