diff --git a/app/app.py b/app/app.py index 7af1b54..5cfb695 100644 --- a/app/app.py +++ b/app/app.py @@ -248,6 +248,12 @@ def collect_all(): logger.info("Collection complete, updated %d servers", len(results)) +_collect_event = threading.Event() + +def trigger_collect(): + """Wake up the collector loop to run immediately.""" + _collect_event.set() + def collector_loop(): time.sleep(2) # Brief pause to let Flask start while True: @@ -255,7 +261,8 @@ def collector_loop(): collect_all() except Exception as e: logger.error("Collection loop error: %s", e) - time.sleep(COLLECTION_INTERVAL) + _collect_event.wait(timeout=COLLECTION_INTERVAL) + _collect_event.clear() # --- Web Routes --- @@ -297,6 +304,54 @@ def api_servers(): return jsonify(result) +@app.route('/api/refresh', methods=['POST']) +def api_refresh(): + trigger_collect() + return jsonify({'ok': True, 'message': 'Collection triggered'}) + + +@app.route('/api/servers//refresh', methods=['POST']) +def api_refresh_one(server_id): + server = Server.query.get_or_404(server_id) + try: + ssh_key = load_ssh_key() + except Exception as e: + return jsonify({'ok': False, 'error': str(e)}), 500 + + entry = { + 'group': server.group_name, + 'username': server.username, + 'hostname': server.hostname, + 'url': server.url, + } + result = collect_one(entry, ssh_key) + + server.is_online = result.get('is_online', False) + server.last_collected = datetime.now(timezone.utc) + server.details = result + + # Extract primary IP + default_iface = '' + routing = result.get('routing', {}) + if isinstance(routing, dict): + default_iface = routing.get('interface', '') + primary_ip = '' + for iface in result.get('net', []): + ipv4 = iface.get('ipv4', '') + if not ipv4 or ipv4.startswith('127.'): + continue + iface_name = iface.get('name', '') or iface.get('_name', '') + if iface_name == default_iface: + primary_ip = ipv4 + break + if not primary_ip: + primary_ip = ipv4 + server.primary_ip = primary_ip + + db.session.commit() + return jsonify({'ok': True}) + + @app.route('/api/servers//notes', methods=['PUT']) def api_update_notes(server_id): from flask import request diff --git a/app/static/style.css b/app/static/style.css index a476a24..6155285 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -31,6 +31,50 @@ header h1 { color: #64748b; } +.refresh-btn { + margin-left: auto; + background: #334155; + color: #94a3b8; + border: 1px solid #475569; + border-radius: 6px; + padding: 4px 12px; + font-size: 0.8rem; + cursor: pointer; + transition: all 0.2s; +} + +.refresh-btn:hover { + background: #3b82f6; + color: #fff; + border-color: #3b82f6; +} + +.refresh-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.refresh-btn-sm { + margin-left: auto; + background: none; + color: #475569; + border: none; + font-size: 0.85rem; + cursor: pointer; + padding: 0 4px; + transition: color 0.2s; + flex-shrink: 0; +} + +.refresh-btn-sm:hover { + color: #3b82f6; +} + +.refresh-btn-sm:disabled { + opacity: 0.4; + cursor: not-allowed; +} + main { max-width: 1400px; margin: 0 auto; diff --git a/app/templates/index.html b/app/templates/index.html index 03b8c4a..1f928ce 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -10,6 +10,7 @@

Infrastructure Map

Auto-refreshes every 60s | Built: {{ build_date }} +
@@ -52,6 +53,7 @@ {% if server.url %} {% endif %} +
{{ server.primary_ip or 'No IP' }}
{% if sys.get('platform') %}{{ sys.get('platform')|capitalize }} {{ sys.get('platform_version', '') }} / {% endif %}{{ sys.get('os_pretty', '') }}
@@ -411,6 +413,22 @@ if (card) toggleDetails(card); } + function refreshServer(btn, serverId) { + btn.disabled = true; + btn.textContent = '...'; + fetch('/api/servers/' + serverId + '/refresh', {method: 'POST'}) + .then(() => location.reload()); + } + + function triggerRefresh(btn) { + btn.disabled = true; + btn.textContent = 'Collecting...'; + fetch('/api/refresh', {method: 'POST'}).then(() => { + // Wait a few seconds for collection to finish, then reload + setTimeout(() => location.reload(), 8000); + }); + } + // If no servers have data yet, refresh quickly; otherwise every 60s const hasData = document.querySelectorAll('.server-card').length > 0; const refreshMs = hasData ? 60000 : 5000;