live reloading of detected things
This commit is contained in:
@@ -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() {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user