feat: event detail page styling and deleted events indicator

- Fix event detail page for direct navigation by using FastHTML's
  idiomatic htmx parameter instead of manual header check
- Add custom toaster.py with HTML support using NotStr to render
  clickable links in toast messages
- Add hx_preserve to toast container to survive HTMX body swaps
- Add is_deleted column to event_log_by_location table
- Update event_log projection revert() to set is_deleted flag
  instead of deleting rows
- Add strikethrough styling for deleted events in event log

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-03 11:03:47 +00:00
parent e86af247da
commit 240cf440cb
8 changed files with 158 additions and 52 deletions

View File

@@ -405,19 +405,23 @@ class TestEventLogProjectionRevert:
event = make_product_collected_event(event_id, location_id, animal_ids)
projection.apply(event)
# Verify row exists
count = seeded_db.execute("SELECT COUNT(*) FROM event_log_by_location").fetchone()[0]
assert count == 1
# Verify row exists and is not deleted
row = seeded_db.execute(
"SELECT is_deleted FROM event_log_by_location WHERE event_id = ?", (event_id,)
).fetchone()
assert row[0] == 0
# Revert
projection.revert(event)
# Verify row removed
count = seeded_db.execute("SELECT COUNT(*) FROM event_log_by_location").fetchone()[0]
assert count == 0
# Verify row is marked as deleted (not removed)
row = seeded_db.execute(
"SELECT is_deleted FROM event_log_by_location WHERE event_id = ?", (event_id,)
).fetchone()
assert row[0] == 1
def test_revert_only_affects_specific_event(self, seeded_db):
"""Revert only removes the specific event log entry."""
"""Revert only marks the specific event log entry as deleted."""
row = seeded_db.execute("SELECT id FROM locations WHERE name = 'Strip 1'").fetchone()
location_id = row[0]
@@ -439,16 +443,23 @@ class TestEventLogProjectionRevert:
)
projection.apply(event2)
# Verify both exist
# Verify both exist and are not deleted
count = seeded_db.execute("SELECT COUNT(*) FROM event_log_by_location").fetchone()[0]
assert count == 2
# Revert only event1
projection.revert(event1)
# Event2 should still exist
count = seeded_db.execute("SELECT COUNT(*) FROM event_log_by_location").fetchone()[0]
assert count == 1
# Event1 should be marked as deleted
row = seeded_db.execute(
"SELECT is_deleted FROM event_log_by_location WHERE event_id = ?",
("01ARZ3NDEKTSV4RRFFQ69G5001",),
).fetchone()
assert row[0] == 1
row = seeded_db.execute("SELECT event_id FROM event_log_by_location").fetchone()
assert row[0] == "01ARZ3NDEKTSV4RRFFQ69G5002"
# Event2 should still be active (not deleted)
row = seeded_db.execute(
"SELECT is_deleted FROM event_log_by_location WHERE event_id = ?",
("01ARZ3NDEKTSV4RRFFQ69G5002",),
).fetchone()
assert row[0] == 0