Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed2ddb0a77 | ||
|
|
31bb032a4e | ||
|
|
22dcf36b14 | ||
|
|
088bf495f5 | ||
|
|
c0aa82241b | ||
|
|
9544463bd6 | ||
|
|
60cd5140d2 | ||
|
|
dcbc8dd062 | ||
|
|
08f232bf51 | ||
|
|
75d068fef6 | ||
|
|
373ce1247e | ||
|
|
eaa983e955 | ||
|
|
652bbba9c0 | ||
|
|
69d6ba277d | ||
|
|
8791c58cbf | ||
|
|
258a359ce1 | ||
|
|
21b210a689 | ||
|
|
430b144d92 | ||
|
|
d4cfa4815c | ||
|
|
9f8f89fde2 |
@@ -10,12 +10,18 @@ Dependencies:
|
||||
- flask
|
||||
- pytest
|
||||
- coverage
|
||||
- libxapp-gtk3-module
|
||||
- gettext
|
||||
|
||||
Recommended:
|
||||
- libjs-htmx (needed if the web front-end is to be used)
|
||||
- sass-stylesheets-bulma (needed if the web front-end is to be used)
|
||||
- libxapp-gtk3-module
|
||||
|
||||
On Debian-based systems, you should get everything with the following:
|
||||
|
||||
```
|
||||
apt install python3-flask python3-command-runner python3-pytest python3-dmm gettext libjs-htmx sass-stylesheets-bulma fonts-fork-awesome
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('install', __name__,
|
||||
template_folder='')
|
||||
|
||||
from applets.install import routes
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
|
||||
<center>
|
||||
<p style="position: absolute: left: 45px; top: 10px;"> <big><big> Installing...</big></big></p> <br />
|
||||
<img style="width: 400px; padding: 20px;" src="/static/slide1.png" /> <br />
|
||||
<p> Installing system, the rest of the process is automated. </p>
|
||||
<p style="margin: 20px;"> <input style="background-color: #777777;" type="checkbox" id="reboot" name="reboot" value="reboot" checked>
|
||||
<label for="reboot"> Reboot automatically when ready </label></p><br>
|
||||
</center>
|
||||
|
||||
<div style="position: absolute; padding: 10px; background-color: #26495e; left: 40px; right: 40px; bottom: 40px; height: text-align: middle;"> <center> Initializing... </center> </div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,37 +0,0 @@
|
||||
from applets.install import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
url_for, render_template, flash, Blueprint
|
||||
from flask import current_app
|
||||
|
||||
@bp.route('/install',methods=['GET', 'POST', 'PUT'])
|
||||
def install_index():
|
||||
"""
|
||||
The page you'd get if you access the root of
|
||||
this app in a browser.
|
||||
"""
|
||||
install_start()
|
||||
return render_template('install.html')
|
||||
|
||||
|
||||
@bp.route('/install-start',methods=['GET', 'POST', 'PUT'])
|
||||
def install_start():
|
||||
"""
|
||||
Trigger the installation process
|
||||
"""
|
||||
print("The installation process is starting!... in theory at least")
|
||||
|
||||
|
||||
@bp.route('/install-status',methods=['GET', 'POST', 'PUT'])
|
||||
def install_status():
|
||||
"""
|
||||
Update on the status of the installation process.
|
||||
"""
|
||||
print("installation en coers")
|
||||
|
||||
|
||||
@bp.route('/settings',methods=['GET', 'POST', 'PUT'])
|
||||
def settings():
|
||||
"""
|
||||
Manage settings for the installation module.
|
||||
"""
|
||||
print("Settings")
|
||||
@@ -1,7 +0,0 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('main', __name__,
|
||||
template_folder='')
|
||||
|
||||
from applets.main import routes
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
from applets.main import bp
|
||||
|
||||
|
||||
@bp.route('/')
|
||||
def index():
|
||||
"""
|
||||
The page you'd get if you access the root of
|
||||
this app in a browser.
|
||||
"""
|
||||
return ("Welcome to System Installer Daemon POC <br />"
|
||||
"Version: Unavailable")
|
||||
|
||||
|
||||
@bp.route('/api/v0')
|
||||
def apihome():
|
||||
"""
|
||||
Not sure what this function should do, but have
|
||||
a feeling that it should exist.
|
||||
"""
|
||||
return ("0")
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('software', __name__,
|
||||
template_folder='')
|
||||
|
||||
from applets.software import routes
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('users', __name__,
|
||||
template_folder='')
|
||||
|
||||
from applets.users import routes
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('webui', __name__)
|
||||
|
||||
from applets.webui import routes
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
from applets.webui import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
url_for, render_template, flash, Blueprint
|
||||
|
||||
|
||||
@bp.route('/webui')
|
||||
def webui_index():
|
||||
"""
|
||||
The page you'd get if you access the root of
|
||||
this app in a browser.
|
||||
"""
|
||||
return ("""
|
||||
<head>
|
||||
<script src="/static/htmx.min.js.gz crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<button hx-post="/clicked"
|
||||
hx-trigger="click"
|
||||
hx-target="#parent-div"
|
||||
hx-swap="outerHTML" >
|
||||
Click Me!
|
||||
</button>
|
||||
|
||||
|
||||
<div style="background-color: black; color: white; height: 200px; width: 200px;" hx-get="/welcome" hx-trigger="every 2s"></div>
|
||||
<div hx-post="/welcome" hx-trigger="mouseenter">
|
||||
1
|
||||
<br><br><br><br>
|
||||
[Here Mouse, Mouse!]
|
||||
<br><Br><br><br>
|
||||
2
|
||||
</div>
|
||||
|
||||
Welcome to System Installer Daemon POC <br />
|
||||
This is the WebUI Index
|
||||
""")
|
||||
|
||||
|
||||
@bp.route('/webui/welcome')
|
||||
def webui_welcome():
|
||||
"""
|
||||
Welcome screen for the webui.
|
||||
|
||||
It's job right now is to:
|
||||
|
||||
- Obtain the language
|
||||
- Check basic system eligibility
|
||||
"""
|
||||
return render_template('welcome.html')
|
||||
|
||||
|
||||
@bp.route('/webui/users')
|
||||
def webui_users():
|
||||
"""
|
||||
Users screen for the webui.
|
||||
|
||||
It's job right now is to:
|
||||
|
||||
- Set up an initial user
|
||||
|
||||
More functions will follow at a later stage
|
||||
"""
|
||||
return render_template('users.html')
|
||||
|
||||
|
||||
@bp.route('/webui/disks')
|
||||
def webui_disks():
|
||||
"""
|
||||
Disks screen for the webui.
|
||||
"""
|
||||
return render_template('disks.html')
|
||||
|
||||
|
||||
@bp.route('/webui/disks/partition/<part>')
|
||||
def webui_disks_partition(part):
|
||||
"""
|
||||
Partition modal for the webui partition screen.
|
||||
"""
|
||||
return render_template('disks_partition.html')
|
||||
|
||||
|
||||
@bp.route('/webui/software')
|
||||
def webui_software():
|
||||
"""
|
||||
Software screen for the webui.
|
||||
"""
|
||||
return render_template('software.html')
|
||||
|
||||
|
||||
@bp.route('/webui/summary')
|
||||
def webui_summary():
|
||||
"""
|
||||
Summary screen for the webui.
|
||||
"""
|
||||
return render_template('summary.html')
|
||||
@@ -1,6 +0,0 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('welcome', __name__,
|
||||
template_folder='')
|
||||
|
||||
from applets.welcome import routes
|
||||
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,112 +0,0 @@
|
||||
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
|
||||
|
||||
# Set up Gettext
|
||||
def set_language(LANG):
|
||||
"""
|
||||
Sets language for this applet
|
||||
"""
|
||||
translations = gettext.translation("welcome", './applets/welcome/locales',
|
||||
fallback=True, languages=[LANG])
|
||||
translations.install()
|
||||
_ = translations.gettext
|
||||
|
||||
|
||||
@bp.route('/welcome',methods=['GET', 'POST', 'PUT'])
|
||||
def welcome_index():
|
||||
"""
|
||||
The page you'd get if you access the root of
|
||||
this app in a browser.
|
||||
"""
|
||||
set_language(current_app.config['CONFIG']['settings']['language'])
|
||||
if request.method == 'POST':
|
||||
if "lang" in request.form.keys():
|
||||
current_app.config['CONFIG']['settings']['language'] = request.form["lang"]
|
||||
LANG = current_app.config['CONFIG']['settings']['language']
|
||||
set_language(LANG)
|
||||
FORMLANG = request.form["lang"]
|
||||
if "keyboard" in request.form.keys():
|
||||
print(request.form["keyboard"])
|
||||
if "timezone" in request.form.keys():
|
||||
print(request.form["timezone"])
|
||||
global lang
|
||||
lang = current_app.config['CONFIG']['settings']['language']
|
||||
blkid = lsblk.list_scsi_devices()
|
||||
string_dict = build_stringlist()
|
||||
build_menu()
|
||||
build_summary()
|
||||
menu = current_app.config['CONFIG']['settings']['menu_order'].split(" ")
|
||||
next_step_url = menu[menu.index("welcome")+1]
|
||||
previous_step_url = menu[menu.index("welcome")-1]
|
||||
|
||||
print("index is: " , menu.index("welcome"))
|
||||
if menu.index("welcome") == 0:
|
||||
previous_step_url = False
|
||||
else:
|
||||
previous_step_url = menu[menu.index("users")-1]
|
||||
|
||||
print("next is: " + next_step_url)
|
||||
print("previous is: " , previous_step_url)
|
||||
power_button = '<button class="button is-dark"> <img width="16px;" src="/static/icons/greencheck.png"> Power: AC </button>'
|
||||
internet_button = ' <button class="button is-dark"> <img width="16px;" src="/static/icons/greencheck.png"> Internet </button>'
|
||||
bottom_menu = power_button + internet_button
|
||||
|
||||
return render_template('welcome.html',
|
||||
string_dict=string_dict, selected_lang=lang,
|
||||
menu=current_app.config['CONFIG']['settings']['menu'],
|
||||
menu_order=current_app.config['CONFIG']['settings']['menu_order'].split(),
|
||||
previous_step=previous_step_url,
|
||||
next_step=next_step_url,
|
||||
bottom_menu=bottom_menu)
|
||||
|
||||
|
||||
def build_stringlist():
|
||||
"""
|
||||
Return all the strings that is used in this applet."
|
||||
"""
|
||||
string_dict = {}
|
||||
string_dict['menu_item'] = _("Welcome")
|
||||
string_dict['welcome_text'] = _("Welcome! This setup program will install Debian on to your system.")
|
||||
string_dict['confirm_text'] = _("Please confirm the following details:")
|
||||
string_dict['language_text'] = _("Language:")
|
||||
string_dict['keylayout_text'] = _("Keyboard Layout:")
|
||||
string_dict['timezone_text'] = _("Time Zone:")
|
||||
string_dict['basicsettings_text'] = _("Basic Settings:")
|
||||
lang_dict = {}
|
||||
lang_dict['af'] = _("Afrikaans")
|
||||
lang_dict['en'] = _("English (International)")
|
||||
lang_dict['en-us'] = _("English (United States)")
|
||||
lang_dict['en-uk'] = _("English (United Kingdom)")
|
||||
lang_dict['en-za'] = _("English (South Africa)")
|
||||
string_dict['lang_list'] = lang_dict
|
||||
return string_dict
|
||||
|
||||
def build_menu():
|
||||
"""
|
||||
Define menu items and paths.
|
||||
"""
|
||||
current_app.config['CONFIG']['settings']['menu']['welcome'] = (build_stringlist()['menu_item'], "/welcome", 10)
|
||||
|
||||
|
||||
def build_summary():
|
||||
"""
|
||||
Write up a summary of what this module will do.
|
||||
"""
|
||||
html = ("<b><big>Basic settings</big></b><p> Language: " + lang + "</p>")
|
||||
if not 'Summary' in current_app.config['CONFIG']:
|
||||
current_app.config['CONFIG']['Summary'] = {}
|
||||
current_app.config['CONFIG']['Summary']['welcome'] = {}
|
||||
current_app.config['CONFIG']['Summary']['welcome']['heading'] = "Basic Settings"
|
||||
print(current_app.config['CONFIG']['Summary']['welcome'])
|
||||
text = "Language: " + str(current_app.config['CONFIG']['settings']['language'])
|
||||
current_app.config['CONFIG']['Summary']['welcome']['text'] = text
|
||||
return(html)
|
||||
|
||||
|
||||
set_language(current_app.config['CONFIG']['settings']['language'])
|
||||
build_menu
|
||||
@@ -1,57 +0,0 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
|
||||
<img style="width: 100%; border-radius: 8px;"
|
||||
src="/static/applets/welcome/img/banner.png"
|
||||
alt="Debian Image banner" />
|
||||
|
||||
<p><b> {{ string_dict['welcome_text'] }} </b></p>
|
||||
<p>{{ string_dict['confirm_text'] }} </p> <br />
|
||||
|
||||
<div style="padding-left: 15px;">
|
||||
|
||||
<form action="/welcome" method="POST">
|
||||
<i class="fa fa-language" aria-hidden="true"></i> {{ string_dict['language_text'] }}
|
||||
<div class="control is-link" width="180px">
|
||||
<div class="select">
|
||||
<select hx-post="/welcome" hx-target="body" name="lang" style="width: 220px">
|
||||
{% for lang in string_dict['lang_list'] %}
|
||||
<option value="{{lang}}" {% if lang == selected_lang %} selected=selected {% endif %}>{{ string_dict['lang_list'][lang] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<br>
|
||||
|
||||
<form>
|
||||
<i class="fa fa-keyboard-o" aria-hidden="true"></i> {{ string_dict['keylayout_text'] }}
|
||||
<div class="control is-link">
|
||||
<div class="select">
|
||||
<select hx-post="/welcome" hx-target="body" name="keyboard" style="width: 220px">
|
||||
<option>en-us</option>
|
||||
<option>en-uk</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<br />
|
||||
|
||||
<form>
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i> {{ string_dict['timezone_text'] }}
|
||||
<div class="control is-link">
|
||||
<div class="select">
|
||||
<select hx-post="/welcome" hx-target="body" name="timezone" style="width: 220px">
|
||||
<option>Africa/Johannesburg</option>
|
||||
<option>UTC</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -1 +0,0 @@
|
||||
../../../applets/welcome/img
|
||||
|
Before Width: | Height: | Size: 304 KiB |
|
Before Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 8 0 c -4.40625 0 -8 3.59375 -8 8 s 3.59375 8 8 8 s 8 -3.59375 8 -8 s -3.59375 -8 -8 -8 z m 3.398438 4.507812 c 0.265624 -0.027343 0.527343 0.050782 0.734374 0.21875 c 0.425782 0.351563 0.488282 0.980469 0.140626 1.40625 l -4.5 5.5 c -0.179688 0.21875 -0.441407 0.351563 -0.722657 0.367188 c -0.28125 0.011719 -0.558593 -0.09375 -0.757812 -0.292969 l -2.5 -2.5 c -0.390625 -0.390625 -0.390625 -1.023437 0 -1.414062 s 1.023437 -0.390625 1.414062 0 l 1.71875 1.71875 l 3.800781 -4.644531 c 0.167969 -0.203126 0.410157 -0.335938 0.671876 -0.363282 z m 0 0" fill="#2e3436"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 719 B |
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
sodipodi:docname="keyboard.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="namedview2"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="52.375"
|
||||
inkscape:cx="8"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-width="1236"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="662"
|
||||
inkscape:window-y="199"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" />
|
||||
<g
|
||||
font-weight="400"
|
||||
fill="#474747"
|
||||
id="g2"
|
||||
style="fill:#c0bfbc">
|
||||
<path
|
||||
d="M3.702 1C2.17 1 .984 2.32.984 3.844v8.344c0 1.524 1.185 2.843 2.718 2.843h8.58c1.532 0 2.75-1.32 2.75-2.844V3.845c0-1.525-1.218-2.844-2.75-2.844zm.782 1.031c3.526.256 5.317.134 7.047 0 .754-.058 1.532.616 1.532 1.438v7.375c0 .665-.532 1.095-1.188 1.187-2.836.397-4.753.44-7.673 0-.655-.099-1.187-.522-1.187-1.187V3.5c0-.822.714-1.524 1.469-1.469z"
|
||||
style="line-height:normal;-inkscape-font-specification:'Bitstream Vera Sans';text-indent:0;text-align:start;text-decoration-line:none;text-transform:none;marker:none;fill:#c0bfbc"
|
||||
color="#bebebe"
|
||||
font-family="Bitstream Vera Sans"
|
||||
overflow="visible"
|
||||
id="path1" />
|
||||
<path
|
||||
d="M10.564 5.977l-2.939.044.016 1 2.879-.043c.2.018.33.076.396.135.067.06.105.121.105.293l-.008.604H8.517l.037.002a1.457 1.457 0 00-1.164.43 1.558 1.558 0 00-.416 1.023c-.013.367.092.75.352 1.053.26.303.687.496 1.162.482h3.482l.051-3.59v-.004c0-.402-.16-.786-.435-1.035-.276-.249-.63-.364-.998-.393zM8.48 9.01h2.519l-.014.99H8.457c-.22.007-.302-.051-.371-.133a.553.553 0 01-.112-.367.587.587 0 01.141-.371c.079-.083.163-.134.363-.12zm2.862-5.985l-3 1 .316.95 3-1z"
|
||||
style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;text-orientation:mixed;shape-padding:0;isolation:auto;mix-blend-mode:normal;marker:none;fill:#c0bfbc"
|
||||
color="#000"
|
||||
font-family="sans-serif"
|
||||
overflow="visible"
|
||||
id="path2" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 1 v 3 l 3 -3 h 6 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 0" fill="#2e3436"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 329 B |
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 1 v 3 l 3 -3 h 6 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 2 h 10 c 0.554688 0 1 0.445312 1 1 v 6 c 0 0.554688 -0.445312 1 -1 1 h -10 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.554688 0.445312 -1 1 -1 z m 0 0" fill="#2e3436" fill-opacity="0.34902"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 502 B |
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import webview
|
||||
|
||||
LOCATION = "http://localhost:8080/welcome"
|
||||
|
||||
def on_closed():
|
||||
"""
|
||||
Actions to take when System Installer is closed.
|
||||
"""
|
||||
print('pywebview window is closed')
|
||||
|
||||
|
||||
window = webview.create_window('System Installer', LOCATION,
|
||||
transparent=True, easy_drag=False, frameless=True,
|
||||
width=1050, focus=True, zoomable=True,
|
||||
confirm_close=True, resizable=True)
|
||||
|
||||
window.events.closed += on_closed
|
||||
webview.start()
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env dmm-perform-recipe
|
||||
|
||||
module_path:
|
||||
- local
|
||||
|
||||
settings:
|
||||
language: en
|
||||
devmode: True
|
||||
apt_depends: util-linux adduser parted e2fsprogs debootstrap
|
||||
apps: main welcome users disks software summary install
|
||||
menu_order: welcome users disks software summary
|
||||
|
||||
recipe:
|
||||
installer_dependencies:
|
||||
description: Installing Dependencies
|
||||
module: aptpkg
|
||||
function: install
|
||||
packagooes: apt
|
||||
chrooti: /tmp
|
||||
users:
|
||||
module: users
|
||||
function: add
|
||||
users:
|
||||
- username:
|
||||
password:
|
||||
fullname:
|
||||
sudo: True
|
||||
popcon:
|
||||
module: software
|
||||
function: popcon
|
||||
enable_popcon: False
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<!-- Buttons on the left -->
|
||||
<div style="position: absolute; bottom: 15px; left: 15px;">
|
||||
|
||||
{% if previous_step %}
|
||||
<a href="/{{ previous_step }}"><button class="button is-light">Back</button></a>
|
||||
{% endif %}
|
||||
|
||||
{% if bottom_menu %}
|
||||
{{ bottom_menu | safe }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Buttons on the right -->
|
||||
<div style="position: absolute; bottom: 15px; right: 15px;">
|
||||
{% if next_step %}
|
||||
{% if next_step == "install" %}
|
||||
<a href="/{{ next_step }}"><button hx-trigger="click, keyup[shiftKey&&key=='I'] from:body" class="button is-link">Install</button></a>
|
||||
{% else %}
|
||||
<a href="/{{ next_step }}"><button hx-trigger="click, keyup[shiftKey&&key=='N'] from:body" hx-target="/{{ next_step }}" class="button is-link">Next</button></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -1,20 +0,0 @@
|
||||
<!-- Header -->
|
||||
<div id="titlebar" style="padding: 15px; margin: -15px; padding-bottom: 30px;">
|
||||
|
||||
<!-- drag region class: -->
|
||||
<!-- <div id="titlebar" class="pywebview-drag-region" style="padding: 15px; margin: -15px; padding-bottom: 30px;"> -->
|
||||
|
||||
<button class="button is-link"> ☰ </button>
|
||||
|
||||
{% for item in menu_order %}
|
||||
<a href="{{ menu[item][1]}}"> <button class="button is-{% if request.path == menu[item][1] %}info{% else %}dark{% endif %}"> {{ menu[item][0]}} </button></a>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
<div style="position: absolute; top: 15px; right: 15px;">
|
||||
<a href="/help"> <button class="button is-light"> <b> ? </b> </button></a>
|
||||
<button onclick="closeApp()" class="button is-danger" > 🗙 </button>
|
||||
</div>
|
||||
|
||||
</div> <!-- end pywebview-drag-region -->
|
||||
<!-- End Header -->
|
||||
@@ -1,28 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="/static/bulma.css" rel="stylesheet">
|
||||
<link href="/static/system-installer.css" rel="stylesheet">
|
||||
<link rel="shortcut icon" href="/static/icons/blippie.png" type="image/x-icon">
|
||||
<link rel="stylesheet" href="/usr/share/fonts-fork-awesome/css/fork-awesome.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css" integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
|
||||
<script src="/static/htmx.min.js" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="frame">
|
||||
{% include "header.html" %}
|
||||
|
||||
<div class="applet">
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% include "footer.html" %}
|
||||
|
||||
</div> <!-- class "frame" -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Welcome to SID - The System Installer Daemon!
|
||||
Welcome to YaSID - The The Yasi System Installer Daemon!
|
||||
"""
|
||||
|
||||
from flask import Flask, request, session, redirect, \
|
||||
@@ -10,9 +10,10 @@ import logging
|
||||
import dmm.lsblk as lsblk
|
||||
import importlib
|
||||
import yaml
|
||||
import sys
|
||||
|
||||
# configuration
|
||||
CONFIGFILE="templates/dmm-installer-template.yaml"
|
||||
CONFIGFILE="/etc/yasi/yasi.yaml"
|
||||
|
||||
# import config
|
||||
global config
|
||||
@@ -27,6 +28,7 @@ app.config.from_object(__name__)
|
||||
app.config['CONFIG'] = config
|
||||
app.app_context().push()
|
||||
config['settings']['menu'] = {}
|
||||
sys.path.append('/usr/share/yasi-daemon')
|
||||
|
||||
if DEV_MODE:
|
||||
print("Note: Starting in devmode!")
|
||||
@@ -37,7 +39,7 @@ if DEV_MODE:
|
||||
for APP in APPS.split(" "):
|
||||
print(f"Loading applet: {APP} ")
|
||||
# Dynamically import the blueprint module
|
||||
module = importlib.import_module(f"applets.{APP}")
|
||||
module = importlib.import_module(f"yasi_applets.{APP}")
|
||||
# Get the blueprint (bp) from the imported module
|
||||
bp = getattr(module, "bp")
|
||||
# Register the blueprint with the app
|
||||
@@ -52,8 +54,8 @@ if DEV_MODE == "1":
|
||||
|
||||
if __name__ == '__main__':
|
||||
serve(app,
|
||||
host='0.0.0.0',
|
||||
port=8080,
|
||||
host='127.0.0.1',
|
||||
port=9274,
|
||||
url_scheme='http',
|
||||
expose_tracebacks=DEV_MODE)
|
||||
|
||||
35
src/yasi-webclient
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import webview
|
||||
|
||||
LOCATION = "http://localhost:9274/welcome"
|
||||
|
||||
def on_closed():
|
||||
"""
|
||||
Actions to take when System Installer is closed.
|
||||
"""
|
||||
print('pywebview window is closed')
|
||||
|
||||
|
||||
window = webview.create_window('System Installer', LOCATION,
|
||||
transparent=True, easy_drag=False, frameless=True,
|
||||
width=1050, focus=True, zoomable=True,
|
||||
confirm_close=True, resizable=True, shadow=True,
|
||||
text_select=False, draggable=False
|
||||
)
|
||||
|
||||
webview.settings = {
|
||||
'ALLOW_DOWNLOADS': False,
|
||||
'ALLOW_FILE_URLS': False,
|
||||
'DRAG_REGION_SELECTOR': '.pywebview-drag-region',
|
||||
'DRAG_REGION_DIRECT_TARGET_ONLY': True,
|
||||
'OPEN_EXTERNAL_LINKS_IN_BROWSER': True,
|
||||
'OPEN_DEVTOOLS_IN_DEBUG': True,
|
||||
'IGNORE_SSL_ERRORS': False,
|
||||
'REMOTE_DEBUGGING_PORT': None,
|
||||
'SHOW_DEFAULT_MENUS': True
|
||||
}
|
||||
|
||||
window.events.closed += on_closed
|
||||
#webview.start(icon='/usr/share/icons/yasi.png')
|
||||
webview.start()
|
||||
0
src/yasi_applets/__init__.py
Normal file
@@ -3,5 +3,5 @@ from flask import Blueprint
|
||||
bp = Blueprint('disks', __name__,
|
||||
template_folder='')
|
||||
|
||||
from applets.disks import routes
|
||||
from yasi_applets.disks import routes
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
<div class="radios">
|
||||
<label class="radio">
|
||||
<input type="radio" name="rsvp" />
|
||||
<input selected type="radio" name="rsvp" />
|
||||
Preconfigured partitioning
|
||||
<!-- Let's hide these babies for the initial release.
|
||||
<label class="radio">
|
||||
<input type="radio" name="rsvp" disabled />
|
||||
Erase entire disk
|
||||
@@ -23,10 +24,11 @@
|
||||
<input type="radio" name="rsvp" disabled />
|
||||
Edit existing partitions
|
||||
</label>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="columns" width="100%">
|
||||
<div class="column"><p> <br>Proposed layout: </p></div>
|
||||
<div class="column"><p> <br>Current layout: </p></div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
@@ -64,10 +66,9 @@
|
||||
-->
|
||||
|
||||
|
||||
<!-- {% for disk in blockdevs["blockdevices"] if disk["name"] != "zram0"%} -->
|
||||
{% for disk in blockdevs["blockdevices"] if disk["name"] != "zram0" and "loop" not in disk["name"] and disk["name"] != "sr0" %}
|
||||
|
||||
<!--
|
||||
|
||||
<h1> Raw data </h1>
|
||||
{{ disk }}
|
||||
|
||||
@@ -137,17 +138,40 @@ fssize: {{ child['fssize'] }}
|
||||
{% endfor %}
|
||||
-->
|
||||
|
||||
<br>
|
||||
{% endfor %}
|
||||
|
||||
<!-- Add Undetected Disk
|
||||
Add Virtual Filesystem
|
||||
Add Network Filesystem -->
|
||||
|
||||
<div class="columns" width="100%">
|
||||
<div class="column"><p> <br>Proposed partitioning: </p></div>
|
||||
</div>
|
||||
|
||||
<div style=""> <!-- partition bars -->
|
||||
<div style="background-color: gray; padding: 4px 6px 7px 6px; border-radius: 10px;">
|
||||
<p> <span style="width: 100%; border-radius: 8px 8px 0 0;" class="tag is-black">
|
||||
<small><small> New GPT Partition Table</small></small>
|
||||
<div class="columns">
|
||||
{% for partition in partitions %}
|
||||
{% if "mkpart" in partition['command'] %}
|
||||
<a hx-get="/disks/partition/{{ partition['device'] }}" hx-swap="outerHTML"/ style="{% if "100%" in partition['command'] %}width: 100%; {% endif %}">
|
||||
<div class="column is-narrow is-primary">
|
||||
<div class="box" style="min-width: 220px; border-radius: 0 0 0px 5px; height: 60px; padding-top: 5px;">
|
||||
<p class="is-tiny"> {{ partition['device'] }} </p>
|
||||
<p class="title is-5"><span class="tag is-black"> {{ partition['mountpoint'] }} </span>
|
||||
<span class="tag is-link"> {{ partition['fstype'] }} </span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
from applets.disks import bp
|
||||
from yasi_applets.disks import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
url_for, render_template, flash, Blueprint
|
||||
import dmm.lsblk as lsblk
|
||||
@@ -21,14 +21,18 @@ def disks():
|
||||
add_disks_button = ' <button class="button iis-info"> <i class="fa fa-hdd-o" aria-hidden="true"></i> Add Disk or Filesystem </button>'
|
||||
add_swap_button = ' <button class="button iis-info"> <i class="fa fa-object-group" aria-hidden="true"></i> Swap Configuration </button>'
|
||||
bottom_menu = add_disks_button + add_swap_button
|
||||
# no bottom menu for this release
|
||||
bottom_menu = ""
|
||||
build_summary()
|
||||
|
||||
return render_template('disks.html', blockdevs=blockdevs,
|
||||
menu=current_app.config['CONFIG']['settings']['menu'],
|
||||
menu_order=current_app.config['CONFIG']['settings']['menu_order'].split(),
|
||||
previous_step = previous_step_url,
|
||||
next_step = next_step_url,
|
||||
bottom_menu = bottom_menu)
|
||||
next_step=next_step_url,
|
||||
partitions=current_app.config['CONFIG']['recipe']['create_partitions']['command_set'],
|
||||
format_partitions=current_app.config['CONFIG']['recipe']['format_partitions'],
|
||||
bottom_menu=bottom_menu)
|
||||
|
||||
|
||||
@bp.route('/disks/partition/<part>')
|
||||
7
src/yasi_applets/hardware/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('hardware', __name__,
|
||||
template_folder='')
|
||||
|
||||
from yasi_applets.hardware import routes
|
||||
|
||||
41
src/yasi_applets/hardware/hardware.html
Normal file
@@ -0,0 +1,41 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
|
||||
<p> <b> Would you like fries with that? </b></p>
|
||||
|
||||
<br>
|
||||
|
||||
<div style="background-color: gray; padding: 4px 6px 7px 6px;
|
||||
border-radius: 10px; margin-bottom: 20px;">
|
||||
<span style="width: 100%; border-radius: 8px 8px 0 0;"
|
||||
class="tag is-black">
|
||||
Real-time Clock
|
||||
</span>
|
||||
<div style="padding-left: 15px; padding-right: 15px; background-color: #fff;
|
||||
color: #000;">
|
||||
<p>Date / time. / timezone</p> <br>
|
||||
<input style="background-color: #777777;" type="checkbox" id="popcon"
|
||||
name="popcon" hx-post="/software/settings" hx-trigger="change"
|
||||
{% if popcon %} checked {% endif %}>
|
||||
<label for="popcon"> Participate in PopCon </label><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background-color: gray; padding: 4px 6px 7px 6px;
|
||||
border-radius: 10px; margin-bottom: 20px;">
|
||||
<span style="width: 100%; border-radius: 8px 8px 0 0;"
|
||||
class="tag is-black">
|
||||
Firmware
|
||||
</span>
|
||||
<div style="padding-left: 15px; padding-right: 15px; background-color: #fff;
|
||||
color: #000;">
|
||||
<p>Install additional firmware.</p> <br>
|
||||
<input style="background-color: #777777;" type="checkbox" id="popcon"
|
||||
name="popcon" hx-post="/software/settings" hx-trigger="change"
|
||||
{% if popcon %} checked {% endif %}>
|
||||
<label for="popcon"> Participate in PopCon </label><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
65
src/yasi_applets/hardware/routes.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from yasi_applets.hardware import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
url_for, render_template, flash, Blueprint
|
||||
from flask import current_app
|
||||
|
||||
@bp.route('/hardware')
|
||||
def webui_hardware():
|
||||
"""
|
||||
Hardware screen for the webui.
|
||||
"""
|
||||
menu = current_app.config['CONFIG']['settings']['menu_order'].split(" ")
|
||||
next_step_url = menu[menu.index("hardware")+1]
|
||||
if menu[menu.index("hardware")] == 1:
|
||||
previous_step_url = False
|
||||
else:
|
||||
previous_step_url = menu[menu.index("hardware")-1]
|
||||
|
||||
sources_button = ' <button class="button iis-info"> <i class="fa fa-cloud-download" aria-hidden="true"></i> Configure Network </button>'
|
||||
blends_button = ' <button class="button iis-info"> <i class="fa fa-download" aria-hidden="true"></i> Install a Blend </button>'
|
||||
bottom_menu = sources_button + blends_button
|
||||
build_summary()
|
||||
|
||||
return render_template('hardware.html',
|
||||
menu=current_app.config['CONFIG']['settings']['menu'],
|
||||
menu_order=current_app.config['CONFIG']['settings']['menu_order'].split(),
|
||||
previous_step = previous_step_url,
|
||||
next_step = next_step_url,
|
||||
bottom_menu = bottom_menu,
|
||||
popcon=current_app.config['CONFIG']['recipe']['popcon']['enable_popcon'])
|
||||
|
||||
|
||||
@bp.route('/hardware/settings', methods=['GET', 'POST'])
|
||||
def hardware_settings():
|
||||
"""
|
||||
Receive settings for the hardware applet.
|
||||
"""
|
||||
if request.method == 'POST':
|
||||
popcon = "popcon" in request.form
|
||||
current_app.config['CONFIG']['recipe']['popcon']['enable_popcon'] = popcon
|
||||
print(current_app.config['CONFIG']['recipe']['popcon']['enable_popcon'])
|
||||
build_summary()
|
||||
return ('', 204)
|
||||
|
||||
|
||||
def build_menu():
|
||||
"""
|
||||
Define menu items and paths.
|
||||
"""
|
||||
# proper one once translations are done:
|
||||
#current_app.config['CONFIG']['settings']['menu']['welcome'] = (build_stringlist()['menu_item'], "/welcome", 10)
|
||||
current_app.config['CONFIG']['settings']['menu']['hardware'] = ("Hardware", "/hardware", 40)
|
||||
|
||||
|
||||
def build_summary():
|
||||
"""
|
||||
Write up a summary of what this module will do.
|
||||
"""
|
||||
current_app.config['CONFIG']['Summary']['hardware'] = {}
|
||||
current_app.config['CONFIG']['Summary']['hardware']['heading'] = "Hardware"
|
||||
current_app.config['CONFIG']['Summary']['hardware']['bleh'] = current_app.config['CONFIG']['recipe']['popcon']['enable_popcon']
|
||||
current_app.config['CONFIG']['Summary']['hardware']['text'] = "Participate in Popularity Contest: " + str(current_app.config['CONFIG']['recipe']['popcon']['enable_popcon']) + "<br/>No desktop environment selected."
|
||||
return("ok?")
|
||||
|
||||
|
||||
build_menu()
|
||||
9
src/yasi_applets/install/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('install', __name__,
|
||||
template_folder='',
|
||||
static_folder='static',
|
||||
static_url_path='/welcome/static')
|
||||
|
||||
from yasi_applets.install import routes
|
||||
|
||||
52
src/yasi_applets/install/install.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
|
||||
<center>
|
||||
<p style="position: absolute: left: 45px; top: 10px;">
|
||||
<big><big>
|
||||
Installing...
|
||||
</big></big>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<img style="width: 400px; padding: 20px;" src="/install/static/img/slide1.png" /> <br />
|
||||
<p>
|
||||
Installing system, the rest of the process is automated.
|
||||
</p>
|
||||
|
||||
<p style="margin: 20px;">
|
||||
<input style="background-color: #777777;" type="checkbox"
|
||||
id="reboot" name="reboot" value="reboot" checked>
|
||||
<label for="reboot"> Reboot automatically when ready </label></p><br>
|
||||
|
||||
<div id="output"></div>
|
||||
|
||||
<!-- Hidden input to track last line -->
|
||||
<div id="last-line-container">
|
||||
<input type="hidden" id="last-line" name="last_line" value="0">
|
||||
</div>
|
||||
|
||||
<!-- Poller -->
|
||||
<div hx-get="/install/status"
|
||||
hx-trigger="load, every 1s"
|
||||
hx-include="#last-line"
|
||||
hx-swap-oob="true"
|
||||
hx-target="this"
|
||||
hx-ext="json-enc"
|
||||
hx-vars="{}">
|
||||
</div>
|
||||
|
||||
|
||||
</center>
|
||||
|
||||
<div style="position: absolute; padding: 10px; background-color: #26495e; left: 40px;
|
||||
right: 40px; bottom: 40px; height: text-align: middle;">
|
||||
<center> Initializing... </center>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
109
src/yasi_applets/install/routes.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from yasi_applets.install import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
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():
|
||||
"""
|
||||
The page you'd get if you access the root of
|
||||
this app in a browser.
|
||||
"""
|
||||
install_start()
|
||||
return render_template('install.html')
|
||||
|
||||
|
||||
@bp.route('/install-start',methods=['GET', 'POST', 'PUT'])
|
||||
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?")
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
# 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'<div>{line}</div>'
|
||||
|
||||
return {
|
||||
"output": status['output'],
|
||||
"status": status['status'],
|
||||
"lines": lines_html,
|
||||
"last_line": f'<input type="hidden" id="last-line" name="last_line" value="{last_line + len(new_lines)}">'
|
||||
}
|
||||
|
||||
|
||||
@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'])
|
||||
def settings():
|
||||
"""
|
||||
Manage settings for the installation module.
|
||||
"""
|
||||
print("Settings")
|
||||
BIN
src/yasi_applets/install/static/img/slide1.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
9
src/yasi_applets/main/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('main', __name__,
|
||||
template_folder='',
|
||||
static_folder='static',
|
||||
static_url_path='/main/static')
|
||||
|
||||
from yasi_applets.main import routes
|
||||
|
||||
36
src/yasi_applets/main/footer.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!-- Buttons on the left -->
|
||||
<div style="position: absolute; bottom: 15px; left: 15px;">
|
||||
|
||||
{% if previous_step %}
|
||||
<!-- Why two of these? So that we can use two different keyboard shortcuts for back. -->
|
||||
<button style="display: none;" hx-get="/{{ previous_step }}" hx-target="body"
|
||||
hx-trigger="click, keydown[altKey&&key=='b'] from:body"></button>
|
||||
<a href="/{{ previous_step }}"><button hx-get="/{{ previous_step }}" hx-target="body"
|
||||
hx-trigger="click, keydown[ctrlKey&&code=='PageUp'] from:body" class="button is-light">Back</button></a>
|
||||
{% endif %}
|
||||
|
||||
{% if bottom_menu %}
|
||||
{{ bottom_menu | safe }}
|
||||
{% endif %}
|
||||
|
||||
</div> <!-- end buttons on the left -->
|
||||
|
||||
|
||||
<!-- Buttons on the right -->
|
||||
<div style="position: absolute; bottom: 15px; right: 15px;">
|
||||
|
||||
{% if next_step %}
|
||||
|
||||
{% if next_step == "install" %}
|
||||
<a href="/{{ next_step }}"><button hx-get="/{{ next_step }}" hx-target="body"
|
||||
hx-trigger="click, keyup[altKey&&key=='i'] from:body" class="button is-link">Install</button></a>
|
||||
{% else %}
|
||||
<!-- Why two of these? So that we can use two different keyboard shortcuts for next. -->
|
||||
<a href="/{{ next_step }}"<button hx-get="/{{ next_step }}" hx-target="body"
|
||||
hx-trigger="click, keydown[ctrlKey&&code=='PageDown'] from:body" class=""></button></a>
|
||||
<a href="/{{ next_step }}"<button hx-get="/{{ next_step }}" hx-target="body"
|
||||
hx-trigger="click, keydown[altKey&&key=='n'] from:body" class="button is-link">Next</button></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</div> <!-- end buttons on the right -->
|
||||
28
src/yasi_applets/main/header.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!-- Header -->
|
||||
<div id="titlebar" style="padding: 15px; margin: -15px; padding-bottom: 30px;">
|
||||
|
||||
<!-- drag region class: -->
|
||||
<div id="titlebar" class="pywebview-drag-region" style="padding: 15px; margin: -15px; padding-bottom: 30px;">
|
||||
|
||||
<!--
|
||||
You might be tempted to replace the unicode character by a fa-code as in the
|
||||
alternate commend below. Don't do it, it causes all kinds of artifacts and
|
||||
glitches as the page reloads (and makes it feel much more like an old website
|
||||
than a proper webapp.
|
||||
-->
|
||||
<a hx-get="/main/menu" hx-swap="outerHTML"/> <button class="button is-link"> ☰ </button> </a>
|
||||
<!--
|
||||
<a hx-get="/main/menu" hx-swap="outerHTML"/> <button class="button is-link"> <i class="fa fa-bars" aria-hidden="true"></i> </button> </a> -->
|
||||
|
||||
{% for item in menu_order %}
|
||||
<a href="{{ menu[item][1]}}"> <button class="button is-{% if request.path == menu[item][1] %}info{% else %}dark{% endif %}"> {{ menu[item][0]}} </button></a>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
<div style="position: absolute; top: 15px; right: 15px;">
|
||||
<a hx-get="/main/help" hx-swap="outerHTML"/> <button class="button is-light"> <i class="fa fa-question" aria-hidden="true"></i> </button></a>
|
||||
<a hx-get="/main/quit" hx-swap="outerHTML"/><button onclick="closeApp()" class="button is-danger" > 🗙 </button></a>
|
||||
</div>
|
||||
|
||||
</div> <!-- end pywebview-drag-region -->
|
||||
<!-- End Header -->
|
||||
24
src/yasi_applets/main/help.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="modal is-active">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-content">
|
||||
|
||||
<div style="background-color: #424242; padding: 15px; border-radius: 15px; boders: none; color: white;">
|
||||
<h1 class="is-size-4"> Help </h1>
|
||||
<br>
|
||||
|
||||
<p>The help system is not yet implemented.</p>
|
||||
<br>
|
||||
<p>Some keyboard tips:<p>
|
||||
<br>
|
||||
<ul>
|
||||
<li>ALT+n or CTRL+PGDn moves to the next page.</li>
|
||||
<li>ALT+p or CTRL+PGUp moves to the previous page.</li>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
<div class="columns">
|
||||
<a href="/welcome"><div class="column"><button class="button is-link">Continue</button></div></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
27
src/yasi_applets/main/layout.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="/main/static/bulma.css" rel="stylesheet">
|
||||
<link href="/main/static/system-installer.css" rel="stylesheet">
|
||||
<link rel="shortcut icon" href="/main/static/icons/blippie.png" type="image/x-icon">
|
||||
<link rel="stylesheet" href="/main/static/fork-awesome.css">
|
||||
<script src="/main/static/htmx.min.js" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="frame">
|
||||
{% include "header.html" %}
|
||||
|
||||
<div class="applet">
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% include "footer.html" %}
|
||||
|
||||
</div> <!-- class "frame" -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
17
src/yasi_applets/main/menu.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<div class="modal is-active">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-content">
|
||||
|
||||
<div style="background-color: #424242; padding: 15px; border-radius: 15px; borders: none; color: white;">
|
||||
<h1 class="is-size-4"> Main menu </h1>
|
||||
|
||||
<br />
|
||||
<p> There's nothing yet to do here.</p>
|
||||
<br />
|
||||
|
||||
<div class="columns">
|
||||
<a href="/welcome"><div class="column"><button class="button is-link">Continue</button></div></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
19
src/yasi_applets/main/quit.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<div class="modal is-active">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-content">
|
||||
|
||||
<div style="background-color: #424242; padding: 15px; border-radius: 15px; boders: none; color: white;">
|
||||
<h1 class="is-size-4"> Exit system installer </h1>
|
||||
<br /><p class="title is-6"><span class="tag is-danger">Quitting is not yet implemented.</span>
|
||||
|
||||
<br />
|
||||
|
||||
<p> ALT+F4 will bring up a dialog that works though. </p>
|
||||
|
||||
<br />
|
||||
<div class="columns">
|
||||
<a href="/welcome"><div class="column"><button class="button is-link">Continue</button></div></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
62
src/yasi_applets/main/routes.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from yasi_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
|
||||
|
||||
# Set up Gettext
|
||||
def set_language(LANG):
|
||||
"""
|
||||
Sets language for this applet
|
||||
"""
|
||||
# TODO: unhardcode this path
|
||||
translations = gettext.translation("welcome", '/usr/share/yasi-daemon/yasi_applets/welcome/locales',
|
||||
fallback=True, languages=[LANG])
|
||||
translations.install()
|
||||
_ = translations.gettext
|
||||
|
||||
|
||||
@bp.route('/')
|
||||
def index():
|
||||
"""
|
||||
The page you'd get if you access the root of
|
||||
this app in a browser.
|
||||
"""
|
||||
return ("Welcome to System Installer Daemon POC <br />"
|
||||
"Version: Unavailable")
|
||||
|
||||
|
||||
@bp.route('/main/help',methods=['GET'])
|
||||
def main_welcome():
|
||||
"""
|
||||
Manages the main help system.
|
||||
"""
|
||||
return render_template('help.html')
|
||||
|
||||
|
||||
@bp.route('/main/quit',methods=['GET'])
|
||||
def main_quit():
|
||||
"""
|
||||
Manages the quit dialog.
|
||||
"""
|
||||
return render_template('quit.html')
|
||||
|
||||
|
||||
@bp.route('/main/menu',methods=['GET'])
|
||||
def main_menu():
|
||||
"""
|
||||
Manages the main menu.
|
||||
"""
|
||||
return render_template('menu.html')
|
||||
|
||||
|
||||
def build_stringlist():
|
||||
"""
|
||||
Return all the strings that is used in this applet.
|
||||
"""
|
||||
string_dict = {}
|
||||
string_dict['next_text'] = _("Next")
|
||||
string_dict['previous_text'] = _("Previous")
|
||||
return string_dict
|
||||
|
||||
1
src/yasi_applets/main/static/fork-awesome.css
Symbolic link
@@ -0,0 +1 @@
|
||||
/usr/share/fonts-fork-awesome/css/fork-awesome.css
|
||||
BIN
src/yasi_applets/main/static/icons/highvoltage.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
src/yasi_applets/main/static/icons/keyboard.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 585 B After Width: | Height: | Size: 585 B |
BIN
src/yasi_applets/main/static/icons/yasi.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
@@ -10,6 +10,7 @@ body {
|
||||
overflow: hidden;
|
||||
min-width: 1050px;
|
||||
min-height: 600px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html, body {margin: 0; height: 100%; overflow: hidden;}
|
||||
@@ -23,19 +24,31 @@ html, body {margin: 0; height: 100%; overflow: hidden;}
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.applet a:link a:hover a:active {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.applet::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.applet {
|
||||
width: 100%;
|
||||
height: 442px;
|
||||
height: 512px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
overflow: -moz-scrollbars-none;
|
||||
}
|
||||
|
||||
.radio:hover {
|
||||
color: #f1f1f1;
|
||||
}
|
||||
|
||||
.pywebview-drag-region {
|
||||
width: 100%;
|
||||
height: 85px;
|
||||
}
|
||||
9
src/yasi_applets/software/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('software', __name__,
|
||||
template_folder='',
|
||||
static_folder='static',
|
||||
static_url_path='/software/static')
|
||||
|
||||
from yasi_applets.software import routes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from applets.software import bp
|
||||
from yasi_applets.software import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
url_for, render_template, flash, Blueprint
|
||||
from flask import current_app
|
||||
@@ -18,6 +18,8 @@ def webui_software():
|
||||
sources_button = ' <button class="button iis-info"> <i class="fa fa-cloud-download" aria-hidden="true"></i> Edit Sources </button>'
|
||||
blends_button = ' <button class="button iis-info"> <i class="fa fa-download" aria-hidden="true"></i> Install a Blend </button>'
|
||||
bottom_menu = sources_button + blends_button
|
||||
# Leave out useless buttons until they do more
|
||||
bottom_menu = ''
|
||||
build_summary()
|
||||
|
||||
return render_template('software.html',
|
||||
@@ -26,7 +28,8 @@ def webui_software():
|
||||
previous_step = previous_step_url,
|
||||
next_step = next_step_url,
|
||||
bottom_menu = bottom_menu,
|
||||
popcon=current_app.config['CONFIG']['recipe']['popcon']['enable_popcon'])
|
||||
popcon=current_app.config['CONFIG']['recipe']['popcon']['enable_popcon'],
|
||||
desktop=current_app.config['CONFIG']['recipe']['install_desktop_environment']['packages'])
|
||||
|
||||
|
||||
@bp.route('/software/settings', methods=['GET', 'POST'])
|
||||
@@ -42,6 +45,19 @@ def software_settings():
|
||||
return ('', 204)
|
||||
|
||||
|
||||
@bp.route('/software/select-desktop', methods=['GET', 'POST'])
|
||||
def software_select_desktop():
|
||||
"""
|
||||
Select a desktop environment for installation
|
||||
"""
|
||||
if request.method == 'POST':
|
||||
desktop = request.form['software-desktop']
|
||||
print(desktop)
|
||||
current_app.config['CONFIG']['recipe']['install_desktop_environment']['packages'] = desktop
|
||||
build_summary()
|
||||
return ('', 204)
|
||||
|
||||
|
||||
def build_menu():
|
||||
"""
|
||||
Define menu items and paths.
|
||||
@@ -58,7 +74,7 @@ def build_summary():
|
||||
current_app.config['CONFIG']['Summary']['software'] = {}
|
||||
current_app.config['CONFIG']['Summary']['software']['heading'] = "Software"
|
||||
current_app.config['CONFIG']['Summary']['software']['bleh'] = current_app.config['CONFIG']['recipe']['popcon']['enable_popcon']
|
||||
current_app.config['CONFIG']['Summary']['software']['text'] = "Participate in Popularity Contest: " + str(current_app.config['CONFIG']['recipe']['popcon']['enable_popcon']) + "<br/>No desktop environment selected."
|
||||
current_app.config['CONFIG']['Summary']['software']['text'] = "Participate in Popularity Contest: " + str(current_app.config['CONFIG']['recipe']['popcon']['enable_popcon']) + "<br/>Desktop environment selected: " + str(current_app.config['CONFIG']['recipe']['install_desktop_environment']['packages'])
|
||||
return("ok?")
|
||||
|
||||
|
||||
@@ -4,26 +4,45 @@
|
||||
<p> <b> Would you like fries with that? </b></p>
|
||||
|
||||
<br>
|
||||
|
||||
<div style="background-color: gray; padding: 4px 6px 7px 6px;
|
||||
border-radius: 10px; margin-bottom: 20px;">
|
||||
|
||||
<span style="width: 100%; border-radius: 8px 8px 0 0;"
|
||||
class="tag is-black">
|
||||
Popularity Contest
|
||||
</span>
|
||||
|
||||
<div style="padding-left: 15px; padding-right: 15px; background-color: #fff;
|
||||
color: #000;">
|
||||
|
||||
<big> Popularity Contest </big>
|
||||
<br><br>
|
||||
<p>The Popularity Contest (popcon) is a programme where anonymous data is sent back to Debian, tracking the number of packages installed. More information can be obtained at https://popcon.debian.org.</p> <br>
|
||||
|
||||
<input style="background-color: #777777;" type="checkbox" id="popcon"
|
||||
name="popcon" hx-post="/software/settings" hx-trigger="change"
|
||||
{% if popcon %} checked {% endif %}>
|
||||
<label for="popcon"> Participate in PopCon </label><br>
|
||||
|
||||
<br>
|
||||
<big><h3> Desktop Environment </h3></big>
|
||||
<br>
|
||||
<p>Would you like to install a graphical environment for this system?</p>
|
||||
|
||||
<br>
|
||||
|
||||
<form>
|
||||
<div class="control is-link">
|
||||
<div class="select">
|
||||
<select hx-post="/software/select-desktop" hx-target="body" name="software-desktop" style="width: 220px">
|
||||
<option value="" {% if desktop == "None" %} selected=selected {% endif %}> None</option>
|
||||
<option value="task-gnome-desktop" {% if desktop == "task-gnome-desktop" %} selected=selected {% endif %} >GNOME</option>
|
||||
<option value="task-kde-desktop" {% if desktop == "task-kde-desktop" %} selected=selected {% endif %}>KDE Plasma</option>
|
||||
<option value="task-xfce-desktop" {% if desktop == "task-xfce-desktop" %} selected=selected {% endif %}>Xfce</option>
|
||||
<option value="task-lxde-desktop" {% if desktop == "task-lxde-desktop" %} selected=selected {% endif %}>LXDE</option>
|
||||
<option value="task-lxqt-desktop" {% if desktop == "task-lxqt-desktop" %} selected=selected {% endif %}>LXQt</option>
|
||||
<option value="task-mate-desktop" {% if desktop == "task-mate-desktop" %} selected=selected {% endif %}>MATE</option>
|
||||
<option value="lomiri" {% if desktop == "lomiri" %} selected=selected {% endif %}>Lomiri</option>
|
||||
<option value="task-cinnamon-desktop" {% if desktop == "task-cinnamon-desktop" %} selected=selected {% endif %}>Cinnamon</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
<div style="background-color: gray; padding: 4px 6px 7px 6px; border-radius: 10px;">
|
||||
<p> <span style="width: 100%; border-radius: 8px 8px 0 0;" class="tag is-black">
|
||||
@@ -56,5 +75,6 @@ Select software from Debian archives</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
{% endblock %}
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
@@ -3,5 +3,5 @@ from flask import Blueprint
|
||||
bp = Blueprint('summary', __name__,
|
||||
template_folder='')
|
||||
|
||||
from applets.summary import routes
|
||||
from yasi_applets.summary import routes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from applets.summary import bp
|
||||
from yasi_applets.summary import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
url_for, render_template, flash, Blueprint
|
||||
from flask import current_app
|
||||
@@ -19,6 +19,9 @@ def summary_index():
|
||||
html = (str(current_app.config['CONFIG']['Summary']['welcome']) + "<br>" + str(current_app.config['CONFIG']['Summary']['software']))
|
||||
summary = config['Summary']
|
||||
|
||||
print("Config is: ")
|
||||
print(config)
|
||||
|
||||
return render_template('summary.html',
|
||||
menu=current_app.config['CONFIG']['settings']['menu'],
|
||||
menu_order=current_app.config['CONFIG']['settings']['menu_order'].split(),
|
||||
10
src/yasi_applets/users/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('users', __name__,
|
||||
template_folder='',
|
||||
static_folder='static',
|
||||
static_url_path='/users/static')
|
||||
|
||||
|
||||
from yasi_applets.users import routes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from applets.software import bp
|
||||
from yasi_applets.software import bp
|
||||
from flask import Flask, request, session, redirect, \
|
||||
url_for, render_template, flash, Blueprint
|
||||
import gettext
|
||||
@@ -10,7 +10,7 @@ def set_language(LANG):
|
||||
"""
|
||||
Sets language for this applet
|
||||
"""
|
||||
translations = gettext.translation("users", './applets/users/locales',
|
||||
translations = gettext.translation("users", '/usr/share/yasi-daemon/yasi_applets/users/locales',
|
||||
fallback=True, languages=[LANG])
|
||||
translations.install()
|
||||
_ = translations.gettext
|
||||
@@ -33,11 +33,12 @@ def users_root():
|
||||
else:
|
||||
previous_step_url = menu[menu.index("users")-1]
|
||||
|
||||
root_button = ' <button class="button is-light"> <i class="fa fa-user" aria-hidden="true"></i> Setup root user </button>'
|
||||
root_button = ' <button class="button not-allowed is-light"> <i class="fa fa-user" aria-hidden="true"></i> Setup root user </button>'
|
||||
ldap_button = ' <button class="button is-light"> <i class="fa fa-address-card" aria-hidden="true"></i> Connect LDAP </button>'
|
||||
ad_button = ' <button class="button is-light"> <i class="fa fa-address-card" aria-hidden="true"></i> Connect AD </button>'
|
||||
csv_button = ' <button class="button is-light"> <i class="fa fa-users" aria-hidden="true"></i> Import CSV </button>'
|
||||
bottom_menu = root_button + ldap_button + ad_button + csv_button
|
||||
bottom_menu = ""
|
||||
|
||||
initial_user = current_app.config['CONFIG']['recipe']['users']['users'][0]
|
||||
|
||||
@@ -55,28 +56,32 @@ def users_root():
|
||||
@bp.route('/users/user-check/', methods=['GET', 'POST', 'PUT'])
|
||||
def check_user():
|
||||
if request.method == 'POST':
|
||||
print("Ok, so method is POST")
|
||||
print("keys are: ", request.form.keys())
|
||||
username = request.form["username"]
|
||||
fullname = request.form["fullname"]
|
||||
password = request.form["password"]
|
||||
password_confirm = request.form["password_confirm"]
|
||||
print(current_app.config['CONFIG']['recipe']['users']['users'][0])
|
||||
print("fullname is: " + fullname)
|
||||
print("password is: " + password)
|
||||
print("password_confirm is: " + password_confirm)
|
||||
current_app.config['CONFIG']['recipe']['users']['users'][0]['username'] = username
|
||||
current_app.config['CONFIG']['recipe']['users']['users'][0]['fullname'] = fullname
|
||||
current_app.config['CONFIG']['recipe']['users']['users'][0]['password'] = password
|
||||
current_app.config['CONFIG']['recipe']['users']['users'][0]['password_confirm'] = password_confirm
|
||||
if username in ["root", "games"]:
|
||||
return('<p class="has-text-danger"><b>That username is not available</b> </p>')
|
||||
else:
|
||||
return('<p class="has-text-success"><b>That username is available</b> </p>')
|
||||
build_summary()
|
||||
return("bleh")
|
||||
return("")
|
||||
|
||||
|
||||
@bp.route('/users/password-check/', methods=['GET', 'POST', 'PUT'])
|
||||
def check_password():
|
||||
if request.method == 'POST':
|
||||
password = request.form["password"]
|
||||
password_confirm = request.form["password_confirm"]
|
||||
current_app.config['CONFIG']['recipe']['users']['users'][0]['password'] = password
|
||||
current_app.config['CONFIG']['recipe']['users']['users'][0]['password_confirm'] = password_confirm
|
||||
if password != password_confirm:
|
||||
return('<p class="has-text-danger"><b>Passwords do not match</b> </p>')
|
||||
else:
|
||||
return('<p class="has-text-success"><b>Passwords match</b> </p>')
|
||||
build_summary()
|
||||
return("")
|
||||
|
||||
|
||||
def build_stringlist():
|
||||
"""
|
||||
@@ -96,6 +101,8 @@ def build_stringlist():
|
||||
string_dict['password_confirm'] = _("Password (confirm)")
|
||||
string_dict['password_nomatch'] = _("These passwords do now match")
|
||||
string_dict['password_tooshort'] = _("This password is too short")
|
||||
string_dict['next_text'] = _("Next")
|
||||
string_dict['back_text'] = _("Back")
|
||||
return string_dict
|
||||
|
||||
|
||||
@@ -104,7 +111,6 @@ def build_menu():
|
||||
Define menu items and paths.
|
||||
"""
|
||||
current_app.config['CONFIG']['settings']['menu']['users'] = (build_stringlist()['menu_item'], "/users", 20)
|
||||
print(current_app.config['CONFIG']['settings']['menu'])
|
||||
|
||||
|
||||
def build_summary():
|
||||
@@ -113,7 +119,6 @@ def build_summary():
|
||||
"""
|
||||
current_app.config['CONFIG']['Summary']['users'] = {}
|
||||
current_app.config['CONFIG']['Summary']['users']['heading'] = "Users and Identity"
|
||||
current_app.config['CONFIG']['Summary']['users']['bleh'] = current_app.config['CONFIG']['recipe']['popcon']['enable_popcon']
|
||||
current_app.config['CONFIG']['Summary']['users']['settings'] = current_app.config['CONFIG']['recipe']['users']['users']
|
||||
current_app.config['CONFIG']['Summary']['users']['text'] = "Add primary user with the username: " + str(current_app.config['CONFIG']['recipe']['users']['users'][0]['username'])
|
||||
return("ok?")
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
@@ -7,7 +7,7 @@
|
||||
|
||||
<form action="/users" method="POST">
|
||||
|
||||
<img src="/static/icons/avatar-default.svg" width="160px" style="float: left; position: absolute;" />
|
||||
<img src="/users/static/img/avatar-default.svg" width="160px" style="float: left; position: absolute;" />
|
||||
|
||||
<div style="margin-left: 180px;">
|
||||
|
||||
@@ -18,16 +18,22 @@
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-user-circle-o" aria-hidden="true"></i>
|
||||
</span>
|
||||
<!-- <span class="icon is-small is-right">
|
||||
<img src="/static/icons/emblem-default-symbolic.svg">
|
||||
</span> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>{{ string_dict['user_name'] }}</label>
|
||||
<div class="control has-icons-left has-icons-right">
|
||||
<input class="input is-success" type="text" placeholder="{{ string_dict['user_name'] }}" value="{% if initial_user['username'] %}{{ initial_user['username'] }}{% endif %}" name="username" hx-post="/users/user-check" hx-trigger="keyup changed delay:200ms" hx-trigger="load" hx-target="#username-status">
|
||||
<input class="input" type="text" placeholder="{{ string_dict['user_name'] }}" value="{% if initial_user['username'] %}{{ initial_user['username'] }}{% endif %}" name="username" hx-post="/users/user-check" hx-trigger="keyup changed delay:200ms" hx-trigger="load" hx-target="#username-status">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-user-circle-o" aria-hidden="true"></i>
|
||||
</span>
|
||||
<!-- <span class="icon is-small is-right">
|
||||
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
|
||||
</span> -->
|
||||
</div>
|
||||
<div id="username-status">
|
||||
<p> {{ string_dict['user_name_hint'] }}</p>
|
||||
@@ -37,7 +43,7 @@
|
||||
<div class="field">
|
||||
<label class="password">{{ string_dict['password'] }}</label>
|
||||
<div class="control has-icons-left has-icons-right">
|
||||
<input class="input" name="password" type="password" placeholder="{{ string_dict['password'] }}" value="{% if initial_user['password'] %}{{ initial_user['password'] }}{% endif %}" hx-post="/users/user-check" hx-trigger="keyup changed delay:200ms" hx-target="#username-status">
|
||||
<input class="input" name="password" type="password" placeholder="{{ string_dict['password'] }}" value="{% if initial_user['password'] %}{{ initial_user['password'] }}{% endif %}" hx-post="/users/password-check" hx-trigger="keyup changed delay:200ms" hx-target="#password-status">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-address-card" aria-hidden="true"></i>
|
||||
</span>
|
||||
@@ -47,10 +53,13 @@
|
||||
<div class="field">
|
||||
<label class="password">{{ string_dict['password_confirm'] }}</label>
|
||||
<div class="control has-icons-left has-icons-right">
|
||||
<input class="input" name="password_confirm" type="password" placeholder="{{ string_dict['password_confirm'] }}" value="{% if initial_user['password_confirm'] %}{{ initial_user['password_confirm'] }}{% endif %}" hx-post="/users/user-check" hx-trigger="keyup changed delay:200ms" hx-target="#password-status">
|
||||
<input class="input" name="password_confirm" type="password" placeholder="{{ string_dict['password_confirm'] }}" value="{% if initial_user['password_confirm'] %}{{ initial_user['password_confirm'] }}{% endif %}" hx-post="/users/password-check" hx-trigger="keyup changed delay:200ms" hx-target="#password-status">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-address-card" aria-hidden="true"></i>
|
||||
</span>
|
||||
<div id="password-status">
|
||||
<p> </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
8
src/yasi_applets/welcome/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('welcome', __name__,
|
||||
template_folder='',
|
||||
static_folder='static',
|
||||
static_url_path='/welcome/static')
|
||||
|
||||
from yasi_applets.welcome import routes
|
||||
BIN
src/yasi_applets/welcome/locales/af/LC_MESSAGES/welcome.mo
Normal file
@@ -12,6 +12,33 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: UTF-8\n"
|
||||
|
||||
msgid "Welcome"
|
||||
msgstr "Welkom"
|
||||
|
||||
msgid "Users"
|
||||
msgstr "Gebruikers"
|
||||
|
||||
msgid "Disks"
|
||||
msgstr "Skywe"
|
||||
|
||||
msgid "Software"
|
||||
msgstr "Sagteware"
|
||||
|
||||
msgid "Summary"
|
||||
msgstr "Opsomming"
|
||||
|
||||
msgid "Power"
|
||||
msgstr "Krag"
|
||||
|
||||
msgid "Internet"
|
||||
msgstr "Internet"
|
||||
|
||||
msgid "Back"
|
||||
msgstr "Terug"
|
||||
|
||||
msgid "Next"
|
||||
msgstr "Volgende"
|
||||
|
||||
#: routes.py:27
|
||||
msgid "Welcome! This setup program will install Debian on to your system."
|
||||
msgstr "Welkom! Hierdie program sal jou deur die proses lei om Debian te installeer na jou sisteem."
|
||||