Development
This commit is contained in:
parent
adcfe55c7c
commit
59d3d65d18
7 changed files with 146 additions and 75 deletions
|
|
@ -594,22 +594,27 @@ def collect_tokens():
|
|||
pending_items = get_dashboard_pending()
|
||||
if pending_items:
|
||||
rows = ''
|
||||
_tr_onclick = (
|
||||
'onclick="if(event.target.type!==\'checkbox\')'
|
||||
'this.nextElementSibling.hidden=!this.nextElementSibling.hidden"'
|
||||
)
|
||||
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 = 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_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 ''
|
||||
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">{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>')
|
||||
rows += (f'<tr style="cursor:pointer" {_tr_onclick}>'
|
||||
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">{snap_desc}</td>'
|
||||
f'<td class="table-cell">{_render_snap_val(before_val)}</td>'
|
||||
f'<td class="table-cell">{_render_snap_val(after_val)}</td>'
|
||||
f'<td class="table-cell">{snap_id}</td>'
|
||||
f'<td class="table-cell">{e(user)}</td>'
|
||||
f'</tr>'
|
||||
f'{_snap_expand_row(before_val, after_val, 7)}')
|
||||
select_all = (
|
||||
'<input type="checkbox" '
|
||||
'onchange="document.querySelectorAll(\'[name=selected_uuids]\').forEach(c=>c.checked=this.checked)"/>'
|
||||
|
|
@ -636,25 +641,27 @@ def collect_tokens():
|
|||
done_items = get_dashboard_done()
|
||||
if done_items:
|
||||
hist_rows = ''
|
||||
_hist_onclick = 'onclick="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_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 ''
|
||||
snap_user = e(snap['user']) if snap else ''
|
||||
hist_rows += (f'<tr>'
|
||||
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 ''
|
||||
hist_rows += (f'<tr style="cursor:pointer" {_hist_onclick}>'
|
||||
f'<td class="table-cell">{e(dt_str)}</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">{_render_snap_val(before_val)}</td>'
|
||||
f'<td class="table-cell">{_render_snap_val(after_val)}</td>'
|
||||
f'<td class="table-cell">{snap_id}</td>'
|
||||
f'<td class="table-cell">{snap_user}</td>'
|
||||
f'</tr>')
|
||||
f'</tr>'
|
||||
f'{_snap_expand_row(before_val, after_val, 6)}')
|
||||
history_html = (
|
||||
'<table class="data-table" style="margin-bottom:1rem">'
|
||||
'<thead><tr>'
|
||||
|
|
@ -813,25 +820,42 @@ 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."""
|
||||
def _snap_text(val):
|
||||
"""Return the plain-text representation of a snapshot before/after 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)
|
||||
return f'{k}: {v}'
|
||||
if isinstance(val, (dict, list)):
|
||||
return json.dumps(val, separators=(',', ':'))
|
||||
return str(val)
|
||||
|
||||
|
||||
def _render_snap_val(val):
|
||||
"""Return truncated escaped HTML for a snapshot before/after table cell."""
|
||||
text = _snap_text(val)
|
||||
if not text:
|
||||
return ''
|
||||
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>')
|
||||
return e(trunc)
|
||||
|
||||
|
||||
def _snap_expand_row(before_val, after_val, colspan):
|
||||
"""Return a hidden <tr> that expands with full before/after content."""
|
||||
pre = ('max-height:200px;overflow-y:auto;white-space:pre-wrap;'
|
||||
'font-size:0.85em;background:#fff;border:1px solid #ddd;'
|
||||
'padding:0.5rem;margin:0.25rem 0')
|
||||
def box(label, val):
|
||||
text = _snap_text(val) if val is not None else ''
|
||||
if isinstance(val, (dict, list)):
|
||||
text = json.dumps(val, indent=2)
|
||||
body = e(text) if text else '<em>(none)</em>'
|
||||
return f'<div style="flex:1;min-width:0"><strong>{label}</strong><pre style="{pre}">{body}</pre></div>'
|
||||
inner = f'<div style="display:flex;gap:1rem">{box("Before", before_val)}{box("After", after_val)}</div>'
|
||||
return (f'<tr hidden>'
|
||||
f'<td colspan="{colspan}" style="padding:0.5rem 1rem;background:#f8f8f8">'
|
||||
f'{inner}</td></tr>')
|
||||
|
||||
|
||||
def apply_tokens(text, tokens):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue