d01228a21e
- gui/main.py: FastAPI app with Jinja2 templates and static files - gui/state.py: shared application state (runner, template env) - gui/services/pos_runner.py: abstracted command execution layer with subprocess, SSE streaming, and sudo support - gui/routes/: 8 route modules (dashboard, install, compose, network, vbox, system, media, ssh) - gui/templates/: Bulma-based layout with sidebar navigation + section templates for all routes - gui/static/css/style.css: dark theme styling - gui/requirements.txt: fastapi, uvicorn, jinja2, python-multipart - 1- Start_GUI.sh: entry point with sudo cache, pip install, uvicorn launch Architecture: routes delegate to pos_runner which shells out to actual pos-* scripts — no logic duplication. SSE streaming for real-time output (install, compose up/down/logs, network scan, media).
59 lines
2.7 KiB
HTML
59 lines
2.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
<section class="section">
|
|
<h1 class="title">Installation</h1>
|
|
<div class="box">
|
|
<h2 class="subtitle">Select Phases</h2>
|
|
<div class="field">
|
|
<label class="checkbox"><input type="checkbox" class="phase-checkbox" value="1" checked> Phase 1: System Packages</label>
|
|
</div>
|
|
<div class="field">
|
|
<label class="checkbox"><input type="checkbox" class="phase-checkbox" value="2" checked> Phase 2: Install Scripts</label>
|
|
</div>
|
|
<div class="field">
|
|
<label class="checkbox"><input type="checkbox" class="phase-checkbox" value="3" checked> Phase 3: Post-install Config</label>
|
|
</div>
|
|
<div class="field">
|
|
<label class="checkbox"><input type="checkbox" class="phase-checkbox" value="4" checked> Phase 4: ScaleTail Templates</label>
|
|
</div>
|
|
</div>
|
|
{% if app_categories %}
|
|
<div class="box">
|
|
<h2 class="subtitle">Optional Apps</h2>
|
|
{% for category, apps in app_categories.items() %}
|
|
<div class="mb-3">
|
|
<h3 class="has-text-weight-bold">{{ category | capitalize }}</h3>
|
|
{% for app in apps %}
|
|
<div class="field">
|
|
<label class="checkbox"><input type="checkbox" class="app-checkbox" value="{{ category }}/{{ app }}"> {{ app }}</label>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
<button class="button is-primary" onclick="startInstall()">Start Installation</button>
|
|
<div id="output" class="mt-4" style="display:none;">
|
|
<pre id="log" class="log-box"></pre>
|
|
</div>
|
|
</section>
|
|
<script>
|
|
function startInstall() {
|
|
const phases = Array.from(document.querySelectorAll('.phase-checkbox:checked')).map(c => c.value);
|
|
const apps = Array.from(document.querySelectorAll('.app-checkbox:checked')).map(c => c.value);
|
|
if (phases.length === 0 && apps.length === 0) return;
|
|
const el = document.getElementById('output');
|
|
const log = document.getElementById('log');
|
|
el.style.display = 'block';
|
|
log.textContent = '';
|
|
const evt = new EventSource(`/install/stream?phases=${phases.join(',')}&apps=${apps.join(',')}`);
|
|
evt.addEventListener('phase_start', e => { log.textContent += '\n=== ' + e.data + ' ===\n'; });
|
|
evt.addEventListener('stdout', e => { log.textContent += e.data + '\n'; });
|
|
evt.addEventListener('stderr', e => { log.textContent += e.data + '\n'; });
|
|
evt.addEventListener('exit', e => { log.textContent += '\nDone (exit: ' + e.data + ')\n'; evt.close(); });
|
|
evt.addEventListener('error', e => { log.textContent += '\nERROR: ' + e.data + '\n'; });
|
|
log.scrollTop = log.scrollHeight;
|
|
}
|
|
</script>
|
|
{% endblock %}
|