From fa8a5c1b457634ad314419f352f2cc2452da60a4 Mon Sep 17 00:00:00 2001 From: Matthew Grotke Date: Tue, 26 May 2026 00:28:04 -0400 Subject: [PATCH] Development --- docker/routlin-dash/app/config_utils.py | 34 +++++++++++++++++++++++++ docker/routlin-dash/app/view_page.py | 29 ++++++++++----------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/docker/routlin-dash/app/config_utils.py b/docker/routlin-dash/app/config_utils.py index 7319787..6107d65 100644 --- a/docker/routlin-dash/app/config_utils.py +++ b/docker/routlin-dash/app/config_utils.py @@ -166,6 +166,40 @@ def get_dashboard_done(): return items +def get_done_timestamps(): + """Return dict of {uuid: applied_ts} from .dashboard-done.""" + result = {} + try: + for line in open(DASHBOARD_DONE).read().splitlines(): + if not line.strip(): + continue + parts = line.split(None, 1) + if len(parts) >= 2: + result[parts[0]] = int(parts[1]) + elif len(parts) == 1: + result[parts[0]] = None + except Exception: + pass + return result + + +def load_all_snapshots(): + """Return all snapshot dicts from .snapshots/, sorted newest first.""" + snaps = [] + try: + for fname in sorted(os.listdir(SNAPSHOTS_DIR), reverse=True): + if not fname.endswith('.json'): + continue + try: + with open(os.path.join(SNAPSHOTS_DIR, fname)) as f: + snaps.append(json.load(f)) + except Exception: + pass + except Exception: + pass + return snaps + + def flush_pending_to_queue(): """Move all entries from .dashboard-pending to .dashboard-queue and clear pending.""" items = _read_dashboard_pending() diff --git a/docker/routlin-dash/app/view_page.py b/docker/routlin-dash/app/view_page.py index 7fde6dd..ab5acf6 100644 --- a/docker/routlin-dash/app/view_page.py +++ b/docker/routlin-dash/app/view_page.py @@ -4,7 +4,7 @@ import json, re, subprocess, os, sys, html as html_mod import sanitize import validation as validate from datetime import datetime, timezone -from config_utils import config_hash, get_pending_entries, get_dashboard_pending, get_dashboard_done, load_snapshot_for_uuid, queue_command, _apply_changes_immediately, _seconds_until_next_run, _format_timing, _is_locked, _lock_mtime, WEB_APP_DISPLAY_NAME, CONFIGS_DIR, DATA_DIR +from config_utils import config_hash, get_pending_entries, get_dashboard_pending, get_dashboard_done, load_snapshot_for_uuid, load_all_snapshots, get_done_timestamps, queue_command, _apply_changes_immediately, _seconds_until_next_run, _format_timing, _is_locked, _lock_mtime, WEB_APP_DISPLAY_NAME, CONFIGS_DIR, DATA_DIR bp = Blueprint('view_page', __name__) @@ -622,24 +622,23 @@ def collect_tokens(): tokens['PENDING_ACTIONS_HTML'] = pending_html tokens['NO_PENDING'] = 'true' if not pending_items else '' - done_items = get_dashboard_done() - if done_items: + all_snaps = load_all_snapshots() + done_ts_map = get_done_timestamps() + if all_snaps: hist_rows = '' _hist_onclick = ( 'onclick="if(event.target.type!==\'checkbox\')' 'this.nextElementSibling.hidden=!this.nextElementSibling.hidden"' ) - for _uuid, applied_ts in done_items: - snap = load_snapshot_for_uuid(_uuid) - if applied_ts: - dt_str = datetime.fromtimestamp(applied_ts).strftime('%Y-%m-%d %H:%M') - else: - dt_str = '-' - snap_desc = e(snap['description']) if snap else '' - before_val = snap.get('before') if snap else None - after_val = snap.get('after') if snap else None - snap_id = e(_uuid[:8]) if snap else '' - snap_user = e(snap['user']) if snap else '' + for snap in all_snaps: + _uuid = snap.get('uuid', '') + applied_ts = done_ts_map.get(_uuid) + dt_str = datetime.fromtimestamp(applied_ts).strftime('%Y-%m-%d %H:%M') if applied_ts else '-' + snap_desc = e(snap.get('description', '')) + before_val = snap.get('before') + after_val = snap.get('after') + snap_id = e(_uuid[:8]) + snap_user = e(snap.get('user', '')) hist_rows += (f'' f'' f'{e(dt_str)}' @@ -671,7 +670,7 @@ def collect_tokens(): else: history_html = '

No change history.

' tokens['CHANGE_HISTORY_HTML'] = history_html - tokens['NO_HISTORY'] = 'true' if not done_items else '' + tokens['NO_HISTORY'] = 'true' if not all_snaps else '' servers = dns.get('upstream_servers', []) tokens['DNS_STRICT_ORDER'] = 'true' if dns.get('strict_order') else 'false'