Desktop: first-run setup wizard + FlyWithLua/Web-API/Lua-status guidance
Adds the four onboarding pieces that were missing:
- flywithlua_present Tauri command + wizard step that checks the plugin and
links the FlyWithLua NG+ download when it's absent.
- Wizard step explaining how to enable X-Plane's Web/REST API (Settings>Network).
- FlyWithLua-Sync status row in the live diagnostics, from /api/health.lua
('N Skripte aktiv' / 'FlyWithLua fehlt' / 'kein X-Plane').
- 4-step guided wizard (X-Plane folder → FlyWithLua → Web-API → install+start)
that auto-opens on first launch and is reachable via the header Einrichten
button; the final step hands off to the normal server start (auto-installs Lua).
Verified the wizard DOM flow + the dLua status against a live bridge.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+74
-1
@@ -107,9 +107,19 @@ function resetUi() {
|
||||
if (healthTimer) { clearInterval(healthTimer); healthTimer = null; }
|
||||
}
|
||||
|
||||
// Human-readable FlyWithLua-install status from /api/health.lua.
|
||||
function luaText(lua) {
|
||||
if (!lua) return { t: '—', cls: '' };
|
||||
if (lua.reason === 'no-xplane') return { t: 'kein X-Plane', cls: 'warn' };
|
||||
if (lua.reason === 'no-flywithlua') return { t: 'FlyWithLua fehlt', cls: 'bad' };
|
||||
if (lua.reason === 'no-source') return { t: 'Skripte fehlen', cls: 'bad' };
|
||||
const n = (lua.installed?.length || 0) + (lua.updated?.length || 0) + (lua.unchanged?.length || 0);
|
||||
return { t: `${n} Skripte aktiv`, cls: 'ok' };
|
||||
}
|
||||
|
||||
function pollHealth(port) {
|
||||
if (healthTimer) clearInterval(healthTimer);
|
||||
const dXp = $('dXp'), dClients = $('dClients'), dNav = $('dNav'), dRefs = $('dRefs');
|
||||
const dXp = $('dXp'), dClients = $('dClients'), dNav = $('dNav'), dRefs = $('dRefs'), dLua = $('dLua');
|
||||
const check = async () => {
|
||||
try {
|
||||
const r = await fetch(`http://127.0.0.1:${port}/api/health`, { cache: 'no-store' });
|
||||
@@ -123,6 +133,7 @@ function pollHealth(port) {
|
||||
const n = d.nav || {};
|
||||
dNav.textContent = n.loaded ? `${n.airports ?? 0} APT · ${n.navaids ?? 0} Navaids` : 'lädt…';
|
||||
dRefs.textContent = d.datarefs ?? 0;
|
||||
if (dLua) { const l = luaText(d.lua); dLua.textContent = l.t; dLua.className = l.cls; }
|
||||
} catch { setStatus('warn', 'Server läuft'); }
|
||||
};
|
||||
check();
|
||||
@@ -242,4 +253,66 @@ $('updateBtn').addEventListener('click', () => checkUpdate(false));
|
||||
$('ubInstall').addEventListener('click', installUpdate);
|
||||
$('ubDismiss').addEventListener('click', () => $('updateBanner').classList.add('hidden'));
|
||||
|
||||
/* ---------------- first-run setup wizard ---------------- */
|
||||
const FWL_URL = 'https://github.com/X-Friese/FlyWithLua/releases';
|
||||
let wizStep = 1;
|
||||
const wiz = $('wizard');
|
||||
|
||||
function showStep(n) {
|
||||
wizStep = Math.max(1, Math.min(4, n));
|
||||
document.querySelectorAll('.wiz-step').forEach((s) => s.classList.toggle('hidden', +s.dataset.step !== wizStep));
|
||||
document.querySelectorAll('.wiz-steps span').forEach((s) => s.classList.toggle('on', +s.dataset.s <= wizStep));
|
||||
$('wizBack').disabled = wizStep === 1;
|
||||
$('wizNext').textContent = wizStep === 4 ? (demoEl.checked || $('wizDemo').checked ? 'Demo starten' : 'Lua installieren & starten') : 'Weiter';
|
||||
if (wizStep === 2) checkFwl();
|
||||
}
|
||||
function openWizard() {
|
||||
wiz.classList.remove('hidden');
|
||||
$('wizPath').value = xpPath.value || '';
|
||||
$('wizDemo').checked = demoEl.checked;
|
||||
validateWizPath();
|
||||
showStep(1);
|
||||
}
|
||||
function closeWizard() { wiz.classList.add('hidden'); localStorage.setItem('setupDone', '1'); }
|
||||
|
||||
async function validateWizPath() {
|
||||
const p = $('wizPath').value.trim();
|
||||
const h = $('wizPathHint');
|
||||
if (!p) { h.textContent = 'Leer = Demo-Modus möglich.'; h.className = 'hint'; return; }
|
||||
const ok = await invoke('valid_xplane_path', { path: p });
|
||||
h.textContent = ok ? '✓ X-Plane erkannt' : '⚠ kein „Resources/default data" — Pfad prüfen';
|
||||
h.className = 'hint ' + (ok ? 'ok' : 'bad');
|
||||
}
|
||||
async function checkFwl() {
|
||||
const el = $('wizFwl'); const p = $('wizPath').value.trim();
|
||||
if (!p) { el.textContent = '— (kein X-Plane gewählt; im Demo-Modus nicht nötig)'; el.className = 'wiz-status'; return; }
|
||||
const present = await invoke('flywithlua_present', { path: p });
|
||||
el.textContent = present ? '✓ FlyWithLua ist installiert' : '✗ FlyWithLua nicht gefunden';
|
||||
el.className = 'wiz-status ' + (present ? 'ok' : 'bad');
|
||||
}
|
||||
|
||||
$('setupBtn').addEventListener('click', openWizard);
|
||||
$('wizClose').addEventListener('click', closeWizard);
|
||||
$('wizBrowse').addEventListener('click', async () => {
|
||||
try { const dir = await T.dialog.open({ directory: true, multiple: false, title: 'X-Plane 12 Ordner wählen' });
|
||||
if (dir) { $('wizPath').value = dir; validateWizPath(); } } catch (e) { appendLog('dialog: ' + e); }
|
||||
});
|
||||
$('wizPath').addEventListener('input', validateWizPath);
|
||||
$('wizFwlCheck').addEventListener('click', checkFwl);
|
||||
$('wizFwlLink').addEventListener('click', (e) => { e.preventDefault(); openUrl(FWL_URL); });
|
||||
$('wizDemo').addEventListener('change', () => { demoEl.checked = $('wizDemo').checked; showStep(wizStep); });
|
||||
$('wizBack').addEventListener('click', () => showStep(wizStep - 1));
|
||||
$('wizNext').addEventListener('click', async () => {
|
||||
if (wizStep < 4) { showStep(wizStep + 1); return; }
|
||||
// final step: carry the chosen path/demo to the main controls and start
|
||||
xpPath.value = $('wizPath').value.trim();
|
||||
demoEl.checked = $('wizDemo').checked;
|
||||
await validatePath();
|
||||
$('wizResult').textContent = 'Starte Server …'; $('wizResult').className = 'wiz-status';
|
||||
closeWizard();
|
||||
if (!running) startBtn.click();
|
||||
});
|
||||
|
||||
init();
|
||||
// Offer the wizard automatically on the very first launch.
|
||||
if (!localStorage.getItem('setupDone')) setTimeout(openWizard, 400);
|
||||
|
||||
Reference in New Issue
Block a user