feat: replace Git-DAG timeline with flat snapshot browser

Replace HistoryTree (DAG with branches, Graphviz rendering) with a flat
chronological SnapshotTimeline. New UI features: split-view layout,
snapshot compare/diff, cherry-pick restore of individual sequences or
fields, auto-snapshots with debounce, and pin/filter support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-21 18:14:22 +01:00
parent 686d4687c3
commit 1ec3abf17a
9 changed files with 966 additions and 660 deletions
+8 -8
View File
@@ -295,12 +295,12 @@ def index():
sync_to_db, pane_state.db, pane_state.current_project, fp, data)
tree = data.get('history_tree')
if tree and isinstance(tree, dict):
for node in tree.get('nodes', {}).values():
node.pop('data', None)
for entry in tree.get('snapshots', tree.get('nodes', {})).values():
entry.pop('data', None)
for backup in data.get('history_tree_backup', []):
if isinstance(backup, dict):
for node in backup.get('nodes', {}).values():
node.pop('data', None)
for entry in backup.get('snapshots', backup.get('nodes', {})).values():
entry.pop('data', None)
pane_state.data_cache = data
pane_state.last_mtime = fp.stat().st_mtime if fp.exists() else 0
pane_state.loaded_file = str(fp)
@@ -339,13 +339,13 @@ def index():
sync_to_db, state.db, state.current_project, fp, data)
tree = data.get('history_tree')
if tree and isinstance(tree, dict):
for node in tree.get('nodes', {}).values():
node.pop('data', None)
for entry in tree.get('snapshots', tree.get('nodes', {})).values():
entry.pop('data', None)
# Strip snapshot data from history_tree_backup to prevent RAM/disk bloat
for backup in data.get('history_tree_backup', []):
if isinstance(backup, dict):
for node in backup.get('nodes', {}).values():
node.pop('data', None)
for entry in backup.get('snapshots', backup.get('nodes', {})).values():
entry.pop('data', None)
state.data_cache = data
state.last_mtime = fp.stat().st_mtime if fp.exists() else 0
state.loaded_file = str(fp)