Compare commits

...

20 Commits

Author SHA1 Message Date
Jonathan Carter
ed2ddb0a77 list debian deps 2025-12-10 21:18:21 +02:00
Jonathan Carter
31bb032a4e Set text_select to false for new pywbview' 2025-10-25 21:52:17 +02:00
Jonathan Carter
22dcf36b14 cleanup mainapplet a bit 2025-08-31 18:31:51 +02:00
Jonathan Carter
088bf495f5 Bunch of ui stuff 2025-08-31 14:53:40 +02:00
Jonathan Carter
c0aa82241b Fix static scrolling 2025-08-28 12:26:13 +02:00
Jonathan Carter
9544463bd6 Minor changes 2025-08-26 16:07:34 +02:00
Jonathan Carter
60cd5140d2 Add systemd unit 2025-08-26 15:58:42 +02:00
Jonathan Carter
dcbc8dd062 Try to make header moving work 2025-08-26 15:58:32 +02:00
Jonathan Carter
08f232bf51 Rename to yasi, add icon 2025-08-26 15:22:26 +02:00
Jonathan Carter
75d068fef6 Exclude cd and loop devs 2025-08-25 20:58:26 +02:00
Jonathan Carter
373ce1247e More cleanup 2025-08-23 23:59:50 +02:00
Jonathan Carter
eaa983e955 Fix extension 2025-08-23 22:59:18 +02:00
Jonathan Carter
652bbba9c0 re-add yasi-applets 2025-08-23 22:33:58 +02:00
Jonathan Carter
69d6ba277d Move a whole bunch of stuff around 2025-08-23 22:33:41 +02:00
Jonathan Carter
8791c58cbf Various ui work 2025-08-23 16:03:38 +02:00
Jonathan Carter
258a359ce1 commit some failed experiments 2025-08-19 20:28:02 +02:00
Jonathan Carter
21b210a689 Some more UI work 2025-08-18 23:08:51 +02:00
Jonathan Carter
430b144d92 Add installer slide placeholder 2025-08-16 14:23:29 +02:00
Jonathan Carter
d4cfa4815c Add button menu placeholders 2025-08-16 14:22:34 +02:00
Jonathan Carter
9f8f89fde2 More UI work 2025-08-16 14:22:13 +02:00
111 changed files with 1016 additions and 624 deletions

View File

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

View File

@@ -1,7 +0,0 @@
from flask import Blueprint
bp = Blueprint('install', __name__,
template_folder='')
from applets.install import routes

View File

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

View File

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

View File

@@ -1,7 +0,0 @@
from flask import Blueprint
bp = Blueprint('main', __name__,
template_folder='')
from applets.main import routes

View File

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

View File

@@ -1,7 +0,0 @@
from flask import Blueprint
bp = Blueprint('software', __name__,
template_folder='')
from applets.software import routes

View File

@@ -1,7 +0,0 @@
from flask import Blueprint
bp = Blueprint('users', __name__,
template_folder='')
from applets.users import routes

View File

@@ -1,6 +0,0 @@
from flask import Blueprint
bp = Blueprint('webui', __name__)
from applets.webui import routes

View File

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

View File

@@ -1,6 +0,0 @@
from flask import Blueprint
bp = Blueprint('welcome', __name__,
template_folder='')
from applets.welcome import routes

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -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"> &nbsp; Power: AC </button>'
internet_button = '&nbsp; <button class="button is-dark"> <img width="16px;" src="/static/icons/greencheck.png"> &nbsp; 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

View File

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

View File

@@ -1 +0,0 @@
../../../applets/welcome/img

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

View 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

View File

@@ -9,8 +9,9 @@
<div class="radios">
<label class="radio">
<input type="radio" name="rsvp" />
Preconfigured partitioning &nbsp;
<input selected type="radio" name="rsvp" />
Preconfigured partitioning &nbsp;
<!-- 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>

View File

@@ -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 = '&nbsp; <button class="button iis-info"> <i class="fa fa-hdd-o" aria-hidden="true"></i> &nbsp; Add Disk or Filesystem </button>'
add_swap_button = '&nbsp; <button class="button iis-info"> <i class="fa fa-object-group" aria-hidden="true"></i> &nbsp; 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>')

View File

@@ -0,0 +1,7 @@
from flask import Blueprint
bp = Blueprint('hardware', __name__,
template_folder='')
from yasi_applets.hardware import routes

View 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 %}

View 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 = '&nbsp; <button class="button iis-info"> <i class="fa fa-cloud-download" aria-hidden="true"></i> &nbsp; Configure Network </button>'
blends_button = '&nbsp; <button class="button iis-info"> <i class="fa fa-download" aria-hidden="true"></i> &nbsp; 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()

View 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

View 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 %}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View 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

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

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

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

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

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

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

View 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

View File

@@ -0,0 +1 @@
/usr/share/fonts-fork-awesome/css/fork-awesome.css

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

Before

Width:  |  Height:  |  Size: 585 B

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

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

View 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

View File

@@ -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 = '&nbsp; <button class="button iis-info"> <i class="fa fa-cloud-download" aria-hidden="true"></i> &nbsp; Edit Sources </button>'
blends_button = '&nbsp; <button class="button iis-info"> <i class="fa fa-download" aria-hidden="true"></i> &nbsp; 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?")

View File

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

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

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

View File

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

View 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

View File

@@ -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 = '&nbsp; <button class="button is-light"> <i class="fa fa-user" aria-hidden="true"></i> &nbsp; Setup root user </button>'
root_button = '&nbsp; <button class="button not-allowed is-light"> <i class="fa fa-user" aria-hidden="true"></i> &nbsp; Setup root user </button>'
ldap_button = '&nbsp; <button class="button is-light"> <i class="fa fa-address-card" aria-hidden="true"></i> &nbsp; Connect LDAP </button>'
ad_button = '&nbsp; <button class="button is-light"> <i class="fa fa-address-card" aria-hidden="true"></i> &nbsp; Connect AD </button>'
csv_button = '&nbsp; <button class="button is-light"> <i class="fa fa-users" aria-hidden="true"></i> &nbsp; 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?")

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

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

View 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

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

Some files were not shown because too many files have changed in this diff Show More