live reloading of detected things

This commit is contained in:
Michael Neale
2025-11-14 16:31:46 +11:00
parent 0466405d87
commit 8d8ddbe4b9
4 changed files with 45 additions and 7 deletions

View File

@@ -3,7 +3,7 @@ use anyhow::Result;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use std::path::PathBuf; use std::path::PathBuf;
use sysinfo::{System, Pid, Process}; use sysinfo::{System, Pid, Process};
use tracing::{debug, warn}; use tracing::{debug, info, warn};
pub struct ProcessDetector { pub struct ProcessDetector {
system: System, system: System,
@@ -17,7 +17,11 @@ impl ProcessDetector {
} }
pub fn detect_instances(&mut self) -> Result<Vec<Instance>> { pub fn detect_instances(&mut self) -> Result<Vec<Instance>> {
self.system.refresh_processes(); info!("Scanning for g3 processes...");
// Refresh all processes to ensure we catch newly started ones
// Using refresh_all() instead of just refresh_processes() to ensure
// we get complete information about new processes
self.system.refresh_all();
let mut instances = Vec::new(); let mut instances = Vec::new();
// Find all g3 processes // Find all g3 processes
@@ -33,7 +37,7 @@ impl ProcessDetector {
} }
} }
debug!("Detected {} g3 instances", instances.len()); info!("Detected {} g3 instances", instances.len());
Ok(instances) Ok(instances)
} }
@@ -168,7 +172,7 @@ impl ProcessDetector {
} }
pub fn get_process_status(&mut self, pid: u32) -> Option<InstanceStatus> { pub fn get_process_status(&mut self, pid: u32) -> Option<InstanceStatus> {
self.system.refresh_processes(); self.system.refresh_all();
let sysinfo_pid = Pid::from_u32(pid); let sysinfo_pid = Pid::from_u32(pid);
if self.system.process(sysinfo_pid).is_some() { if self.system.process(sysinfo_pid).is_some() {

View File

@@ -15,7 +15,7 @@
<div id="app"> <div id="app">
<header class="header"> <header class="header">
<div class="header-content"> <div class="header-content">
<h1 class="header-title">G3 Console</h1> <h1 class="header-title">G3 Console <span id="live-indicator" class="live-indicator" title="Scanning for processes every 3 seconds">● LIVE</span></h1>
<div class="header-actions"> <div class="header-actions">
<button id="new-run-btn" class="btn btn-primary">+ New Run</button> <button id="new-run-btn" class="btn btn-primary">+ New Run</button>
<button id="theme-toggle" class="btn btn-secondary">🌙</button> <button id="theme-toggle" class="btn btn-secondary">🌙</button>

View File

@@ -6,6 +6,7 @@ const router = {
currentInstanceId: null, currentInstanceId: null,
initialized: false, initialized: false,
renderInProgress: false, renderInProgress: false,
REFRESH_INTERVAL_MS: 3000, // Refresh every 3 seconds for live updates
init() { init() {
console.log('[Router] init() called'); console.log('[Router] init() called');
@@ -84,6 +85,9 @@ const router = {
this.renderInProgress = true; this.renderInProgress = true;
try { try {
// Flash live indicator
this.flashLiveIndicator();
// Check if we already have a container for instances // Check if we already have a container for instances
let instancesList = container.querySelector('.instances-list'); let instancesList = container.querySelector('.instances-list');
const isInitialLoad = !instancesList; const isInitialLoad = !instancesList;
@@ -167,11 +171,11 @@ const router = {
// Schedule next refresh only if still on home route // Schedule next refresh only if still on home route
if (this.currentRoute === '/' || this.currentRoute === '') { if (this.currentRoute === '/' || this.currentRoute === '') {
console.log('[Router] Scheduling auto-refresh in 5 seconds'); console.log(`[Router] Scheduling auto-refresh in ${this.REFRESH_INTERVAL_MS}ms`);
this.refreshTimeout = setTimeout(() => { this.refreshTimeout = setTimeout(() => {
console.log('[Router] Auto-refresh triggered'); console.log('[Router] Auto-refresh triggered');
this.renderHome(container); this.renderHome(container);
}, 5000); }, this.REFRESH_INTERVAL_MS);
} }
} catch (error) { } catch (error) {
console.error('[Router] Error in renderHome:', error); console.error('[Router] Error in renderHome:', error);
@@ -187,12 +191,26 @@ const router = {
} }
}, },
flashLiveIndicator() {
const indicator = document.getElementById('live-indicator');
if (indicator) {
indicator.style.animation = 'none';
// Force reflow
void indicator.offsetWidth;
indicator.style.animation = null;
indicator.style.opacity = '1';
}
},
async renderDetail(container, id) { async renderDetail(container, id) {
console.log('[Router] renderDetail called for', id); console.log('[Router] renderDetail called for', id);
this.currentInstanceId = id; this.currentInstanceId = id;
try { try {
// Flash live indicator
this.flashLiveIndicator();
// Check if we already have a detail view for this instance // Check if we already have a detail view for this instance
let detailView = container.querySelector('.detail-view'); let detailView = container.querySelector('.detail-view');
const isInitialLoad = !detailView || detailView.getAttribute('data-instance-id') !== id; const isInitialLoad = !detailView || detailView.getAttribute('data-instance-id') !== id;

View File

@@ -64,6 +64,22 @@ body {
color: var(--text-primary); color: var(--text-primary);
} }
.live-indicator {
font-size: 0.625rem; /* 75% of 0.833rem */
font-weight: 600;
color: var(--success);
margin-left: 0.75rem;
display: inline-flex;
align-items: center;
gap: 0.25rem;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.header-actions { .header-actions {
display: flex; display: flex;
gap: 1rem; gap: 1rem;