From 9f8f89fde2b7130f40c54e4ce70855e208ebc636 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Sat, 16 Aug 2025 14:22:13 +0200 Subject: [PATCH] More UI work --- .../__pycache__/routes.cpython-313.pyc | Bin 1720 -> 4434 bytes src/applets/install/install.html | 42 +++++++++- src/applets/install/routes.py | 78 +++++++++++++++++- src/applets/main/routes.py | 32 ++++++- src/applets/welcome/welcome.html | 3 +- src/system-installer-daemon | 3 +- src/templates/footer.html | 12 ++- src/templates/header.html | 7 +- 8 files changed, 160 insertions(+), 17 deletions(-) diff --git a/src/applets/install/__pycache__/routes.cpython-313.pyc b/src/applets/install/__pycache__/routes.cpython-313.pyc index 7be89bb2ff804401e30f3d88581e34ad7bcb06fc..bf059ee2994a49ba8b3eb9ae827608048adb7a1d 100644 GIT binary patch literal 4434 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 delta 733 zcmZ{h&r2IY6vyZ7j~I8eyHOKKYt?lllqeDv#aKmpYqgNlt`|WFF)nc--GsNBOD+*F zdX>5AF^8TDrC0w0E94R=^wL9bDJgjEOq!OBv;+HPcKCeey_vbQK52SS(-gwSVyA$@&05?Y~AeWQ>Lk zeaJZZTZt7>LW&wvj3Fg##6pG^GU8=DV|?di20Fq~Efb~J@Y-NMYN?LsctN39t9@7z zc0rzGRD?FgX-Lp((WFm|g;7h{N4H#dkj|=)XiM73=ifs|uA%D%IKc!=@JR9){}XXG z@ii8wQ_8GQ*u=O-2wmFgR>NGnxEAdD8 E1rtPzb^rhX diff --git a/src/applets/install/install.html b/src/applets/install/install.html index e1fa811..3184fc4 100644 --- a/src/applets/install/install.html +++ b/src/applets/install/install.html @@ -2,14 +2,48 @@ {% block body %}
-

Installing...


+

+ + Installing... + +

+ +
+
-

Installing system, the rest of the process is automated.

-

+

+ Installing system, the rest of the process is automated. +

+ +

+


+ +
+ + +
+ +
+ + +
+
+ +
-
Initializing...
+
+
Initializing...
+
diff --git a/src/applets/install/routes.py b/src/applets/install/routes.py index e7124b0..b343f2b 100644 --- a/src/applets/install/routes.py +++ b/src/applets/install/routes.py @@ -1,8 +1,20 @@ from applets.install import bp from flask import Flask, request, session, redirect, \ - url_for, render_template, flash, Blueprint + url_for, render_template, flash, Blueprint, jsonify from flask import current_app +import subprocess +import threading + + +status = { + "status": "idle", # idle | running | finished + "output": "", + "exit_code": None, + "lines": [] +} + + @bp.route('/install',methods=['GET', 'POST', 'PUT']) def install_index(): """ @@ -19,14 +31,74 @@ def install_start(): Trigger the installation process """ print("The installation process is starting!... in theory at least") + if status["status"] == "running": + return jsonify({"status": "already running"}), 409 # Conflict + threading.Thread(target=run_script).start() + return jsonify({"status": "started"}) + print("did it finish?") -@bp.route('/install-status',methods=['GET', 'POST', 'PUT']) +def run_script(): + global status + status["status"] = "running" + + process = subprocess.Popen( + ["bash", "/data/jonathan/devel/highvoltage/system-installer/daemon/src/fake-install-shell.sh"], + stdout = subprocess.PIPE, + stderr = subprocess.STDOUT, + text = True) + + lines = [] + for line in iter(process.stdout.readline,''): + #lines.append(line.strip()) + #status["output"] = "\n".join(lines) + status["lines"].append(line.strip()) + + process.wait() + status["status"] = 'finished' + status["exit_code"] = process.returncode + + print(lines) + print("status:", status["status"], "code:", status["exit_code"]) + + +@bp.route('/install/status', methods=['GET', 'POST']) def install_status(): """ Update on the status of the installation process. """ - print("installation en coers") + + # Keep track of the last line posted, so that we can include + # any new lines not provided to the UI yet + last_line = int(request.args.get("last_line", 0)) + new_lines = status["lines"][last_line:] + + if not new_lines and status["status"] == "finished": + return "" # Empty response = HTMX will stop polling + + lines_html = "" + for i, line in enumerate(new_lines, start=last_line + 1): + lines_html += f'
{line}
' + + return { + "output": status['output'], + "status": status['status'], + "lines": lines_html, + "last_line": f'' + } + + +@bp.route('/install/cancel', methods=["POST"]) +def install_cancel(): + """ + Cancel the installation process. + """ + if status["status"] != "running" or not status["process"]: + return Response("No running script", status=400) + process["process"].terminate() + process["status"] = "cancelled" + process["exit_code"] = -1 + return Response("Cancelled", status=200) @bp.route('/settings',methods=['GET', 'POST', 'PUT']) diff --git a/src/applets/main/routes.py b/src/applets/main/routes.py index 5cc9f5a..da1a1cf 100644 --- a/src/applets/main/routes.py +++ b/src/applets/main/routes.py @@ -1,5 +1,10 @@ -from applets.main import bp - +from applets.welcome import bp +from flask import Flask, request, session, redirect, \ + url_for, render_template, flash, Blueprint +# we use this neat little trick to get config data from the main app +from flask import current_app +import gettext +import dmm.lsblk as lsblk @bp.route('/') def index(): @@ -19,3 +24,26 @@ def apihome(): """ return ("0") + +@bp.route('/main/help',methods=['GET', 'POST', 'PUT']) +def main_welcome(): + """ + Manages the main help system. + """ + return render_template('help.html') + + +@bp.route('/main/quit',methods=['GET', 'POST', 'PUT']) +def main_quit(): + """ + Manages the quit dialog. + """ + return render_template('quit.html') + + +@bp.route('/main/menu',methods=['GET', 'POST', 'PUT']) +def main_menu(): + """ + Manages the main menu. + """ + return render_template('menu.html') diff --git a/src/applets/welcome/welcome.html b/src/applets/welcome/welcome.html index 59a095b..a9a6df7 100644 --- a/src/applets/welcome/welcome.html +++ b/src/applets/welcome/welcome.html @@ -11,7 +11,8 @@
- {{ string_dict['language_text'] }} + +{{ string_dict['language_text'] }}