Files
PTT-Live/electron/ui/index.html
T
benoit 06cb6a7dd1 refactor: simplifier AudioBridge, filtrer bridge dans PWA, option aucune sortie
- AudioBridge: retire GroupAudioRouter, LiveKitClient, routing per-group
- AudioBridgeManager: génère tokens uniquement pour server_audio_users
- ServerAudioUser: outputChannel null = pas d'émission outputReady
- PWA useLiveKit: filtre les participants role=bridge de la liste
- Electron UI: page Routing sans matrices, noms canaux + server audio users
- config.yaml: nettoyé (pas de section routing)
2026-07-03 14:55:55 +02:00

267 lines
10 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PTT Live Server</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Toast Container -->
<div class="toast-container" id="toast-container"></div>
<div id="app">
<!-- Header -->
<header class="header">
<div class="header-left">
<h1>🎙️ PTT Live Server</h1>
<span class="version" id="version">v0.3.0</span>
</div>
<div class="header-right">
<div class="server-status">
<span class="status-indicator" id="status-indicator"></span>
<span id="status-text">Arrêté</span>
</div>
<button id="btn-start" class="btn btn-primary">Démarrer</button>
<button id="btn-stop" class="btn btn-secondary" disabled>Arrêter</button>
</div>
</header>
<!-- Main Content -->
<main class="main-content">
<!-- Sidebar Navigation -->
<nav class="sidebar">
<button class="nav-item active" data-view="dashboard">
📊 Dashboard
</button>
<button class="nav-item" data-view="config">
⚙️ Configuration
</button>
<button class="nav-item" data-view="groups">
👥 Groupes
</button>
<button class="nav-item" data-view="routing">
🔀 Routing
</button>
<button class="nav-item" data-view="monitoring">
📈 Monitoring
</button>
<button class="nav-item" data-view="logs">
📝 Logs
</button>
</nav>
<!-- Content Area -->
<div class="content">
<!-- Dashboard View -->
<div id="view-dashboard" class="view active">
<h2>Dashboard</h2>
<!-- Stats Cards -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">Uptime</div>
<div class="stat-value" id="stat-uptime">--</div>
</div>
<div class="stat-card">
<div class="stat-label">Utilisateurs</div>
<div class="stat-value" id="stat-users">--</div>
</div>
<div class="stat-card">
<div class="stat-label">Groupes actifs</div>
<div class="stat-value" id="stat-groups">--</div>
</div>
<div class="stat-card">
<div class="stat-label">Connexions totales</div>
<div class="stat-value" id="stat-total-connections">--</div>
</div>
</div>
<!-- QR Code Section -->
<div class="section">
<h3>📱 Connexion rapide clients</h3>
<div class="qr-container">
<div class="qr-wrapper">
<img id="qr-code" width="256" height="256" alt="QR Code connexion" />
<div class="qr-placeholder" id="qr-placeholder">
<span class="qr-placeholder-icon">📷</span>
<span>En attente du démarrage du serveur</span>
</div>
</div>
<div class="qr-info">
<p><strong>URL clients :</strong></p>
<p class="url-text" id="client-url">--</p>
<button class="btn btn-small" id="btn-copy-url">Copier l'URL</button>
</div>
</div>
</div>
<!-- Active Users -->
<div class="section">
<h3>👤 Utilisateurs connectés</h3>
<div id="users-list" class="users-list">
<p class="empty-state">Aucun utilisateur connecté</p>
</div>
</div>
</div>
<!-- Configuration View -->
<div id="view-config" class="view">
<h2>Configuration Audio</h2>
<div class="section">
<h3>🔌 Périphériques Audio</h3>
<div class="form-group">
<label>Device Input</label>
<select id="input-device" class="form-control">
<option>Chargement...</option>
</select>
</div>
<div class="form-group">
<label>Device Output</label>
<select id="output-device" class="form-control">
<option>Chargement...</option>
</select>
</div>
<button class="btn btn-primary" id="btn-save-device">Appliquer</button>
</div>
<div class="section">
<h3>💾 Sauvegarde de configuration</h3>
<div class="config-actions">
<button class="btn btn-secondary" id="btn-export-config">Exporter config.yaml</button>
<button class="btn btn-secondary" id="btn-import-config">Importer config.yaml</button>
</div>
<p class="config-note">L'import remplace config.yaml (backup automatique en .bak). Redémarrez le serveur pour appliquer.</p>
</div>
<div class="section">
<h3>🎚️ Paramètres Audio</h3>
<div class="form-group">
<label>Sample Rate</label>
<select id="sample-rate" class="form-control">
<option value="44100">44.1 kHz</option>
<option value="48000" selected>48 kHz</option>
<option value="96000">96 kHz</option>
</select>
</div>
<div class="form-group">
<label>Bitrate par défaut (kbps)</label>
<input type="number" id="default-bitrate" class="form-control" value="96" min="32" max="320" step="32">
</div>
<div class="form-group">
<label>Jitter Buffer (ms)</label>
<input type="number" id="jitter-buffer" class="form-control" value="40" min="20" max="100" step="10">
</div>
<button class="btn btn-primary" id="btn-save-audio">Sauvegarder</button>
</div>
</div>
<!-- Groups View -->
<div id="view-groups" class="view">
<h2>Gestion des Groupes</h2>
<button class="btn btn-primary" id="btn-add-group"> Nouveau groupe</button>
<div id="groups-list" class="groups-list">
<p class="empty-state">Chargement des groupes...</p>
</div>
</div>
<!-- Routing View -->
<div id="view-routing" class="view">
<h2>Routing Audio</h2>
<!-- Device info -->
<div class="section">
<div class="routing-device-banner">
<div class="routing-device-info" id="routing-device-info">Chargement...</div>
<button class="btn btn-small btn-secondary" id="btn-refresh-channels">🔄 Actualiser</button>
</div>
</div>
<!-- Labels canaux physiques -->
<div class="section">
<h3>🏷️ Canaux Physiques</h3>
<p class="config-note">Labels des canaux de votre carte son. La liste est déterminée par le device sélectionné en <strong>Configuration</strong>.</p>
<div class="channel-names-grid">
<div class="channel-names-col">
<h4>Entrées</h4>
<div id="channel-names-inputs" class="channel-names-list">
<p class="empty-state">Chargement...</p>
</div>
</div>
<div class="channel-names-col">
<h4>Sorties</h4>
<div id="channel-names-outputs" class="channel-names-list">
<p class="empty-state">Chargement...</p>
</div>
</div>
</div>
</div>
<!-- Participants Serveur -->
<div class="section">
<h3>🎙️ Participants Serveur</h3>
<p class="config-note">Participants LiveKit côté serveur — chaque ligne branche des canaux physiques d'E/S sur un groupe.</p>
<button class="btn btn-primary btn-small" id="btn-add-server-audio-user"> Ajouter</button>
<div id="server-audio-users-list" class="sau-list"></div>
</div>
<!-- Actions -->
<div class="routing-actions">
<button class="btn btn-primary" id="btn-save-routing">Sauvegarder noms de canaux</button>
<button class="btn btn-secondary" id="btn-reload-routing">Recharger</button>
</div>
</div>
<!-- Monitoring View -->
<div id="view-monitoring" class="view">
<h2>Monitoring Audio</h2>
<div class="section">
<h3>🔊 VU-Mètres</h3>
<div id="vu-meters" class="vu-meters">
<p class="empty-state">En attente de données audio...</p>
</div>
</div>
</div>
<!-- Logs View -->
<div id="view-logs" class="view">
<h2>Logs Serveur</h2>
<div class="logs-controls">
<button class="btn btn-small" id="btn-clear-logs">Effacer</button>
<button class="btn btn-small btn-secondary" id="btn-export-logs">Exporter JSON</button>
<select id="log-level-filter" class="form-control form-control-small">
<option value="">Tous les niveaux</option>
<option value="error">Erreurs</option>
<option value="warn">Warnings</option>
<option value="info">Info</option>
<option value="debug">Debug</option>
</select>
</div>
<div id="logs-container" class="logs-container">
<p class="empty-state">Aucun log</p>
</div>
</div>
</div>
</main>
</div>
<!-- Modal générique -->
<div id="modal-overlay" class="modal-overlay hidden">
<div class="modal">
<div class="modal-header">
<h3 id="modal-title"></h3>
</div>
<div class="modal-body" id="modal-body"></div>
<div class="modal-footer">
<button class="btn btn-secondary" id="modal-cancel">Annuler</button>
<button class="btn btn-primary" id="modal-confirm">Confirmer</button>
</div>
</div>
</div>
<!-- Le QR Code est généré côté Main Process (lib qrcode Node), pas de dépendance CDN -->
<script src="app.js"></script>
</body>
</html>