Compare commits

...

15 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
106 changed files with 606 additions and 528 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,7 +0,0 @@
from flask import Blueprint
bp = Blueprint('main', __name__,
template_folder='')
from applets.main import routes

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,114 +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
import dmm.timezone as timezone
# 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(),
timezones=timezone.list_timezones()[1].split("\n"),
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,55 +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="float: left; padding-left: 100px;">
<button class="button is-dark" style="height: 180px;">
<img src="/static/icons/language.jpg" width="96px" alt="{{ 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>
</button>
</div>
-->
<button class="button is-dark" style="float: left; margin-left: 100px; background-color: #242424; padding: 25px;">
<img src="/static/icons/language.jpg" width="96px" alt="{{ string_dict['language_text'] }}" />
<br> {{ string_dict['language_text'] }} {{ selected_lang }}
</button>
<!--
<div style="float: left; position: relative; top: -10px; padding-left: 100px;"
<button class="button is-dark">
<img src="/static/icons/keyboard.png" width="90px" />
<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-za</option>
</select>
</div>
</div>
</button>
</div>
-->
<div style="float: left; margin-left: 100px; background-color: #242424; padding: 25px;">
<img src="/static/icons/keyboard,png" width="96px" /><br>
Keyboard
</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,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,10 +10,10 @@ import logging
import dmm.lsblk as lsblk
import importlib
import yaml
import sys
# configuration
#CONFIGFILE="templates/dmm-installer-template.yaml"
CONFIGFILE="templates/dmm-installer-vm-template.yaml"
CONFIGFILE="/etc/yasi/yasi.yaml"
# import config
global config
@@ -28,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!")
@@ -38,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
@@ -53,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

@@ -3,5 +3,5 @@ from flask import Blueprint
bp = Blueprint('hardware', __name__,
template_folder='')
from applets.hardware import routes
from yasi_applets.hardware import routes

View File

@@ -1,4 +1,4 @@
from applets.hardware import bp
from yasi_applets.hardware import bp
from flask import Flask, request, session, redirect, \
url_for, render_template, flash, Blueprint
from flask import current_app

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

@@ -10,7 +10,7 @@
<br />
<img style="width: 400px; padding: 20px;" src="/static/slide1.png" /> <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>

View File

@@ -1,4 +1,4 @@
from applets.install import bp
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

View File

Before

Width:  |  Height:  |  Size: 38 KiB

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

@@ -4,7 +4,15 @@
<!-- drag region class: -->
<div id="titlebar" class="pywebview-drag-region" style="padding: 15px; margin: -15px; padding-bottom: 30px;">
<a hx-get="/main/menu" hx-swap="outerHTML"/> <button class="button is-link"></button </a>
<!--
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>
@@ -12,7 +20,7 @@
<div style="position: absolute; top: 15px; right: 15px;">
<a hx-get="/main/help" hx-swap="outerHTML"/> <button class="button is-light"> <b> ? </b> </button></a>
<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>

View File

@@ -4,12 +4,18 @@
<div style="background-color: #424242; padding: 15px; border-radius: 15px; boders: none; color: white;">
<h1 class="is-size-4"> Help </h1>
<br/><p class="title is-6"><span class="tag is-danger">The help system is not yet implemented.</span>
<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>

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

@@ -1,10 +1,21 @@
from applets.welcome import bp
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
import dmm.lsblk as lsblk
# 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():
@@ -16,16 +27,7 @@ def index():
"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")
@bp.route('/main/help',methods=['GET', 'POST', 'PUT'])
@bp.route('/main/help',methods=['GET'])
def main_welcome():
"""
Manages the main help system.
@@ -33,7 +35,7 @@ def main_welcome():
return render_template('help.html')
@bp.route('/main/quit',methods=['GET', 'POST', 'PUT'])
@bp.route('/main/quit',methods=['GET'])
def main_quit():
"""
Manages the quit dialog.
@@ -41,9 +43,20 @@ def main_quit():
return render_template('quit.html')
@bp.route('/main/menu',methods=['GET', 'POST', 'PUT'])
@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
@@ -38,6 +38,7 @@ def users_root():
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