feat(home): multi-file upload + per-file analysis, drop tool grid

Home is now upload + analysis only. The page accepts multiple files in
one go, analyzes each independently, and renders findings grouped by
filename in bordered containers. The 3-section tool-card grid is gone —
discovery happens via the sidebar now.

Mechanics:
- file_uploader uses accept_multiple_files=True. Each file's findings
  cache in session_state["home_findings_by_file"] keyed by filename so
  removing a file via Streamlit's "x" button drops its findings too,
  and re-clicking Run only re-analyzes pending files.
- The first uploaded file is mirrored into the singular
  home_uploaded_{name,bytes,size} keys so tool pages continue to pick
  up an "active" upload through pickup_or_upload — no tool-page changes.
- New i18n keys: upload.intro_multi, upload.uploader_label_multi,
  upload.clear_results, upload.empty_state. upload.heading text is
  updated to "Upload one or more files to start" (EN + ES).

Dropped tests pinning the tool grid:
- TestHomeToolGridLocalization (test_chrome.py)
- test_home_tool_card_uses_es_name (test_smoke.py)
- TestLiteHomeGridBadges (test_lite_tier.py — locked-card lock-badge
  assertions; locking is still enforced per-tool-page via
  require_feature_or_render_upgrade)

2009 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 20:12:48 +00:00
parent dad744f17f
commit ff2eaeb6c4
6 changed files with 99 additions and 140 deletions

View File

@@ -94,36 +94,6 @@ class TestLiteLockedPages:
)
# ---------------------------------------------------------------------------
# Home grid shows lock badges
# ---------------------------------------------------------------------------
class TestLiteHomeGridBadges:
def test_locked_tool_card_shows_lock_badge(
self, lite_license, home_app,
):
home_app.run()
text = collected_text(home_app)
# Fix Missing Values is locked under Lite — its card should
# have a 🔒 Locked badge.
# We assert the lock glyph appears alongside the locked tool's
# display name. Streamlit renders the markdown verbatim so the
# ``🔒 Locked`` text appears in the page markdown stream.
assert "🔒" in text or "Locked" in text, (
"home grid missing lock badge for Lite-locked tool"
)
def test_unlocked_tool_card_no_lock(self, lite_license, home_app):
home_app.run()
# Dedup is unlocked under Lite. Its card markdown should NOT
# contain a lock glyph adjacent to its name. We can't easily
# scope by card without parsing the markdown stream, but we
# can confirm both ``Ready`` (unlocked) and ``Locked``
# (locked) badges coexist on the page.
text = collected_text(home_app)
assert "Ready" in text or "Listo" in text
# ---------------------------------------------------------------------------
# Sidebar status shows Lite
# ---------------------------------------------------------------------------