Add active WebSocket client tracking and display
Track and display the number of active WebSocket connections viewing the aircraft tracker. Features: Backend: - Add getActiveClientCount() method for thread-safe client counting - Include active_clients count in all statistics responses - Integrate with existing stats API endpoints Frontend: - Display "X viewer(s)" in header stats with proper plural/singular grammar - Add "Active Viewers" card to Statistics view - Real-time updates as clients connect/disconnect - Fallback to 1 when stats not yet available This adds a social element showing "Now being watched by X users" style information prominently in the interface. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
802e964cc0
commit
6414ea72f1
3 changed files with 34 additions and 4 deletions
|
|
@ -54,6 +54,7 @@
|
|||
<div class="stats-summary">
|
||||
<span id="aircraft-count">0 aircraft</span>
|
||||
<span id="sources-count">0 sources</span>
|
||||
<span id="active-clients">1 viewer</span>
|
||||
<span id="connection-status" class="connection-status disconnected">Connecting...</span>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -195,6 +196,10 @@
|
|||
<h3>Active Sources</h3>
|
||||
<div class="stat-value" id="active-sources">0</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<h3>Active Viewers</h3>
|
||||
<div class="stat-value" id="active-viewers">1</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<h3>Messages/sec</h3>
|
||||
<div class="stat-value" id="messages-sec">0</div>
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ export class UIManager {
|
|||
updateStatistics() {
|
||||
const totalAircraftEl = document.getElementById('total-aircraft');
|
||||
const activeSourcesEl = document.getElementById('active-sources');
|
||||
const activeViewersEl = document.getElementById('active-viewers');
|
||||
const maxRangeEl = document.getElementById('max-range');
|
||||
const messagesSecEl = document.getElementById('messages-sec');
|
||||
|
||||
|
|
@ -248,6 +249,9 @@ export class UIManager {
|
|||
if (activeSourcesEl) {
|
||||
activeSourcesEl.textContent = Array.from(this.sourcesData.values()).filter(s => s.active).length;
|
||||
}
|
||||
if (activeViewersEl) {
|
||||
activeViewersEl.textContent = this.stats.active_clients || 1;
|
||||
}
|
||||
|
||||
// Calculate max range
|
||||
let maxDistance = 0;
|
||||
|
|
@ -267,10 +271,18 @@ export class UIManager {
|
|||
updateHeaderInfo() {
|
||||
const aircraftCountEl = document.getElementById('aircraft-count');
|
||||
const sourcesCountEl = document.getElementById('sources-count');
|
||||
const activeClientsEl = document.getElementById('active-clients');
|
||||
|
||||
if (aircraftCountEl) aircraftCountEl.textContent = `${this.aircraftData.size} aircraft`;
|
||||
if (sourcesCountEl) sourcesCountEl.textContent = `${this.sourcesData.size} sources`;
|
||||
|
||||
// Update active clients count
|
||||
const clientCount = this.stats.active_clients || 1;
|
||||
if (activeClientsEl) {
|
||||
const clientText = clientCount === 1 ? 'viewer' : 'viewers';
|
||||
activeClientsEl.textContent = `${clientCount} ${clientText}`;
|
||||
}
|
||||
|
||||
this.updateClocks();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue