feat(mobile): read and comment on pages from the phone

Merged
HA
2mo ago
+4414-58

Summary

  • Adds Pages to the mobile app: a native list, a WebView viewer, and the element-picker comment flow (remove / comment / quick feedback / approve).
  • The shared comment runtime is unchanged — host and frame already talk over postMessage, never the DOM, so a WebView is a drop-in for desktop's iframe.

Why / Context

Pages were desktop-only. The viewer is the whole point of the feature on a phone: an agent publishes a page, and you want to read it and leave feedback without opening a laptop.

How It Works

Viewer. page.pull already returns a signed viewUrl on the usercontent worker — exactly what desktop's <iframe src> loads (PageFrame.tsx:24 on the desktop side). Mobile loads the same URL in a WebView, so there is no auth or asset-resolution problem: the tRPC call is already authenticated and the page keeps its own origin.

Bridge. The runtime posts with parent.postMessage (page-comments-runtime.ts:69). In a WebView the page is the top document, so parent === window and that lands as a message event on its own window. An injected listener forwards those to React Native; host messages go back as a plain window.postMessage, which the runtime's own listener (line 242) already handles. Nothing in packages/shared changed.

Comment mode. The runtime's pick is driven by a click with clientX/Y (line 191) — hover only drives the highlight preview — so a tap already produces a pick with anchor + rect. No new gesture, no runtime change.

Manual QA Checklist

Validated on iPhone 16e simulator against production data.

  • Pages list renders with thumbnails, owner, visibility icon, date
  • Pull-to-refresh works
  • Tapping a page opens the viewer; page renders with assets
  • Links inside a page open in the system browser, not the frame
  • Focus (comment-mode) toolbar button toggles the picker
  • Tapping a block highlights it and shows the toolbar
  • Toolbar clamps inside the frame near edges
  • Quick feedback sheet posts a preset
  • Write-a-comment sheet posts and the pin appears
  • All comments sheet lists threads; tapping opens the thread
  • Thread opens scrolled to the composer
  • Not verified: resolve/reopen round-trip, agent-authored comment rendering, a page whose viewUrl ticket expires while open

Testing

  • bun run typecheck — 38/38 tasks pass
  • bun run lint — clean
  • bun run check:i18n — all 17 locales compile --strict
  • bunx sherif — clean
  • bun test apps/mobile/screens/.../pages — 11 pass (new: pinLayout, toolbarPlacement)

bun test repo-wide has 40 failures, all in packages/agent-setup, the node-pty patch guard, and host-service process/socket utils — tests that spawn processes or open sockets. None touch this diff, but I did not verify them against a clean tree.

Design Decisions

  • WebView on viewUrl, not inlined HTML. A page version is a document plus assets served by the worker, so source={{ html }} would break relative asset refs and lose the page's own origin.
  • Sheets as formSheet routes per apps/mobile/AGENTS.md, with a transient zustand store carrying the pick. Route params would have to carry a 2000-char anchor path.
  • Absolute dates instead of formatRelativeTime. Hermes ships no Intl.RelativeTimeFormat, and apps/mobile/lib/intl-polyfills installs only Locale and PluralRules. formatDate uses Intl.DateTimeFormat, which Hermes has. Adding the polyfill means a new dependency plus 16 locale-data imports — deferred deliberately.

Known Limitations

  • No intent on remove/approve. The enum lands in #7359, which is not on main and whose migration is unapplied. Those two buttons post their preset text as ordinary comments, so nothing downstream can distinguish them yet. Wiring intent is one line per action once that merges.
  • Catalog collision with #7359. Twelve msgids overlap (the ten QUICK_PRESETS, "Looks good", "Delete this"). Lingui keys on English text, so every messages.po will conflict on merge. #7359's translations should win — they went through review alongside the intent work.
  • pinLayout is duplicated, not shared. It belongs in @superset/shared next to the runtime types it imports, but #7359 rewrites pinLayout.ts heavily and moving it now guarantees a conflict. Follow-up.
  • Pins lag a fling. Rects cross the RN bridge per frame; desktop gets this free from a same-process iframe. Acceptable at rest, visible while scrolling fast.

Follow-ups

  • Wire intent and consolidate pinLayout into @superset/shared after #7359.
  • Search and scope tabs on the list (desktop has All/Pinned/Team/Just me).
  • Edit and delete a comment; agent-activation affordance.

Summary by cubic

Adds native mobile browsing and commenting for published Pages. Links to same-origin /page/<slug> URLs that previously opened in Safari now open an in-app preview sheet; all other links still open externally.

  • Uses the existing signed viewUrl and comment runtime through a WebView bridge.
  • Supports element comments, quick feedback, replies, threads, pins, and optimistic resolve with rollback; remove and approve still post preset text as regular comments.
  • Pages now live in the organization sheet, with org switching on its own screen.
  • Comment composition is a native pill composer; sharing is an in-app sheet with copy link, access, and version, read-only for non-creators.
  • Keeps page links and subframes in the reader, retries failed or expired loads with a fresh ticket, preserves scroll position when expanding a preview, and lets only http/https links open externally while worker redirects for expired tickets pass through.
  • Clips off-screen pins, caches pulled pages per slug and organization, distinguishes offline from empty in the list, and surfaces resolve failures.
  • Adds loading, empty, error, retry, pull-to-refresh, localized copy, pin layout, toolbar placement, and link parsing tests.
  • Keeps the Pages shortcut available when the selected host is offline.

Summary by CodeRabbit

  • New Features
    • Added mobile page browsing with persistent filters for all, team, or personal pages.
    • Added page sharing controls, visibility settings, version selection, and link copying.
    • Added comment threads, replies, inline comment pins, quick feedback, and review actions.
    • Added clearer offline, loading, and error states.
    • Added organization switching and improved page navigation.
  • Localization
    • Added and updated translations for page, comment, review, sharing, and connection-related messages across supported languages.
  • Bug Fixes
    • CLI tables now display full URLs without truncation while preserving layout.
    • Mobile link handling now validates URLs before opening them.