Development

This commit is contained in:
Matthew Grotke 2026-05-25 16:07:21 -04:00
parent b63aed53fc
commit 6221ee3691
12 changed files with 511 additions and 245 deletions

View file

@ -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 core_hash, get_pending_entries, get_dashboard_pending, _seconds_until_next_run, _format_timing, _is_locked, _lock_mtime, WEB_APP_DISPLAY_NAME, CONFIGS_DIR, DATA_DIR
from config_utils import core_hash, get_pending_entries, get_dashboard_pending, load_snapshot_for_uuid, _seconds_until_next_run, _format_timing, _is_locked, _lock_mtime, WEB_APP_DISPLAY_NAME, CONFIGS_DIR, DATA_DIR
bp = Blueprint('view_page', __name__)
@ -594,16 +594,21 @@ def collect_tokens():
pending_items = get_dashboard_pending()
if pending_items:
rows = ''
for _uuid, ts, cmd, user, desc in pending_items:
dt_str = datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M')
for _uuid, ts, cmd, user in pending_items:
snap = load_snapshot_for_uuid(_uuid)
dt_str = datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M')
snap_desc = e(snap['description']) if snap else ''
before_html = _render_snap_val(snap.get('before') if snap else None)
after_html = _render_snap_val(snap.get('after') if snap else None)
snap_id = e(_uuid[:8]) if snap else ''
rows += (f'<tr>'
f'<td class="table-cell"><input type="checkbox" name="selected_uuids" value="{e(_uuid)}"/></td>'
f'<td class="table-cell">{e(dt_str)}</td>'
f'<td class="table-cell">{e(cmd)}</td>'
f'<td class="table-cell">{e(desc)}</td>'
f'<td class="table-cell"></td>'
f'<td class="table-cell"></td>'
f'<td class="table-cell"></td>'
f'<td class="table-cell">{snap_desc}</td>'
f'<td class="table-cell">{before_html}</td>'
f'<td class="table-cell">{after_html}</td>'
f'<td class="table-cell">{snap_id}</td>'
f'<td class="table-cell">{e(user)}</td>'
f'</tr>')
select_all = (
@ -769,6 +774,28 @@ def collect_tokens():
def e(text):
return html_mod.escape(str(text))
def _render_snap_val(val):
"""Return an HTML string for a snapshot before/after cell value."""
if val is None:
return ''
if isinstance(val, dict) and len(val) == 1:
k, v = next(iter(val.items()))
text = f'{k}: {v}'
elif isinstance(val, (dict, list)):
text = json.dumps(val, separators=(',', ':'))
else:
text = str(val)
trunc = (text[:23] + '') if len(text) > 24 else text
if trunc == text:
return e(text)
return (f'<details style="display:inline">'
f'<summary style="cursor:pointer;list-style:none">{e(trunc)}</summary>'
f'<pre style="margin:0.5rem 0;white-space:pre-wrap;font-size:0.85em">'
f'{e(json.dumps(val, indent=2) if isinstance(val, (dict, list)) else text)}'
f'</pre></details>')
def apply_tokens(text, tokens):
"""Substitute %TOKEN% placeholders. Values are NOT auto-escaped - callers
that use results in HTML attribute or text context should call e() around