Development

This commit is contained in:
Matthew Grotke 2026-05-26 00:58:51 -04:00
parent 222f43feff
commit 3c7b13e98a
3 changed files with 21 additions and 6 deletions

View file

@ -404,6 +404,7 @@ def revert_snapshot_to_config(entry_uuid):
before=after, after=before,
description=f"Reverted: {snap.get('description', '')}",
cmd=snap.get('cmd', 'core apply'),
reverts=entry_uuid,
)
return msg or 'Reverted.', True
@ -421,7 +422,7 @@ def load_snapshot_for_uuid(entry_uuid):
def save_config_with_snapshot(new_config, path, key, operation, before, after,
description='', cmd='core apply', queue=True):
description='', cmd='core apply', queue=True, reverts=None):
"""
Write a .snapshots/{ts}-{uuid}.json file, save new_config to disk, and
optionally create a pending queue entry. Returns a flash message string.
@ -448,6 +449,7 @@ def save_config_with_snapshot(new_config, path, key, operation, before, after,
'before': before,
'after': after,
'depends_on': depends_on,
'reverts': reverts,
}
with open(os.path.join(SNAPSHOTS_DIR, f'{entry_ts}-{entry_uuid}.json'), 'w') as f:
json.dump(snapshot, f, indent=2)

View file

@ -632,6 +632,14 @@ def collect_tokens():
all_snaps = load_all_snapshots()
done_ts_map = get_done_timestamps()
if all_snaps:
# UUIDs that cannot be reverted: revert entries themselves, and entries
# that have already been reverted (referenced in another snap's 'reverts').
_no_revert = set()
for _s in all_snaps:
if _s.get('operation') == 'revert':
_no_revert.add(_s.get('uuid', ''))
if _s.get('reverts'):
_no_revert.add(_s['reverts'])
hist_rows = ''
_hist_onclick = (
'onclick="if(event.target.type!==\'checkbox\')'
@ -650,8 +658,9 @@ def collect_tokens():
f'<span class="tl-min">{e(_uuid[:8])}</span>'
f'</span></div>')
snap_user = e(snap.get('user', ''))
_cb_attrs = 'disabled title="Cannot revert"' if _uuid in _no_revert else ''
hist_rows += (f'<tr class="row-expandable" data-uuid="{e(_uuid)}" {_hist_onclick}>'
f'<td class="table-cell"><input type="checkbox" name="selected_uuids" value="{e(_uuid)}"/></td>'
f'<td class="table-cell"><input type="checkbox" name="selected_uuids" value="{e(_uuid)}" {_cb_attrs}/></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>'
@ -662,7 +671,7 @@ def collect_tokens():
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)"/>'
'onchange="document.querySelectorAll(\'[name=selected_uuids]:not(:disabled)\').forEach(c=>c.checked=this.checked)"/>'
)
history_html = (
'<table class="data-table">'

View file

@ -37,6 +37,7 @@ DASHB_LOCK_FILE = SCRIPT_DIR / ".dashboard-lock"
DASHB_PENDING_FILE = SCRIPT_DIR / ".dashboard-pending"
DASHB_SCRIPT_FILE = SCRIPT_DIR / "do_dashboard_queue.sh"
HEALTH_FILE = SCRIPT_DIR / ".health"
SNAPSHOTS_DIR = SCRIPT_DIR / ".snapshots"
# Dashboard systemd timer
DASHB_TIMER_NAME = f"{PRODUCT_NAME}-dashboard-queue"
@ -347,12 +348,15 @@ def setup_docker_compose(reuse_config=False):
def create_dotfiles():
dir_stat = SCRIPT_DIR.stat()
uid, gid = dir_stat.st_uid, dir_stat.st_gid
if not SNAPSHOTS_DIR.exists():
SNAPSHOTS_DIR.mkdir()
os.chown(SNAPSHOTS_DIR, uid, gid)
for f in (DASHB_QUEUE_FILE, DASHB_DONE_FILE, DASHB_LAST_RUN_FILE, DASHB_LOCK_FILE, DASHB_PENDING_FILE, HEALTH_FILE):
if not f.exists():
f.touch()
# chown to the routlin dir owner so the timer can write
stat = SCRIPT_DIR.stat()
os.chown(f, stat.st_uid, stat.st_gid)
os.chown(f, uid, gid)
# ===================================================================