diff --git a/app/__pycache__/app.cpython-312.pyc b/app/__pycache__/app.cpython-312.pyc
index 1656844..fcb7531 100644
Binary files a/app/__pycache__/app.cpython-312.pyc and b/app/__pycache__/app.cpython-312.pyc differ
diff --git a/app/app.py b/app/app.py
index 83dc115..fc331af 100644
--- a/app/app.py
+++ b/app/app.py
@@ -240,12 +240,6 @@ def collect_all():
# Update database (all in main collector thread)
with app.app_context():
- # Remove servers no longer in config
- config_keys = {(e['username'], e['hostname']) for e in entries}
- for server in Server.query.all():
- if (server.username, server.hostname) not in config_keys:
- db.session.delete(server)
-
for key, (entry, result) in results.items():
server = Server.query.filter_by(
username=entry['username'],
@@ -289,12 +283,23 @@ def collector_loop():
@app.route('/')
def index():
+ # Get group order from config file and filter to configured servers only
+ config_entries = parse_infrastructure_conf()
+ config_keys = {(e['username'], e['hostname']) for e in config_entries}
+ group_order = []
+ for e in config_entries:
+ g = e['group']
+ if g not in group_order:
+ group_order.append(g)
+
all_servers = Server.query.order_by(Server.group_name, Server.primary_ip).all()
- # Separate parents and children
+ # Separate parents and children (only servers in current config)
children_map = {} # parent_hostname -> [child_servers]
parents = []
for s in all_servers:
+ if (s.username, s.hostname) not in config_keys:
+ continue
if s.parent_hostname:
children_map.setdefault(s.parent_hostname, []).append(s)
else:
@@ -304,14 +309,6 @@ def index():
for hostname in children_map:
children_map[hostname].sort(key=lambda s: _ip_sort_key(s.primary_ip))
- # Get group order from config file
- config_entries = parse_infrastructure_conf()
- group_order = []
- for e in config_entries:
- g = e['group']
- if g not in group_order:
- group_order.append(g)
-
# Group parents, preserving config order
groups = {}
for s in parents:
@@ -430,11 +427,6 @@ def api_refresh_stream():
# Update database
with app.app_context():
- config_keys = {(e['username'], e['hostname']) for e in entries}
- for server in Server.query.all():
- if (server.username, server.hostname) not in config_keys:
- db.session.delete(server)
-
for key, (entry, result) in results.items():
server = Server.query.filter_by(
username=entry['username'], hostname=entry['hostname'],
@@ -530,19 +522,19 @@ def api_refresh_one_stream(server_id):
t.start()
# Stream progress while collecting
- while not host_done.is_set():
+ result = None
+ while not host_done.is_set() or not progress_q.empty():
try:
kind, val = progress_q.get(timeout=0.3)
if kind == 'progress':
yield f"data: {val}\n\n"
elif kind == 'result':
- break
+ result = val
except _queue.Empty:
continue
t.join()
- # Drain remaining messages
- result = None
+ # Drain anything remaining
while not progress_q.empty():
kind, val = progress_q.get_nowait()
if kind == 'progress':
@@ -592,18 +584,18 @@ def api_refresh_one_stream(server_id):
ct = threading.Thread(target=_collect_child)
ct.start()
- while not child_done.is_set():
+ child_result = None
+ while not child_done.is_set() or not child_q.empty():
try:
kind, val = child_q.get(timeout=0.3)
if kind == 'progress':
yield f"data: {val}\n\n"
elif kind == 'result':
- break
+ child_result = val
except _queue.Empty:
continue
ct.join()
- child_result = None
while not child_q.empty():
kind, val = child_q.get_nowait()
if kind == 'progress':
@@ -655,6 +647,33 @@ def api_update_links(server_id):
return jsonify({'ok': True})
+@app.route('/api/all-notes')
+def api_all_notes():
+ servers = Server.query.filter(Server.notes != '', Server.notes != None).all()
+ return jsonify([{
+ 'id': s.id,
+ 'hostname': s.hostname,
+ 'group_name': s.group_name,
+ 'notes': s.notes,
+ } for s in servers])
+
+
+@app.route('/api/all-links')
+def api_all_links():
+ servers = Server.query.filter(Server.links != None, Server.links != '[]').all()
+ result = []
+ for s in servers:
+ links = s.links or []
+ if links:
+ result.append({
+ 'id': s.id,
+ 'hostname': s.hostname,
+ 'group_name': s.group_name,
+ 'links': links,
+ })
+ return jsonify(result)
+
+
def _ip_sort_key(ip_str):
if not ip_str:
return [999, 999, 999, 999]
diff --git a/app/static/style.css b/app/static/style.css
index 02b32ed..5cfa83c 100644
--- a/app/static/style.css
+++ b/app/static/style.css
@@ -31,6 +31,22 @@ header h1 {
color: #64748b;
}
+.header-btn {
+ background: #334155;
+ color: #94a3b8;
+ border: 1px solid #475569;
+ border-radius: 6px;
+ padding: 4px 12px;
+ font-size: 0.8rem;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.header-btn:hover {
+ background: #475569;
+ color: #e2e8f0;
+}
+
.refresh-btn {
margin-left: auto;
background: #334155;
diff --git a/app/templates/index.html b/app/templates/index.html
index 7ec0a70..e5691f5 100644
--- a/app/templates/index.html
+++ b/app/templates/index.html
@@ -10,6 +10,8 @@
Infrastructure Map
Auto-refreshes every 60s | Built: {{ build_date }}
+
+