Files
Linux_post_install/gui/templates/install/index.html
T
he d01228a21e feat(GUI): web interface for install and pos commands
- 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).
2026-07-28 11:47:48 -04:00

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