<!doctype html>
<html lang="fr">
<head>
  <meta charset="utf-8">
  <title>cosma-qc — dashboard</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="/static/htmx.min.js"></script>
  <link rel="stylesheet" href="/static/style.css">
</head>
<body>
<header>
  <h1>cosma-qc</h1>
  <span class="sub">post-acquisition QC · lingbot-map pipeline</span>
  <a class="docs-link" href="/docs/" target="_blank">📖 docs</a>
</header>

<section id="monitor" hx-get="/partials/monitor" hx-trigger="load, every 5s" hx-swap="innerHTML">
  <p class="muted">Chargement des workers…</p>
</section>

<section id="pipeline">
  <h2>Pipeline reconstruction</h2>
  <div hx-get="/partials/pipeline" hx-trigger="load, every 5s" hx-swap="innerHTML">
    <p class="muted">Chargement pipeline...</p>
  </div>
</section>

<section id="jobs">
  <h2>Jobs</h2>
  <div id="jobs-table" hx-get="/partials/jobs" hx-trigger="load, every 3s" hx-swap="innerHTML">
    <p class="muted">Chargement…</p>
  </div>
</section>

<section id="evolutions">
  <h2>Évolutions récentes</h2>
  <table class="evol-table">
    <thead>
      <tr>
        <th>Repo</th>
        <th>Branche</th>
        <th>Ce qui a changé</th>
        <th>Liens</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><b>cosma-qc</b></td>
        <td>main</td>
        <td>Dispatcher z620 → worker GPU (SCP glob fix) · --save_poses lingbot · migration .83 · dashboard</td>
        <td><a href="http://192.168.0.82:3000/floppyrj45/cosma-qc" target="_blank">Gitea</a></td>
      </tr>
      <tr>
        <td><b>lingbot-map</b></td>
        <td>main</td>
        <td>demo.py : <code>--save_ply</code> · <code>--save_poses</code> · <code>--save_poses_fps</code> → génère lingbot_poses.npz</td>
        <td><a href="http://192.168.0.82:3000/floppyrj45/lingbot-map" target="_blank">Gitea</a></td>
      </tr>
      <tr>
        <td><b>cosma-nav</b></td>
        <td>master</td>
        <td>Pipeline complet : extract_mcap · parse_usv_gps · fuse_trajectory (Umeyama) · viewer Three.js :5051</td>
        <td><a href="http://192.168.0.82:3000/floppyrj45/cosma-nav" target="_blank">Gitea</a></td>
      </tr>
    </tbody>
  </table>

  <div class="pipeline-box">
    <h3>Pipeline complet (once logs La Ciotat dispo)</h3>
    <ol>
      <li><code>extract_mcap.py logs/SUB/bags/ data/sparse_fixes.h5</code></li>
      <li><code>parse_usv_gps.py logs/SHIP/ data/sparse_fixes.h5</code></li>
      <li><code>demo.py ... --save_poses data/lingbot_poses.npz --save_ply data/scene.ply</code></li>
      <li><code>fuse_trajectory.py data/sparse_fixes.h5 data/lingbot_poses.npz data/trajectory_world.h5</code></li>
      <li><code>viz/server.py --trajectory data/trajectory_world.h5 --fixes data/sparse_fixes.h5</code></li>
    </ol>
  </div>
</section>

<script>
document.addEventListener('click', async (e) => {
  const btn = e.target.closest('.viewer-btn');
  if (!btn) return;
  e.preventDefault();
  const liveUrl = btn.dataset.liveUrl;
  const viewUrl = btn.dataset.viewUrl;
  btn.textContent = '…';
  btn.disabled = true;
  let url = null;
  if (liveUrl) {
    try {
      const res = await fetch(liveUrl, { method: 'POST' });
      if (res.ok) { const d = await res.json(); url = d.url; }
    } catch {}
  }
  if (!url && viewUrl) {
    try {
      const res = await fetch(viewUrl, { method: 'POST' });
      if (res.ok) { const d = await res.json(); url = d.url; }
      else { const d = await res.json(); alert(d.detail || 'Erreur lancement viewer'); }
    } catch (err) { alert('Erreur réseau: ' + err); }
  }
  if (url) window.open(url, '_blank');
  btn.textContent = 'viser ↗';
  btn.disabled = false;
});

document.addEventListener('click', async (e) => {
  const btn = e.target.closest('.btn-viser-auv');
  if (!btn) return;
  e.preventDefault();
  const url = btn.dataset.url;
  if (!url) return;
  const original = btn.textContent;
  btn.textContent = 'launch…';
  btn.disabled = true;
  try {
    const res = await fetch(url, { method: 'POST' });
    const d = await res.json().catch(() => ({}));
    if (res.ok && d.url) {
      window.open(d.url, '_blank');
    } else {
      alert(d.error || d.detail || ('HTTP ' + res.status));
    }
  } catch (err) {
    alert('Erreur réseau: ' + err);
  } finally {
    btn.textContent = original;
    btn.disabled = false;
  }
});
</script>
</body>
</html>
